OpenAPI integration
Preface
The Mocks Server main distribution includes the openapi plugin preinstalled. It enables to automatically create Mocks Server routes and collections from OpenAPI documents.
module.exports = [
{
basePath: "/api", // basePath to add to the url of every created route
document: { // OpenAPI document
$ref: "../fixtures/openapi.json"
}
}
];
How does it work
OpenAPI versions 3.0 and 3.1 are supported.
Routes and variants are created using the response examples found in the OpenAPI document's paths
property, or using status codes when the response has no content. Basically, it creates a different route variant from:
- Each different example found on each
paths[path][method].responses[code].content[media-type].examples[example-id]
property. - Each different status code without content found on each
paths[path][method].responses[code]
property.
Collections are created using the first variant found on each OpenAPI route. They can also extend from other collections.
Read the OpenAPI conversion section for further info about the required OpenAPI structure for creating routes.
Usage
The plugin can be used to create routes in two different ways:
- Usage through files. It searches for files in the
/mocks/openapi
folder and it automatically converts the exported plugin's OpenAPI definitions into routes and loads them. - Programmatic usage. It provides JavaScript functions to create routes and collections from OpenAPI definitions. The returned routes and collections should be loaded manually. The function could be used to export routes in a file in the
mocks/routes
folder, or to load routes programmatically, for example.
OpenAPI conversion supports JSON refs, so, routes can be created from complete or partial OpenAPI documents hosted on remote servers, defined in separated JSON files, etc. Check out the Recipes section for examples.
OpenAPI definitions
Each OpenAPI document from which to generate routes has to be provided using an object with next properties:
basePath
(String): Path to be added to the url of every route created from the OpenAPI document.document
(Object): OpenAPI document. Read OpenAPI conversion for further details.collection
(Object): Optional. Allows to create a collection with the first variant of each route generated from the OpenAPI document. When not provided, no collection will be created for this particular document routes (but the routes will still be added to the plugin's default collection).id
(String): ID for the collection.from
(String): Collection ID from which the collection will extend.
refs
(Object): Optional. Options for resolving possible$refs
in the OpenAPI document. Thejson-refs
library is used behind the scenes to resolve refs, so any of its options is supported here.location
(String): The location of the document being processed. It will be used to locate relative references found within the document being resolved. If this value is relative, it will be calculated fromprocess.cwd()
.subDocPath
(String): The JSON Pointer or array of path segments to the sub document location to search from.- ...any other
json-refs
option.
Usage through files
The plugin automatically searches for files in the /mocks/openapi
folder. Each file must export an array of OpenAPI definitions, or a function exporting an array of OpenAPI definitions.
The plugin can be used to create routes from multiple OpenAPI documents. So, it expects an array of OpenAPI definitions in every file. You can export multiple OpenAPI definitions in one or multiple files. Check out Recipes for examples.
- JS files
- JSON files
- YAML files
- TypeScript files
project-root/
├── mocks/
│ ├── openapi/ <- DEFINE OPENAPIS HERE
│ │ └── definitions.js
│ └── collections.js
└── mocks.config.js
project-root/
├── mocks/
│ ├── openapi/ <- DEFINE OPENAPIS HERE
│ │ └── definitions.json
│ └── collections.json
└── mocks.config.js
project-root/
├── mocks/
│ ├── openapi/ <- DEFINE OPENAPIS HERE
│ │ └── definitions.yml
│ └── collections.yaml
└── mocks.config.js
project-root/
├── mocks/
│ ├── openapi/ <- DEFINE OPENAPIS HERE
│ │ └── definitions.ts
│ └── collections.ts
└── mocks.config.js
Read the using Babel guide for further info about how to use TypeScript.
The plugin takes advantage of the files loaders API provided by Mocks Server. So, OpenAPI definitions files can also be defined using JSON, Yaml, JavaScript, TypeScript, etc. And any custom Babel configuration will be also applied to these files. Read the organizing files guide for further info.
Examples
- JavaScript
- JSON
- YAML
module.exports = [
{
basePath: "/testing-api", // basePath to add to the url of every created route
collection: {
id: "testing-api", // Id for the collection generated with all routes created from the OpenAPI document
from: "base" // Id of the collection to extend from
},
document: { // OpenAPI document
openapi: "3.1.0",
info: {
version: "1.0.0",
title: "Testing API",
description: "OpenAPI document to create routes",
},
paths: {
//... OpenAPI document paths
}
}
}
];
[
{
"basePath": "/testing-api", // basePath to add to the url of every created route
"collection": {
"id": "testing-api", // Id for the collection generated with all routes created from the OpenAPI document
"from": "base" // Id of the collection to extend from
},
"document": {
"openapi": "3.1.0",
"info": {
"version": "1.0.0",
"title": "Testing API",
"description": "OpenAPI document to create routes"
},
"paths": {
//... OpenAPI document paths
}
}
}
]
- basePath: "/testing-api"
collection:
id: "testing-api"
from: "base"
document:
openapi: "3.1.0"
info:
version: "1.0.0"
title: "Testing API"
description: "OpenAPI document to create routes"
paths:
# ... OpenAPI document paths
OpenAPI conversion supports JSON refs, so, routes can be created from complete or partial OpenAPI documents hosted on remote servers, defined in separated JSON files, etc. Check out the Recipes section for examples.
Configuring refs
When OpenAPI definitions are exported from files in the /mocks/openapi
folder, relative refs in the OpenAPI document by default will be resolved from the file path. This default value can be changed using the refs.location
option.
- mocks/openapi/definitions.js
- mocks/documents/openapi.json
- File tree
module.exports = [
{
basePath: "/testing-api",
document: {
$ref: "../documents/openapi.json"
}
}
];
{
"openapi": "3.1.0",
"info": {
"version": "1.0.0",
"title": "Testing API",
"description": "OpenAPI document to create routes"
},
"paths": {
//... OpenAPI document paths
}
}
project-root/
├── mocks/
│ ├── documents/
│ │ └── openapi.json
│ ├── openapi/
│ │ └── definitions.js
│ └── collections.js
└── mocks.config.js
OpenAPI conversion
Routes
Routes are created using the paths and methods found in the document paths
property. It creates a different route from:
- Each different path and method found on each
paths[path][method]
property.
Route ID
The route ID is assigned following the next criteria, from higher to lower priority:
- The value of the
x-mocks-server-route-id
property in the path method, when defined. - The value of the
operationId
property in the path method, when defined. - A combination of the method and path (
[method]-[path]
), applying next replacements:- Path separators (
/
) are replaced by-
- Path templates characters are removed (
{
or}
)
- Path separators (
Example
{
"openapi": "3.1.0",
"info": {
"title": "Foo API",
//...
},
"paths": {
"/users": {
// ROUTE "getUsers"
"get": {
"x-mocks-server-route-id": "getUsers"
//...
},
// ROUTE "createUser"
"post": {
"operationId": "createUser"
//...
}
},
"/users/{id}": {
// ROUTE "get-users-id"
"get": {
//...
}
}
}
}
Variants
Variants of each route are created using the examples found on each different response code content media type. It creates a different variant from:
- Each different example found on each
paths[path][method].responses[code].content[media-type].examples[example-id]
property. - Each different status code without content found on each
paths[path][method].responses[code]
property.
Variant type
The created variants will have different types depending on the method responses properties:
json
when the response code content media type containsapplication/json
. The example value must be an object, otherwise the route won't pass the validation.text
when the response code content media type containstext/
. The example value must be a string, otherwise the route won't pass the validation.status
when the the response code does not have acontent
property
Variant ID
The variant ID is assigned following the next criteria, from higher to lower priority:
- The value of the
x-mocks-server-variant-id
property in the example, when defined. - A combination of the code, variant type and example id (
[code]-[variant type]-[example id]
) when the response code has content - A combination of the code and variant type (
[code]-[variant type]
) when the response code has no content
Example
{
"openapi": "3.1.0",
"info": {
"title": "Foo API",
//...
},
"paths": {
"/users": {
// ROUTE "get-users"
"get": {
"responses": {
"200": {
"content": {
"application/json": {
"examples": {
// VARIANT "all-users-json"
"all-users": {
"x-mocks-server-variant-id": "all-users-json",
"value": [
{
"name": "John Doe"
},
{
"name": "Jane Doe"
}
]
},
// VARIANT "200-json-no-users"
"no-users": {
"value": []
}
}
},
"text/plain": {
"examples": {
// VARIANT "200-text-all-users"
"all-users": {
"value": "John Doe, Jane Doe"
},
// VARIANT "200-text-no-users"
"no-users": {
"value": ""
}
}
}
}
}
}
},
// ROUTE "post-users"
"post": {
"responses": {
// VARIANT "200-status"
"200": {
//...
}
}
}
}
}
}
Variant headers
All headers defined in the OpenAPI headers
response code will be added to all of the variants created for that response status code.
Example
{
"openapi": "3.1.0",
"info": {
"title": "Foo API",
//...
},
"paths": {
"/users": {
// ROUTE "get-users"
"get": {
"responses": {
"200": {
"headers": {
"foo-header-1": "foo-value-1",
"foo-header-2": "foo-value-2"
},
"content": {
"application/json": {
"examples": {
// VARIANT "200-json-all-users" will have headers "foo-header-1" and "foo-header-2"
"all-users": {
//...
},
// VARIANT "200-json-no-users" will have headers "foo-header-1" and "foo-header-2"
"no-users": {
//...
}
}
},
"text/plain": {
"examples": {
// VARIANT "200-text-all-users" will have headers "foo-header-1" and "foo-header-2"
"all-users": {
//...
},
// VARIANT "200-text-no-users" will have headers "foo-header-1" and "foo-header-2"
"no-users": {
//...
}
}
}
}
}
}
}
}
}
}
Document collection
The plugin's OpenAPI definitions collection
options allows to automatically create a collection containing all routes generated from each OpenAPI document.
The first variant found on each route will be the selected one when the collection is created, but you can change it afterwards defining custom route variants through any of the available APIs or integration tools.
Example
Two collections will be created in the next example. Each one will contain only the routes in the base collection and the routes from each correspondent OpenAPI document:
module.exports = [
{
basePath: "/api-1",
collection: {
id: "api-1",
from: "base"
},
document: { // OpenAPI document
$ref: "../fixtures/api-1.json"
}
},
{
basePath: "/api-1",
collection: {
id: "api-2",
from: "base"
},
document: { // OpenAPI document
$ref: "../fixtures/api-2.json"
}
}
];
All documents collection
The plugin supports to create routes from multiple OpenAPI documents. A different collection can be created from each different document, but the plugin also allows to create a collection containing all routes from all OpenAPI documents loaded. So, all routes from all OpenAPI documents can be available at the same time in the API mock.
By default, it creates a collection with "openapi" id, containing all routes from all documents, but you can use the plugin options to change the collection name and the collection to extend from. The creation of this default collection can also be disabled setting the plugins.openapi.collection.id
option to null
.
Example
Only one collection will be created in the next example. It will contain all routes in the "base" collection and in both OpenAPI documents:
- OpenAPI definitions
- Plugin config
module.exports = [
{
basePath: "/api-1",
document: { // OpenAPI document
$ref: "../fixtures/api-1.json"
}
},
{
basePath: "/api-1",
document: { // OpenAPI document
$ref: "../fixtures/api-2.json"
}
}
];
// mocks.config.js file
module.exports = {
plugins: {
openapi: {
collection: {
id: "openapi",
from: "base"
}
}
}
}
Configuration
Here are described the plugin's options. Take into account that these options only have effect when it is the plugin who loads the OpenAPI definitions in the /mocks/openapi
folder. When used programmatically, these options have no effect.
You can use the next Mocks Server configuration properties to change the plugin's options:
plugins.openapi.collection.id
(String | Null): Id for the collection to be created with all routes from all OpenAPI documents. Default is "openapi". When it is set tonull
, no collection will be created.plugins.openapi.collection.from
(String): When provided, the created collection will extend from this one.
Programmatic usage
The plugin also exports a function allowing to create routes manually from OpenAPI definitions. Created routes should be loaded manually using any of the Mocks Server available methods.
Note that you'll have to create the collections by your own when getting routes programmatically.
API
The plugin exports next methods:
openApiRoutes(openAPIdefinition[, options])
: (Async Function): Resolves with an array of routes generated from the provided OpenAPI definition. Rejects with error if it is not possible to resolve OpenAPI document refs or there is any other error trying to convert it.openAPIdefinition
(Object): OpenAPI definitionoptions
(Object): Optional Object containing any of next properties:defaultLocation
(String): Set this location asrefs.location
option in the OpenAPI definition. It is ignored if the OpenAPI definition contains arefs.location
property.logger
(Object): Mocks Server Logger instance. If received, the function will log details during the conversion process using it.alerts
(Object): Mocks Server Alerts instance. If received, the function will create alerts using this object when any error is produced while trying to convert the OpenAPI document instead of throwing an error.
When the OpenAPI document contain relative refs, they will be resolved from the process.cwd()
path by default. Use the refs.location
option in the OpenAPI definitions, or the defaultLocation
option in the methods in order to change it.
Examples
- JavaScript API
- JS routes files
const path = require("path");
const { createServer } = require("@mocks-server/main");
const { openApiRoutes } = require("@mocks-server/plugin-openapi");
const openApiDocument = require("../openapi.json");
const core = createServer();
core.start().then(async () => {
const routes = await openApiRoutes({
basePath: "/foo-api",
document: openApiDocument,
refs: {
// Define next option only if the document contains relative refs
location: path.resolve(__dirname, "..", "openapi.json"),
}
});
// Load routes
const { loadRoutes } = core.mock.createLoaders();
loadRoutes(routes);
});
const { openApiRoutes } = require("@mocks-server/plugin-openapi");
const openApiDocument = require("../fixtures/openapi.json");
// Files in the mocks/routes folder can also export an async function
module.exports = function() {
return openApiRoutes({
basePath: "/foo-api",
document: openApiDocument,
refs: {
// Define next option only if the document contains relative refs
location: path.resolve(__dirname, "..", "fixtures", "openapi.json"),
}
});
}
Recipes
Remote OpenAPI document
Using JSON refs, an OpenAPI document hosted on a remote server can be used to create mock routes. Simply define the document as a ref to the url of the remote document:
module.exports = [
{
basePath: "/openapi", // basePath to add to the url of every created route
document: { // OpenAPI document
$ref: "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/api-with-examples.json"
}
}
];
OpenAPI JSON file document
Using JSON refs, a JSON OpenAPI document located in the file system can be used to create mock routes. Simply define the document as a ref to the path of the document:
module.exports = [
{
basePath: "/openapi", // basePath to add to the url of every created route
document: { // OpenAPI document
$ref: "../fixtures/api-with-examples.json"
}
}
];
When using relative refs, remember to configure properly the location option.
Multiple OpenAPI documents
The plugin allows to create routes from multiple API documents. Each file in the /mocks/openapi
folder can export multiple definitions. Using the collection option, you'll be able to have all routes available at the same time, or to switch between one API and another.
The next example:
- Creates routes from remote OpenAPI document in the
/api-1
path, and a collection namedapi-1
only with that routes. - Creates routes from local OpenAPI document in the
/api-2
path, and a collection namedapi-2
only with that routes. - Load routes defined "manually" in the
routes
folder, and a collection namedbase
only with that routes. - Configures this plugin to create a collection using routes from all OpenAPI documents, extending from the
base
collection.
- mocks/openapi/definitions.js
- mocks/routes/users.js
- mocks/collections.js
- mocks.config.js
- File tree
module.exports = [
{
basePath: "/api-2", // basePath to add to the url of every created route
collection: {
id: "api-2",
},
document: { // OpenAPI document
$ref: "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/api-with-examples.json"
}
},
{
basePath: "/api-3", // basePath to add to the url of every created route
collection: {
id: "api-3",
},
document: { // OpenAPI document
$ref: "../documents/openapi.json"
}
}
];
module.exports = [
{
id: "get-users",
url: "/api-1/users",
method: "GET",
variants: [
{
id: "success",
type: "json", // variant of type json
options: {
status: 200, // status to send
body: [ // body to send
{
id: 1,
name: "John Doe"
},
]
},
}
]
}
];
module.exports = [
{
id: "base",
routes: ["get-users:success"],
}
]
module.exports = {
mock: {
collections: {
selected: "all-routes"
},
},
plugins: {
openapi: {
collection: {
id: "all-routes",
from: "base"
}
}
}
}
project-root/
├── mocks/
│ ├── documents/
│ │ └── openapi.json
│ ├── openapi/
│ │ └── definitions.js
│ ├── routes/
│ │ └── users.js
│ └── collections.js
└── mocks.config.js
So, there will be 4 collections in the server:
base
: Only routes defined "manually" are available (/api-1/users
)api-2
: Only routes created from remote OpenAPI document are available (/api-2/*
)api-3
: Only routes created from local OpenAPI document are available (/api-3/*
)all-routes
: All routes are available (/api-1/users
,/api-2/*
,/api-3/*
)