skip to content

What changed structurally from Swagger 2.0 to OpenAPI 3.0 in a spec document?

level: middleimportance: should knowfreq 45%

answer

  1. One host key becomes an array
  2. Body parameters stop being parameters
  3. Media type now owns the schema
  4. Reuse buckets consolidate under one key
  5. Every $ref pointer path changes

basics

~20 s

OpenAPI 3.0 replaced Swagger 2.0's host, basePath and schemes with a servers array, turned body and formData parameters into requestBody, replaced document-level consumes and produces with per-operation content maps, and moved definitions, parameters, responses and securityDefinitions under components.

solid answer

~40 s

The root key changes from `swagger: "2.0"` to `openapi: "3.0.x"`. Four structural moves matter. First, the single `host` + `basePath` + `schemes` triple becomes a `servers` array of full, optionally templated URLs, so one document can describe several environments. Second, the `in: body` and `in: formData` parameters disappear; payloads become a `requestBody` object whose `content` is keyed by media type, which also retires the document-level `consumes` and `produces`. Third, all reusable definitions consolidate under `components`: `definitions` becomes `components.schemas`, `securityDefinitions` becomes `components.securitySchemes`, and new buckets appear for `requestBodies`, `headers`, `examples`, `links` and `callbacks` — so every `$ref` path changes. Fourth, schemas gain `oneOf`, `anyOf` and `not` alongside `allOf`, cookie parameters become expressible, and `collectionFormat` gives way to `style` and `explode`.

code

yaml · 18 lines
yaml
# Swagger 2.0
swagger: "2.0"
host: api.example.com
basePath: /v1
schemes: [https]
consumes: [application/json]
paths:
  /orders:
    post:
      parameters:
        - name: body
          in: body
          required: true
          schema:
            $ref: '#/definitions/NewOrder'
definitions:
  NewOrder:
    type: object

go deeper

for a junior

Recall that Swagger 2.0 and OpenAPI 3.x are the same lineage, and that 3.x uses servers, requestBody and components where 2.0 used host, body parameters and definitions.

for a middle

Explain each structural move and why it was made — especially media-type-keyed content replacing the flat consumes/produces lists.

for a senior

Show what a real migration costs: rewritten $ref pointers across tooling, reworked security schemes, and the fact that a converted document stays shaped like 2.0 until someone redesigns it.

for a principal

Own the decision of whether to migrate at all — consumer impact, SDK regeneration, gateway support for 3.x, and whether the new expressiveness pays for the coordination.

## Why this question is asked Plenty of live systems still serve a Swagger 2.0 document, and plenty of engineers learned the format there. An interviewer wants to know you can read both, and that you understand a 2.0 → 3.0 conversion is a restructuring of the document rather than a version-number bump. ## The root `swagger: "2.0"` becomes `openapi: "3.0.3"` (or whichever 3.0.x patch). `info` survives essentially unchanged, still requiring `title` and `version`. ## Hosts: three flat keys become an array Swagger 2.0 described exactly one deployment: `host: api.example.com`, `basePath: /v1`, `schemes: [https]`. A document could therefore describe only one server, and multi-environment setups resorted to templating the file at build time. OpenAPI 3.0 replaces all three with `servers`, an array of Server Objects. Each holds a full `url`, which may be relative and may contain `{variable}` placeholders backed by a `variables` map (each variable requires a `default`, and may restrict values with `enum`). Prod, staging and regional hosts now live in one document, and `servers` can additionally be overridden on a path item or a single operation. ## Request payloads: body parameters become requestBody In 2.0, the payload was smuggled in as a parameter with `in: body` (at most one per operation, carrying a `schema`) or as several `in: formData` parameters for form submissions. The media types the operation accepted were listed separately in `consumes`, at document or operation level, with no link between a given media type and a given schema. OpenAPI 3.0 introduces a first-class `requestBody` object with its own `required` flag, `description`, and a `content` map keyed by media type — each key carrying its own `schema`, `example`/`examples` and `encoding`. Form submissions become `application/x-www-form-urlencoded` or `multipart/form-data` entries in that same map. This means one operation can genuinely accept a JSON body and a CSV body with different schemas, which 2.0 could not express. The mirror-image change applies to responses: `produces` disappears and each response gets a `content` map keyed by media type. ## Reuse: everything consolidates under components Swagger 2.0 scattered reusable objects across root-level keys: `definitions`, `parameters`, `responses`, `securityDefinitions`. OpenAPI 3.0 gathers them into a single `components` object with the buckets `schemas`, `responses`, `parameters`, `examples`, `requestBodies`, `headers`, `securitySchemes`, `links` and `callbacks`. The practical consequence is that every reference changes: `$ref: '#/definitions/Pet'` becomes `$ref: '#/components/schemas/Pet'`. Any hand-written tooling, documentation snippet or test fixture that hard-codes 2.0 pointer paths breaks on conversion. ## Security declarations `securityDefinitions` moves to `components.securitySchemes`, and the scheme shapes change. 2.0's `type: basic` becomes `type: http` with `scheme: basic`, which is also how bearer tokens are now expressed. OAuth2's single `flow` key with a sibling `authorizationUrl`/`tokenUrl` becomes a `flows` object that can declare several flows at once, each with its own URLs and scopes. The way requirements are *applied* — a root-level or operation-level `security` array — is unchanged in shape. ## Schemas and parameter serialization Swagger 2.0's schema subset supported only `allOf`. OpenAPI 3.0 adds `oneOf`, `anyOf` and `not`, plus `nullable`, `deprecated`, `writeOnly` and a richer `discriminator` object, which is what finally made polymorphic payloads describable. Parameter serialization also changed: 2.0's `collectionFormat` (`csv`, `ssv`, `pipes`, `multi`) is replaced by the `style` + `explode` pair, which covers more of RFC 6570-style templating. And 2.0 had no way to describe a cookie parameter at all; 3.0 adds `in: cookie`. ## New capabilities with no 2.0 equivalent `links` (describing how one operation's output feeds another's input) and `callbacks` (out-of-band requests the API makes back to the client, the basis for webhook description in 3.0) are both new. Neither has a 2.0 counterpart, so a conversion tool can only add them by hand. ## How conversion goes in practice Tools such as swagger2openapi handle the mechanical moves — servers, requestBody, components, `$ref` rewriting — reliably. What they cannot do is exploit the new expressiveness: splitting a single vague body schema into per-media-type schemas, introducing `oneOf` where the 2.0 document faked polymorphism with a loose object, or adding the `links` a hypermedia-aware client would want. Expect a converted document to be *valid* 3.0 and still read like 2.0 until someone edits it deliberately.

  • Why can OpenAPI 3.0 describe an operation that accepts both JSON and CSV bodies when Swagger 2.0 could not?
    Because 3.0 keys the schema by media type inside `requestBody.content`. In 2.0 the accepted media types lived in a flat `consumes` list with a single `in: body` schema, so there was no way to bind a different schema to each type.
  • What breaks in your tooling when you convert a 2.0 document to 3.0?
    Every hard-coded JSON pointer. `#/definitions/Pet` becomes `#/components/schemas/Pet`, and `#/parameters/...`, `#/responses/...` and `#/securityDefinitions/...` all move under `components` too. Scripts, fixtures and docs that referenced the old paths must be rewritten alongside the spec.
  • How does a bearer-token security scheme differ between the two versions?
    Swagger 2.0 had no first-class bearer support — teams modelled it as an `apiKey` in the `Authorization` header. OpenAPI 3.0 expresses it properly as `type: http` with `scheme: bearer` and an optional `bearerFormat`, which is why converted documents often still carry the old apiKey workaround.

saying these in an interview costs you the question

  • Calls it only a version-string change
  • Thinks $ref paths survive the conversion
  • Says host and basePath still exist in 3.0
  • Believes 2.0 supported oneOf and anyOf
  • Expects a converter to modernise the design too

context