api versioning for fastapi web applications

Overview

fastapi-versioning

api versioning for fastapi web applications

Installation

pip install fastapi-versioning

Examples

from fastapi import FastAPI
from fastapi_versioning import VersionedFastAPI, version

app = FastAPI(title="My App")


@app.get("/")
@version(1, 0)
def greet_with_hello():
    return "Hello"


@app.get("/")
@version(1, 1)
def greet_with_hi():
    return "Hi"


app = VersionedFastAPI(app)
)

this will generate two endpoints:

/v1_0/greet
/v1_1/greet

as well as:

/docs
/v1_0/docs
/v1_1/docs
/v1_0/openapi.json
/v1_1/openapi.json

Try it out:

pip install pipenv
pipenv install --dev
pipenv run uvicorn example.app:app

Usage without minor version

from fastapi import FastAPI
from fastapi_versioning import VersionedFastAPI, version

app = FastAPI(title='My App')

@app.get('/greet')
@version(1)
def greet():
  return 'Hello'

@app.get('/greet')
@version(2)
def greet():
  return 'Hi'

app = VersionedFastAPI(app,
    version_format='{major}',
    prefix_format='/v{major}')

this will generate two endpoints:

/v1/greet
/v2/greet

as well as:

/docs
/v1/docs
/v2/docs
/v1/openapi.json
/v2/openapi.json

Extra FastAPI constructor arguments

It's important to note that only the title from the original FastAPI will be provided to the VersionedAPI app. If you have any middleware, event handlers etc these arguments will also need to be provided to the VersionedAPI function call, as in the example below

from fastapi import FastAPI, Request
from fastapi_versioning import VersionedFastAPI, version
from starlette.middleware import Middleware
from starlette.middleware.sessions import SessionMiddleware

app = FastAPI(
    title='My App',
    description='Greet uses with a nice message',
    middleware=[
        Middleware(SessionMiddleware, secret_key='mysecretkey')
    ]
)

@app.get('/greet')
@version(1)
def greet(request: Request):
    request.session['last_version_used'] = 1
    return 'Hello'

@app.get('/greet')
@version(2)
def greet(request: Request):
    request.session['last_version_used'] = 2
    return 'Hi'

@app.get('/version')
def last_version(request: Request):
    return f'Your last greeting was sent from version {request.session["last_version_used"]}'

app = VersionedFastAPI(app,
    version_format='{major}',
    prefix_format='/v{major}',
    description='Greet users with a nice message',
    middleware=[
        Middleware(SessionMiddleware, secret_key='mysecretkey')
    ]
)
Comments
  • Replaced deprecated openapi_prefix for root_path.

    Replaced deprecated openapi_prefix for root_path.

    Fixes the following annoying warning:

    "openapi_prefix" has been deprecated in favor of "root_path", which follows more closely the ASGI standard, is simpler, and more automatic. Check the docs at https://fastapi.tiangolo.com/advanced/sub-applications/
    

    Fixes #13.

    opened by synchronizing 5
  • root_path is not propagated to versioned apps properly, breaking openapi docs

    root_path is not propagated to versioned apps properly, breaking openapi docs

    My app is behind some proxy so it's url is smth like http://abc.cd/some/path/v1_0/ to support it properly I'm adding root_path="/some/path", and in general everything is working ok as in most cases this param is just ignored, except openapidocs, where it's used to generate path to openapi.json:

    http://abc.cd/some/path/v1_0/docs

        const ui = SwaggerUIBundle({
            url: '/v1_0/openapi.json',
    

    should be:

        const ui = SwaggerUIBundle({
            url: '/some/path/v1_0/openapi.json',
    
    opened by kosz85 4
  • :sparkles: Reflect attributes in version decorator

    :sparkles: Reflect attributes in version decorator

    Rewriting the decorator using functools.wraps() allows for tab completion and correctly reflecting of attributes and signature of wrapped function.

    Closes #11.

    opened by HacKanCuBa 4
  • Support for a single method to handle multiple versions

    Support for a single method to handle multiple versions

    Currently, if we are to support multiple versions of an API with many endpoints, we need to duplicate each endpoint (even if logic does not change for every endpoint) in order to be backward compatible.

    An array of values could be passed to @version() to allow a single method to support multiple versions. Example:

    Current:

    def handle_home() -> str:
        return "You are home."
    
    @app.get("/home")
    @version(1, 0)
    def home() -> str:
        return handle_home()
    
    @app.get("/home")
    @version(1, 1)
    def home() -> str:
        return handle_home()
    
    @app.get("/home")
    @version(1, 2)
    def home() -> str:
        return handle_home()
    

    Suggested:

    @app.get("/home")
    @version([1, 0], [1, 1], [1, 2])
    def home() -> str:
        return "You are home"
    
    opened by c-tanner 3
  • Description from tags metadata not shown in OpenAPI docs

    Description from tags metadata not shown in OpenAPI docs

    First of all, thank you so much for this extension, saved us a lot of additional unnecessary work!

    Bug description Looks like description from tags metadata is not loaded/visible on OpenAPI docs, even if I pass it directly to VersionedFastAPI constructor. name is loaded, but description not. I haven't checked externalDocs attribute yet.

    To Reproduce Here is the part of the code from my main.py:

    tags_metadata = [
        {"name": "products", "description": "Operations with products and product types."},
        {"name": "cameras", "description": "Operations with cameras."}
    ]
    
    app = FastAPI(title="My App")
    
    app.include_router(product_router.router)
    app.include_router(camera_router.router)
    
    @app.get("/")
    @version(1, 0)
    def root():
        return {"message": "Hello World!"}
    
    app = VersionedFastAPI(app, openapi_tags=tags_metadata)
    

    ... and in the product_router.py, I have defined:

    router = APIRouter(prefix="/products", tags=["products"])
    

    ... and the same way in camera_router.py.

    Expected behavior How it should look like, is described here: FastAPI-Metadata. When I turn off fastapi-versioning, everything works like expected.

    Environment

    • Docker version: 19.03.13
    • FastAPI version: 0.62.0 (built with official FastAPI Docker image and manually updated fastapi)
    • fastapi-versioning version: 0.5.0

    Thanks!

    opened by Acerinth 3
  • feat: add customisable default versioning functionality

    feat: add customisable default versioning functionality

    • we are implementing FastAPI to replace an existing API of ours which currently sits at version 2
    • we want the ability to make the default version in fastapi-versioning customisable, as opposed to always defaulting to (1, 0)
    • this PR implements this!
    opened by gtlambert 3
  • Type checking

    Type checking

    Hi,

    Thanks for this project. Shouldn't it be version_route_mapping: Dict[Tuple[int, int], List[APIRoute]] = defaultdict(list) instead of:

    https://github.com/DeanWay/fastapi-versioning/blob/3db32d809caa70217700902a31eb8093d0d647cf/fastapi_versioning/versioning.py#L37

    opened by joel314 2
  • Warning:

    Warning: "openapi_prefix" has been deprecated in favor of "root_path"

    First of all thank you for your work on the module! I really like what you are doing and its working great.

    Describe the bug During startup of the API a warning message is shown (likely due to a change in FastAPI): "openapi_prefix" has been deprecated in favor of "root_path", which follows more closely the ASGI standard, is simpler, and more automatic. Check the docs at https://fastapi.tiangolo.com/advanced/sub-applications-proxy/ Might be a simple change here ?

    To Reproduce Minimal example:

    #example.py
    import uvicorn
    from fastapi import Depends, FastAPI
    from fastapi_versioning import version, VersionedFastAPI
    
    app = FastAPI()
    
    @app.get(path='/example')
    @version(1, 0)
    def example():
        return 'test'
    
    app = VersionedFastAPI(app) #here the warning is shown
    
    if __name__ == "__main__":
        uvicorn.run("example:app",host="127.0.0.1",port=8000,reload=True,debug=True)
    

    Warning message: Anmerkung 2020-07-07 144511

    Not related to the bug I was happy to find that module is even doing more than you write in the readme: If a route is only specified in version v1_0 and not overwritten by a new version it is also available in newer endpoints (e.g. v2_0). For me this seems worth mentioning in the readme 👍

    opened by p-rinnert 2
  • Use functools.wraps for decorator

    Use functools.wraps for decorator

    Implement functools.wraps in the version decorator to avoid breaking tab completion and breaking wrapped function signature:

    https://github.com/DeanWay/fastapi-versioning/blob/875863c0a312e4d30ecbb351abc3e145fa203b62/fastapi_versioning/versioning.py#L12

    opened by HacKanCuBa 2
  • Support bound methods

    Support bound methods

    In cases where FastAPI routes are defined as bound methods on a Class, attribute assignment for the method requires .__func__._api_version to access the underlying function.

    opened by tijptjik 2
  • Avoid defining own dunder property(s)

    Avoid defining own dunder property(s)

    Is your feature request related to a problem? Please describe. In code used dunder property __api_version__ for function.

    Describe the solution you'd like Just set the _api_version.

    Describe alternatives you've considered This looks more pythonic, than your idea.

    opened by prostomarkeloff 2
  • Maintained Fork Inquiry

    Maintained Fork Inquiry

    Are there a good number of people interested in this still? Could potentially fork this and address some of the issues here based off how many people would want that. I see it hasn't been maintained in over a year.

    opened by TheJumpyWizard 3
  • Additional arguments of FastAPI() not working, such as swagger_ui_parameters or description

    Additional arguments of FastAPI() not working, such as swagger_ui_parameters or description

    Describe the bug Some arguments of FastAPI() won't work

    To Reproduce Use argument swagger_ui_parameters={"docExpansion": "none"} and check that it won't work in the versioning, as it won't collapse the tabs.

    Expected behavior I expect all arguments of FastAPI() to work.

    Additional context I already did a PR with a quick fix. PR #71

    opened by PabloRuizCuevas 1
  • Supported kargs in versioned documentation

    Supported kargs in versioned documentation

    Till now some arguments of FastAPI where not working, like:

        description="Core API",
        swagger_ui_parameters={"docExpansion": "none"},
    

    This issue is yet fixed

    opened by PabloRuizCuevas 5
  • Docs URL is served even when set to None

    Docs URL is served even when set to None

    Describe the bug Even with docs_url set to None, the docs are still served. Per the FastAPI documentation, the app should no longer serve docs with this option set.

    You can disable it by setting docs_url=None. https://fastapi.tiangolo.com/tutorial/metadata/#docs-urls

    def docs_url_kwargs() -> dict:
        return  {
            "openapi_url": None,
            "docs_url": None,
            "redoc_url": None,
        }
    
    application = FastAPI(
        title='Example FastApi',
        description='Nice',
        **docs_url_kwargs(),
    )
    application = VersionedFastAPI(
        application,
        version_format="{major}",
        prefix_format="/v{major}/api/",
        description='version',
        enable_latest=True,
        **docs_url_kwargs(),
    )
    
    

    To Reproduce Set docs_url=None when instantiating the FastAPI app and VersionedFastAPI but still see the docs served at /docs.

    Expected behavior Expecting docs to no longer be served (for production use case).

    Additional details Issue may be here: https://github.com/DeanWay/fastapi-versioning/blob/18d480f5bb067088f157f235a673cb4c65ec77d5/fastapi_versioning/versioning.py#L68-L73

    opened by jshields 1
  • remove

    remove "latest" keyword from url path for the latest version API?

    Is your feature request related to a problem? Please describe. This is a question regarding #35. I am curious about why you would want the keyword "latest" to be in the path, because it feels more natural that /api/endpoint serve the latest version of the API by default.

    Describe the solution you'd like If that is clear, i guess we can remove the keyword "latest" from the prefix in versioning.py, line 76, so anything from the default API direct to the latest API. Reference source code link:

    modification:

    if enable_latest:
            prefix = "/"
    ......
    

    Alternative option The above question is actually from the concern whether I could set some version of API to be a generic API like... suppose you have v1, v2, and v3 APIs where all have /items endpoint, and you want v2 to be accessible by default path like /items ( /items redirect to /v2/items )

    Additional context I would mainly want to know the decision behind the usage of the keyword; #35 describes the reason, but it's not really convincing to me and if the concern here is about serving the latest version to client, generic API call without any version, keyword, etc would be better for users and also for restfulness too.

    opened by qmffkem 2
Releases(0.8.0)
Owner
Dean Way
Dean Way
Docker image with Uvicorn managed by Gunicorn for high-performance FastAPI web applications in Python 3.6 and above with performance auto-tuning. Optionally with Alpine Linux.

Supported tags and respective Dockerfile links python3.8, latest (Dockerfile) python3.7, (Dockerfile) python3.6 (Dockerfile) python3.8-slim (Dockerfil

Sebastián Ramírez 2.1k Dec 31, 2022
Flask-vs-FastAPI - Understanding Flask vs FastAPI Web Framework. A comparison of two different RestAPI frameworks.

Flask-vs-FastAPI Understanding Flask vs FastAPI Web Framework. A comparison of two different RestAPI frameworks. IntroductionIn Flask is a popular mic

Mithlesh Navlakhe 1 Jan 1, 2022
Simple FastAPI Example : Blog API using FastAPI : Beginner Friendly

fastapi_blog FastAPI : Simple Blog API with CRUD operation Steps to run the project: git clone https://github.com/mrAvi07/fastapi_blog.git cd fastapi-

Avinash Alanjkar 1 Oct 8, 2022
CLI and Streamlit applications to create APIs from Excel data files within seconds, using FastAPI

FastAPI-Wrapper CLI & APIness Streamlit App Arvindra Sehmi, Oxford Economics Ltd. | Website | LinkedIn (Updated: 21 April, 2021) fastapi-wrapper is mo

Arvindra 49 Dec 3, 2022
:rocket: CLI tool for FastAPI. Generating new FastAPI projects & boilerplates made easy.

Project generator and manager for FastAPI. Source Code: View it on Github Features ?? Creates customizable project boilerplate. Creates customizable a

Yagiz Degirmenci 1k Jan 2, 2023
Пример использования GraphQL Ariadne с FastAPI и сравнение его с GraphQL Graphene FastAPI

FastAPI Ariadne Example Пример использования GraphQL Ariadne с FastAPI и сравнение его с GraphQL Graphene FastAPI - GitHub ###Запуск на локальном окру

ZeBrains Team 9 Nov 10, 2022
Sample-fastapi - A sample app using Fastapi that you can deploy on App Platform

Getting Started We provide a sample app using Fastapi that you can deploy on App

Erhan BÜTE 2 Jan 17, 2022
FastAPI Server Session is a dependency-based extension for FastAPI that adds support for server-sided session management

FastAPI Server-sided Session FastAPI Server Session is a dependency-based extension for FastAPI that adds support for server-sided session management.

DevGuyAhnaf 5 Dec 23, 2022
fastapi-admin2 is an upgraded fastapi-admin, that supports ORM dialects, true Dependency Injection and extendability

FastAPI2 Admin Introduction fastapi-admin2 is an upgraded fastapi-admin, that supports ORM dialects, true Dependency Injection and extendability. Now

Glib 14 Dec 5, 2022
Code Specialist 27 Oct 16, 2022
Fastapi-ml-template - Fastapi ml template with python

FastAPI ML Template Run Web API Local $ sh run.sh # poetry run uvicorn app.mai

Yuki Okuda 29 Nov 20, 2022
FastAPI-Amis-Admin is a high-performance, efficient and easily extensible FastAPI admin framework. Inspired by django-admin, and has as many powerful functions as django-admin.

简体中文 | English 项目介绍 FastAPI-Amis-Admin fastapi-amis-admin是一个拥有高性能,高效率,易拓展的fastapi管理后台框架. 启发自Django-Admin,并且拥有不逊色于Django-Admin的强大功能. 源码 · 在线演示 · 文档 · 文

AmisAdmin 318 Dec 31, 2022
Full stack, modern web application generator. Using FastAPI, PostgreSQL as database, Docker, automatic HTTPS and more.

Full Stack FastAPI and PostgreSQL - Base Project Generator Generate a backend and frontend stack using Python, including interactive API documentation

Sebastián Ramírez 10.8k Jan 8, 2023
The template for building scalable web APIs based on FastAPI, Tortoise ORM and other.

FastAPI and Tortoise ORM. Powerful but simple template for web APIs w/ FastAPI (as web framework) and Tortoise-ORM (for working via database without h

prostomarkeloff 95 Jan 8, 2023
Github timeline htmx based web app rewritten from Common Lisp to Python FastAPI

python-fastapi-github-timeline Rewrite of Common Lisp htmx app _cl-github-timeline into Python using FastAPI. This project tries to prove, that with h

Jan Vlčinský 4 Mar 25, 2022
High-performance Async REST API, in Python. FastAPI + GINO + Arq + Uvicorn (w/ Redis and PostgreSQL).

fastapi-gino-arq-uvicorn High-performance Async REST API, in Python. FastAPI + GINO + Arq + Uvicorn (powered by Redis & PostgreSQL). Contents Get Star

Leo Sussan 351 Jan 4, 2023
Boilerplate code for quick docker implementation of REST API with JWT Authentication using FastAPI, PostgreSQL and PgAdmin ⭐

FRDP Boilerplate code for quick docker implementation of REST API with JWT Authentication using FastAPI, PostgreSQL and PgAdmin ⛏ . Getting Started Fe

BnademOverflow 53 Dec 29, 2022
API Simples com python utilizando a biblioteca FastApi

api-fastapi-python API Simples com python utilizando a biblioteca FastApi Para rodar esse script são necessárias duas bibliotecas: Fastapi: Comando de

Leonardo Grava 0 Apr 29, 2022
REST API with FastAPI and JSON file.

FastAPI RESTAPI with a JSON py 3.10 First, to install all dependencies, in ./src/: python -m pip install -r requirements.txt Second, into the ./src/

Luis Quiñones Requelme 1 Dec 15, 2021