Skip to content

OpenAPI Schema Generation in Flask-X-OpenAPI-Schema

This document explains how to generate OpenAPI schemas using Flask-X-OpenAPI-Schema, including customizing the schema, adding additional components, and serving the schema to clients.

Overview

Flask-X-OpenAPI-Schema provides tools for generating OpenAPI 3.0.x schemas from your Flask and Flask-RESTful applications. The schema generation process is automatic and based on the metadata provided in your API endpoints.

Basic Schema Generation

With Flask.MethodView

from flask import Flask, Blueprint
from flask_x_openapi_schema.x.flask.views import MethodViewOpenAPISchemaGenerator
import yaml

# Create a Flask app
app = Flask(__name__)
blueprint = Blueprint("api", __name__, url_prefix="/api")

# Register your views
# ...

# Register the blueprint
app.register_blueprint(blueprint)

# Generate OpenAPI schema
@app.route("/openapi.yaml")
def get_openapi_spec():
    generator = MethodViewOpenAPISchemaGenerator(
        title="My API",
        version="1.0.0",
        description="API for managing resources",
    )

    # Process MethodView resources
    generator.process_methodview_resources(blueprint)

    # Generate the schema
    schema = generator.generate_schema()

    # Convert to YAML
    yaml_content = yaml.dump(
        schema,
        sort_keys=False,
        default_flow_style=False,
        allow_unicode=True,
    )

    return yaml_content, 200, {"Content-Type": "text/yaml"}

With Flask-RESTful

from flask import Flask
from flask_restful import Api
from flask_x_openapi_schema.x.flask_restful import OpenAPIIntegrationMixin
import yaml

# Create a Flask app
app = Flask(__name__)

# Create an OpenAPI-enabled API
class OpenAPIApi(OpenAPIIntegrationMixin, Api):
    pass

api = OpenAPIApi(app)

# Register your resources
# ...

# Generate OpenAPI schema
@app.route("/openapi.yaml")
def get_openapi_spec():
    schema = api.generate_openapi_schema(
        title="My API",
        version="1.0.0",
        description="API for managing resources",
        output_format="json",
    )

    # Convert to YAML
    yaml_content = yaml.dump(
        schema,
        sort_keys=False,
        default_flow_style=False,
        allow_unicode=True,
    )

    return yaml_content, 200, {"Content-Type": "text/yaml"}

Customizing the Schema

Schema Information

You can customize the schema information by providing parameters to the schema generator:

generator = MethodViewOpenAPISchemaGenerator(
    title="My API",
    version="1.0.0",
    description="API for managing resources",
    terms_of_service="https://example.com/terms/",
    contact={
        "name": "API Support",
        "url": "https://example.com/support/",
        "email": "support@example.com",
    },
    license={
        "name": "MIT",
        "url": "https://opensource.org/licenses/MIT",
    },
)

Or with Flask-RESTful:

schema = api.generate_openapi_schema(
    title="My API",
    version="1.0.0",
    description="API for managing resources",
    terms_of_service="https://example.com/terms/",
    contact={
        "name": "API Support",
        "url": "https://example.com/support/",
        "email": "support@example.com",
    },
    license={
        "name": "MIT",
        "url": "https://opensource.org/licenses/MIT",
    },
    output_format="json",
)

Servers

You can specify the servers that the API is available on:

generator = MethodViewOpenAPISchemaGenerator(
    # ...
    servers=[
        {
            "url": "https://api.example.com/v1",
            "description": "Production server",
        },
        {
            "url": "https://staging-api.example.com/v1",
            "description": "Staging server",
        },
        {
            "url": "https://dev-api.example.com/v1",
            "description": "Development server",
        },
    ],
)

Or with Flask-RESTful:

schema = api.generate_openapi_schema(
    # ...
    servers=[
        {
            "url": "https://api.example.com/v1",
            "description": "Production server",
        },
        {
            "url": "https://staging-api.example.com/v1",
            "description": "Staging server",
        },
        {
            "url": "https://dev-api.example.com/v1",
            "description": "Development server",
        },
    ],
    output_format="json",
)

Security Schemes

You can define security schemes for your API:

generator = MethodViewOpenAPISchemaGenerator(
    # ...
    security_schemes={
        "bearerAuth": {
            "type": "http",
            "scheme": "bearer",
            "bearerFormat": "JWT",
        },
        "apiKeyAuth": {
            "type": "apiKey",
            "in": "header",
            "name": "X-API-Key",
        },
    },
)

Or with Flask-RESTful:

schema = api.generate_openapi_schema(
    # ...
    security_schemes={
        "bearerAuth": {
            "type": "http",
            "scheme": "bearer",
            "bearerFormat": "JWT",
        },
        "apiKeyAuth": {
            "type": "apiKey",
            "in": "header",
            "name": "X-API-Key",
        },
    },
    output_format="json",
)

Registering Additional Components

Manually Registering Models

You can manually register additional models that might not be automatically detected:

from flask_x_openapi_schema.x.flask.views import MethodViewOpenAPISchemaGenerator
from flask_x_openapi_schema.core.utils import pydantic_to_openapi_schema

# Create the schema generator
generator = MethodViewOpenAPISchemaGenerator(
    title="My API",
    version="1.0.0",
    description="API for managing resources",
)

# Manually register models
generator._register_model(UserResponse)
generator._register_model(ErrorResponse)
generator._register_model(ProductCategory)
generator._register_model(ProductStatus)

# Process MethodView resources
generator.process_methodview_resources(blueprint)

# Generate the schema
schema = generator.generate_schema()

Or with Flask-RESTful:

# Generate the schema
schema = api.generate_openapi_schema(
    title="My API",
    version="1.0.0",
    description="API for managing resources",
    output_format="json",
)

# Manually register models
if "components" not in schema:
    schema["components"] = {}
if "schemas" not in schema["components"]:
    schema["components"]["schemas"] = {}

for model in [UserResponse, ErrorResponse, ProductCategory, ProductStatus]:
    model_schema = pydantic_to_openapi_schema(model)
    schema["components"]["schemas"][model.__name__] = model_schema

Adding Tags

You can add tags to your OpenAPI schema to group operations:

generator = MethodViewOpenAPISchemaGenerator(
    # ...
    tags=[
        {
            "name": "users",
            "description": "Operations related to users",
        },
        {
            "name": "products",
            "description": "Operations related to products",
        },
        {
            "name": "orders",
            "description": "Operations related to orders",
        },
    ],
)

Or with Flask-RESTful:

schema = api.generate_openapi_schema(
    # ...
    tags=[
        {
            "name": "users",
            "description": "Operations related to users",
        },
        {
            "name": "products",
            "description": "Operations related to products",
        },
        {
            "name": "orders",
            "description": "Operations related to orders",
        },
    ],
    output_format="json",
)

Serving the Schema

Serving as YAML

@app.route("/openapi.yaml")
def get_openapi_yaml():
    # Generate the schema
    # ...

    # Convert to YAML
    yaml_content = yaml.dump(
        schema,
        sort_keys=False,
        default_flow_style=False,
        allow_unicode=True,
    )

    return yaml_content, 200, {"Content-Type": "text/yaml"}

Serving as JSON

@app.route("/openapi.json")
def get_openapi_json():
    # Generate the schema
    # ...

    # Convert to JSON
    import json
    json_content = json.dumps(schema, ensure_ascii=False)

    return json_content, 200, {"Content-Type": "application/json"}

Serving Swagger UI

@app.route("/")
def index():
    return """
    <!DOCTYPE html>
    <html>
    <head>
        <title>API Documentation</title>
        <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.9.1/swagger-ui.min.css">
    </head>
    <body>
        <div id="swagger-ui"></div>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.9.1/swagger-ui-bundle.min.js"></script>
        <script>
            window.onload = function() {
                SwaggerUIBundle({
                    url: "/openapi.yaml",
                    dom_id: "#swagger-ui",
                    presets: [
                        SwaggerUIBundle.presets.apis,
                        SwaggerUIBundle.SwaggerUIStandalonePreset
                    ],
                    layout: "BaseLayout",
                    validatorUrl: null,
                    displayRequestDuration: true,
                    syntaxHighlight: {
                        activated: true,
                        theme: "agate"
                    }
                });
            }
        </script>
    </body>
    </html>
    """

Serving ReDoc

@app.route("/redoc")
def redoc():
    return """
    <!DOCTYPE html>
    <html>
    <head>
        <title>API Documentation</title>
        <meta charset="utf-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
        <style>
            body {
                margin: 0;
                padding: 0;
            }
        </style>
    </head>
    <body>
        <redoc spec-url="/openapi.yaml"></redoc>
        <script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"></script>
    </body>
    </html>
    """

Advanced Schema Generation

Internationalization

You can generate schemas in different languages using the internationalization support:

from flask_x_openapi_schema import set_current_language

# Set the language for schema generation
set_current_language("zh-Hans")

# Generate the schema
# ...

Customizing Schema Generation

You can customize the schema generation process by subclassing the schema generator:

from flask_x_openapi_schema.x.flask.views import MethodViewOpenAPISchemaGenerator

class CustomSchemaGenerator(MethodViewOpenAPISchemaGenerator):
    def process_methodview_resources(self, blueprint):
        # Custom processing logic
        super().process_methodview_resources(blueprint)

    def generate_schema(self):
        # Custom schema generation logic
        schema = super().generate_schema()

        # Add custom components
        if "components" not in schema:
            schema["components"] = {}

        # Add custom security schemes
        if "securitySchemes" not in schema["components"]:
            schema["components"]["securitySchemes"] = {}

        schema["components"]["securitySchemes"]["customAuth"] = {
            "type": "apiKey",
            "in": "header",
            "name": "X-Custom-Auth",
        }

        return schema

# Use the custom generator
generator = CustomSchemaGenerator(
    title="My API",
    version="1.0.0",
    description="API for managing resources",
)

Generating Multiple Schemas

You can generate multiple schemas for different parts of your API:

# Generate schema for the main API
main_generator = MethodViewOpenAPISchemaGenerator(
    title="Main API",
    version="1.0.0",
    description="Main API for managing resources",
)
main_generator.process_methodview_resources(main_blueprint)
main_schema = main_generator.generate_schema()

# Generate schema for the admin API
admin_generator = MethodViewOpenAPISchemaGenerator(
    title="Admin API",
    version="1.0.0",
    description="Admin API for managing resources",
)
admin_generator.process_methodview_resources(admin_blueprint)
admin_schema = admin_generator.generate_schema()

# Serve the schemas
@app.route("/openapi.yaml")
def get_openapi_yaml():
    return yaml.dump(main_schema, sort_keys=False, default_flow_style=False), 200, {"Content-Type": "text/yaml"}

@app.route("/admin/openapi.yaml")
def get_admin_openapi_yaml():
    return yaml.dump(admin_schema, sort_keys=False, default_flow_style=False), 200, {"Content-Type": "text/yaml"}

Working Examples

For complete working examples of schema generation, check out the example applications in the repository:

These examples show how to:

  • Generate OpenAPI schema from Flask.MethodView classes and Flask-RESTful resources
  • Customize schema information (title, version, description)
  • Serve the schema as YAML or JSON
  • Integrate Swagger UI for interactive API documentation

You can run the examples using the provided justfile commands:

# Run the Flask MethodView example
just run-example-flask

# Run the Flask-RESTful example
just run-example-flask-restful

Conclusion

Flask-X-OpenAPI-Schema provides powerful tools for generating OpenAPI schemas from your Flask and Flask-RESTful applications. By using the schema generators and customizing the schema generation process, you can create comprehensive API documentation that accurately reflects your API's capabilities.