diff --git a/openapi/frameworks/assets/pydantic/speakeasy-quickstart-output.png b/openapi/frameworks/assets/pydantic/speakeasy-quickstart-output.png new file mode 100644 index 00000000..3ddf5b90 Binary files /dev/null and b/openapi/frameworks/assets/pydantic/speakeasy-quickstart-output.png differ diff --git a/openapi/frameworks/assets/pydantic/speakeasy-studio-suggestions.png b/openapi/frameworks/assets/pydantic/speakeasy-studio-suggestions.png new file mode 100644 index 00000000..c2fb8aca Binary files /dev/null and b/openapi/frameworks/assets/pydantic/speakeasy-studio-suggestions.png differ diff --git a/openapi/frameworks/pydantic.mdx b/openapi/frameworks/pydantic.mdx index 1f1717bd..4a5ce9d1 100644 --- a/openapi/frameworks/pydantic.mdx +++ b/openapi/frameworks/pydantic.mdx @@ -1,15 +1,15 @@ --- -title: How To Generate an OpenAPI Spec with Pydantic V2 -description: "How to generate OpenAPI schemas and great SDK clients for your Pydantic V2 Models" +title: How To Generate an OpenAPI Document With Pydantic V2 +description: "How to generate OpenAPI documents and great SDKs for your Pydantic V2 Models" --- -# How to generate an OpenAPI/Swagger spec with Pydantic V2 +# How to generate an OpenAPI document with Pydantic V2 -[Pydantic](https://docs.pydantic.dev/latest/) is considered by many API developers to be the best data validation library for Python, and with good reason. By defining an application's models in Pydantic, developers benefit from a vastly improved development experience, runtime data validation and serialization, and automatic OpenAPI schema generation. +[Pydantic](https://docs.pydantic.dev/latest/) is considered by many API developers to be the best data validation library for Python, and with good reason. By defining an application's models in Pydantic, developers benefit from a vastly improved development experience, runtime data validation and serialization, and automatic OpenAPI document generation. -However, many developers don't realize they can generate OpenAPI schemas from their Pydantic models, which they can then use to create SDKs, documentation, and server stubs. +However, many developers don't realize they can generate OpenAPI documents from their Pydantic models, which they can then use to create SDKs, documentation, and server stubs. -In this guide, you'll learn how to create new Pydantic models, generate an OpenAPI schema from them, and use the generated schema to create an SDK for your API. We'll start with the simplest possible Pydantic model and gradually add more features to show how Pydantic models translate to OpenAPI schemas. +In this guide, you'll learn how to create new Pydantic models, generate an OpenAPI document from them, and use the generated schema to create an SDK for your API. We'll start with the simplest possible Pydantic model and gradually add more features to show how Pydantic models translate to OpenAPI documents. ## Prerequisites @@ -19,9 +19,9 @@ Before we get started, make sure you have [Python](https://www.python.org/downlo python --version ``` -We use Python 3.12.4 in this guide, but any version of Python 3.8 or higher should work. +We use Python 3.13.3 in this guide, but any version of Python 3.8 or higher should work. -## Create a New Python Project +## Creating a new Python project First, create a new Python project and install the Pydantic library: @@ -37,9 +37,9 @@ python -m venv venv source venv/bin/activate ``` -## Install the Required Libraries +## Install the required libraries -We'll install Pydantic and PyYAML to generate and pretty-print the OpenAPI schema: +We'll install Pydantic and PyYAML to generate and pretty-print the OpenAPI document: ```bash Terminal # Install the Pydantic library @@ -49,11 +49,11 @@ pip install pydantic pip install pyyaml ``` -## Pydantic to OpenAPI Schema Walkthrough +## Pydantic to OpenAPI document walkthrough -Let's follow a step-by-step process to generate an OpenAPI schema from a Pydantic model without any additional libraries. +Let's follow a step-by-step process to generate an OpenAPI document from a Pydantic model without any additional libraries. -### Define a Simple Pydantic Model +### Defining a simple Pydantic model Create a new Python file called `models.py` and define a simple Pydantic model. @@ -69,7 +69,7 @@ class Pet(BaseModel): breed: str ``` -### Generate JSON Schema for the Pydantic Model +### Generating a JSON schema for the Pydantic model Add a new function called `print_json_schema` to the `models.py` file that prints the JSON schema for the `Pet` model. @@ -115,7 +115,7 @@ title: Pet type: object ``` -### Multiple Pydantic Models +### Multiple Pydantic models Let's add another Pydantic model called `Owner` to the `models.py` file. @@ -146,7 +146,7 @@ if __name__ == "__main__": print_json_schema() ``` -### Generate JSON Schema for Multiple Pydantic Models +### Generating a JSON schema for multiple Pydantic models Update the `print_json_schema` function to print the JSON schema for both the `Pet` and `Owner` models. @@ -227,7 +227,7 @@ The generated schema includes definitions for both the `Pet` and `Owner` models. Note that the root of the schema includes a `$defs` key that contains the definitions for both models, and the `Owner` model references the `Pet` model using the `$ref` keyword. -### Customize Pydantic JSON Schema Generation +### Customizing Pydantic JSON schema generation Let's customize the generated JSON schema to reference the `Pet` model using the `#/components/schemas` path instead of `$defs`. @@ -263,7 +263,7 @@ if __name__ == "__main__": print_json_schema([Pet, Owner]) ``` -Next, we'll update the `print_json_schema` function to print a JSON schema that resembles an OpenAPI schema's `components` section. +Next, we'll update the `print_json_schema` function to print a JSON schema that resembles an OpenAPI document's `components` section. ```python import yaml @@ -300,9 +300,9 @@ if __name__ == "__main__": print_json_schema([Pet, Owner]) ``` -Run `python models.py` to generate the OpenAPI schema for both the `Pet` and `Owner` models. +Run `python models.py` to generate the OpenAPI document for both the `Pet` and `Owner` models. -The generated OpenAPI schema includes the `components` section, with definitions for both the `Pet` and `Owner` models. +The generated OpenAPI document includes the `components` section, with definitions for both the `Pet` and `Owner` models. ```yaml components: @@ -345,9 +345,9 @@ components: type: object ``` -The JSON Schema we generated resembles an OpenAPI schema's `components` section, but to generate a valid OpenAPI schema, we need to add the `openapi` and `info` sections. +The JSON schema we generated resembles an OpenAPI document's `components` section, but to generate a valid OpenAPI document, we need to add the `openapi` and `info` sections. -Edit the `print_json_schema` function in `models.py` to include the `openapi` and `info` sections in the generated OpenAPI schema. +Edit the `print_json_schema` function in `models.py` to include the `openapi` and `info` sections in the generated OpenAPI document. ```python import yaml @@ -389,9 +389,9 @@ if __name__ == "__main__": print_json_schema([Pet, Owner]) ``` -Run `python models.py` to generate the complete OpenAPI schema for both the `Pet` and `Owner` models. +Run `python models.py` to generate the complete OpenAPI document for both the `Pet` and `Owner` models. -The generated OpenAPI schema includes the `openapi`, `info`, and `components` sections with definitions for both the `Pet` and `Owner` models. +The generated OpenAPI document includes the `openapi`, `info`, and `components` sections with definitions for both the `Pet` and `Owner` models. ```yaml openapi: 3.1.0 @@ -438,11 +438,11 @@ components: type: object ``` -Now we have a complete OpenAPI document that we can use to generate SDK clients for our API. However, the generated OpenAPI schema does not contain descriptions or example values for the models. We can add these details to the Pydantic models to improve the generated OpenAPI schema. +Now we have a complete OpenAPI document that we can use to generate SDK clients for our API. However, the generated OpenAPI document does not contain descriptions or example values for the models. We can add these details to the Pydantic models to improve the generated OpenAPI document. -### Adding Descriptions to Pydantic Models +### Adding descriptions to Pydantic models -Let's add docstrings to the `Pet` and `Owner` models to include additional information in the generated OpenAPI schema. +Let's add docstrings to the `Pet` and `Owner` models to include additional information in the generated OpenAPI document. ```python import yaml @@ -559,9 +559,9 @@ components: The `Pet` schema now also includes a description field, derived from the docstring we added to the `Pet` Pydantic model. -### Adding OpenAPI Titles and Descriptions to Pydantic Fields +### Adding OpenAPI titles and descriptions to Pydantic fields -Let's add titles and descriptions to the fields of the `Pet` and `Owner` models to include additional information in the generated OpenAPI schema. +Let's add titles and descriptions to the fields of the `Pet` and `Owner` models to include additional information in the generated OpenAPI document. We'll use the `Field` class from Pydantic to add descriptions to the fields. @@ -686,7 +686,7 @@ components: type: object ``` -### Adding OpenAPI Example Values to Pydantic Models +### Adding OpenAPI example values to Pydantic models Examples help API users understand your API's data structures, and some SDK and documentation generators use OpenAPI example values to generate useful code snippets and documentation. @@ -857,7 +857,7 @@ components: type: object ``` -### Marking Fields as Optional in Pydantic Models +### Marking fields as optional in Pydantic models By default, Pydantic marks all fields as required. You can mark a field as optional by setting the `default` parameter to `None`. @@ -1028,7 +1028,7 @@ components: type: object ``` -### Adding Enums to OpenAPI using Pydantic Models +### Adding enums to OpenAPI using Pydantic models Enums in OpenAPI are useful for defining a set of possible values for a field. @@ -1135,7 +1135,7 @@ if __name__ == "__main__": print_json_schema([Pet, Owner]) ``` -In our generated OpenAPI schema, we have a new `pet_type` field in the `Pet` schema. +In our generated OpenAPI document, we have a new `pet_type` field in the `Pet` schema. ```yaml openapi: 3.1.0 @@ -1236,23 +1236,23 @@ components: This enum is represented as a separate schema in the OpenAPI document. -## Adding Paths and Operations to the OpenAPI Schema +## Adding paths and operations to the OpenAPI document -Now that we have generated an OpenAPI schema from our Pydantic models, we can use the schema to generate SDK clients for our API. +Now that we have generated an OpenAPI document from our Pydantic models, we can use the schema to generate SDK clients for our API. However, the OpenAPI document we generated, while valid, does not include the `paths` section, which defines the API endpoints and operations. -When using Pydantic with FastAPI, you can define your API endpoints and operations directly in your FastAPI application. [FastAPI automatically generates the OpenAPI schema for your API](./fastapi.mdx), including the `paths` section. +When using Pydantic with FastAPI, you can define your API endpoints and operations directly in your FastAPI application. [FastAPI automatically generates the OpenAPI document for your API](/openapi/frameworks/fastapi#speakeasy-integration), including the `paths` section. -Let's see how we can define API endpoints and operations in a framework-agnostic way and add them to the OpenAPI schema. +Let's see how we can define API endpoints and operations in a framework-agnostic way and add them to the OpenAPI document. -### Install openapi-pydantic +### Installing openapi-pydantic -We'll use the [`openapi-pydantic`](https://github.com/mike-oakley/openapi-pydantic/) library to define a complete OpenAPI schema with paths and operations. +We'll use the [`openapi-pydantic`](https://github.com/mike-oakley/openapi-pydantic/) library to define a complete OpenAPI document with paths and operations. -The benefit of using `openapi-pydantic` is that it allows you to define the API endpoints and operations in a Python dictionary, while still getting the benefit of Pydantic's IDE support and type checking. +The benefit of using `openapi-pydantic` is that it allows you to define the API endpoints and operations in a Python dictionary while still getting the benefit of Pydantic's IDE support and type checking. -The library includes convenience methods to convert Pydantic models to OpenAPI schema components and add them to the OpenAPI schema. +The library includes convenience methods to convert Pydantic models to OpenAPI document components and to add them to the OpenAPI document. Install the `openapi-pydantic` library: @@ -1260,7 +1260,7 @@ Install the `openapi-pydantic` library: pip install openapi-pydantic ``` -### Define API Endpoints +### Defining API endpoints Create a new file called `api.py` to define the API endpoints using the `openapi-pydantic` library: @@ -1474,13 +1474,13 @@ components: The generated OpenAPI document includes all the components from our Pydantic models, along with the API endpoints we defined. The schemas include all the titles, descriptions, examples, and other details we added to our Pydantic models. -## Generating an SDK from the OpenAPI Schema +## Generating an SDK from the OpenAPI document -Now that we have a complete OpenAPI schema with paths and operations, we can use it to generate an SDK client for our API. +Now that we have a complete OpenAPI document with paths and operations, we can use it to generate an SDK client for our API. -### Prerequisites for SDK Generation +### Prerequisites for SDK generation -Install Speakeasy by following the [Speakeasy installation instructions](/docs/speakeasy-cli/getting-started#install). +Install Speakeasy by following the [Speakeasy installation instructions](/docs/speakeasy-reference/cli/getting-started#install) On macOS, you can install Speakeasy using Homebrew: @@ -1494,7 +1494,7 @@ Authenticate with Speakeasy using the following command: speakeasy auth login ``` -### Generate an SDK Using Speakeasy +### Generating an SDK using Speakeasy Run the following command to generate an SDK from the `openapi.yaml` file: @@ -1502,21 +1502,33 @@ Run the following command to generate an SDK from the `openapi.yaml` file: speakeasy quickstart ``` -Follow the onscreen prompts to provide the necessary configuration details for your new SDK such as the name, schema location and output path. Enter `openapi.yaml` when prompted for the OpenAPI document location and select TypeScript when prompted for which language you would like to generate. +Follow the onscreen prompts to provide the necessary configuration details for your new SDK, such as the name, schema location, and output path. Enter `openapi.yaml` when prompted for the OpenAPI document location and select TypeScript when prompted for which language you would like to generate. -### Adding Speakeasy Extensions to the OpenAPI Schema +Speakeasy [validates](/docs/core-concepts#validation) the OpenAPI document to check that it's ready for code generation. Validation issues will be printed in the terminal. The generated SDK will be saved as a folder in your project. -Speakeasy uses [OpenAPI extensions](../../openapi/extensions.md) to provide additional information for generating SDKs. +![Speakeasy quickstart command output](./assets/pydantic/speakeasy-quickstart-output.png) -We can add extensions using [OpenAPI Overlays](../../openapi/overlays.mdx), which are YAML files that [Speakeasy overlays on top of the OpenAPI schema](/docs/prep-openapi/overlays/create-overlays). +Speakeasy also suggests improvements for your SDK using [Speakeasy Suggest](/docs/prep-openapi/maintenance), which is an AI-powered tool in Speakeasy Studio. You can view the suggestions in Speakeasy Studio: -Alternatively, you can add extensions directly to the OpenAPI schema using the `x-` prefix. +![Speakeasy Studio suggestions](./assets/pydantic/speakeasy-studio-suggestions.png) -For example, you can add the [`x-speakeasy-retries` extension](../../docs/customize-sdks/retries.mdx) to have Speakeasy generate retry logic in the SDK. +### Adding Speakeasy extensions to the OpenAPI document + +Speakeasy uses [OpenAPI extensions](/openapi/extensions) to provide additional information for generating SDKs. + +We can add extensions using [OpenAPI overlays](/openapi/overlays), which are YAML files that [Speakeasy lays on top of the OpenAPI document](/docs/prep-openapi/overlays/create-overlays). + +We can use overlays alongside [OpenAPI transformations](/docs/prep-openapi/transformations) to improve the OpenAPI document for SDK generation. + +Transformations are predefined functions that allow you to remove unused components, filter operations, and format your OpenAPI document. Unlike overlays, transformations directly modify the OpenAPI document itself. + +Note that for Speakeasy OpenAPI extensions, you can also add extensions directly to the OpenAPI document using the `x-` prefix. + +For example, you can add the [`x-speakeasy-retries`](/docs/customize/runtime/retries) extension to have Speakeasy generate retry logic in the SDK. Import the `Dict` and `Any` types from the `typing` module in `api.py`, and `ConfigDict` from `pydantic`. -We'll use these types to define the `x-speakeasy-retries` extension in the OpenAPI schema. +We'll use these types to define the `x-speakeasy-retries` extension in the OpenAPI document. ```python api.py from typing import List, Dict, Any @@ -1569,7 +1581,7 @@ def construct_base_open_api() -> OpenAPIwithRetries: ) ``` -This produces an OpenAPI schema with retry functionality: +This produces an OpenAPI document with retry functionality: ```yaml openapi.yaml x-speakeasy-retries: @@ -1584,9 +1596,9 @@ x-speakeasy-retries: retryConnectionErrors: true ``` -### Add Tags to the OpenAPI Schema +### Adding tags to the OpenAPI document -To group operations in the OpenAPI schema, you can use tags. This also allows Speakeasy to structure the generated SDK code and documentation logically. +To group operations in the OpenAPI document, you can use tags. This also allows Speakeasy to structure the generated SDK code and documentation logically. Add a `tags` field to the `OpenAPIwithRetries` object, then add a `tags` field to each operation in the `construct_base_open_api` function: @@ -1624,12 +1636,24 @@ python api.py speakeasy quickstart ``` -Speakeasy will detect the changes to your OpenAPI schema, generate the SDK with the updated tags, and automatically increment the SDK's version number. +Speakeasy will detect the changes to your OpenAPI document, generate the SDK with the updated tags, and automatically increment the SDK's version number. Take a look at the generated SDK to see how Speakeasy groups operations by tags. -## We Can Help Get Your Pydantic Models Ready for SDK Generation +In the SDK `README.md` file, you'll find documentation about your Speakeasy SDK. TypeScript SDKs generated with Speakeasy include an installable [Model Context Protocol (MCP) server](/docs/model-context-protocol) where the various SDK methods are exposed as tools that AI applications can invoke. Your SDK documentation includes instructions for installing the MCP server. + +Note that the SDK is not ready for production use. To get it production-ready, follow the steps outlined in your Speakeasy Studio workspace. + +## How Speakeasy helps get your Pydantic models ready for SDK generation -In this tutorial, we learned how to generate an OpenAPI schema from Pydantic models and use it to generate an SDK client using Speakeasy. +In this tutorial, we learned how to generate an OpenAPI document from Pydantic models and use it to generate an SDK client using Speakeasy. If you would like to discuss how to get your Pydantic models ready for SDK generation, give us feedback, or shoot the breeze about all things OpenAPI and SDKs, [join our Slack](https://join.slack.com/t/speakeasy-dev/shared_invite/zt-1cwb3flxz-lS5SyZxAsF_3NOq5xc8Cjw). + +If you haven't already, take a look at our [blog](/blog) to learn more about API design, SDK generation, and our latest features, including: + + - [Native JSONL support in your SDKs](/blog/release-jsonl-support) + - [Introducing comprehensive SDK testing](/blog/release-sdk-testing) + - [Model Context Protocol: TypeScript SDKs for the agentic AI ecosystem](/blog/release-model-context-protocol) + - [Python generation with async and Pydantic support](/blog/release-python) + - [Choosing your Python REST API framework](/blog/choosing-your-framework-python)