How to Write Open API 3.x Specifications
API First
When implementing capabilities, the design of the services must start with the externally visible service contract specification (the API). An API is a contract that all parties need to follow exactly. Changing such a contract is always difficult. This makes the design stage of an API extremely important.
OpenAPI 3
The industry standard for REST API definition is the OpenAPI Specification (OAS). OpenAPI Specification (renamed from the Swagger Specification to OpenAPI Specification in 2015) is an API specification format for REST APIs.
An OpenAPI specs allows you to describe your API, including:
API specifications can be written in YAML or JSON. Writing specifications in YAML is highly recommended because it is more human-readable format.
Best Practices
Tools
Swagger editor and hub are built and contributed by Smartbear.
Swagger Editor
Swagger is a node application which can be installed on a desktop and?the online editor?works just as fine ;
Swagger Hub
Swagger hub gives more control over API specifications and allows developers to develop API specifications collaboratively. (Signup is required).
Swagger Codegen
The Swagger Codegen is an open-source code-generator to build server stubs and client SDKs directly from a Swagger-defined RESTful API. The source code for the Swagger Codegen can be found on GitHub.
Various parts of a well-defined API Specification
API General Information
openapi: 3.0.0info:
# You application title. Required.
title: Ping App
# API version. You can use semantic versioning like 1.0.0,
# or an arbitrary string like 0.99-beta. Required.
version: 1.0.0
# API description. Arbitrary text in CommonMark or HTML.
description: This is a Ping API description
# Link to the page that describes the terms of service.
# Must be in the URL format.
termsOfService: <https://example.com/terms/>
# Contact information: name, email, URL.
contact:
name: API Support
email: [email protected]
url: <https://example.com/support>
# Name of the license and a URL to the license description.
license:
name: Apache 2.0
url: <https://www.apache.org/licenses/LICENSE-2.0.html>
# Link to the external documentation (if any).
# Code or documentation generation tools can use description as the text of the link.
externalDocs:
description: Find out more
url:<https://example.com>
Auth
Describing Bearer Authentication
Bearer authentication means “give access to the bearer of this token.” The bearer token is a cryptic string, usually generated by the server in response to a login request. The client must send this token in the Authorization header when making requests to protected resources:
Authorization: Bearer <token>
JWT Tokens
JSON Web Token (JWT) is an open standard that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret or a public/private key pair using RSA or ECDSA.
1. Define Security Scheme for JWT tokens
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
Since bearer tokens are usually generated by the server, bearerFormat is used mainly for documentation purposes, as a hint to the clients. In the example above, it is “JWT”, meaning JSON Web Token.
2. Apply security scheme
Following applies the security globally to all operations
security:
- bearerAuth: []
The square brackets [] in bearerAuth: [] contain a list of security scopes required for API calls. The list is empty because scopes are only used with OAuth 2 and OpenID Connect. In the example above, Bearer authentication is applied globally to the whole API.
Components
Components serve as a container for various reusable definitions:
The definitions in components have no direct effect on the API unless you explicitly reference them from somewhere outside the components.
Here is the list of what you can put into your OpenAPI 3 components object, and reference throughout your API definitions:
schemas — An object to hold reusable data schema used across your definitions.
responses — An object to hold reusable responses, status codes, and their references.
parameters — An object to hold reusable parameters you are using throughout your API requests.
examples — An object to hold reusable the examples of requests and responses used in your design.
requestBodies — An object to hold reusable the bodies that will be sent with your API request.
headers — An object to hold reusable headers that define the HTTP structure of your requests.
securitySchemes — An object to hold reusable security definitions that protect your API resources.
links — An object to hold reusable links that get applied to API requests, moving it towards hypermedia.
callbacks — An object to hold reusable callbacks that can be applied.
All subsections are optional.
The component names are used to reference the components via $ref from other parts of the API specification:
For example:?components: schemas: Item: type: object ... Customer: type: object
Item can be referenced as:
$ref: '#/components/schemas/Item'
Parameter type
OpenAPI 3 distinguishes between the following parameter types based on the parameter location. The location is determined by the parameter’s in key, for example, in: query or in: path.
Reference:?https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#parameterObject
Paths
API paths and operations are defined in the global paths section of the API specification.
paths:
/ping:
...
/track:
...
Deprecated operations
You can mark specific paths as deprecated to indicate that they should be transitioned out of usage:
/item/findByTags:
get:
**deprecated**: true
HTTP methods
For each path, you define operations (HTTP methods) that can be used to access that path.
OpenAPI 3 supports:
get
paths:
paths:
/login:
get:
security:
- bearerAuth: []
Parameters
You can use curly braces {} to mark parts of an URL as path parameters:
/item/{ids…}
Query String in Paths
Query string parameters must not be included in paths. They should be defined as query parameters instead.
Incorrect:
paths:
/item?type={type}:
Correct:
paths:
/item:
get:
parameters:
- in: query
name: type
schema:
type: string
enum: [type1, type2, type3]
required: true
post
To illustrate form data, consider an HTML POST form:
<form action="<https://example.com/survey>" method="post">
<input type="text" name="name" />
<input type="number" name="fav_number" />
<input type="submit"/>
</form>
This form POSTs data to the form’s endpoint:
POST /survey HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
name=Amy+Smith&fav_number=42
In OpenAPI 3, form data is modelled using a type: object schema where the object properties represent the form fields:
paths:
/survey:
post:
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
name:# <!--- form field name
type: string
fav_number:# <!--- form field name
type: integer
required:
- name
- email
put
PUT method intends to replace an existing resource.
For example:
paths:
/avatar:
put:
summary: Upload an avatar
requestBody:
content:
image/*: # Can be image/png, image/svg, image/gif, etc.
schema:
type: string
format: binary
delete
Delete removes a resource. For example:
delete:
description: deletes a single item based on the ID supplied
operationId: deleteItem
parameters:
- name: id
in: path
description: ID of item to delete
required: true
type: integer
format: int64
responses:
"204":
description: item deleted
Request Body
OpenAPI 3 uses the requestBody keyword to distinguish the payload from parameters (such as query string). The requestBody is more flexible in that it lets you consume different media types, such as JSON, XML, form data, plain text, and others, and use different schemas for different media types. requestBody consists of the content object, an optional Markdown-formatted description, and an optional required flag (false by default). content lists the media types consumed by the operation (such as application/json) and specifies the schema for each media type.
paths:
/items:
post:
summary: Add a new item
requestBody:
description: Optional description in *Markdown*
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Item'
application/xml:
schema:
$ref: '#/components/schemas/Item'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/ItemForm'
text/plain:
schema:
type: string
responses:
'201':
description: Created
Request bodies are optional by default. To mark the body as required, use required: true.
Response Body
Each operation within API specifications must have at least one response defined, usually a successful response. A response is defined by its HTTP status code and the data returned in the response body and/or headers.
Media Types
An API can respond with various media types. JSON is the most common format for data exchange, but not the only one possible. To specify the response media types, use the content keyword at the operation level.
paths:
/items:
get:
summary: Get all items
responses:
'200':
description: A list of items
content:
application/json:
schema:
$ref: '#/components/schemas/ArrayOfItems'
application/xml:
schema:
$ref: '#/components/schemas/ArrayOfItems'
text/plain:
schema:
type: string
# This operation returns image
/logo:
get:
summary: Get the logo image
responses:
'200':
description: Logo image in PNG format
content:
image/png:
schema:
type: string
format: binary
HTTP Response Codes
Under responses, each response definition starts with a status code, such as 200 or 404. An operation typically returns one successful status code and one or more error statuses. To define a range of response codes, you may use the following range definitions: 1XX, 2XX, 3XX, 4XX, and 5XX.
responses:
'200':
description: OK
'400':
description: Bad request. Item ID must be an integer and larger than 0.
'401':
description: Authorization information is missing or invalid.
'404':
description: A user with the specified ID was not found.
'5XX':
description: Unexpected error.
Errors
Following definition returns 401 error if user isn’t authorized:
paths:
/ping:
get:
...
responses:
'401':
$ref: '#/components/responses/UnauthorizedError'
...
post:
...
responses:
'401':
$ref: '#/components/responses/UnauthorizedError'
...
components:
responses:
UnauthorizedError:
description: Access token is missing or invalid
Example OpenAPI 3.0 Specifications
openapi: 3.0.0
# Created by Mazhar Choudhryinfo:
version: "1.0.0"
title: Ping API with Auth
description: >-
API to Ping
termsOfService: <https://example.com/terms-of-use>
contact:
name: Mazhar Choudhry
url: <https://mazrnow.com>
license:
name: Objex License
url: <https://license.example.com>
servers:
# Added by API Auto Mocking Plugin
- description: SwaggerHub API Auto Mocking
url: <https://virtserver.swaggerhub.com/mazrc/Track/1.0.0>
- description: dev server
url: dev.example.com/v1
- description: prod server
url: prod.example.com/v1
paths:
/login:
get:
summary: Return JWT token
description: >-
This is an example opeartion to show how security is applied to the
call.
responses:
'200':
description: OK
/ping:
get:
summary: Server heartbeat operation
description: >-
This operation shows how to override the global security defined above,
as we want to open it up for all users.
security: []
responses:
'200':
description: OK
components:
schemas: {}
# Security Scheme
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT# we can use this to pass in customer
# Apply the security globally to all operations
security:
- bearerAuth: []
Open API 3.1 Update
Open API 3.1 updated the specifications, major change is a webhooks native support:
Webhooks
Webhooks provide a mechanism where by a server-side application can communicate with a client application when a new event (that the client-side application is subscribed to) has occurred on the server side.
webhooks:
itemShipped:
post:
requestBody:
description: Information about item shipped
content:
application/json:
schema:
$ref: "#/components/schemas/Item"
responses:
"200":
description: Return a 200 status to indicate that the data was received successfully
Other updates
Additions
Updates
References
Author
Mazhar Choudhry is a Cloud Solutions Architect who also architected and developed a Social First Media marketing web application Rabbito Social Hub https://rabbito.io ?Follow the link to benefit from the special promotion.