Working With OpenAPI Specifications
- Introduction
- Goals
- Prerequisites
- OpenAPI Specification Benefits
- SwaggerHub Editor Basics
- Hello World OpenAPI Specification
- References
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
- list benefits of OpenAPI Specification
- explain an example specification
Prerequisites
- knowledge of web API design (help me)
- a SwaggerHub account (help me)
- Hello World Service OAS3 YAML (help me)
- Hello World Service OAS3 JSON (help me)
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:
- online editing
- documentation generation
- test creation
- mock servers
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
PREVIOUS | NEXT | HOME |