Skip to the content.

Working With OpenAPI Specifications

Introduction

The OpenAPI Specification is a human and machine-readable format for defining Application Programming Interfaces (APIs). Writing an OpenAPI Specification for your API makes it easier to reason about the contract, and reduces interface churn. There are also tools to create mock service implementations from their definitions without writing any code.

Goals

Prerequisites

OpenAPI Specification Benefits

Here are some benefits of using OpenAPI Specification.

Contract Driven

You can design and mock the API without writing any code. It is easier to iterate on a language agnostic definition than a concrete implementation.

Code Generators

There are server and client generators for multiple languages and frameworks. The server generators will create server stubs and a matching data model, which reduces the amount of boilerplate code that has to be written manually. The client generators make it possible to create SDK clients with little effort.

Version Management

Each OpenAPI Specification has a version which simplifies tracking what the API contract is for each release. No more digging through code to work out the expected behaviour for a specific version, the specification becomes the single source of truth.

Additional Tooling

The benefits listed above form the backbone of OpenAPI Specification, however there is additional tooling available for:

Community Support

OpenAPI Specification has been around since 2011 and has been adopted by many teams. As a result there is wealth of experience out there, so answers to most questions are a simple search away.

SwaggerHub Editor Basics

The prerequisites call for a SwaggerHub account, which whilst not essential is a useful tool. Once you have created an account download the Hello World Service example specification (help me). Then you can use the “Create New -> Import and Document API” menu item in the top left hand corner to import the downloaded file.

The screenshot below shows the default view in SwaggerHub, composed of a navigation panel on the left, a YAML editor in the middle, and a preview window on the right. Spend a few minutes clicking around to explore how those three elements correspond.

Hello World OpenAPI Specification

The reference documentation for OpenAPI Specification is excellent but we present this example to illustrate the basic ideas and prepare the ground for the next guide. There we will write a Java service based on the API contract below.

Info Section

The important pieces of information here are the name and version, but you can also include contact details, terms and conditions, and the license under which the API is made available.

openapi: 3.0.0
info:
  title: 'Hello World Service'
  description: 'This contract defines the public interface to a Hello World service.'
  version: '1'

Paths Section

This section describes the request that can be made with the API. In addition to declaring the inputs and outputs for each HTTP request we also specify an operationId, this is the name that will be used to expose requests in the SDK. In the first part of the paths section we define a CRUD bucket for “Langauge” resources. Note that the identifiers will be generated by the server.

id name description
01f643a5-7e34-4366-af1a-9cce5e5c68e8 English A West Germanic language that uses the Roman alphabet.
55f3028f-1b94-4edd-b14f-183b51b33d68 Russian An East Slavic language that uses the Cyrillic alphabet.
85d9484d-9c09-4d76-80e2-14da26b0d8f3 Japanese An East Asian language that uses a combination of logographic kanji and syllabic kana.
9e3aa5ce-fab2-48a3-ab47-053599622324 Welsh A Brittonic language spoken in Wales and a Welsh colony in Argentina.
29144abd-8363-43be-b5cd-cfe5b8b48fb7 Spanish A Romance language used to write the first modern novel Don Quixote.
paths:
  #
  # Languages
  #
  '/helloworld/api/v1/languages':
    post:
      tags:
        - Languages
      summary: Creates a new langauge.
      operationId: createLanguage
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Language'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Language'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '409':
          $ref: '#/components/responses/409'
        '500':
          $ref: '#/components/responses/500'
          
    get:
      tags:
        - Languages
      summary: Returns a list of languages.
      operationId: getLanguages
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Language'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '500':
          $ref: '#/components/responses/500'
      
  '/helloworld/api/v1/languages/{id}':
    get:
      tags:
        - Languages
      summary: Returns a language.
      operationId: getLanguage
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Language'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'        
        '404':
          $ref: '#/components/responses/404'
        '500':
          $ref: '#/components/responses/500'  
          
    put:
      tags:
        - Languages
      summary: Updates a langauge.
      operationId: updateLanguage
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Language'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Language'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'        
        '404':
          $ref: '#/components/responses/404'
        '409':
          $ref: '#/components/responses/409'
        '500':
          $ref: '#/components/responses/500'  
  
    delete:
      tags:
        - Languages
      summary: Deletes a langauge.
      operationId: deleteLanguage
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '204':
          $ref: '#/components/responses/204'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'        
        '404':
          $ref: '#/components/responses/404'
        '500':
          $ref: '#/components/responses/500'  

The second part of the paths section defines a CRUD bucket for “Item” resources, where an “Item” represents the expression “Hello, World!” in a given language. Note that once again the identifiers will be generated by the system, and you will need to lookup a “Language” identifier before creating an item.

id languageId value
68963944-a88c-4e39-98fd-d77878231d81 01f643a5-7e34-4366-af1a-9cce5e5c68e8 Hello, World!
62ef8e5f-628a-4f8b-92c9-485981205d92 55f3028f-1b94-4edd-b14f-183b51b33d68 Привет мир!
4277e6db-3350-4a29-9cfd-dfbad35f226d 85d9484d-9c09-4d76-80e2-14da26b0d8f3 こんにちは世界!
3c6ddae4-69b2-4281-b581-2ec48c6a0b61 9e3aa5ce-fab2-48a3-ab47-053599622324 Helo Byd!
dafbc5bf-cf74-491c-907a-b99c93fda5d7 29144abd-8363-43be-b5cd-cfe5b8b48fb7 ¡Hola Mundo!
  #
  # Items
  #
  '/helloworld/api/v1/items':
    post:
      tags:
        - Items
      summary: Creates a new Hello World item.
      operationId: createItem
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Item'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Item'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '500':
          $ref: '#/components/responses/500'
          
    get:
      tags:
        - Items
      summary: Returns a list of Hello World items.
      operationId: getItems
      parameters:
        - name: languageId
          in: query
          schema: 
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Item'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '500':
          $ref: '#/components/responses/500'
      
  '/helloworld/api/v1/items/{id}':
    get:
      tags:
        - Items
      summary: Returns a Hello World item.
      operationId: getItem
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Item'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'        
        '404':
          $ref: '#/components/responses/404'
        '500':
          $ref: '#/components/responses/500'  
          
    put:
      tags:
        - Items
      summary: Updates a Hello World item.
      operationId: updateItem
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Item'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Item'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'        
        '404':
          $ref: '#/components/responses/404'
        '500':
          $ref: '#/components/responses/500'  
  
    delete:
      tags:
        - Items
      summary: Deletes a Hello World item.
      operationId: deleteItem
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '204':
          $ref: '#/components/responses/204'
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'        
        '404':
          $ref: '#/components/responses/404'
        '500':
          $ref: '#/components/responses/500'  

Components Section

This final section contains our data model and some HTTP responses that we want to use in multiple places. This saves on typing and reduces copy and paste errors. You can also declare input validation rules such as type, format, and length to make your API more robust. These rules will be enforced in code produced by the generators. The OpenAPI Specification Reference contains details of all the bells and whistles you can use to write your API.

components:
  schemas:
    Language:
      type: object
      required:
        - name
      properties: 
        id: 
          type: string
          format: uuid
          readOnly: true
        name:
          type: string
          minLength: 2
          maxLength: 128
        description:
          type: string
          maxLength: 512
    
    Item:
      type: object
      required:
        - languageId
        - value
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        languageId:
          type: string
          format: uuid
        languageName:
          type: string
          readOnly: true
        value: 
          type: string
          minLength: 2
          maxLength: 128
          
    Error:
      type: object
      properties:
        code:
          type: string
          readOnly: true
        message:
          type: string
          readOnly: true
  
  responses:
    204:
      description: No Content
      
    400:
      description: Bad Request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

    401:
      description: Unauthenticated
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'    
            
    403:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'    
            
    404:
      description: Not Found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'          
    409:
      description: Conflict
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error' 
            
    500: 
      description: Internal Server Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

References

Web API Design by Brian Mulloy

OpenAPI Specification Reference

Hello World Collection

PREVIOUS NEXT HOME