Swagger is the standard way of documenting REST APIs. Swagger is a set of open-source tools built around the OpenAPI Specification that can help to design, build, document and consume REST APIs. This is a popular framework which used for documenting the APIs in a common format.
To learn more about Swagger, please follow the documentation.
We can think swagger documentation as a blueprint of the APIs. By checking the blueprint developer can get an idea of the task of an API. Swagger gives a visual idea of the APIs, where user doesn’t need to know what technologies is being used to develop the APIs. API is documented in a common format in swagger where HTTP Verb, resopnse samples, request samples, description, etc is present. so anyone can get a clear picture of the API just by checking it.
Swagger can be written in yml and json. We will use yml here. And, we will use Swagger Editor tool to write the documentation. Here, we will use an example of User Management APIs, where user details can be Retrieved, Updated and Deleted.
- First we need to define the OpenAPI version, here we will use version 3.
openapi: 3.0.0
- Then we need to add information about the projects.
info:
title: User Management APIs
description: This is a sample project for managing users.
contact:
name: John Doe
email: john@example.com
version: "1.0"
Here, info
attribute holds the projects information. title
represents project title. version
represnts the API version.
- Now, we will add the protocol and domain of our API, also we will add other fixed reourceses which is fixed for all the APIs like API version. All the information will be under
servers
attribute.
servers:
- url: https://example.com/v1
Here, we have set our API domain URL for HTTPS protocol. So, what will happen if our API supports both HTTP and HTTPS. How will we add HTTP protocol here? We can simply add another value here in the array.
servers:
- url: https://example.com/v1
- url: http://example.com/v1
now, swagger will show us both of the servers information in a dropdown.
- what happens if we have multiple domain names? We can add more values into the array. But there’s another way. We can use variables attribute to make it more dynamic.
servers:
- url: "{protocol}://{base_url}/v1"
variables:
protocol:
default: https
enum:
- https
- http
base_url:
default: example.com
enum:
- example.com
- bd.example.com
here, we defined protocol
and base_url
as variable into curly braces, these variable name can be anything. Then we set the value of these under variables
attribute.
After setting the values we can see multiple dropdowns for each variable.
- Now, we will add the API details under
paths
attribute. We will add the API summary and reponse sample in the documentation. For example we have an API for getting customer information for given ID, we will add information for it:
paths:
/users/1:
get:
summary: Get User details
operationId: getUser
responses:
200:
description: API to fetch the user information by user id.
headers:
Cache-Control:
schema:
type: string
example: no-cache, private
content:
application/json:
schema:
type: object
properties:
id:
type: integer
example: 1
first_name:
type: string
example: Jalil
last_name:
type: string
example: Uddin
address:
type: object
properties:
area:
type: string
example: Mirpur
city:
type: string
example: Dhaka
country:
type: string
example: Bangladesh
here, we have set our API path customers/1
under paths
attribute. Then we have define the request type. This is a GET request so, we have define it as get
.
Then we have set a short summary for this API in summary
attribute. operationId
represents the identity of the operation, this should be unique.
Then we have added response details under responses
attribute.
First we need to define the status codes, there can be multiple responses with different status code. Here we have set only one for 200
status, we will add one error response later.
The response body needs to define under content
attribute.
We need to add the content type here; we have added application/json
as content type.
Then, response schema needs to define under schema
attribute.
our response is a JSON object, that’s why we have set type: object
. As we have set type = object so, we need to define the object details under properties
attribute.
- Now, we will add the headers info for the success response. We have set the response example under
content
attribute of200
status, we will add the headers informations underheaders
attribute of200
status:
headers:
Cache-Control:
schema:
type: string
example: no-cache, private
Date:
schema:
type: string
example: Thu, 17 Nov 2022 09:52:10 GMT
We have added only two headers, we can add as many headers as we want.
- We might need the example of
user
object on others API. For example, we will return the same user object after creating an user. Then what we can do is copy pasting the response content. That would definitely work, but the contents of the file keeps increasing. It would be better if we can avoid the duplication. The solution for this problem is to add common definitions in the globalcomponents
attribute and add the references using$ref
of the definitions wherever we need. Let's write the user schema undercomponents
attribute:
components:
schemas:
User:
type: object
properties:
id:
type: integer
example: 1
first_name:
type: string
example: Jalil
last_name:
type: string
example: Uddin
address:
type: object
properties:
area:
type: string
example: Mirpur
city:
type: string
example: Dhaka
country:
type: string
example: Bangladesh
Here we have added the user details under schemas
atrribute which parent element is components
. We have named our schema with User
. Then we have added the schema details.
Now, our next task is to add the references in the success response content. We need to remove the user schema from there, and need to add only one line to refer the object. So the changes would be like:
content:
application/json:
schema:
"$ref": "#/components/schemas/User"
We have just set the reference under schema
by setting the value of $ref
attribute. The format is #/components/<type>/<OjbectName>
. Our type is schemas
and our object name is User
. That's why we have set the value #/components/schemas/User
.
After adding these changes, the response object would be as previous. But there will be shown a new component named Schemas
.
That would look like:
- In the example, we have used user's
id
in path with the value 1. So, the path become,/users/1
, which looks like a static route. But our route is dynamic and it is based on the user's unique id. Swagger give us the ability to make the path dynamic. We need to add placeholder in theid
portion. To add place holder we use curly braces{}
, and inside the curly braces we add the variable name. Now, we will make changes in thepath
section like this:
path:
users/{id}:
get:
Now after adding this, we will see an semantic error saying Declared path parameter "id" needs to be defined as a path parameter at either the path or operation level
.
To fix the error, we need to add set the information for the {id}
in the parameters
attribute. We can have multiple variables for a single route, all the information should be added under parameters
. We can use variable in query params, body, header as well.
Here we have only one variable id
, so we will add the information for it only.
paths:
/users/{id}:
get:
summary: Get User details
operationId: getUser
parameters:
- in: path
name: id
schema:
type: integer
example: 1
required: true
Here, as our variable location is in path, that's why we have set path
value for in
attribute. Then, we have entered the schema details for id
variable. We have set example 1
as user's id.
After making these changes, there will be a new row with parameters information in the output section. It will look like:
- Let's add an
POST
API details in the swagger doc. Now, we will add an API specification for creating an user to our system. First we will add the route and other details like we did in theGET
API. We need to create an key with the route name underpaths
attribute. And the key must be siblings of other routes. For example, we are setting this route as/users
. So, it will be siblings of/users/{id}
.
paths:
/users/{id}:
..............
/users:
post:
summary: Create New User
operationId: createUser
Then, we will add the request payload details which contains the users details. To add the request payload, we need to define it under requestBody
attribute. Let's add the information:
/users:
post:
summary: Create New User
operationId: createUser
requestBody:
description: Request payload for creating new user
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UserPayload'
components:
schemas:
UserPayload:
type: object
properties:
first_name:
type: string
example: Hamid
last_name:
type: string
example: Ahmed
address:
type: object
properties:
area:
type: string
example: Mirpur
city:
type: string
example: Dhaka
country:
type: string
example: Bangladesh
Here, description
under requestBody
represents the summary of the request body. Then we have set the payload content type under content
attribute. As our request will contain JSON data, we have set our schema details under application/json
. We have create a new schema for the request payload, and set the references on the schema
attribute.
We can add the full request body as reference, then we can use the reference directly if we need the request body anywhere. To achieve this, we need to add requestBodies
key under components
attribute, then we need to add the details there with a custom key name. Let's add it:
components:
requestBodies:
UserRequestPayload:
description: Request payload for creating new user
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UserPayload'
Then, we can use UserRequestPayload
reference in the API specifications. So, we will make the changes now:
/users:
post:
summary: Create New User
operationId: createUser
requestBody:
"$ref": '#/components/requestBodies/UserRequestPayload'
Now, the only part left here is adding the response information. The response will be same as our GET
request. So, our complete code will be looking like below:
/users:
post:
summary: Create New User
operationId: createUser
requestBody:
"$ref": '#/components/requestBodies/UserRequestPayload'
responses:
201:
description: API to Create the user information and get created user's details.
headers:
Cache-Control:
schema:
type: string
example: no-cache, private
Date:
schema:
type: string
example: Thu, 17 Nov 2022 09:52:10 GMT
content:
application/json:
schema:
"$ref": "#/components/schemas/User"
After adding the POST
API specification, there will be a new block for the user create API. After expanding the block, It will look like:
- All the API details are shown under default group, It is called
tags
. If we don't set any tags for the route or API it will be set to default. Let's create a tag here and set to the routes.
To create a tag, we need to define the details under tags
attribute. This attribute will be siblings of paths
attribute. It has no parent element.
paths:
...................
tags:
- name: Users
description: Users API specifications
Then, we need to add the tag name in the routes details to group it together under tags
attribute as array value. Now the changes will be:
paths:
/users/{id}:
get:
tags:
- Users
.............................
/users:
post:
tags:
- Users
.............................
Now both of the routes group name is changed to Users
.