Replies: 11 comments
-
Stripe is a company that I think has figured out a great middleground regarding API versioning - a great writeup on it is https://stripe.com/en-ca/blog/api-versioning. I wonder how feasible/easy this is to accomplish with FastAPI? I'm not currently a FastAPI user, but am eying it for a future project, and API versioning is a big question I have with it. Would love to hear other answers/if the Stripe approach is feasible with FastAPI. |
Beta Was this translation helpful? Give feedback.
-
Hello, I think this is the same question as in
#200
Le mar. 20 août 2019 à 11:51 PM, James Addison <notifications@github.com> a
écrit :
… Stripe is a company that I think has figured out a great middleground
regarding API versioning - a great writeup on it is
https://stripe.com/en-ca/blog/api-versioning.
I wonder how feasible/easy this is to accomplish with FastAPI? I'm not
currently a FastAPI user, but am eying it for a future project, and API
versioning is a big question I have with it. Would love to hear other
answers/if the Stripe approach is feasible with FastAPI.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#381?email_source=notifications&email_token=AAINSPUPX2J4W7FLLCXZWKDQFRRNLA5CNFSM4IBI3LEKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD4XYU5Y#issuecomment-523209335>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAINSPTN5OBK32UU4YKJDETQFRRNLANCNFSM4IBI3LEA>
.
|
Beta Was this translation helpful? Give feedback.
-
I posted a description of an approach to this in #200 (though this issue would probably have been a better place.. I can move it if desired) that I think would enable something akin to the Stripe approach. |
Beta Was this translation helpful? Give feedback.
-
I've implemented something along the lines of what @dmontagu suggested in this comment: #200 (comment) a more realistic example of it can be found here: https://github.com/DeanWay/fastapi-versioning/tree/master/example The idea is that each version registered at some point in the app becomes a sub-application mounted at each version builds upon the previous, and overrides matching paths. The parent app's docs endpoint just lists the versions The reason for using sub-applications is to separate the openapi.json and docs of each version (kind of a surprise for me that there's nothing in the openapi spec to handle for mulitple api versions in one document) I'd like to allow for version headers as well, but I think you still need the url version for openapi to make sense, so maybe some sort of redirection middleware? Might be a terrible idea, not sure yet. Anyway, might be helpful, take a look, let me know what you think! |
Beta Was this translation helpful? Give feedback.
-
Looks good but I think needed version for routers :) Like: from fastapi_versioning import VersionedAPIRouter
router = VersionAPIRouter(router, version=(1, 0)) |
Beta Was this translation helpful? Give feedback.
-
If you want completely different API docs (Swagger UI) you could create multiple If you want to have different versions in the same API, like If you want to include only some of the endpoints, you could create an |
Beta Was this translation helpful? Give feedback.
-
Assuming the original issue was solved, it will be automatically closed now. But feel free to add more comments or create new issues. |
Beta Was this translation helpful? Give feedback.
-
Hello @tiangolo,
With this choice, is it possible to have a generated doc that separates |
Beta Was this translation helpful? Give feedback.
-
I had a similar need as well. A quick way to achieve that will be to extend the from typing import Any
from fastapi.routing import APIRouter
from fastapi_versioning import versioned_api_route
class VersionedAPIRouter(APIRouter):
def __init__(self, major: int = 1, minor: int = 0, *args: Any, **kwargs: Any) -> None:
versioned_route_class = versioned_api_route(major, minor)
super().__init__(*args, **kwargs, route_class=versioned_route_class)
self.major = major
self.minor = minor
def include_router(self, *args, **kwargs):
super().include_router(*args, **kwargs)
for route in self.routes:
try:
route.endpoint._api_version = (self.major, self.minor)
except AttributeError:
# Support bound methods
route.endpoint.__func__._api_version = (self.major, self.minor) Here is an example - router = APIRouter()
@router.get("/")
def a():
return True
router_v1 = VersionedAPIRouter(1, 0)
router_v1.include_router(router)
router_v2 = VersionedAPIRouter(2, 0)
@router_v2.get("/cool_route")
def cool_route():
return "wasssuppp"
from fastapi import FastAPI
from fastapi_versioning import VersionedFastAPI
app = FastAPI()
app.include_router(router_v2)
app.include_router(router_v1)
app = VersionedFastAPI(
app,
version_format="{major}",
prefix_format="/v{major}",
enable_latest=True,
) |
Beta Was this translation helpful? Give feedback.
-
You could make v1, v2 endpoints as sub-applications instead of routers, then use sub-app mounting for separate docs # instead of these
# api_v1 = APIRouter()
# api_v2 = APIRouter()
# ...
# app.include_router(api_v1, '/v1')
# app.include_router(api_v2, '/v2')
# try these
api_v1 = FastAPI()
api_v2 = FastAPI()
...
app.mount('/v1', api_v1)
app.mount('/v2', api_v2) For example: app = FastAPI(root_path='/api')
api_v1 = FastAPI()
api_v2 = FastAPI()
@api_v1.get('/users')
def get_users():
return {'user': 'John Doe'}
@api_v2.get('/users')
def get_users():
return {'user': 'you-know-who'}
app.mount('/v1', api_v1)
app.mount('/v2', api_v2) Then, go to /api/v1/docs or /api/v2/docs to check it. Besides, there is an empty doc at /api/docs too, people may be confused if nothing is there. So you may wanna tell users how to access those sub-docs. For example: ...
tags_metadata = [
{
'name': 'v1',
"description": "API version 1, check link on the right",
'externalDocs': {
'description': 'sub-docs',
'url': 'http://127.0.0.1/api/v1/docs'
}
},
{
'name': 'v2',
"description": "API version 2, check link on the right",
'externalDocs': {
'description': 'sub-docs',
'url': 'http://127.0.0.1/api/v2/docs'
}
},
]
app = FastAPI(root_path='/api', openapi_tags=tags_metadata)
... Then, /v1, /v2 tags will be shown in /api/docs, and there will be links to redirect to other docs Update: For example: app = FastAPI(root_path='/api')
api_v1 = FastAPI()
...
app.mount('/v1', api_v1)
# for reference, it shd already be applied as dependency
# def get_settings():
# return Settings()
def get_settings_override():
return Settings(db_name='test')
app.dependency_overrides[get_settings] = get_settings_override
#### most important part ####
api_v1.dependency_overrides[get_settings] = get_settings_override |
Beta Was this translation helpful? Give feedback.
-
@tiangolo : With reference to the suggestion from @benlau6 above:
is there a way to allow us to put the relative path of the sub-app there instead? Right now, if I do
And is this still the recommended way to add versioning to an API? |
Beta Was this translation helpful? Give feedback.
-
Description
Is there a recommended way to do API versioning. I know I could use
APIRouter
and keep all the files for a version in separate subdirectories but that doesn't seem very DRY.Is there a way to say "version 1.1 looks just like version 1.0 except in these certain cases"? And save
APIRouter
for major version changes or rewrites?Beta Was this translation helpful? Give feedback.
All reactions