An API description becomes harder to navigate as it grows. A server address sits near the top, a response refers to a schema near the bottom, and an operation may override a setting the document declares for the whole API. Without understanding those relationships, it is easy to put a correct piece of information in the wrong place.
This chapter explains the structure of an OpenAPI document, how its major sections connect, and how to read settings at different levels. The examples use OpenAPI 3.1.2 and a fictional bookstore's public catalog over HTTPS.
An OpenAPI document contains a root object, the outermost collection of named fields. In YAML, its fields start at the left margin. Nested objects hold more specific information, while arrays hold lists of entries.
The root provides the document's overall organization. It identifies the description format, supplies metadata, and connects the API's operations to shared definitions and settings.
This diagram shows a useful subset of that structure. Solid arrows represent nesting; the dashed arrow shows an operation using a definition elsewhere in the document.
The important relationship is between placement and purpose. Metadata describes the API generally. An operation describes a particular interaction. Components store definitions that other parts can use.
For OpenAPI 3.1.2, the root must include openapi and info, and info must contain title and version. The description must also contain at least one of paths, components, or webhooks.
A minimal document can therefore look like this:
This is a valid structural starting point, but it describes no operations. The empty object {} is intentional. Writing paths: without a value would produce a YAML null value instead, which is not a Paths Object.
Not every valid description needs paths. A document devoted to reusable components or webhooks can serve a different purpose. For a catalog that clients query, however, paths is the natural place to describe the available requests.
The following fields provide the main map of a 3.1.2 document. You do not need to populate every optional field just to make a document look complete.
A schema dialect defines the rules tools use to interpret schema keywords. The examples omit jsonSchemaDialect and use the OpenAPI 3.1 default. It is not the place to select JSON versus YAML or declare a response's media type.
A consistent field order helps reviewers scan files, but moving components above paths does not change their meaning. Nesting does. A description inside info explains the API, while a description inside a response explains that response.
Assume the catalog allows anyone to retrieve a published book by identifier. Successful responses contain a book's identifier and title. An identifier that does not match a published book produces a bodyless 404 response. No credentials or custom identifier-format validation are part of this operation's contract.
This complete document gives those decisions a home. It includes one operation and one shared schema so the relationships remain easy to follow.
To find the successful response body, start at paths, choose /books/{bookId}, then follow get, responses, '200', and content. Under application/json, the schema refers to Book in components.schemas.
That reference connects the response to the shared definition. It does not make Book an endpoint. The client still calls the path, and the server still returns the book data directly rather than wrapping it inside a property named Book.
The 404 belongs alongside 200 because both describe outcomes of the same operation. The common Book shape belongs under components.schemas. This arrangement makes the operation's outcomes visible together without repeating the data definition wherever a book appears.
The document's YAML format is separate from the JSON format the document declares for the response. A documentation file can be YAML while the service exchanges JSON.
The info object gives readers context before they inspect individual requests. A useful title identifies the service. A short summary states its purpose. A description explains boundaries that a title cannot convey, such as the exclusion of draft and withdrawn books.
In the catalog example, make the API's scope clear: consumers should not expect it to behave like an editorial inventory system. Put that explanation in the document rather than only in a YAML comment, because ordinary YAML parsing does not preserve comments as document data.
The | after description introduces a YAML string that preserves line breaks. All indented lines below it belong to that string until the indentation returns to the surrounding level. Fields such as contact, license, and termsOfService can provide additional metadata when applicable; use approved information rather than copying placeholders from another API.
There are several independent version signals to keep straight:
Changing info.version does not change the server address, request paths, or compatibility of the interface. A team can align document versions with releases, but that is its versioning policy, not automatic OpenAPI behavior.
Similarly, changing openapi is a format decision. Do not copy fields from a different OpenAPI release merely because their names look useful. Check whether they belong to the version the document declares.
The root servers array tells consumers where the API is available. Each entry supplies a url; a description helps readers distinguish destinations. Multiple entries describe alternative locations, not a required sequence of calls or an automatic failover policy.
The following root-level fragment could describe the catalog if the service exposed the same interface under /v1 in both environments:
With the path /books/{bookId} and identifier bk_1042, the production request target becomes https://api.bookstore.example/v1/books/bk_1042. Clients append the path to the server URL. Repeating /v1 in both locations would describe a different target with two copies of the prefix.
Only list environments together when this description accurately represents their interface. If a sandbox exposes unreleased operations, presenting it as interchangeable with production can mislead consumers even if both URLs are reachable.
A servers array can also appear on a Path Item or an Operation. A Path Item groups the operations and shared settings for one path. A more specific server list overrides the broader list instead of extending it.
The diagram shows how to select the applicable list for an operation that does not use external references:
A reader who checks only the top of a large document can miss an operation-specific destination. Use overrides when the API needs them, and keep them visible during review.
If the root servers field is absent or empty, its default is a server URL of /. For a document that a server hosts at an HTTPS URL, this points to that origin's root, not necessarily the directory containing the document. An explicit absolute URL avoids depending on where someone hosts the description.
Server URLs may also contain variables with declared defaults. Those configure the base URL and are distinct from request path parameters such as bookId.
The location of a field tells you whether it defines something, applies something, or describes something. These roles are especially important for components, security, and tags.
components groups reusable objects by kind, such as schemas, parameters, responses, and securitySchemes. A name under schemas identifies a data definition; a name under responses identifies an entire reusable response definition. They are not interchangeable.
In the catalog document, $ref: '#/components/schemas/Book' selects a definition in the same document. The quoted value begins with #, which would introduce a comment if you leave it unquoted in that position in YAML.
Defining a component alone does not attach it to an operation. An unused Book schema does not describe any response until a response uses it. Keep the distinction between a library of definitions and the operations that consume them clear.
References can connect several files into one API description. Tools begin at an entry document, commonly openapi.yaml or openapi.json. Splitting files changes how you maintain the source; it does not turn component files into additional HTTP endpoints. A single file is a reasonable starting point while the description is small.
Security has two related locations. components.securitySchemes defines mechanisms, while security selects requirements by scheme name. An Operation can override root security requirements; a Path Item has no security field in OpenAPI 3.1.2.
For example, this root-level fragment defines and applies bearer authentication for a hypothetical private API:
Here, bearerAuth: [] still requires bearer authentication. The empty array is the value associated with that scheme, not an empty list of security requirements.
By contrast, an operation-level security: [] removes the root requirement for that operation. Omitting operation-level security inherits the root declaration. The public catalog uses security: [] at the root intentionally.
These are structural rules for expressing requirements. The service must still check tokens and resource permissions. Document the actual error behavior of protected operations.
Root tags supplies descriptions for named groups. Operation tags, such as [Books], assigns those names to an operation. Merely declaring Books at the root does not place every operation in that group or change a URL.
Root tag names must be unique. Although operations can use undeclared tags, declaring the groups you intend to present gives documentation tools clearer information to work with.
externalDocs provides a place for supporting documentation, while webhooks describes provider-initiated interactions consumers may implement. Neither needs an empty placeholder in a catalog document that does not use it.
A file can parse as YAML while still violating OpenAPI's structure. For example, the following intentionally incorrect fragment places schemas directly at the root:
The corrected placement is under components:
Both fragments are readable YAML. Only the second places the shared schema in the appropriate OpenAPI location. A YAML parser alone cannot establish that distinction.
Other mistakes come from confusing objects and arrays. servers is a list, so each server is an array entry. paths is an object whose keys are path strings. The shape is part of the format, not a formatting preference.
Use spaces consistently for YAML indentation, reject duplicate keys, and quote response-code keys such as '200' so they remain strings. Duplicate paths blocks are particularly dangerous because some parsers silently retain only one block, hiding part of the API. Put all path entries inside one paths object instead.
OpenAPI-defined field names also need exact spelling and casing. operationId and operationID are different keys. If a team needs custom metadata, a supported extension location can use an x- prefixed field such as x-owner; adding an arbitrary owner field does not make it standard OpenAPI metadata. Extensions do not have portable behavior unless the consuming tools agree on their meaning.
When reviewing a document, follow one operation from its effective server through its inputs and responses, then resolve every definition it uses. That small walkthrough catches mistakes that are easy to overlook while reading isolated sections. Combine it with validation for the declared OpenAPI version and reference resolution across the complete description.
An OpenAPI document connects API metadata, server locations, operations, and reusable definitions through a defined hierarchy. The root establishes the overall context, while nested fields describe more specific parts of the interface.
Read placement and scope carefully: more specific settings can override server lists; security requirements must select security definitions; and operations must use shared components in locations that accept their object type. Consistent YAML structure and OpenAPI validation help ensure that people and tools interpret the same document as intended.