skip to content

In OpenAPI, what can you store under components besides schemas, and how is each reused?

level: middleimportance: should knowfreq 44%

answer

  1. Nine fixed fields, not one
  2. Same pattern: $ref where the object would go
  3. Headers, examples and links reuse too
  4. Security is the odd one out
  5. 3.1 adds a place for whole paths

basics

~20 s

OpenAPI's components object also holds responses, parameters, examples, requestBodies, headers, securitySchemes, links and callbacks — plus pathItems in 3.1. Each is reused with a $ref at a position where that object type is allowed; security schemes are the exception, referenced by key name.

solid answer

~40 s

Most people only ever use `components.schemas`, but the registry has nine fixed fields in 3.0 — `schemas`, `responses`, `parameters`, `examples`, `requestBodies`, `headers`, `securitySchemes`, `links`, `callbacks` — and 3.1 adds `pathItems`. Reuse works the same way for all of them: put a `$ref` where an object of that type would otherwise be written inline. So a shared error response goes in the `responses` map under an operation's status code, a shared pagination parameter goes in the operation's `parameters` array, a shared rate-limit header goes in a response's `headers` map. The one that does not use `$ref` is security: an operation's `security` array names a scheme by its **key** under `components.securitySchemes`. In 3.0 a Path Item Object also has its own `$ref` field, letting a whole path be defined elsewhere; 3.1 formalises that with `components.pathItems`.

code

yaml · 47 lines
yaml
paths:
  /orders:
    get:
      operationId: listOrders
      parameters:
        - $ref: '#/components/parameters/PageSize'
      security:
        - bearerAuth: []
      responses:
        '200':
          description: A page of orders
          headers:
            X-RateLimit-Remaining:
              $ref: '#/components/headers/RateLimitRemaining'
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Order'
              examples:
                twoOrders:
                  $ref: '#/components/examples/TwoOrders'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  parameters:
    PageSize:
      name: pageSize
      in: query
      schema:
        type: integer
  headers:
    RateLimitRemaining:
      description: Calls left in the current window
      schema:
        type: integer
  examples:
    TwoOrders:
      summary: A short page
      value:
        - id: o-1
        - id: o-2
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer

go deeper

for a junior

Know that components holds more than schemas and that reuse always looks the same: a $ref written where the full object would otherwise appear.

for a middle

Be able to list the sub-maps and place a reference correctly for each — a response under a status code, a parameter in the array, a header inside a response's headers map.

for a senior

Show judgment about how far to push reuse: shared responses carry their own description, so deduplicating error responses trades per-operation wording for a single point of change.

for a principal

Own the registry as a shared asset — naming conventions, a lint rule for unused entries, and a decision about which components are org-wide versus service-local.

## The registry is wider than schemas `components` is a container of named, reusable pieces. It has a fixed set of fields — you cannot invent new ones — and each field is a map from a name you choose to an object of one specific type. In OpenAPI 3.0 the fields are: - **`schemas`** — Schema Objects; by far the most used. - **`responses`** — full Response Objects: `description`, `content`, `headers`. - **`parameters`** — Parameter Objects, complete with `name`, `in`, `required`, `schema`. - **`examples`** — Example Objects (a `value` or an `externalValue`, with a `summary`). - **`requestBodies`** — Request Body Objects: `content` keyed by media type, plus `required`. - **`headers`** — Header Objects, used inside response `headers` maps. - **`securitySchemes`** — Security Scheme Objects. - **`links`** — Link Objects describing how one operation's response feeds another operation's input. - **`callbacks`** — Callback Objects describing out-of-band requests the API makes back to the client. OpenAPI 3.1 adds **`pathItems`**. Component names must match `^[a-zA-Z0-9\.\-_]+$`, and the maps are namespaced per field — a `Pet` under `schemas` and a `Pet` under `examples` do not collide. ## How each is referenced The rule is uniform: write `$ref` where the inline object would go, and point at the matching sub-map. - A response: under an operation's `responses`, replace the whole status-code value with `$ref: '#/components/responses/NotFound'`. Note the shared response carries its own `description`, so you must not write one alongside the reference in 3.0. - A parameter: an entry in the operation's (or path item's) `parameters` array becomes `- $ref: '#/components/parameters/PageSize'`. - A request body: the operation's `requestBody` value becomes a reference. - A header: inside a Response Object's `headers` map, the value for `X-RateLimit-Remaining` becomes a reference into `components.headers`. - An example: inside a Media Type Object's `examples` map, each named example may be a reference into `components.examples`. - A link or callback: same pattern, in the operation's `links` and `callbacks` maps. Putting a reference in the wrong slot is the common error — pointing an operation's `responses.'404'` at `#/components/schemas/Error` yields a document where a schema is being used as a response, and validators reject it because a Response Object requires a `description`. ## The security exception Security requirements do not use `$ref`. Once a scheme is defined as `components.securitySchemes.bearerAuth`, an operation opts into it with `security: [ { bearerAuth: [] } ]` — the map key *is* the reference, and the array holds scopes (empty for non-OAuth2 schemes). Reaching for `$ref` here is a reliable sign someone has not read that part of the specification. ## Path items: reusing a whole path In OpenAPI 3.0 the Path Item Object has a dedicated `$ref` field, so a path's entire definition can live in another file and be pulled in: ``` /pets: $ref: './paths/pets.yaml' ``` This is how large specs are split by resource. It is a quirk — the reference sits *inside* the path item rather than replacing it — and tool support has historically been uneven. OpenAPI 3.1 tidies this up by adding `components.pathItems`, so a path item can be a named component like anything else. ## Why the breadth matters Reusing only schemas leaves most of the duplication in place. A large document typically repeats the same four or five error responses on every operation, the same pagination parameters on every collection, and the same correlation-id header on every response. Moving those into `components.responses`, `components.parameters` and `components.headers` collapses hundreds of lines and, more importantly, makes a change to the error envelope a one-line edit rather than a search-and-replace across the file. There is a limit: a shared response bakes in its own `description`, so operations that need different wording for the same status code cannot share one component in 3.0 — you either accept generic wording or define two components. That tension between deduplication and per-operation nuance is the main reason teams stop short of full reuse. ## Practical hygiene Unreferenced components accumulate silently; a linter rule that flags unused entries is worth having, because many code generators emit a model for every schema in the registry, referenced or not, and stale entries end up in shipped SDKs.

  • Why can't an operation reference a security scheme with $ref?
    Because a security requirement is not a Reference Object — it is a map whose *key* is the scheme's name under `components.securitySchemes` and whose value is the list of required scopes. Writing `security: [ { bearerAuth: [] } ]` is the reference. There is no `$ref` form, and tools will reject one.
  • You want the same 404 response on every operation but with operation-specific wording. Can one component do that?
    Not in OpenAPI 3.0: the shared Response Object carries its own `description`, and a sibling `description` beside the `$ref` is ignored. You either accept one generic description or define separate components. In 3.1 the Reference Object's `description` overrides the target's, so a single shared response can be re-worded per use.
  • How do you split a large spec so each resource's paths live in their own file?
    In 3.0, use the Path Item Object's own `$ref` field: under `paths`, set `/pets: { $ref: './paths/pets.yaml' }`. In 3.1 you can also register path items under `components.pathItems` and reference them by pointer. Check your toolchain first — support for path-level references has historically lagged schema references.

saying these in an interview costs you the question

  • Believes components can only hold schemas
  • Tries to $ref a security scheme instead of naming its key
  • Points a response slot at a schema component
  • Invents new sub-maps under components
  • Writes a description beside a shared response reference in 3.0

context