OpenAPI (Swagger)

Learn how to generate request handlers from OpenAPI documents.

Import

Import the fromOpenApi() function from @mswjs/source/open-api:

import { fromOpenApi } from '@mswjs/source/open-api'

OpenAPI document

You can use both OpenAPI 2.0 and 3.0 documents with Source. Get the document you have or author a new one. Learn more about writing OpenAPI documents.

Generate request handlers

Import the OpenAPI document and provide it as an argument to the fromOpenApi() function:

import { fromOpenApi } from '@mswjs/source/open-api'
import spec from './api.spec.json'
 
const handlers = await fromOpenApi(spec)

If your OpenAPI document was not authored in JSON, you would have to convert it to JSON before using fromOpenApi().

You can also provide an inline definition of a OpenAPI document as an argument to the fromOpenApi() function:

fromOpenApi({
  openapi: '3.0.0',
  paths: {
    '/user': {
      get: {
        responses: {
          200: {
            example: {
              id: 'abc-123',
              firstName: 'John',
            },
          },
        },
      },
    },
  },
})

Features

Base path

Source respects both basePath and servers properties of your OpenAPI specification. If you define those, they will be included in the request URL predicate of the generated request handlers.

await fromOpenApi({
  // ...
  basePath: 'https://api.example.com',
  paths: {
    '/cart/{cartId}': {
      post: {
        // ...
      },
    },
  },
})

This generates the following request handler:

http.post('https://api.example.com/cart/:cartId', resolver)

In the case of servers, Source will generate a request handler for each defined server URL.

await fromOpenApi({
  // ...
  servers: [
    { url: 'https://prod.example.com' },
    { url: 'https://staging.example.com' },
  ],
  paths: {
    '/user': {
      get: {
        // ...
      },
    },
  },
})
http.get('https://prod.example.com/user', resolver)
http.get('https://staging.example.com/user', resolver)

Response definition

Source can get the response definition to use for the mocked responses from various places in your OpenAPI specification, listed by the order of priority:

  1. responses[status].example. Literal response examples are always used as the mocked response bodies.
  2. responses[status].schema. If no response example is provided, the response JSON schema will be evolved into a mocked response.
  3. If the request is described but has no 200 successful response, a hard-coded 504 Not Implemented mocke response will be returned unless you choose a conditional response.
  4. If the request is described but has no responses, a hard-coded 504 Not Implemented mocked response will be returned.

Conditional responses

A single request can describe multiple responses in your specification. For example:

await fromOpenApi({
  // ...
  paths: {
    '/user': {
      get: {
        responses: {
          200: {
            example: {
              id: 'abc-123',
            },
          },
          404: {
            example: {
              errorMessage: 'User not found',
            },
          },
        },
      },
    },
  },
})

If present, the 200 successful response is used as the mocked response by default:

await fetch('/user').then((res) => res.json())
// 200 OK
// content-type: application/json
//
// {"id":"abc-123"}

You can choose which mocked response your client receives by using setting the response search parameter of the request URL to equal to the desired response status code.

await fetch('/user?response=404').then((res) => res.json())
// 404 Not Found
// content-type: application/json
//
// {"errorMessage":"User not found"}

JSON schema

Whenever a JSON schema is encountered in the response definition of the OpenAPI document, it will automatically be “evolved” into literal values based on the data types defined in the schema.

await fromOpenApi({
  // ...
  paths: {
    '/user/{id}': {
      get: {
        responses: {
          200: {
            content: {
              'application/json': {
                schema: {
                  type: 'object',
                  properties: {
                    id: {
                      type: 'string',
                      format: 'uuid',
                    },
                  },
                },
              },
            },
          },
        },
      },
    },
  },
})

The document above will generate a GET /user/:id request handler with the following JSON response:

{ "id": "a5d43b08-2446-4da3-ab63-47e3dced6b0c" }

Source will use faker to produce literal values based on the data types from the schema. It supports string, number, integer, boolean, array, and object types.

Custom data formats

Source supports the following data formats:

  • "uuid"
  • "uri"
  • "firstName"
  • "lastName"
  • "email"
  • "password"
  • "date"
  • "date-time"
  • "creditCard"
  • "hexColor"
  • "hostname"
  • "mac"
  • "ipv4"
  • "ipv6"
  • "byte"
  • "binary"

You can provide any of these formats as the value of the format property in the JSON schemas of your API specification:

{
  "type": "string",
  "format": "email"
}
{ "email": "hayley.johnson@gmail.com" }

Content types

A single response can have multiple content types defined.

await fromOpenApi({
  // ...
  paths: {
    '/user': {
      get: {
        responses: {
          content: {
            'application/json': {
              example: { id: 'abc-123' },
            },
            'application/xml': {
              example: `<id>abc-123</id>`,
            },
          },
        },
      },
    },
  },
})

By default, the first content type in the definition is used in the mocked response.

await fetch('/user').then((res) => res.json())
// 200 OK
// content-type: application/json
//
// {"id":"abc-123"}

You can choose a different content types by specifying as the value of the Accept request header.

await fetch('/resource', {
  headers: {
    Accept: 'application/xml',
  },
}).then((res) => res.json())
// 200 OK
// content-type: application/xml
//
// <id>abc-123</id>

Wildcards like * and application/* are also supported.

If multiple content types are listed in the Accept request header, the first content type found in the response specification is used.