Integrate FastAPI with Speakeasy

Many developers who use Speakeasy to generate SDKs start their API development with FastAPI, and with good reason. FastAPI has rapidly gained traction in the Python community for its excellent performance, intuitive design, and flexibility. It enables developers to craft API solutions that not only run fast but also meet their users' unique needs.

FastAPI is great for building your core API, but you'll want to layer on SDKs and docs to provide your users with easy integration. For that, you'll want an OpenAPI file.

The good news is that FastAPI provides you with an OpenAPI file out of the box. The less good news is that you'll need some tweaking to get the OpenAPI spec to a level where it becomes usable with other tooling.

And that's what we'll be exploring in this article, the changes you'll want to make to FastAPIs default OpenAPI generation so that you can automate SDK creation.

Generating an OpenAPI Spec with FastAPI

Understanding how FastAPI generates OpenAPI schemas can help you make more informed decisions when you customize your FastAPI setup.

The process is fairly straightforward: FastAPI builds the OpenAPI schema based on the routes and models you've defined in your application. For every route in your FastAPI application, FastAPI adds an operation to the OpenAPI schema. For every model used in these routes, FastAPI adds a schema definition. The request and response bodies, parameters, and headers all draw from these schema definitions.

While this process works well out of the box, FastAPI also offers several customization options that can change the generated OpenAPI schema and, in turn, improve the SDKs generated by Speakeasy. We'll cover some of these options in the following sections.

Our FastAPI Example App: APItizing Burgers

Let's get this out of the way: the name came in a daydream shortly before lunchtime.

To guide us through this journey, we'll use a simple example FastAPI application: the "APItizing Burgers" burger shop API. This API includes two models: Burger and Order, and provides basic CRUD operations for managing burgers and orders at our hypothetical burger shop. Additionally, we have a webhook defined for order status events.

We'll look at how we optimized this FastAPI application and refined our models and routes so that the OpenAPI specification generated by FastAPI leads to intuitive, easy-to-use SDKs generated by Speakeasy. The source code for our example API is available in a repository: apitizing-burgers (opens in a new tab).

The repository consists of two directories: app and sdk.

The app directory contains only our FastAPI server definition: app/main.py. This is where we'll look at what we customized.

The sdk directory and the two specifications, openapi.yaml and openapi.json, are generated by running gen.sh in the root of the project.

Join us as we dive into FastAPI customization and discover how these tweaks can streamline your SDK generation process.

Warning Icon

WARN

When using Pydantic to define models, a known issue is that the serialization of datetime objects is not timezone-aware. This will cause a mismatch with the OpenAPI format date-time, which requires RFC 3339 date-time strings with timezones included. Consider using AwareDatetime (opens in a new tab) fields in Pydantic models to enable the appropriate validation (opens in a new tab) and ensure your SDK behavior matches the response definition from your server.

Basic FastAPI Setup

Let's get started with the basics – some things you probably do already.

These straightforward examples are trivial but will help you better understand the three steps in the automation pipeline: how FastAPI setup influences OpenAPI specifications, which, in turn, influences SDK code.

Add a List of Servers to Your FastAPI App

This may seem obvious, but while first working with FastAPI in development, the generated docs, development server, and API operations all work out of the box without the need to manually specify your server address.

However, when generating SDKs, Speakeasy requires your OpenAPI spec to list servers.

If you start testing out Speakeasy in development for SDK generation, make sure to add a list of servers to your FastAPI app, starting with your local development server.

In our app/main.py, we added our local server as shown.

main.py

from fastapi import FastAPI
app = FastAPI(
servers=[
{"url": "http://127.0.0.1:8000", "description": "Local server"},
],
)

This leads to the following generated output in openapi.yaml.

main.py
openapi.yaml

servers:
- description: Local server
url: http://127.0.0.1:8000/

Which, after Speakeasy generates the SDK, leads to the following abbreviated code in sdk/src/sdk/sdkconfiguration.py.

main.py
openapi.yaml
sdkconfiguration.py

from dataclasses import dataclass
SERVERS = [
'http://127.0.0.1:8000/',
# Local server
]
"""Contains the list of servers available to the SDK"""
@dataclass
class SDKConfiguration:
server_url: str = ''
server_idx: int = 0
def get_server_details(self) -> tuple[str, dict[str, str]]:
if self.server_url:
return self.server_url.removesuffix('/'), {}
if self.server_idx is None:
self.server_idx = 0
return SERVERS[self.server_idx], {}

You'll find calls to SDKConfiguration.get_server_details() when the SDK builds API URLs.

main.py
openapi.yaml
sdkconfiguration.py

from dataclasses import dataclass
SERVERS = [
'http://127.0.0.1:8000/',
# Local server
]
"""Contains the list of servers available to the SDK"""
@dataclass
class SDKConfiguration:
server_url: str = ''
server_idx: int = 0
def get_server_details(self) -> tuple[str, dict[str, str]]:
if self.server_url:
return self.server_url.removesuffix('/'), {}
if self.server_idx is None:
self.server_idx = 0
return SERVERS[self.server_idx], {}

Add a Title, Summary, Description, and Version to Your FastAPI App

In our app/main.py, if we have the following.

main.py
openapi.yaml
sdkconfiguration.py

from fastapi import FastAPI
app = FastAPI(
summary="A simple API to manage burgers and orders",
description="This API is used to manage burgers and orders in a restaurant",
version="0.1.0",
title="Apitizing Burger API",
)

FastAPI generates the following yaml in our openapi.yaml file.

main.py
openapi.yaml
sdkconfiguration.py

info:
description: This API is used to manage burgers and orders in a restaurant
summary: A simple API to manage burgers and orders
title: Apitizing Burger API
version: 0.1.0

Which adds helpful text to the generated SDK documentation, including comments in the SDK code. For example, in sdk/src/sdk/sdk.py.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py

class SDK:
r"""Apitizing Burger API: A simple API to manage burgers and orders
This API is used to manage burgers and orders in a restaurant
"""

Speakeasy adds the version to the SDKConfiguration in sdk/src/sdk/sdkconfiguration.py.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py

from dataclasses import dataclass
@dataclass
class SDKConfiguration:
openapi_doc_version: str = '0.1.0'

Eventually, when your users call your API using the generated SDK, this version makes its way into the headers passed with requests. For example, in sdk/src/sdk/burger.py, we see that headers['user-agent'] includes a reference to SDKConfiguration.openapi_doc_version.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

def create_burger(self, request: shared.BurgerCreate, retries: Optional[utils.RetryConfig] = None) -> operations.CreateBurgerResponse:
r"""Create Burger
Create a burger
"""
base_url = utils.template_url(*self.sdk_configuration.get_server_details())
url = base_url + '/burger/'
headers = {}
req_content_type, data, form = utils.serialize_request_body(request, "request", 'json')
if req_content_type not in ('multipart/form-data', 'multipart/mixed'):
headers['content-type'] = req_content_type
if data is None and form is None:
raise Exception('request body is required')
headers['Accept'] = 'application/json'
headers['user-agent'] = f'speakeasy-sdk/{self.sdk_configuration.language} {self.sdk_configuration.sdk_version} {self.sdk_configuration.gen_version} {self.sdk_configuration.openapi_doc_version}'
client = self.sdk_configuration.client

This way, your server logs will include the FastAPI App version along with other helpful details about the SDK.

Route-Level Customizations: Enhancing SDK Usability

With the basics out of the way, let's look at a few more substantial recommendations.

Add Typed Additional Responses to FastAPI Routes

When developers use your generated SDK, they may wish to see what all the possible responses for an API call could be.

With FastAPI, you can add additional responses to each route by specifying a response type.

In our app/main.py, we added this abbreviated code.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

from fastapi import FastAPI
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field
class ResponseMessage(BaseModel):
"""A response message"""
message: str = Field(description="The response message")
OPENAPI_RESPONSE_BURGER_NOT_FOUND = {
"model": ResponseMessage,
"description": "Burger not found",
}
def response_burger_not_found(burger_id: int):
"""Response for burger not found"""
return JSONResponse(
status_code=404,
content=f"Burger with id {burger_id} does not exist",
)
class Burger(BaseModel):
id: int
name: str
description: str = None
app = FastAPI()
@app.get(
"/burger/{burger_id}",
response_model=BurgerOutput,
responses={404: OPENAPI_RESPONSE_BURGER_NOT_FOUND},
tags=["burger"],
)
def read_burger(burger_id: Annotated[int, Path(title="Burger ID")]):
"""Read a burger"""
for burger in burgers_db:
if burger.id == burger_id:
return burger
return response_burger_not_found(burger_id)

FastAPI adds a schema for our specific error message to openapi.yaml.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

components:
schemas:
ResponseMessage:
description: A response message
properties:
message:
description: The response message
title: Message
type: string
required:
- message
title: ResponseMessage
type: object

Speakeasy then generates documentation for this error in sdk/docs/models/errors/responsemessage.md and adds a data class in sdk/src/sdk/models/errors/responsemessage.py, so that the SDK returns typed errors when, for example, users try to request a burger that does not exist.

Group FastAPI Operations With OpenAPI Tags and Tag Metadata

As your API develops and grows bigger, you're likely to split your API into separate files. FastAPI provides conveniences (opens in a new tab) to help reduce boilerplate and repetition when splitting an API into multiple modules.

While this separation may reduce cognitive overhead while you're working in particular sections of the API code, it doesn't mean similar groups are automatically created in your documentation and SDK code.

We recommend you add tags to all operations in FastAPI, whether you're building a big application or only have a handful of operations so that operations can be grouped by tag in generated SDK code and documentation.

Add Tags to Operations

The most straightforward way to add tags is to edit each operation and add a list of tags. This example highlights the tags list.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

from fastapi import FastAPI
app = FastAPI()
@app.get(
"/burger/{burger_id}",
tags=["burger"],
)
def read_burger(burger_id: int):
return {
"burger_id": burger_id,
}

Add Metadata to Tags

You can add metadata to your tags to further improve the developer experience of your SDK.

FastAPI accepts a parameter called openapi_tags, which we can use to add metadata, such as a description and a list of external documentation links.

Here's how to add metadata to tags.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

from fastapi import FastAPI
tags_metadata = [
{
"name": "burger",
"description": "Operations related to burgers",
"externalDocs": {
"description": "Burger external docs",
"url": "https://en.wikipedia.org/wiki/Hamburger",
},
},
{
"name": "order",
"description": "Operations related to orders",
},
]
app = FastAPI(
openapi_tags=tags_metadata,
)
@app.get(
"/burger/{burger_id}",
tags=["burger"],
)
def read_burger(burger_id: int):
return {
"burger_id": burger_id,
}

How Tags Are Added to the OpenAPI Spec and SDK Code

When we add metadata to tags, FastAPI adds a top-level tags section to our OpenAPI spec.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

tags:
- description: Operations related to burgers
externalDocs:
description: Burger external docs
url: https://en.wikipedia.org/wiki/Hamburger
name: burger
- description: Operations related to orders
name: order

Each tagged path in our OpenAPI spec also gets a list of tags.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

paths:
/burger/{burger_id}:
get:
description: Read a burger
operationId: readBurger
summary: Read Burger
tags:
- burger
# ...

Speakeasy then splits SDK files into separate modules and adds helpful links in docstrings and generated documentation. For example, in sdk/src/sdk/burger.py.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

class Burger:
r"""Operations related to burgers
https://en.wikipedia.org/wiki/Hamburger - Burger external docs
"""

Customize the OpenAPI operationId Generated by FastAPI

When FastAPI outputs an OpenAPI spec, it generates a unique OpenAPI operationId for each path. By default, this unique ID is generated by the FastAPI generate_unique_id function.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

def generate_unique_id(route: "APIRoute") -> str:
operation_id = route.name + route.path_format
operation_id = re.sub(r"\W", "_", operation_id)
assert route.methods
operation_id = operation_id + "_" + list(route.methods)[0].lower()
return operation_id

For our operation that returns a burger by burger_id, this unique ID would be read_burger_burger__burger_id__get. This makes its way into SDK code, leading to class names such as ReadBurgerBurgerBurgerIDGetRequest or function names like read_burger_burger_burger_id_get.

Here's a usage example after generating an SDK without customizing the operationId.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

import sdk
from sdk.models import operations
s = sdk.SDK()
req = operations.ReadBurgerBurgerBurgerIDGetRequest(
burger_id=847252,
)
res = s.burger.read_burger_burger_burger_id_get(req)

To improve usability, we have three methods of customizing these generated strings.

Option 1: Change Method Names in Speakeasy with x-speakeasy-name-override

Firstly, we can add the top-level x-speakeasy-name-override extension to our OpenAPI spec, allowing Speakeasy to override these generated names when it generates SDK code.

To add this extension, follow the Speakeasy guide on changing method names.

Option 2: Customize the FastAPI generate_unique_id_function Function

The preferred alternative, though, is to use a custom function when you generate unique IDs for paths.

The example below is an illustrative function that doesn't generate guaranteed-unique IDs and doesn't handle method names without an underscore. However, it demonstrates how you can add a function that generates IDs based on an operation's method name.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

from fastapi import FastAPI
def convert_snake_case_to_camel_case(string: str) -> str:
"""Convert snake case to camel case"""
words = string.split("_")
return words[0] + "".join(word.title() for word in words[1:])
def custom_generate_unique_id_function(route: APIRoute) -> str:
"""Custom function to generate unique id for each endpoint"""
return convert_snake_case_to_camel_case(route.name)
app = FastAPI(
generate_unique_id_function=custom_generate_unique_id_function,
)

Using our custom function above, our read_burger operation gets a much friendlier operation ID: readBurger. And our usage example becomes much easier to read.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

import sdk
from sdk.models import operations
s = sdk.SDK()
req = operations.ReadBurgerRequest(
burger_id=847252,
)
res = s.burger.read_burger(req)

Option 3: Add an Operation ID per Operation

With FastAPI, you can specify the operationId per operation. For our example, we'll add a new parameter called operation_id to the operation decorator.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

from fastapi import FastAPI
app = FastAPI()
@app.get(
"/burger/{burger_id}",
operation_id="readBurger",
)
def read_burger(burger_id: int):
pass

Add Retries to Your SDK With x-speakeasy-retries

Speakeasy can generate SDKs that follow custom rules for retrying failed requests. For instance, if your server failed to return a response within a specified time, you may want your users to retry their request without clobbering your server.

To add retries to SDKs generated by Speakeasy, add a top-level x-speakeasy-retries schema to your OpenAPI spec. You can also override the retry strategy per operation by adding x-speakeasy-retries to each operation.

Adding Global Retries

To add global retries, we need to customize the schema generated by the FastAPI get_openapi function.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
app = FastAPI(
summary="A simple API to manage burgers and orders",
description="This API is used to manage burgers and orders in a restaurant",
version="0.1.0",
title="Apitizing Burger API",
)
@app.get("/")
def root():
return {"message": "Root"}
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title=app.title,
version=app.version,
summary=app.summary,
description=app.description,
routes=app.routes,
)
# Add retries
openapi_schema["x-speakeasy-retries"] = {
"strategy": "backoff",
"backoff": {
"initialInterval": 500,
"maxInterval": 60000,
"maxElapsedTime": 3600000,
"exponent": 1.5,
},
"statusCodes": [
"5XX",
],
"retryConnectionErrors": True,
}
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi

Keep in mind you'll need to add this customization after declaring your operation routes.

This change adds the following top-level section to openapi.yaml.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

x-speakeasy-retries:
backoff:
exponent: 1.5
initialInterval: 500
maxElapsedTime: 3600000
maxInterval: 60000
retryConnectionErrors: true
statusCodes:
- 5XX
strategy: backoff

Adding Retries Per Request

To add x-speakeasy-retries to a single operation, update the operation and add the openapi_extra parameter as follows.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

from fastapi import FastAPI
app = FastAPI()
@app.get(
"/burger/",
openapi_extra={
"x-speakeasy-retries": {
"strategy": "backoff",
"backoff": {
"initialInterval": 500,
"maxInterval": 60000,
"maxElapsedTime": 3600000,
"exponent": 1.5,
},
"statusCodes": [
"5XX",
],
"retryConnectionErrors": True,
}
},
)
def list_burgers():
return []

Add Webhooks for Real-Time Notifications

Starting with OpenAPI version 3.1.0, it is possible to specify webhooks for your application in OpenAPI. Speakeasy generates request and response objects for webhooks as part of SDK generation, which provides a consistent interface to your users.

Here's how to add a webhook to FastAPI:

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

from fastapi import FastAPI
app = FastAPI()
class Order(BaseModel):
id: int
note: str
@app.webhooks.post(
"order-status-changed",
operation_id="webhookOrderStatusChanged",
)
def webhook_order_status_changed(body: Order):
"""
When an order status is changed, this webhook will be triggered.
The server will send a `POST` request with the order details to the webhook URL.
"""
pass

FastAPI generates the following top-level webhooks section in openapi.yaml.

main.py
openapi.yaml
sdkconfiguration.py
sdk.py
burger.py

webhooks:
order-status-changed:
post:
description: 'When an order status is changed, this webhook will be triggered.
The server will send a `POST` request with the order details to the webhook
URL.'
operationId: webhookOrderStatusChanged
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
required: true
responses:
'200':
content:
application/json:
schema: {}
description: Successful Response
'422':
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
description: Validation Error
summary: Webhook Order Status Changed

In turn, Speakeasy generates a model and corresponding documentation for WebhookOrderStatusChangedResponse.

Add a List of Servers to Your FastAPI App

This may seem obvious, but while first working with FastAPI in development, the generated docs, development server, and API operations all work out of the box without the need to manually specify your server address.

However, when generating SDKs, Speakeasy requires your OpenAPI spec to list servers.

If you start testing out Speakeasy in development for SDK generation, make sure to add a list of servers to your FastAPI app, starting with your local development server.

In our app/main.py, we added our local server as shown.

This leads to the following generated output in openapi.yaml.

Which, after Speakeasy generates the SDK, leads to the following abbreviated code in sdk/src/sdk/sdkconfiguration.py.

You'll find calls to SDKConfiguration.get_server_details() when the SDK builds API URLs.

Add a Title, Summary, Description, and Version to Your FastAPI App

In our app/main.py, if we have the following.

FastAPI generates the following yaml in our openapi.yaml file.

Which adds helpful text to the generated SDK documentation, including comments in the SDK code. For example, in sdk/src/sdk/sdk.py.

Speakeasy adds the version to the SDKConfiguration in sdk/src/sdk/sdkconfiguration.py.

Eventually, when your users call your API using the generated SDK, this version makes its way into the headers passed with requests. For example, in sdk/src/sdk/burger.py, we see that headers['user-agent'] includes a reference to SDKConfiguration.openapi_doc_version.

This way, your server logs will include the FastAPI App version along with other helpful details about the SDK.

Route-Level Customizations: Enhancing SDK Usability

With the basics out of the way, let's look at a few more substantial recommendations.

Add Typed Additional Responses to FastAPI Routes

When developers use your generated SDK, they may wish to see what all the possible responses for an API call could be.

With FastAPI, you can add additional responses to each route by specifying a response type.

In our app/main.py, we added this abbreviated code.

FastAPI adds a schema for our specific error message to openapi.yaml.

Speakeasy then generates documentation for this error in sdk/docs/models/errors/responsemessage.md and adds a data class in sdk/src/sdk/models/errors/responsemessage.py, so that the SDK returns typed errors when, for example, users try to request a burger that does not exist.

Group FastAPI Operations With OpenAPI Tags and Tag Metadata

As your API develops and grows bigger, you're likely to split your API into separate files. FastAPI provides conveniences (opens in a new tab) to help reduce boilerplate and repetition when splitting an API into multiple modules.

While this separation may reduce cognitive overhead while you're working in particular sections of the API code, it doesn't mean similar groups are automatically created in your documentation and SDK code.

We recommend you add tags to all operations in FastAPI, whether you're building a big application or only have a handful of operations so that operations can be grouped by tag in generated SDK code and documentation.

Add Tags to Operations

The most straightforward way to add tags is to edit each operation and add a list of tags. This example highlights the tags list.

Add Metadata to Tags

You can add metadata to your tags to further improve the developer experience of your SDK.

FastAPI accepts a parameter called openapi_tags, which we can use to add metadata, such as a description and a list of external documentation links.

Here's how to add metadata to tags.

How Tags Are Added to the OpenAPI Spec and SDK Code

When we add metadata to tags, FastAPI adds a top-level tags section to our OpenAPI spec.

Each tagged path in our OpenAPI spec also gets a list of tags.

Speakeasy then splits SDK files into separate modules and adds helpful links in docstrings and generated documentation. For example, in sdk/src/sdk/burger.py.

Customize the OpenAPI operationId Generated by FastAPI

When FastAPI outputs an OpenAPI spec, it generates a unique OpenAPI operationId for each path. By default, this unique ID is generated by the FastAPI generate_unique_id function.

For our operation that returns a burger by burger_id, this unique ID would be read_burger_burger__burger_id__get. This makes its way into SDK code, leading to class names such as ReadBurgerBurgerBurgerIDGetRequest or function names like read_burger_burger_burger_id_get.

Here's a usage example after generating an SDK without customizing the operationId.

To improve usability, we have three methods of customizing these generated strings.

Option 1: Change Method Names in Speakeasy with x-speakeasy-name-override

Firstly, we can add the top-level x-speakeasy-name-override extension to our OpenAPI spec, allowing Speakeasy to override these generated names when it generates SDK code.

To add this extension, follow the Speakeasy guide on changing method names.

Option 2: Customize the FastAPI generate_unique_id_function Function

The preferred alternative, though, is to use a custom function when you generate unique IDs for paths.

The example below is an illustrative function that doesn't generate guaranteed-unique IDs and doesn't handle method names without an underscore. However, it demonstrates how you can add a function that generates IDs based on an operation's method name.

Using our custom function above, our read_burger operation gets a much friendlier operation ID: readBurger. And our usage example becomes much easier to read.

Option 3: Add an Operation ID per Operation

With FastAPI, you can specify the operationId per operation. For our example, we'll add a new parameter called operation_id to the operation decorator.

Add Retries to Your SDK With x-speakeasy-retries

Speakeasy can generate SDKs that follow custom rules for retrying failed requests. For instance, if your server failed to return a response within a specified time, you may want your users to retry their request without clobbering your server.

To add retries to SDKs generated by Speakeasy, add a top-level x-speakeasy-retries schema to your OpenAPI spec. You can also override the retry strategy per operation by adding x-speakeasy-retries to each operation.

Adding Global Retries

To add global retries, we need to customize the schema generated by the FastAPI get_openapi function.

Keep in mind you'll need to add this customization after declaring your operation routes.

This change adds the following top-level section to openapi.yaml.

Adding Retries Per Request

To add x-speakeasy-retries to a single operation, update the operation and add the openapi_extra parameter as follows.

Add Webhooks for Real-Time Notifications

Starting with OpenAPI version 3.1.0, it is possible to specify webhooks for your application in OpenAPI. Speakeasy generates request and response objects for webhooks as part of SDK generation, which provides a consistent interface to your users.

Here's how to add a webhook to FastAPI:

FastAPI generates the following top-level webhooks section in openapi.yaml.

In turn, Speakeasy generates a model and corresponding documentation for WebhookOrderStatusChangedResponse.

main.py

from fastapi import FastAPI
app = FastAPI(
servers=[
{"url": "http://127.0.0.1:8000", "description": "Local server"},
],
)

Summary

In this post, we've explored how you can set up a FastAPI-based SDK generation pipeline without hand-editing or updating OpenAPI specifications. By using existing FastAPI methods for extending and customizing OpenAPI specifications, you can improve the usability of your generated client SDKs.