OpenAPI 3

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 needs to exactly follow. Changing such a contract is always difficult. This makes the design stage of an API extremely important.

OpenAPI 3.0

OpenAPI Latest Specs

The 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 file allows you to describe your API, including:

  • Available endpoints (/track) and operations on each endpoint (GET /users, POST /users)
  • Operation parameters Input and output for each operation
  • Authentication methods
  • Corporate information, license, terms of use and other information.

AAPI specifications can be written in YAML or JSON. Writing specifications in YAML is highly recommended because it is more human readable.

Best Practices

Tools

Swagger editor and hub are built and contributed by Smartbear.

Swagger Editor

https://editor.swagger.io

Swagger is a node application which can be installed on a desktop and online editor work just as well ;

Swagger Hub

https://app.swaggerhub.com

Swagger hub gives more control over API specifications and provides ability to develop API specification collaboratively.

Note: Registration 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 in GitHub.

GitHub: https://github.com/swagger-api/swagger-codegen

Various parts of a good 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: http://example.com/terms/

# Contact information: name, email, URL.
contact:
name: API Support
email: support@example.com
url: http://example.com/support

# Name of the license and a URL to the license description.
license:
name: Apache 2.0
url: http://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: http://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 — schemas (data models), parameters, responses, examples, and others. 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.0 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.0 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.

  1. path parameters, such as /users/{id}
  2. query parameters, such as /users?role=admin
  3. header parameters, such as X-MyHeader: Value
  4. cookie parameters, which are passed in the Cookie header, such as Cookie: debug=0; csrftoken=BUSe35dohU3O1MZvDCU

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.0 supports:

  • get
  • post
  • put
  • patch
  • delete
  • head
  • options
  • and trace.

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="http://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.0, 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 replaces 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.0 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 Choudhry
info:
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: []

--

--

--

CEO Objex (https://objex.tech), Rabbito.io (https://rabbito.io) and HBHM (https://hbhm.org)

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Kick starter for python --beginners;

Spring MVC — Abstract Controller | Code Factory

How to Run WordPress on a Kubernetes Cluster from Scratch

How to switch between FortiGate and FortiWLC as controller for Fortinet FAP-U series access points…

Mete Atamel and Guillaume Laforge: Choreography vs.

Announcing Yugabyte DB 2.0 GA: Jepsen Tested, High-Performance Distributed SQL

How to Setup Git-LFS

How to calculate CHURN with SQL

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Mazhar Choudhry

Mazhar Choudhry

CEO Objex (https://objex.tech), Rabbito.io (https://rabbito.io) and HBHM (https://hbhm.org)

More from Medium

What is an API?

What is Domain | What is Domain and Range | What is Domain Driven Design

https://www.telly1news.com/2022/03/what-is-domain-and-range.html

How to Work with Flyway Migration Scripts using MySQL Workbench

Reducing Visibility Timeout — Exception Scenarios- Hack I did