Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

trailing slash in parameter vs non #1127

Closed
3 tasks done
mwilson8 opened this issue Mar 17, 2020 · 15 comments
Closed
3 tasks done

trailing slash in parameter vs non #1127

mwilson8 opened this issue Mar 17, 2020 · 15 comments
Labels
question Question or problem question-migrate

Comments

@mwilson8
Copy link

mwilson8 commented Mar 17, 2020

First check

  • I used the GitHub search to find a similar issue and didn't find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google "How to X in FastAPI" and didn't find any information.

Description

Is there a way to have FastAPI treat a parameter the same if it does or does not have a trailing / ?

Additional context

I want to replicate this in a more concise manner and/or configure FastAPI so I don't have to do this for each path similarly

@app.post("/extract")
@app.post("/extract/")
async def create_extraction(...):

EDIT: simplified example code

@mwilson8 mwilson8 added the question Question or problem label Mar 17, 2020
@jmriebold
Copy link
Contributor

What version of fastapi are you using? As of 0.50.0 the trailing slash should be automatically stripped now that fastapi's using the latest version of starlette.

Also for what it's worth, even without that feature you could always do something like this:

@app.post("/extract/?")
async def create_extraction(...):

since routes can take regexes.

@mwilson8
Copy link
Author

mwilson8 commented Mar 18, 2020

[RESOLVED]
@jmriebold we're unfortunately pinned on version 0.47.1
I wasn't aware that FastAPI supported regex. Awesome! Thanks!

@tiangolo
Copy link
Member

tiangolo commented Apr 6, 2020

Thanks for the help @jmriebold ! 🙇‍♂️

Thanks for reporting back and closing the issue @mwilson8 👍

@falkben
Copy link
Contributor

falkben commented Sep 2, 2020

FYI, @jmriebold I don't think path routes can take regex's anymore like this.

Since Starlette version 0.13.5 regex is escaped. See the PR here: encode/starlette#932 and further discussion here: encode/starlette#1010

also... in my testing, Starlette is flexible about the trailing slash (and i think by extension fastapi) so you shouldn't need the trailing ?.

@jmriebold
Copy link
Contributor

Yeah, I noticed that too. Appears to be the case that regexes were never intentionally supported, it was just an artifact of how paths were constructed.

@falkben
Copy link
Contributor

falkben commented Sep 3, 2020

It seems like the best option is to just allow Starlette to do the redirect for you, so long as you are okay with redirects. Note, that curl usually doesn't automatically redirect. And neither does requests for POSTs. So there are some valid reasons to not want your users to have to deal with redirects if you have routes they are using programmatically.

If you don't want the redirect, I think the other option is using multiple decorators as suggested in the original question.

I wish Starlette didn't perform a redirect but just directly accessed the other route, if it matched it. There's probably a good reason they don't do this, though.

@jmriebold
Copy link
Contributor

Yeah I personally thought regexes were an elegant way to do it, but have since switched to an explicit redirect route.

@erhosen
Copy link

erhosen commented Sep 8, 2020

I think this Starlette release broke a lot of services (including mine), and forces us to choose between ugly

@router.get("/block", response_model=pydantic_models.BlockResponse)
@router.get("/block/", response_model=pydantic_models.BlockResponse)
async def blocks(request: Request):
    ...

And ugly

def slash_patcher(app):
    app.router.redirect_slashes = False
    routes = copy.deepcopy(app.router.routes)
    for r in routes:
        if r.path.endswith("/"):
            app.add_route(r.path.rstrip("/"), ...)
        else:
            app.add_route(r.path + "/", ...)

Maybe we can fix it somehow in general way?

@falkben
Copy link
Contributor

falkben commented Sep 9, 2020

Thanks for sharing your slash patcher.

Perhaps a pull request or new issue would get the ball rolling?

@erhosen
Copy link

erhosen commented Sep 9, 2020

I don't think this is a good solution: for example /docs become a mess:

image

@falkben
Copy link
Contributor

falkben commented Sep 9, 2020

Yea, pretty gross. I also think this is probably easier handled in Starlette

@erhosen
Copy link

erhosen commented Sep 9, 2020

In our team we decided to patch proxy-server for all our FastAPI applications: it ensures that every request does not contain \ at the end of path. (otherwise it just removes slashes) :|

@Coppini
Copy link

Coppini commented Apr 12, 2021

Are there any updates on this? Would it be possible to support regex or multiple route options like in @erhosen suggestion

@router.get("/block", response_model=pydantic_models.BlockResponse)
@router.get("/block/", response_model=pydantic_models.BlockResponse)
async def blocks(request: Request):
    ...

Without ending up with the /docs mess he later exemplified in the screenshot?

I've just encountered the same problem, and either using REGEX or being able to add multiple route options would be really helpful.

@falkben
Copy link
Contributor

falkben commented Apr 14, 2021

In general, redirects should occur automatically to the endpoint w/ or w/o the trailing slash (depending on which one you have configured.

If it's absolutely needed to have both routes, you can specify certain routes to not be included in the docs with include_in_schema=False

This gets asked frequently. See this issue for some additional solutions: #2060

@Akkarine
Copy link

Akkarine commented Oct 17, 2022

You should use trailing slash, because there is a caveat, if you have other endpoints with same path. For example, you have endpoints:

GET /v1/users/{user_id}
GET /v1/users/balance

On calls for balance, /v1/users/{user_id} could be called with user_id=balance

@tiangolo tiangolo changed the title [QUESTION] trailing slash in parameter vs non trailing slash in parameter vs non Feb 24, 2023
@tiangolo tiangolo reopened this Feb 28, 2023
@fastapi fastapi locked and limited conversation to collaborators Feb 28, 2023
@tiangolo tiangolo converted this issue into discussion #7663 Feb 28, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
question Question or problem question-migrate
Projects
None yet
Development

No branches or pull requests

7 participants