简体   繁体   中英

FastAPI: How to get raw URL path from request?

I have a GET method with requested parameter in path:

@router.get('/users/{user_id}')
async def get_user_from_string(user_id: str):
    return User(user_id)

Is it possible to get base url raw path (ie, '/users/{user_id}' ) from the request?

I have tried to use the following way:

path = [route for route in request.scope['router'].routes if
        route.endpoint == request.scope['endpoint']][0].path

But it doesn't work and I get:

AttributeError: 'Mount' object has no attribute 'endpoint'

As per FastAPI documentation :

As FastAPI is actually Starlette underneath, with a layer of several tools on top, you can use Starlette's Request object directly when you need to.

Thus, you can use Request object to get the URL path. For instance:

 from fastapi import FastAPI, Request app = FastAPI() @app.get('/users/{user_id}') async def get_user(user_id: str, request: Request): print(request.url.path) return "something"

The above will print, for example, /users/1 (if user_id passed is 1 ).

Update

If, however, what you need is the actual path of the endpoint, ie, /users/{user_id} , then you could use the below:

 @app.get("/users/{user_id}") async def get_user(user_id: str, request: Request): p = [route.path for route in app.routes if route.name == request.scope['endpoint'].__name__] print(p[0]) return "something"

If APIRouter is used instead, you can use the below:

 for route in request.scope['router'].routes

or,, you could get the app instance using the Request object (as described here and here )

 for route in request.app.routes

Note: You could always get the above path by simply stroring it in a variable, since you already know the route's path beforehand.

I'm working on implementing this for OpenTelemetry and the way to get the original route with the data that's available is as follows:

def get_route_from_request(req):
  root_path = req.scope.get("root_path", "")

  route = scope.get("route")
  if not route:
    return None
  path_format = getattr(route, "path_format", None)
  if path_format:
    return f"{route_path}{path_format}"

  return None

Note that the accepted answer is not returning what was asked, as it returns the path as received by the server.

None of the other answers deal with mounted apps.

And finally, answers checking the name of the endpoint are also wrong as the same function could be used in different endpoints.

Having found both the answers to not work I'll share what I use. It's not great as if there's shared values in path params it will not work

path = request.url.path for key, val in request.path_params.items(): path = path.replace(val, F'{{{key}}}')

you can use APIRouter object attribute from Request to get real path

example:

 raw_path = request.scope['route'].path #'/user/{id}'

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM