4

I am trying to add routes from a file and I don't know the actual arguments beforehand so I need to have a general function that handles arguments via **kwargs.

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 which is not there.

Is there any way in FastAPI to achieve this? Or even any solution to accept a path like /foo/... whatever .../?

2

2 Answers 2

3

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)
)

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

Sign up to request clarification or add additional context in comments.

1 Comment

I am using this right now, thanks. However I think FastAPI should support these kind of functions while it is supporting dynamic routing via add_api_route. I edited my question to describe the problem.
2

As described here, you can use the path convertor, provided by Starlette, to capture arbitrary paths. Related answers using the add_route(), or preferably add_api_route() (since it allows using FastAPI dependencies), method can be found here and here.

Example

from fastapi import APIRouter, FastAPI


app = FastAPI()
my_router = APIRouter()


def foo(rest_of_path: str):
    return {"rest_of_path": rest_of_path}

  
route_path = '/foo/{rest_of_path:path}'
my_router.add_api_route(route_path, endpoint=foo)
app.include_router(my_router)

Input test URL:

http://127.0.0.1:8000/foo/https://placebear.com/cache/395-205.jpg

Output:

{"rest_of_path":"https://placebear.com/cache/395-205.jpg"}

1 Comment

Thanks for the answer, your point about path inside route is very useful, however I am trying to extract parameter within url, but your code is extracting query parameters.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.