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
A Python framework to build Slack apps in a flash with the latest platform features.

Bolt for Python A Python framework to build Slack apps in a flash with the latest platform features. Read the getting started guide and look at our co

SlackAPI 684 Jan 09, 2023
A fast and durable Pub/Sub channel over Websockets. FastAPI + WebSockets + PubSub == ⚡ 💪 ❤️

⚡ 🗞️ FastAPI Websocket Pub/Sub A fast and durable Pub/Sub channel over Websockets. The easiest way to create a live publish / subscribe multi-cast ov

8 Dec 06, 2022
Run your jupyter notebooks as a REST API endpoint. This isn't a jupyter server but rather just a way to run your notebooks as a REST API Endpoint.

Jupter Notebook REST API Run your jupyter notebooks as a REST API endpoint. This isn't a jupyter server but rather just a way to run your notebooks as

Invictify 54 Nov 04, 2022
Easily integrate socket.io with your FastAPI app 🚀

fastapi-socketio Easly integrate socket.io with your FastAPI app. Installation Install this plugin using pip: $ pip install fastapi-socketio Usage To

Srdjan Stankovic 210 Dec 23, 2022
FastAPI simple cache

FastAPI Cache Implements simple lightweight cache system as dependencies in FastAPI. Installation pip install fastapi-cache Usage example from fastapi

Ivan Sushkov 188 Dec 29, 2022
Beyonic API Python official client library simplified examples using Flask, Django and Fast API.

Beyonic API Python Examples. The beyonic APIs Doc Reference: https://apidocs.beyonic.com/ To start using the Beyonic API Python API, you need to start

Harun Mbaabu Mwenda 46 Sep 01, 2022
Starlette middleware for Prerender

Prerender Python Starlette Starlette middleware for Prerender Documentation: https://BeeMyDesk.github.io/prerender-python-starlette/ Source Code: http

BeeMyDesk 14 May 02, 2021
This project shows how to serve an ONNX-optimized image classification model as a web service with FastAPI, Docker, and Kubernetes.

Deploying ML models with FastAPI, Docker, and Kubernetes By: Sayak Paul and Chansung Park This project shows how to serve an ONNX-optimized image clas

Sayak Paul 104 Dec 23, 2022
A RESTful API for creating and monitoring resource components of a hypothetical build system. Built with FastAPI and pydantic. Complete with testing and CI.

diskspace-monitor-CRUD Background The build system is part of a large environment with a multitude of different components. Many of the components hav

Nick Hopewell 67 Dec 14, 2022
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 08, 2023
A utility that allows you to use DI in fastapi without Depends()

fastapi-better-di What is this ? fastapi-better-di is a utility that allows you to use DI in fastapi without Depends() Installation pip install fastap

Maxim 9 May 24, 2022
Pagination support for flask

flask-paginate Pagination support for flask framework (study from will_paginate). It supports several css frameworks. It requires Python2.6+ as string

Lix Xu 264 Nov 07, 2022
This repository contains learning resources for Python Fast API Framework and Docker

This repository contains learning resources for Python Fast API Framework and Docker, Build High Performing Apps With Python BootCamp by Lux Academy and Data Science East Africa.

Harun Mbaabu Mwenda 23 Nov 20, 2022
Generate modern Python clients from OpenAPI

openapi-python-client Generate modern Python clients from OpenAPI 3.x documents. This generator does not support OpenAPI 2.x FKA Swagger. If you need

Triax Technologies 558 Jan 07, 2023
OpenAPI for Todolist RESTful API

swagger-client OpenAPI for Todolist RESTful API This Python package is automatically generated by the Swagger Codegen project: API version: 1 Package

Iko Afianando 1 Dec 19, 2021
Cookiecutter template for FastAPI projects using: Machine Learning, Poetry, Azure Pipelines and Pytests

cookiecutter-fastapi In order to create a template to FastAPI projects. 🚀 Important To use this project you don't need fork it. Just run cookiecutter

Arthur Henrique 225 Dec 28, 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 02, 2023
A simple Redis Streams backed Chat app using Websockets, Asyncio and FastAPI/Starlette.

redis-streams-fastapi-chat A simple demo of Redis Streams backed Chat app using Websockets, Python Asyncio and FastAPI/Starlette. Requires Python vers

ludwig404 135 Dec 19, 2022
An alternative implement of Imjad API | Imjad API 的开源替代

HibiAPI An alternative implement of Imjad API. Imjad API 的开源替代. 前言 由于Imjad API这是什么?使用人数过多, 致使调用超出限制, 所以本人希望提供一个开源替代来供社区进行自由的部署和使用, 从而减轻一部分该API的使用压力 优势

Mix Technology 450 Dec 29, 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 01, 2022