Reputation: 95
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 (i.e., '/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'
Upvotes: 6
Views: 14054
Reputation: 8199
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: Request):
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"{root_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.
Upvotes: 1
Reputation: 34551
If what you need is the original route path, i.e., /users/{user_id}
, you could use the below. The way it works is by getting the root_path
first—which would normally be an empty string, unless you have mounted sub-application(s) to the top-level app (e.g., app.mount("/subapi", subapi)
), and hence, you need the result to be prefixed with that specific path /subapi
—and then append to it the route's path , which you can get from the APIRoute object. Example:
from fastapi import Request
@app.get('/users/{user_id}')
def get_user(user_id: str, request: Request):
path = request.scope['root_path'] + request.scope['route'].path
return path
Output:
/users/{user_id}
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 Request
@app.get('/users/{user_id}')
def get_user(user_id: str, request: Request):
return request.url.path
Output (if the received user_id
was 1
):
/users/1
Upvotes: 8
Reputation: 52
You can use the APIRout object property in the request to get the actual path
example:
raw_path = request.scope['route'].path
#'/user/{id}'
Upvotes: -2
Reputation: 29
The below solution worked fine for me
using the string replace with count
parameter replaces the first occurence only. And request.path_params
will return the path parameters in the sequence you take it in the request.
def get_raw_path(request):
path = request.url.path
for key, val in request.path_params.items():
path = path.replace(val, F'{{{key}}}',1)
return path
Upvotes: 1
Reputation: 691
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}}}')
Upvotes: -1