• Stars
    star
    982
  • Rank 46,621 (Top 1.0 %)
  • Language
    Python
  • License
    MIT License
  • Created over 4 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

This code generator creates FastAPI app from an openapi file.

fastapi-code-generator

This code generator creates a FastAPI app from an openapi file.

PyPI version Downloads PyPI - Python Version codecov license Code style: black

This project is in experimental phase.

fastapi-code-generator uses datamodel-code-generator to generate pydantic models

Help

See documentation for more details.

Installation

To install fastapi-code-generator:

$ pip install fastapi-code-generator

Usage

The fastapi-code-generator command:

Usage: fastapi-codegen [OPTIONS]

Options:
  -i, --input FILENAME     [required]
  -o, --output PATH        [required]
  -t, --template-dir PATH
  -m, --model-file         Specify generated model file path + name, if not default to models.py
  -r, --generate-routers   Generate modular api with multiple routers using RouterAPI (for bigger applications).
  --specify-tags           Use along with --generate-routers to generate specific routers from given list of tags.
  -c, --custom-visitors    PATH - A custom visitor that adds variables to the template.
  --install-completion     Install completion for the current shell.
  --show-completion        Show completion for the current shell, to copy it
                           or customize the installation.
  --help                   Show this message and exit.

Example

OpenAPI

$ fastapi-codegen --input api.yaml --output app
api.yaml

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Swagger Petstore
  license:
    name: MIT
servers:
  - url: http://petstore.swagger.io/v1
paths:
  /pets:
    get:
      summary: List all pets
      operationId: listPets
      tags:
        - pets
      parameters:
        - name: limit
          in: query
          description: How many items to return at one time (max 100)
          required: false
          schema:
            type: integer
            format: int32
      responses:
        '200':
          description: A paged array of pets
          headers:
            x-next:
              description: A link to the next page of responses
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Pets"
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
                x-amazon-apigateway-integration:
                  uri:
                    Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PythonVersionFunction.Arn}/invocations
                  passthroughBehavior: when_no_templates
                  httpMethod: POST
                  type: aws_proxy
    post:
      summary: Create a pet
      operationId: createPets
      tags:
        - pets
      responses:
        '201':
          description: Null response
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
                x-amazon-apigateway-integration:
                  uri:
                    Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PythonVersionFunction.Arn}/invocations
                  passthroughBehavior: when_no_templates
                  httpMethod: POST
                  type: aws_proxy
  /pets/{petId}:
    get:
      summary: Info for a specific pet
      operationId: showPetById
      tags:
        - pets
      parameters:
        - name: petId
          in: path
          required: true
          description: The id of the pet to retrieve
          schema:
            type: string
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Pets"
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
    x-amazon-apigateway-integration:
      uri:
        Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PythonVersionFunction.Arn}/invocations
      passthroughBehavior: when_no_templates
      httpMethod: POST
      type: aws_proxy
components:
  schemas:
    Pet:
      required:
        - id
        - name
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
        tag:
          type: string
    Pets:
      type: array
      description: list of pet
      items:
        $ref: "#/components/schemas/Pet"
    Error:
      required:
        - code
        - message
      properties:
        code:
          type: integer
          format: int32
        message:
          type: string

app/main.py:

# generated by fastapi-codegen:
#   filename:  api.yaml
#   timestamp: 2020-06-14T10:45:22+00:00

from __future__ import annotations

from typing import Optional

from fastapi import FastAPI, Query

from .models import Pets

app = FastAPI(version="1.0.0", title="Swagger Petstore", license="{'name': 'MIT'}",)


@app.get('/pets', response_model=Pets)
def list_pets(limit: Optional[int] = None) -> Pets:
    """
    List all pets
    """
    pass


@app.post('/pets', response_model=None)
def create_pets() -> None:
    """
    Create a pet
    """
    pass


@app.get('/pets/{pet_id}', response_model=Pets)
def show_pet_by_id(pet_id: str = Query(..., alias='petId')) -> Pets:
    """
    Info for a specific pet
    """
    pass

app/models.py:

# generated by datamodel-codegen:
#   filename:  api.yaml
#   timestamp: 2020-06-14T10:45:22+00:00

from typing import List, Optional

from pydantic import BaseModel, Field


class Pet(BaseModel):
    id: int
    name: str
    tag: Optional[str] = None


class Pets(BaseModel):
    __root__: List[Pet] = Field(..., description='list of pet')


class Error(BaseModel):
    code: int
    message: str

Custom Template

If you want to generate custom *.py files then you can give a custom template directory to fastapi-code-generator with -t or --template-dir options of the command.

fastapi-code-generator will search for jinja2 template files in given template directory, for example some_jinja_templates/list_pets.py.

fastapi-code-generator --template-dir some_jinja_templates --output app --input api.yaml

These files will be rendered and written to the output directory. Also, the generated file names will be created with the template name and extension of *.py, for example app/list_pets.py will be a separate file generated from the jinja template alongside the default app/main.py

Variables

You can use the following variables in the jinja2 templates

  • imports all imports statements
  • info all info statements
  • operations operations is list of operation
    • operation.type HTTP METHOD
    • operation.path Path
    • operation.snake_case_path Snake-cased Path
    • operation.response response object
    • operation.function_name function name is created operationId or METHOD + Path
    • operation.snake_case_arguments Snake-cased function arguments
    • operation.security Security
    • operation.summary a summary
    • operation.tags Tags

default template

main.jinja2

from __future__ import annotations

from fastapi import FastAPI

{{imports}}

app = FastAPI(
    {% if info %}
    {% for key,value in info.items() %}
    {{ key }} = "{{ value }}",
    {% endfor %}
    {% endif %}
    )


{% for operation in operations %}
@app.{{operation.type}}('{{operation.snake_case_path}}', response_model={{operation.response}})
def {{operation.function_name}}({{operation.snake_case_arguments}}) -> {{operation.response}}:
    {%- if operation.summary %}
    """
    {{ operation.summary }}
    """
    {%- endif %}
    pass
{% endfor %}

modular template

modular_template/main.jinja2:

from __future__ import annotations

from fastapi import FastAPI

from .routers import {{ routers | join(", ") }}

app = FastAPI(
    {% if info %}
    {% for key,value in info.items() %}
    {% set info_value= value.__repr__() %}
    {{ key }} = {{info_value}},
    {% endfor %}
    {% endif %}
    )

{% for router in routers -%}
app.include_router({{router}}.router)
{% endfor -%}

@app.get("/")
async def root():
    return {"message": "Gateway of the App"}

modular_template/routers.jinja2:

from __future__ import annotations

from fastapi import APIRouter
from fastapi import FastAPI

from ..dependencies import *

router = APIRouter(
    tags=['{{tag}}']
    )

{% for operation in operations %}
{% if operation.tags[0] == tag %}
@router.{{operation.type}}('{{operation.snake_case_path}}', response_model={{operation.response}}
    {% if operation.additional_responses %}
        , responses={
            {% for status_code, models in operation.additional_responses.items() %}
                '{{ status_code }}': {
                {% for key, model in models.items() %}
                    '{{ key }}': {{ model }}{% if not loop.last %},{% endif %}
                {% endfor %}
                }{% if not loop.last %},{% endif %}
            {% endfor %}
        }
    {% endif %}
    {% if operation.tags%}
    , tags={{operation.tags}}
    {% endif %})
def {{operation.function_name}}({{operation.snake_case_arguments}}) -> {{operation.return_type}}:
    {%- if operation.summary %}
    """
    {{ operation.summary }}
    """
    {%- endif %}
    pass
{% endif %}
{% endfor %}

modular_template/dependencies.jinja2:

{{imports}}

Custom Visitors

Custom visitors allow you to pass custom variables to your custom templates.

E.g.

custom template

custom-template.jinja2

#{ % custom_header %}
from __future__ import annotations

from fastapi import FastAPI

...

custom visitor

custom-visitor.py

from typing import Dict, Optional

from fastapi_code_generator.parser import OpenAPIParser
from fastapi_code_generator.visitor import Visitor


def custom_visitor(parser: OpenAPIParser, model_path: Path) -> Dict[str, object]:
    return {'custom_header': 'My header'}


visit: Visitor = custom_visitor

Multiple Files using APIRouter (For Bigger Applications)

β”œβ”€β”€ app                      # "app" is a Root directory      
β”‚   β”œβ”€β”€ main.py              # "main" module
β”‚   β”œβ”€β”€ models.py            # "models" of the application
β”‚   β”œβ”€β”€ dependencies.py      # "dependencies" module, e.g. import app.dependencies
β”‚   └── routers              # "routers" is a "app subpackage"
β”‚       β”œβ”€β”€ fat_cats.py      # "fat_cats" submodule, e.g. import app.routers.fat_cats
β”‚       β”œβ”€β”€ slim_dogs.py     # "slim_dogs" submodule, e.g. import app.routers.slim_dogs
β”‚       └── wild_boars.py    # "wild_boars" submodule, e.g. import app.routers.wild_boars

See documentation of APIRouter OpenAPI for more details.

Generate main aside with all of its routers:

$ fastapi-codegen --input swagger.yaml --output app --generate-routers

Regenerate specific routers:

$ fastapi-codegen --input swagger.yaml --output app --generate-routers --specify-tags "Wild Boars, Fat Cats"
swagger.yaml

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Swagger Petstore
  license:
    name: MIT
servers:
  - url: /
  - url: http://petstore.swagger.io/v1
  - url: http://localhost:8080/
paths:
  /boars:
    get:
      summary: List All Wild Boars
      operationId: listWildBoars
      tags:
        - Wild Boars
      parameters:
        - name: limit
          in: query
          description: How many items to return at one time (max 100)
          required: false
          schema:
            type: integer
      responses:
        '200':
          description: An array of wild boars
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WildBoars"
    post:
      summary: Create a Wild Boar
      operationId: createWildBoars
      tags:
        - Wild Boars
      responses:
        '201':
          description: Null response
  /boars/{boarId}:
    get:
      summary: Info For a Specific Boar
      operationId: showBoarById
      tags:
        - Wild Boars
      parameters:
        - name: boarId
          in: path
          required: true
          description: The id of the boar to retrieve
          schema:
            type: string
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Pet"
  /cats:
    get:
      summary: List All Fat Cats
      operationId: listFatCats
      tags:
        - Fat Cats
      parameters:
        - name: limit
          in: query
          description: How many items to return at one time (max 100)
          required: false
          schema:
            type: integer
      responses:
        '200':
          description: An array of fat cats
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FatCats"
    post:
      summary: Create a Fat Cat
      operationId: createFatCats
      tags:
        - Fat Cats
      responses:
        '201':
          description: Null response
  /cats/{catId}:
    get:
      summary: Info For a Specific Cat
      operationId: showCatById
      tags:
        - Fat Cats
      parameters:
        - name: catId
          in: path
          required: true
          description: The id of the cat to retrieve
          schema:
            type: string
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Pet"
  /dogs:
    get:
      summary: List All Slim Dogs
      operationId: listSlimDogs
      tags:
        - Slim Dogs
      parameters:
        - name: limit
          in: query
          description: How many items to return at one time (max 100)
          required: false
          schema:
            type: integer
      responses:
        '200':
          description: An array of slim dogs
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SlimDogs"
    post:
      summary: Create a Slim Dog
      operationId: createSlimDogs
      tags:
        - Slim Dogs
      responses:
        '201':
          description: Null response
  /dogs/{dogId}:
    get:
      summary: Info For a Specific Dog
      operationId: showDogById
      tags:
        - Slim Dogs
      parameters:
        - name: dogId
          in: path
          required: true
          description: The id of the dog to retrieve
          schema:
            type: string
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Pet"
components:
  schemas:
    Pet:
      required:
        - id
        - name
      properties:
        id:
          type: integer
        name:
          type: string
        tag:
          type: string
    FatCats:
      type: array
      description: list of fat cats
      items:
        $ref: "#/components/schemas/Pet"
    SlimDogs:
      type: array
      description: list of slim dogs
      items:
        $ref: "#/components/schemas/Pet"
    WildBoars:
      type: array
      description: list of wild boars
      items:
        $ref: "#/components/schemas/Pet"

app/main.py:

# generated by fastapi-codegen:
#   filename:  swagger.yaml
#   timestamp: 2023-04-04T12:06:16+00:00

from __future__ import annotations

from fastapi import FastAPI

from .routers import fat_cats, slim_dogs, wild_boars

app = FastAPI(
    version='1.0.0',
    title='Swagger Petstore',
    license={'name': 'MIT'},
    servers=[
        {'url': '/'},
        {'url': 'http://petstore.swagger.io/v1'},
        {'url': 'http://localhost:8080/'},
    ],
)

app.include_router(fat_cats.router)
app.include_router(slim_dogs.router)
app.include_router(wild_boars.router)


@app.get("/")
async def root():
    return {"message": "Gateway of the App"}

app/models.py:

# generated by fastapi-codegen:
#   filename:  swagger.yaml
#   timestamp: 2023-04-04T12:06:16+00:00

from __future__ import annotations

from typing import List, Optional

from pydantic import BaseModel, Field


class Pet(BaseModel):
    id: int
    name: str
    tag: Optional[str] = None


class FatCats(BaseModel):
    __root__: List[Pet] = Field(..., description='list of fat cats')


class SlimDogs(BaseModel):
    __root__: List[Pet] = Field(..., description='list of slim dogs')


class WildBoars(BaseModel):
    __root__: List[Pet] = Field(..., description='list of wild boars')

app/routers/fat_cats.py:

# generated by fastapi-codegen:
#   filename:  swagger.yaml
#   timestamp: 2023-04-04T12:06:16+00:00

from __future__ import annotations

from fastapi import APIRouter

from ..dependencies import *

router = APIRouter(tags=['Fat Cats'])


@router.get('/cats', response_model=FatCats, tags=['Fat Cats'])
def list_fat_cats(limit: Optional[int] = None) -> FatCats:
    """
    List All Fat Cats
    """
    pass


@router.post('/cats', response_model=None, tags=['Fat Cats'])
def create_fat_cats() -> None:
    """
    Create a Fat Cat
    """
    pass


@router.get('/cats/{cat_id}', response_model=Pet, tags=['Fat Cats'])
def show_cat_by_id(cat_id: str = Path(..., alias='catId')) -> Pet:
    """
    Info For a Specific Cat
    """
    pass

app/routers/slim_dogs.py:

# generated by fastapi-codegen:
#   filename:  swagger.yaml
#   timestamp: 2023-04-04T12:06:16+00:00

from __future__ import annotations

from fastapi import APIRouter

from ..dependencies import *

router = APIRouter(tags=['Slim Dogs'])


@router.get('/dogs', response_model=SlimDogs, tags=['Slim Dogs'])
def list_slim_dogs(limit: Optional[int] = None) -> SlimDogs:
    """
    List All Slim Dogs
    """
    pass


@router.post('/dogs', response_model=None, tags=['Slim Dogs'])
def create_slim_dogs() -> None:
    """
    Create a Slim Dog
    """
    pass


@router.get('/dogs/{dog_id}', response_model=Pet, tags=['Slim Dogs'])
def show_dog_by_id(dog_id: str = Path(..., alias='dogId')) -> Pet:
    """
    Info For a Specific Dog
    """
    pass

app/routers/wild_boars.py:

# generated by fastapi-codegen:
#   filename:  swagger.yaml
#   timestamp: 2023-04-04T12:06:16+00:00

from __future__ import annotations

from fastapi import APIRouter

from ..dependencies import *

router = APIRouter(tags=['Wild Boars'])


@router.get('/boars', response_model=WildBoars, tags=['Wild Boars'])
def list_wild_boars(limit: Optional[int] = None) -> WildBoars:
    """
    List All Wild Boars
    """
    pass


@router.post('/boars', response_model=None, tags=['Wild Boars'])
def create_wild_boars() -> None:
    """
    Create a Wild Boar
    """
    pass


@router.get('/boars/{boar_id}', response_model=Pet, tags=['Wild Boars'])
def show_boar_by_id(boar_id: str = Path(..., alias='boarId')) -> Pet:
    """
    Info For a Specific Boar
    """
    pass

app/dependencies.py:

# generated by fastapi-codegen:
#   filename:  swagger.yaml
#   timestamp: 2023-04-04T12:06:16+00:00

from __future__ import annotations

from typing import Optional

from fastapi import Path

from .models import FatCats, Pet, SlimDogs, WildBoars

PyPi

https://pypi.org/project/fastapi-code-generator

License

fastapi-code-generator is released under the MIT License. http://www.opensource.org/licenses/mit-license