I am trying to add some routes to a FastAPI project. New routes are not determined beforehand and the code should read them from a file. To add routes I am using add_api_route
as below:
from fastapi import APIRouter
my_router = APIRouter()
def foo(xyz):
return {"Result": xyz}
my_router.add_api_route('/foo/{xyz}', endpoint=foo)
Above works fine.
However enrty path parameters are not fixed and I need to read them from a file, to achieve this, I am trying something like this:
from fastapi import APIRouter
my_router = APIRouter()
def foo(**kwargs):
return {"Result": kwargs['xyz']}
read_from_file = '/foo/{xyz}' # Assume this is read from a file
my_router.add_api_route(read_from_file, endpoint=foo)
But it throws this error:
{"detail":[{"loc":["query","kwargs"],"msg":"field required","type":"value_error.missing"}]}
FastAPI tries to find actual argument xyz
in foo
signature.
Is there any way in FastAPI to achieve this? Or even any solution to accept a path like /foo/... whatever.../
?
This will generate a function with a new signature (I assume every parameter is a string):
from fastapi import APIRouter
import re
import inspect
my_router = APIRouter()
def generate_function_signature(route_path: str):
args = {arg: str for arg in re.findall(r'\{(.*?)\}', route_path)}
def new_fn(**kwargs):
return {"Result": kwargs['xyz']}
params = [
inspect.Parameter(param,
inspect.Parameter.POSITIONAL_OR_KEYWORD,
annotation=type_)
for param, type_ in args.items()
]
new_fn.__signature__ = inspect.Signature(params)
new_fn.__annotations__ = args
return new_fn
read_from_file = '/foo/{xyz}' # Assume this is read from a file
my_router.add_api_route(read_from_file, endpoint=generate_function_signature(read_from_file))
read_from_file = '/foo/bar/{xyz}' # Assume this is read from a file
my_router.add_api_route(read_from_file, endpoint=generate_function_signature(read_from_file))
However I am sure there is a better way of doing whatever you are trying to do, but I would need to understand your problem first
As described here , you can use the path
convertor, provided by Starlette , to capture arbitrary paths. If you are about to pass **kwargs
to your route as part of the path, eg, http://127.0.0.1:8000/foo/foo=2&bar=7
, then you can parse the path string and get a dictionary using urllib.parse.parse_qs
, as demonstrated in this answer (similar to what you would do, if you had to parse a query string). The below also utilises the method described here . Example below:
from fastapi import APIRouter, FastAPI
from urllib.parse import parse_qs
app = FastAPI()
my_router = APIRouter()
def foo(full_path: str):
params = parse_qs(full_path)
d = dict( (k, v if len(v)>1 else v[0])
for k, v in params.items() )
return {"path": full_path, "params": d}
route_path = '/foo/{full_path:path}'
my_router.add_api_route(route_path, endpoint=foo)
app.include_router(my_router)
Input test:
http://127.0.0.1:8000/foo/foo=2&bar=7&foo=10
Output:
{"path":"foo=2&bar=7&foo=10","params":{"foo":["2","10"],"bar":"7"}}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.