Skip to content
routebase
OpenAPI10 chapters

Chapter 06 of 10

Components and Reuse

What lives under components, how a reference works, when extracting something is worth it and when it is premature, and what changes once a definition is shared across teams.

A document without reuse repeats the same error response forty times, and one with too much reuse sends a reader through four indirections to find a string. The useful position is in between and it is easier to find than it looks.

What lives under components

MapHolds
schemasData structures used by bodies, responses and parameters
responsesWhole responses with their description, content and headers
parametersParameter definitions reused across operations
requestBodiesRequest bodies reused across operations
headersResponse header definitions
examplesNamed example values
securitySchemesHow the API authenticates callers
linksRelationships between operations
callbacksRequests the API makes back to the consumer

Nothing under components has any effect on its own. A schema nobody references is inert, which is why a lint rule for unreferenced components is one of the more useful ones to leave on.

How a reference works

A reference replaces an object with a pointer. The common form is local, addressing a location inside the same document.

responses:
  "404":
    $ref: "#/components/responses/NotFound"
  "200":
    description: The order was found.
    content:
      application/json:
        schema:
          $ref: "#/components/schemas/Order"

Two details cause most of the trouble. A reference can point at another file, which is how a large description is split across teams, and every tool that reads the result has to resolve those files. And in OpenAPI 3.0 a reference follows the JSON Reference rules, under which anything written beside the $ref is ignored, so adding a description next to a reference silently does nothing. The 3.0 way around it is to wrap the reference in an allOf with the extra fields as a second member.

When to extract, and when not to

The signal is the second occurrence. One inline schema sits where the reader is already looking, and a second copy of it is two definitions that will disagree eventually.

Three cases are worth extracting on sight, because a second occurrence is certain. The error body qualifies because every operation returns one, and the pagination envelope qualifies because every list endpoint returns one. So does the authentication scheme, since it is referenced from the security requirement rather than written out.

The case against extracting early is readability. A response whose body is a reference to a schema whose properties are references to three more schemas is technically tidy and genuinely hard to read. Names help more than structure here, so a component with an obvious name is worth more than a deep hierarchy with precise ones.

Naming components

Component names are part of what generators produce, so they end up as class names in somebody's client library.

That makes two things worth doing. Pick one convention and hold to it, which across the ecosystem usually means PascalCase, and name a component by what the thing is rather than by where it is used. Order survives a refactor, while GetOrderResponse200 documents a call site that may well move.

Names also have to be unique within their map, which is the reason imported documents from code-first stacks often arrive with namespaced names such as Acme.Orders.Contracts.Order. Shortening them is worth doing at import time, when you can still check that the short names stay unique.

Sharing across documents

The specification scopes components to one document, so sharing across APIs is a question the format leaves open and teams answer in one of two ways.

External references keep one definition and point at it from everywhere. A change reaches every consumer at once. That is the strength when the definition is a genuine standard and the risk when it is not, since every consumer inherits a change none of them asked for.

A library that copies places a snapshot into each document and records where it came from. Each consumer updates when it chooses, so nobody is broken by somebody else's edit, and the cost is that versions coexist for a while.

Neither is wrong. The question to settle first is whether a change to the shared Money type should reach twelve APIs on the same day or over the next quarter.

In Routebase

The Components section of the designer holds the same maps the specification has, each with a usage badge showing how many places reference the item.

The Components section of the designer sidebar with Shared, Schemas, Responses, Parameters, Headers, Header Policies, Request Bodies and Security, showing reusable responses NotFound and Unauthorized with problem+json badges and request bodies CreateOrderBody and UpdateProductBody.
Every reusable definition of a specification version in one place, with a reference count on each one so the blast radius of a change is visible before you make it.

Extraction works from where the duplication is. An inline response becomes a component with one action, and the endpoint is relinked automatically rather than left pointing at a copy. A project-wide view groups schemas across specifications by their structure rather than by their name, which is what finds the three teams who each wrote their own address type.

For sharing across projects there is a library at organisation level. It copies a definition into the specification that links it, records the version that was linked and shows an update indicator when the library moves ahead. Accepting the update is one click and staying behind is a decision rather than an accident. The Components and Shared Library guides cover both levels.

Frequently asked questions

What are components in OpenAPI?

Components is the top-level object holding definitions you reference from more than one place. It has separate maps for schemas, responses, parameters, examples, request bodies, headers, security schemes, links and callbacks. Nothing in components takes effect on its own, because a component only does something once an operation references it.

How does $ref work in OpenAPI?

A reference replaces an object with a pointer to another one. The usual form is a local pointer such as a hash followed by the path through the document, for example to a schema under components. A reference can also point at another file, which is how large descriptions are split, at the cost of needing every consuming tool to resolve external references.

When should you extract a schema into components?

When the same shape appears in a second place, and not before. One inline body is easier to read where it is used, while the same body written twice is two things that can drift apart. The signal to extract is the second occurrence rather than a feeling that a shape looks reusable.

Can components be shared between APIs?

Not by the specification itself, which scopes components to one document. Sharing across documents is done either with external references or with a library that copies a definition into each document and tracks where it came from. The question that decides between them is whether every consumer must move at the same moment or on its own schedule.

Last reviewed by The Routebase Team.

Ready to ship on it?

Routebase is live. Design your API once — docs, mocks, tests, and monitoring all follow from the same source.

14-day Pro trial — no credit card required.