After discovering what is the OpenAPI Specification format, it’s now time to write a first simple OpenAPI Specification file to learn the basics.

Writing OpenAPI (fka Swagger) Specification tutorial

This tutorial is composed of several posts:

If you’re a bit lost in the specification, take a look at my visual documentation:

In this second part you will learn how to give some basic informations about your API, describe endpoints using various HTTP methods with path, query and body parameters and returning various HTTP status and responses.

An almost empty OpenAPI Specification

We’ll start with an almost empty, yet valid, file giving some basic informations.

swagger: "2.0"

info:
  version: 1.0.0
  title: Simple API
  description: A simple API to learn how to write OpenAPI Specification

schemes:
  - https
host: simple.api
basePath: /openapi101

paths: {}

OpenAPI Specification version

First we need to tell which version of the OpenAPI specification we are using via the swagger attribute…

swagger: "2.0"

Yes, swagger. As explained in the introduction, the OpenAPI specification is based on Swagger. It will probably be replaced by something else in the next version of the specification. The only possible value is (for now) 2.0.

API description

Then we give some informations about our API with info: the API’s version (not to be confused with the specification version and the file version) a title and an optionnal description.

info:
  version: 1.0.0
  title: Simple API
  description: A simple API to learn how to write OpenAPI Specification

API URL

Speaking of web API, an important information is the root URL which people and programs will use to call it. This is described by giving a list of accepted schemes (or protocols, like http or https), a host, and a basepath.

schemes:
  - https
host: simple.api
basePath: /openapi101

All of these APIs endpoints URL will use https://simple.api/open101 as base URL. These informations are not required, an OpenAPI specification without these data is still valid.

API operations

Finally, as our API does absolutely nothing for now, we add an empty paths list. (nb. in YAML an empty object is describe using {}).

paths: {}

Defining an operation

Let our API do something by adding an operation to list some persons.

swagger: "2.0"

info:
  version: 1.0.0
  title: Simple API
  description: A simple API to learn how to write OpenAPI Specification

schemes:
  - https
host: simple.api
basePath: /openapi101

paths:
  /persons:
    get:
      summary: Gets some persons
      description: Returns a list containing all persons.
      responses:
        200:
          description: A list of Person
          schema:
            type: array
            items:
              required:
                - username
              properties:
                firstName:
                  type: string
                lastName:
                  type: string
                username:
                  type: string

Adding a path

In the paths section we add a new path /persons corresponding to the persons resource.

paths:
  /persons:

Adding an http method on path

On each path we can add any http verb (like get, post, put or delete) to manipulate the corresponding resource. To list some persons, we need to apply the get http method to the /persons resource (or path). We also give a short description (summary) and a longer one if necessary (description).

    get:
      summary: Gets some persons
      description: Returns a list containing all persons.

Therefore to list some persons we’ll have to call get /persons (or get https://simple.api/open101/persons to be precise).

Describing response

For each operation, you can describe any response matching an http status code (like 200 OK or 404 Not Found) in the responses section. We’ll only handle 200 when responding to get /persons and we’ll tell what the response means via its description.

      responses:
        200:
          description: A list of Person

Describing response’s content

The get /persons operation returns a list of persons, we describe what it is with the schema section of the response. A list of person is an object which type is array. Each item in this array is an object containing three properties of type string: firstName, lastName and username. Only username will be always provided (i.e. required).

          schema:
            type: array
            items:
              required:
                - username
              properties:
                firstName:
                  type: string
                lastName:
                  type: string
                username:
                  type: string

Defining query parameters

As we’ll have to handle many persons, it could be a good idea to add paging capabilities to the get /resources operation. We’ll do that by adding query parameters to define the requested page and number of items per page.

swagger: "2.0"

info:
  version: 1.0.0
  title: Simple API
  description: A simple API to learn how to write OpenAPI Specification

schemes:
  - https
host: simple.api
basePath: /openapi101

paths:
  /persons:
    get:
      summary: Gets some persons
      description: Returns a list containing all persons. The list supports paging.
      parameters:
       - name: pageSize
         in: query
         description: Number of persons returned
         type: integer
       - name: pageNumber
         in: query
         description: Page number
         type: integer
      responses:
        200:
          description: A list of Person
          schema:
            type: array
            items:
              required:
                - username
              properties:
                firstName:
                  type: string
                lastName:
                  type: string
                username:
                  type: string

Adding a parameters section to the get /persons operation

First we add a parameters section in get http method for /persons path.

paths:
  /persons:
    get:
      summary: Gets some persons
      description: Returns a list containing all persons. The list supports paging.
      parameters:

Adding paging query parameters

Then in the parameters list we define two optional parameters named pageSize and pageNumber of type integer located in query. We also provide a description for each one.

      parameters:
       - name: pageSize
         in: query
         description: Number of persons returned
         type: integer
       - name: pageNumber
         in: query
         description: Page number
         type: integer
      responses:

Therefore to list some persons we can use get /persons?pageSize=20&pageNumber=2 and we’ll get the page number 2 with 20 persons max.

Defining a path parameter

We would like to access directly a specific person by it’s username, so we’ll add a get /persons/{username} operation to our API. {username} is called a path parameter.

swagger: "2.0"

info:
  version: 1.0.0
  title: Simple API
  description: A simple API to learn how to write OpenAPI Specification

schemes:
  - https
host: simple.api
basePath: /openapi101

paths:
  /persons:
    get:
      summary: Gets some persons
      description: Returns a list containing all persons. The list supports paging.
      parameters:
       - name: pageSize
         in: query
         description: Number of persons returned
         type: integer
       - name: pageNumber
         in: query
         description: Page number
         type: integer
      responses:
        200:
          description: A list of Person
          schema:
            type: array
            items:
              required:
                - username
              properties:
                firstName:
                  type: string
                lastName:
                  type: string
                username:
                  type: string
  /persons/{username}:
    get:
      summary: Gets a person
      description: Returns a single person for its username
      parameters:
        - name: username
          in: path
          required: true
          description: The person's username
          type: string
      responses:
        200:
          description: A Person
          schema:
            required:
              - username
            properties:
              firstName:
                type: string
              lastName:
                type: string
              username:
                type: string
        404:
          description: The Person does not exists.

Adding a get /persons/{username} operation

First we add a /persons/{username} path, after the /persons one, in the paths section and define the get operation for this path.

swagger: "2.0"

info:
  version: 1.0.0
  title: Simple API
  description: A simple API to learn how to write OpenAPI Specification

schemes:
  - https
host: simple.api
basePath: /openapi101

paths:
  /persons:
                username:
                  type: string
  /persons/{username}:
    get:
      summary: Gets a person
      description: Returns a single person for its username

Describing username path parameter

As {username} is a path parameter, we need to describe it. It is done by adding a parameters section to the get operation and adding a required parameter with a name matching the parameter defined in the path (here username) located in path of type string. We also provide an optional description.

      parameters:
        - name: username
          in: path
          required: true
          description: The person's username
          type: string

A common problem when defining path parameter is to forget required: true (as the Swagger Editor snippet do not provide it). If required is not provided, its default value is false, meaning that the parameter is optional. A path parameter is always required.

Adding responses

Don’t forget to add 200 response returning a person. Note that the schema used in 200 is the same as the array’s item in get /persons 200 response.

      responses:
        200:
          description: A Person
          schema:
            required:
              - username
            properties:
              firstName:
                type: string
              lastName:
                type: string
              username:
                type: string

As a username may not match an existing person we also add a 404 response. Note that this response do not return anything besides the 404 http status code.

        404:
          description: The Person does not exists.

Defining a body parameter

We would like to have the capability of adding a person to our list of persons so we’ll add a post /persons operation to our API.

swagger: "2.0"

info:
  version: 1.0.0
  title: Simple API
  description: A simple API to learn how to write OpenAPI Specification

schemes:
  - https
host: simple.api
basePath: /openapi101

paths:
  /persons:
    get:
      summary: Gets some persons
      description: Returns a list containing all persons. The list supports paging.
      parameters:
       - name: pageSize
         in: query
         description: Number of persons returned
         type: integer
       - name: pageNumber
         in: query
         description: Page number
         type: integer
      responses:
        200:
          description: A list of Person
          schema:
            type: array
            items:
              required:
                - username
              properties:
                firstName:
                  type: string
                lastName:
                  type: string
                username:
                  type: string
    post:
      summary: Creates a person
      description: Adds a new person to the persons list.
      parameters:
        - name: person
          in: body
          description: The person to create.
          schema:
            required:
              - username
            properties:
              firstName:
                type: string
              lastName:
                type: string
              username:
                type: string
      responses:
        204:
          description: Persons succesfully created.
        400:
          description: Persons couldn't have been created.
  /persons/{username}:
    get:
      summary: Gets a person
      description: Returns a single person for its username.
      parameters:
        - name: username
          in: path
          required: true
          description: The person's username
          type: string
      responses:
        200:
          description: A Person
          schema:
            required:
              - username
            properties:
              firstName:
                type: string
              lastName:
                type: string
              username:
                type: string
        404:
          description: The Person does not exists.

Adding post /persons operation

We first add a post method to the /persons path (after the get one) in the paths section.

paths:
  /persons:
    post:
      summary: Creates a person
      description: Adds a new person to the persons list.

Describing a person body parameter

Then we define a parameter named person located in body of type object. The person object’s is described via it’s schema. Note that this schema is the same as the 200 response of get /persons/{username}. The firstName and lastName attributes are optional and username is required.

      parameters:
        - name: person
          in: body
          description: The person to create.
          schema:
            required:
              - username
            properties:
              firstName:
                type: string
              lastName:
                type: string
              username:
                type: string

Defining responses

Don’t forget to define responses for this new operation.

      responses:
        204:
          description: Persons succesfully created.
        400:
          description: Persons couldn't have been created.

To simplicity and beyond

You now have learned the basics of the OpenAPI Specification. But as you may have guess, working that way on huge API may not be so easy. But rest assured, the OpenAPI Specification files we’ve seen can be simplified. We’ll learn in the next part how to describe swiftly and easily even the hugest API by using factorization and references.