API strategy

Platform integration

Definitions in Swagger: a practical guide to writing reusable schema objects

Definitions in Swagger explained: how to write, reference, compose, and generate the definitions object step by step, with the pitfalls that break most files.

6 minute read
Decorative imagery showcasing Pontil's brand

By the end of this guide you will be able to write, reference, and generate the definitions section of a Swagger 2.0 document without copying schemas across every endpoint. You will know how definitions differ from OpenAPI 3's components/schemas, how to reference a schema from a path, and how to generate the whole block from an existing codebase.

Prerequisites: a Swagger 2.0 document you are editing (YAML or JSON), a text editor, and — for the generation step — a running backend in a framework with an OpenAPI/Swagger integration. Roughly 45 minutes end to end.

One clarification before we start. The definitions object exists in Swagger 2.0. In OpenAPI 3.x the same concept moved under components/schemas. If your file starts with swagger: "2.0", follow this guide verbatim. If it starts with openapi: 3.x, the mechanics are identical but the key names change — noted at the end.

Step 1 — Locate or create the definitions object

Open your Swagger file. Look for a top-level definitions: key. It sits alongside swagger, info, paths, and parameters.

If it isn't there, add it. Order doesn't matter to tooling, but convention is: swagger, info, host, basePath, schemes, paths, definitions, parameters, responses, securityDefinitions.

swagger: "2.0"
info:
 title: Orders API
 version: "1.0.0"
paths: {}
definitions: {}

An empty definitions: {} is valid. You'll fill it in the next step.

Step 2 — Add your first schema definition

Each entry under definitions is a named JSON Schema object. The name is how you'll reference it later, so keep it PascalCase and descriptive.

Start with a real object your API returns. Here is an Order schema.

definitions:
 Order:
   type: object
   required:
     - id
     - status
     - total
   properties:
     id:
       type: string
       format: uuid
     status:
       type: string
       enum: [pending, shipped, delivered, cancelled]
     total:
       type: number
       format: double
     created_at:
       type: string
       format: date-time

Two things to notice. required is a sibling of properties, not a flag inside each property — a common mistake. And format is a hint, not a validator: tooling uses it, but Swagger won't reject a bad UUID at spec level.

Step 3 — Reference the definition from a path

Definitions are useless until something points at them. References use the JSON Reference syntax: $ref: "#/definitions/Order".

paths:
 /orders/{id}:
   get:
     parameters:
       - name: id
         in: path
         required: true
         type: string
     responses:
       "200":
         description: The order
         schema:
           $ref: "#/definitions/Order"

The $ref value is a single string. It can't have sibling keys — Swagger 2.0 tooling will silently ignore anything next to a $ref. If you need to add a description, do it inside the referenced schema, not next to the reference.

Open the file in Swagger Editor to confirm the reference resolves. A broken $ref shows as a red error in the right pane.

Step 4 — Compose schemas with allOf

Most real APIs have base shapes and variants. allOf composes them without duplication.

definitions:
 BaseEntity:
   type: object
   required: [id, created_at]
   properties:
     id:
       type: string
       format: uuid
     created_at:
       type: string
       format: date-time

 Order:
   allOf:
     - $ref: "#/definitions/BaseEntity"
     - type: object
       required: [status, total]
       properties:
         status:
           type: string
           enum: [pending, shipped, delivered, cancelled]
         total:
           type: number
           format: double

Order now inherits id and created_at from BaseEntity and adds its own fields. Swagger 2.0 doesn't support oneOf or anyOf — those are OpenAPI 3 features. If you need discriminated unions today, you're waiting for the OpenAPI 3 upgrade.

Step 5 — Reference schemas inside other schemas

A schema can reference another schema in its properties. This is how you model nested objects and arrays of objects.

definitions:
 LineItem:
   type: object
   required: [sku, quantity]
   properties:
     sku:
       type: string
     quantity:
       type: integer
       minimum: 1

 Order:
   type: object
   required: [id, items]
   properties:
     id:
       type: string
     items:
       type: array
       items:
         $ref: "#/definitions/LineItem"

The items field on an array takes the same shape as any schema — either an inline object or a $ref. Prefer the reference. It keeps your LineItem shape in one place and makes generated client code reuse the same type across endpoints.

Step 6 — Generate definitions from an existing codebase

Hand-writing definitions for a mature API is not the job. Every serious backend framework has a library that reads your route handlers, model classes, or type annotations and emits a Swagger document.

Framework
Generator

Spring Boot (Java)

[springdoc-openapi](https://springdoc.org/)

ASP.NET Core

[Swashbuckle](https://github.com/domaindrivendev/Swashbuckle.AspNetCore)

Django

[drf-spectacular](https://drf-spectacular.readthedocs.io/)

FastAPI

Built in — `/openapi.json`

Express (Node)

[swagger-jsdoc](https://github.com/Surnet/swagger-jsdoc) with JSDoc comments

Go

[swaggo/swag](https://github.com/swaggo/swag)


Install the generator, annotate your models (most frameworks do this from class fields or type hints automatically), and run the export.

# Spring Boot — runtime endpoint (springdoc emits OpenAPI 3, not Swagger 2)
curl http://localhost:8080/v3/api-docs > openapi.json

# Django with drf-spectacular
python manage.py spectacular --file schema.yaml

# Go with swag
swag init -g cmd/api/main.go

Note that springdoc-openapi produces OpenAPI 3.x output — if you specifically need Swagger 2.0, you'll need to convert it (e.g. with api-spec-converter). The legacy Springfox project exposed /v2/api-docs for Swagger 2.0 but is no longer actively maintained.

If you're producing OpenAPI 3 output but need Swagger 2.0, we cover the mechanics of generating an OpenAPI spec from an existing codebase in more detail — including the CI checks worth adding.

Once generated, diff it against your hand-written file. Any drift is a bug in one of them.

Step 7 — Validate the whole document

A definition that parses in isolation can still break the document. Run a validator.

# @apidevtools/swagger-cli is deprecated; @redocly/cli is the actively maintained successor
npx @redocly/cli lint swagger.yaml

Or use Spectral with the built-in OpenAPI ruleset, which catches issues a syntax validator won't — unused definitions, missing descriptions, inconsistent naming.

npx @stoplight/spectral-cli lint swagger.yaml

Expected output on a clean file is silence, or a small list of style warnings. Anything red — broken refs, invalid types, sibling keys next to $ref — fails CI.

Common pitfalls

Sibling keys next to $ref. Swagger 2.0 ignores them. If you need to override a field, wrap the reference in allOf.

Definitions that aren't referenced. Unused definitions still appear in generated SDKs and documentation. Spectral's oas2-unused-definition rule catches these — clean them up before publishing.

Confusing Swagger 2.0 with OpenAPI 3. If your file starts with openapi: 3.x, move the block to components/schemas and update refs to #/components/schemas/Order. The OpenAPI specification documents the current structure. Our deep-dive on OpenAPI covers the differences and what changes when agents, not just humans, read the spec.

Treating the spec as documentation only. A spec that drifts from the running code is worse than no spec — it lies. Regenerate on every build and diff against the committed version. OpenAPI spec drift is where most agent integrations quietly break.

Over-nesting with allOf. Two levels of composition is fine. Four levels means you're modelling inheritance in a spec that wasn't built for it. Flatten.

Join our weekly newsletter

Stay up to date on the ever changing agentic landscape.

POSTS

Related content

API strategy

Platform integration

How to generate an OpenAPI spec from an existing codebase

7 minute read

API strategy

Agent infrastructure

What is OpenAPI? A deep-dive on the spec, the ecosystem, and what agents change

10 minute read

API strategy

Platform integration

OpenAPI specification best practices: writing specs agents and SDK generators can actually use

9 minute read