OpenAPI Overview & Best Practices

OpenAPI is a standard for describing RESTful APIs. OpenAPI allows developers to define all the core elements of an API: endpoints, request and response data formats, authentication methods, etc.

There are several versions of the OpenAPI specification in circulation: 2.0 (also known as Swagger), 3.0, and 3.1.

Speakeasy supports OpenAPI versions 3.0 and 3.1. We recommend developers use OpenAPI version 3.1 for all projects. The advantage of using OpenAPI version 3.1 is that it is fully compatible with JSON Schema (opens in a new tab), which gives you access to a much larger ecosystem of tools and libraries.

OpenAPI Basics

An OpenAPI document is a JSON or YAML file made up of several different sections – some required, others optional. Each section is described in detail below.

The following fields are a mix of required and recommended (but optional). However, we strongly recommend you include them all. Together, they will answer the key questions about how your API is built:

  • What security is required to access it?
  • Which endpoints expose which resources?
  • How are those resources constructed?

openapi

The version of the OpenAPI Specification the document conforms to. This should be one of the OpenAPI Specification versions supported by Speakeasy.

Note: Speakeasy tooling currently only supports OpenAPI Specification versions 3.0.x and 3.1.x.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
paths:
/drinks:
get:
tags:
- drinks
operationId: listDrinks
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header

info

Contains information about the document, including fields like title, version, and description that help to identify the purpose and owner of the document.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
paths:
/drinks:
get:
tags:
- drinks
operationId: listDrinks
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header

servers

Contains an optional list of servers the API is available on. If a list of servers is not provided, the default URL is assumed to be /, a path relative to where the OpenAPI document is hosted.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
paths:
/drinks:
get:
tags:
- drinks
operationId: listDrinks
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header

security

Contains an optional list of security requirements that apply to all operations in the API. If no security requirements are provided, the default security requirements are assumed to be [], an empty array.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
paths:
/drinks:
get:
tags:
- drinks
operationId: listDrinks
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header

paths

Contains the paths and operations available that are exposed by the API.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
paths:
/drinks:
get:
tags:
- drinks
operationId: listDrinks
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header

components

Contains an optional list of reusable schemas that can be referenced from other parts of the document. This improves the readability and maintainability of the document by allowing common schemas to be defined once and reused in multiple places.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
paths:
/drinks:
get:
tags:
- drinks
operationId: listDrinks
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header

openapi

The version of the OpenAPI Specification the document conforms to. This should be one of the OpenAPI Specification versions supported by Speakeasy.

Note: Speakeasy tooling currently only supports OpenAPI Specification versions 3.0.x and 3.1.x.

info

Contains information about the document, including fields like title, version, and description that help to identify the purpose and owner of the document.

servers

Contains an optional list of servers the API is available on. If a list of servers is not provided, the default URL is assumed to be /, a path relative to where the OpenAPI document is hosted.

security

Contains an optional list of security requirements that apply to all operations in the API. If no security requirements are provided, the default security requirements are assumed to be [], an empty array.

paths

Contains the paths and operations available that are exposed by the API.

components

Contains an optional list of reusable schemas that can be referenced from other parts of the document. This improves the readability and maintainability of the document by allowing common schemas to be defined once and reused in multiple places.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
paths:
/drinks:
get:
tags:
- drinks
operationId: listDrinks
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header

OpenAPI Best Practices

OpenAPI can describe any HTTP API, whether it's REST or something more akin to RPC-based calls. This gives the OpenAPI Specification a lot of baked-in flexibility: There are many ways to achieve the same result that are equally valid according to the OpenAPI Specification.

With so much flexibility, it isn't always obvious how to construct an OpenAPI spec that is sufficient for code generation. We recommend a set of best practices to follow when writing OpenAPI documents. The following sections will outline key points to consider as you create your OpenAPI description.

tags

Contains an optional list of tags that are generally used to group or categorize a set of operations. We strongly recommend that you always define tags for operations, but it is not required.

In code generation

Tags will be used to namespace the methods in the SDK. For example, if you have a tag called drinks, then all the methods for that tag will be namespaced under drinks.listDrinks(). You can create multi-level namespaces by using a . in the tag name, for example, menu.drinks will become menu.drinks.listDrinks().

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
paths:
/drinks:
get:
tags:
- drinks
operationId: listDrinks
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header

operationId

A unique identifier for the operation. This ID must be unique in the document, and is case sensitive. We strongly recommend that you always define an operationId, but it is not required.

In code generation

The operationId is used to create the name of the method that will be generated for the operation. We recommend you follow a consistent pattern for naming your operations, for example, listDrinks, createDrink, updateDrink, and deleteDrink.

If you are generating your spec from an API framework, ensure that operationId values are human-readable. Some frameworks (for example, FastAPI) create long operationId identifiers that result in method names that are not idiomatic.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
paths:
/drinks:
get:
tags:
- drinks
operationId: listDrinks
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header

$ref

Allows for referencing a Path Item Object defined in the Components Object under the pathItems field. The $ref keyword is most commonly used to reference a schema defined in the Components Object under the schemas field. We strongly recommend that you always define your data types as referenceable components to keep your OpenAPI document clean and readable and allow you to reuse the same data type in multiple places.

In code generation

Component schemas will represent the schemas that describe the request and response bodies of your operations. They will be used to generate the types that are used in the SDK. Using components prevents issues where multiple types are defined for the same data structure.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
paths:
/drinks:
get:
tags:
- drinks
operationId: listDrinks
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header

tags

Contains an optional list of tags that are generally used to group or categorize a set of operations. We strongly recommend that you always define tags for operations, but it is not required.

In code generation

Tags will be used to namespace the methods in the SDK. For example, if you have a tag called drinks, then all the methods for that tag will be namespaced under drinks.listDrinks(). You can create multi-level namespaces by using a . in the tag name, for example, menu.drinks will become menu.drinks.listDrinks().

operationId

A unique identifier for the operation. This ID must be unique in the document, and is case sensitive. We strongly recommend that you always define an operationId, but it is not required.

In code generation

The operationId is used to create the name of the method that will be generated for the operation. We recommend you follow a consistent pattern for naming your operations, for example, listDrinks, createDrink, updateDrink, and deleteDrink.

If you are generating your spec from an API framework, ensure that operationId values are human-readable. Some frameworks (for example, FastAPI) create long operationId identifiers that result in method names that are not idiomatic.

$ref

Allows for referencing a Path Item Object defined in the Components Object under the pathItems field. The $ref keyword is most commonly used to reference a schema defined in the Components Object under the schemas field. We strongly recommend that you always define your data types as referenceable components to keep your OpenAPI document clean and readable and allow you to reuse the same data type in multiple places.

In code generation

Component schemas will represent the schemas that describe the request and response bodies of your operations. They will be used to generate the types that are used in the SDK. Using components prevents issues where multiple types are defined for the same data structure.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
paths:
/drinks:
get:
tags:
- drinks
operationId: listDrinks
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header

Extending OpenAPI

The OpenAPI Specification does not have an exhaustive vocabulary for describing API functionality. To overcome gaps in the specification, you can add several extension fields to an OpenAPI document that describe additional metadata and functionality.

Extensions typically follow a naming format of x-<vendor>-<function>, where <vendor> is the name of the vendor or tool that created the extension and <function> is the goal accomplished by the extension.

A range of Speakeasy extensions are available to help you prepare a spec for code generation. Some of the most commonly used extensions are described below.

x-speakeasy-name-override

Use this extension to override the name of a class, operation, or parameter. The most common use case is to override operationId values in your spec to simplify the created SDK method names.

If your operationId identifiers follow a consistent pattern, you can define the name override globally using a regular expression to match the operationId and replace it with a new name.

In this instance, the SDK will contain a method menu.drinks.list() rather than menu.drinks.list_drinks_v2_get() — much nicer!

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
x-speakeasy-name-override:
- operationId: ^list_.*
methodNameOverride: list
paths:
/drinks:
get:
tags:
- menu
x-speakeasy-group: menu.drinks
operationId: list_drinks_v2_get
x-speakeasy-usage-example: true
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header
x-speakeasy-example: "<YOUR_API_KEY>"

x-speakeasy-group

Sometimes the tags in an OpenAPI spec may already be used for an unrelated purpose (for example, autogenerating labels in documentation). In this scenario, you may want to use something other than tags to organize and group your methods.

You can add the x-speakeasy-group field to any operation in your OpenAPI spec to define custom namespaces and override any tags associated with the method.

In this case, the listDrinks operation is added to a menu.drinks namespace rather than a menu namespace.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
x-speakeasy-name-override:
- operationId: ^list_.*
methodNameOverride: list
paths:
/drinks:
get:
tags:
- menu
x-speakeasy-group: menu.drinks
operationId: list_drinks_v2_get
x-speakeasy-usage-example: true
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header
x-speakeasy-example: "<YOUR_API_KEY>"

x-speakeasy-usage-example

Documentation is an important part of any SDK. This extension allows you to choose which operation is featured at the top of your README.md.

We recommend that you pick the API operation that your users will most frequently employ. At a Speakeasy, that would likely be getting the list of drinks on offer.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
x-speakeasy-name-override:
- operationId: ^list_.*
methodNameOverride: list
paths:
/drinks:
get:
tags:
- menu
x-speakeasy-group: menu.drinks
operationId: list_drinks_v2_get
x-speakeasy-usage-example: true
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header
x-speakeasy-example: "<YOUR_API_KEY>"

x-speakeasy-example

Another useful documentation extension is x-speakeasy-example, which allows you to provide an example value to be used in the Authentication section of your SDK README.md.

This will help signal to users how they should instantiate the SDK with their security token.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
x-speakeasy-name-override:
- operationId: ^list_.*
methodNameOverride: list
paths:
/drinks:
get:
tags:
- menu
x-speakeasy-group: menu.drinks
operationId: list_drinks_v2_get
x-speakeasy-usage-example: true
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header
x-speakeasy-example: "<YOUR_API_KEY>"

x-speakeasy-name-override

Use this extension to override the name of a class, operation, or parameter. The most common use case is to override operationId values in your spec to simplify the created SDK method names.

If your operationId identifiers follow a consistent pattern, you can define the name override globally using a regular expression to match the operationId and replace it with a new name.

In this instance, the SDK will contain a method menu.drinks.list() rather than menu.drinks.list_drinks_v2_get() — much nicer!

x-speakeasy-group

Sometimes the tags in an OpenAPI spec may already be used for an unrelated purpose (for example, autogenerating labels in documentation). In this scenario, you may want to use something other than tags to organize and group your methods.

You can add the x-speakeasy-group field to any operation in your OpenAPI spec to define custom namespaces and override any tags associated with the method.

In this case, the listDrinks operation is added to a menu.drinks namespace rather than a menu namespace.

x-speakeasy-usage-example

Documentation is an important part of any SDK. This extension allows you to choose which operation is featured at the top of your README.md.

We recommend that you pick the API operation that your users will most frequently employ. At a Speakeasy, that would likely be getting the list of drinks on offer.

x-speakeasy-example

Another useful documentation extension is x-speakeasy-example, which allows you to provide an example value to be used in the Authentication section of your SDK README.md.

This will help signal to users how they should instantiate the SDK with their security token.

openapi.yaml

openapi: 3.1.0
info:
title: The Speakeasy Bar
version: 1.0.0
servers:
- url: https://speakeasy.bar
description: The production server
security:
- apiKey: []
x-speakeasy-name-override:
- operationId: ^list_.*
methodNameOverride: list
paths:
/drinks:
get:
tags:
- menu
x-speakeasy-group: menu.drinks
operationId: list_drinks_v2_get
x-speakeasy-usage-example: true
summary: Get a list of drinks
responses:
"200":
description: A list of drinks
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drink"
components:
schemas:
Drink:
type: object
properties:
name:
type: string
price:
type: number
securitySchemes:
apiKey:
type: apiKey
name: Authorization
in: header
x-speakeasy-example: "<YOUR_API_KEY>"