Comments (14)
@wozniakty yep, thanks. It's updated now.
@teuneboon if you have declared a path operation with /users
it should work as-is. If it's /users/
then Starlette/FastAPI will try to redirect.
If it's the main path operation under a router for /users
, you can now declare a path of ""
instead of "/"
and it will accept the /users
even if that's a sub-router.
from fastapi.
Tested and indeed redirect happens using a curl -L
to follow redirects:
curl -L -v http://127.0.0.1:8001/users
* Expire in 0 ms for 6 (transfer 0x563800ebcd30)
* Trying 127.0.0.1...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x563800ebcd30)
* Connected to 127.0.0.1 (127.0.0.1) port 8001 (#0)
> GET /users HTTP/1.1
> Host: 127.0.0.1:8001
> User-Agent: curl/7.64.0
> Accept: */*
>
< HTTP/1.1 302 Found
< server: uvicorn
< date: Mon, 25 Feb 2019 16:05:22 GMT
< location: http://127.0.0.1:8001/users/
< transfer-encoding: chunked
<
* Ignoring the response-body
* Connection #0 to host 127.0.0.1 left intact
* Issue another request to this URL: 'http://127.0.0.1:8001/users/'
* Found bundle for host 127.0.0.1: 0x563800ebbd60 [can pipeline]
* Could pipeline, but not asked to!
* Re-using existing connection! (#0) with host 127.0.0.1
* Connected to 127.0.0.1 (127.0.0.1) port 8001 (#0)
* Expire in 0 ms for 6 (transfer 0x563800ebcd30)
> GET /users/ HTTP/1.1
> Host: 127.0.0.1:8001
> User-Agent: curl/7.64.0
> Accept: */*
>
< HTTP/1.1 200 OK
< server: uvicorn
< date: Mon, 25 Feb 2019 16:05:22 GMT
< content-length: 16
< content-type: application/json
<
* Connection #0 to host 127.0.0.1 left intact
{"users":"root"}%
server-side log:
backend_1_79e424196ea0 | DEBUG:uvicorn:('172.28.0.1', 59822) - Connected
backend_1_79e424196ea0 | DEBUG:uvicorn:('172.28.0.1', 59822) - ASGI [8] Initialized {'type': 'http', 'http_version': '1.1', 'server': ('172.28.0.2', 8000), 'client': ('172.28.0.1', 59822), 'scheme': 'http', 'method': 'GET', 'root_path': '', 'path': '/users', 'query_string': b'', 'headers': '<...>'}
backend_1_79e424196ea0 | DEBUG:uvicorn:('172.28.0.1', 59822) - ASGI [8] Started task
backend_1_79e424196ea0 | DEBUG:uvicorn:('172.28.0.1', 59822) - ASGI [8] Received {'type': 'http.response.start', 'status': 302, 'headers': '<...>'}
backend_1_79e424196ea0 | INFO:uvicorn:('172.28.0.1', 59822) - "GET /users HTTP/1.1" 302
backend_1_79e424196ea0 | DEBUG:uvicorn:('172.28.0.1', 59822) - ASGI [8] Received {'type': 'http.response.body', 'body': '<0 bytes>'}
backend_1_79e424196ea0 | DEBUG:uvicorn:('172.28.0.1', 59822) - ASGI [8] Completed
backend_1_79e424196ea0 | DEBUG:uvicorn:('172.28.0.1', 59822) - ASGI [9] Initialized {'type': 'http', 'http_version': '1.1', 'server': ('172.28.0.2', 8000), 'client': ('172.28.0.1', 59822), 'scheme': 'http', 'method': 'GET', 'root_path': '', 'path': '/users/', 'query_string': b'', 'headers': '<...>'}
backend_1_79e424196ea0 | DEBUG:uvicorn:('172.28.0.1', 59822) - ASGI [9] Started task
backend_1_79e424196ea0 | DEBUG:uvicorn:('172.28.0.1', 59822) - ASGI [9] Received {'type': 'http.response.start', 'status': 200, 'headers': '<...>'}
backend_1_79e424196ea0 | INFO:uvicorn:('172.28.0.1', 59822) - "GET /users/ HTTP/1.1" 200
backend_1_79e424196ea0 | DEBUG:uvicorn:('172.28.0.1', 59822) - ASGI [9] Received {'type': 'http.response.body', 'body': '<16 bytes>'}
backend_1_79e424196ea0 | DEBUG:uvicorn:('172.28.0.1', 59822) - ASGI [9] Completed
backend_1_79e424196ea0 | DEBUG:uvicorn:('172.28.0.1', 59822) - Disconnected
from fastapi.
I forgot to mention, thanks @euri10 for your help here. As always, greatly appreciated! 🌮 🎉 🍰
from fastapi.
@tiangolo Although this is closed, just calling out that starlette just fixed an issue with redirects on non-get methods that would be great to get in someday:
encode/starlette@3f70223
It requires upgrading starlette to 0.12.7 but that's incompatible with the pinned version in FastAPI.
from fastapi.
I'm not sure if this is the right place to ask this, but it looks like the redirect that happens here breaks our use-case. We host our api at https://url/api, using Apache to make sure /api points to FastAPI, FastAPI doesn't receive that it's behind /api(it just gets a request to /users/ instead of /api/users/). For the docs to still work in this case I add openapi_prefix='/api'
to the FastAPI definition. Now, that's all fine and working, but if I request http://url/api/users (no trailing slash) FastAPI wants to try and redirect it to http://url/users/, which is invalid and gives a 404. Is it possible to tell FastAPI/Starlette that we're running behind /api for redirects like this?
from fastapi.
I had this issue as well, in the end I stopped using prefixes so I could have the /items endpoint. Not ideal...
from fastapi.
We are forced to have an ending '/' on the collection endpoints, e.g. /items/ vs /items/{id} This is I think the more formal REST practice, but it results in a 404 when someone uses /items instead - I'd rather follow the mantra of 'be flexible with regards to user input and strict with what I return'. I'd like to have the option of allowing both /items and /items/ for the collection endpoints.
Sorry in advance if I'm totally off, maybe I don't get what you mean, but I don't seem to have the issue you describe.
If for instance I have that users
router, using prefix as described
app = FastAPI()
app.include_router(users_router, prefix='/users')
then for instance, inside my users router I have those routes for instance:
router = APIRouter()
@router.get("/list", response_model=List[User], tags=["Users"])
async def list():
query = users.select()
result = await database.fetch_all(query)
return [r._row for r in result]
@router.get("/me", response_model=User, tags=["Users"])
async def users_me(current_user: User = Depends(get_current_active_user)):
return current_user
As you'll see in image attached none of the routes end with a slash, or that's what you'd expect ?
from fastapi.
Typically - one would use the GET /users to list the users and GET /users/{id} to get one user specified by id
Using the prefix option, if you use /users as the prefix and '/' as the path in the sub-route module, this results in /users/ and no way to generate /users.
I guess that prefix wasn't really designed for this purpose and is more for something like /api/v1 as the prefix and then add in the /users in the sub-route user module.
from fastapi.
I think I understand the problem.
First: declaring a path operation /users/
, and having a client request /users
, should (optionally) redirect to or return the same as /users/
.
Then, using include_router
, should have the same behavior.
I think there is even code in Starlette (although not documented) to handle it.
I'll check it as soon as I'm in front of my laptop (I'm on a trip for a week).
from fastapi.
Yep. I think @euri10 is right.
It seems to be working correctly now.
More details:
In recent versions of Starlette, that is handled automatically, as you expect it. And I have updated FastAPI recently, to be compatible with/pinned to the latest versions of Starlette.
Please, update your version of FastAPI with, e.g.:
pip install --upgrade fastapi
And let me know if it's working for you @wshayes and @alexiri.
To test it, you can just copy-paste the files for the tutorial: https://fastapi.tiangolo.com/tutorial/bigger-applications/ (or copy them directly form the source: https://github.com/tiangolo/fastapi/tree/master/docs/src/bigger_applications)
And then open your browser at: http://127.0.0.1:8000/users.
It should redirect you to: http://127.0.0.1:8000/users/
And return a JSON like:
[
{"username":"Foo"},
{"username":"Bar"}
]
from fastapi.
I'm just tuning in (to the project and this issue), but it seems everyone concluded that Starlette is responsible and seems to have added redirects when you miss a slash (but not when you provide an unnecessary one). But even so, does that solve the case from @wshayes' original screenshot with POST
requests? I still lose that data and it's remapped to GET
.
If I'm not wrong about that, here are some ideas:
-
I commented on a Starlette issue suggesting that we not care about trailing slashes at all. Can anyone think of a downside to that?
-
In the meantime, I figured I'd try adding a
/?
to all my route decorators, and that seems to work great for all cases! However, then the docs include this trailing slash. Perhaps it'd be sufficient to clean that up before generating docs?
Ironically, I had trouble loading the docs at first. I was getting a 404 and assumed I had forgotten some plugin... then I realized I was calling /docs/
and it didn't honor the trailing slash. ;)
Loving the project so far! Let me know how I can help.
from fastapi.
@hjkelly Yep, it's the thing with REST, that it's not very strict (sometimes it's good, sometimes confusing).
About use cases for endpoints without trailing slash, sometimes trailing slashes are used for plurals (items) and non-trailing for things that are single, or that don't return several items (or several X). It might also be useful for declaring actions, like, let's say /publish
.
About the specific case of having /docs/
and /redoc/
instead of /docs
and /redoc
, I would consider it. Would you like to create a new issue adding it as a feature request? I would like to see if anyone opposes to it, I want to check if that would break any use case.
from fastapi.
You can currently fix this behavior by subclassing fastapi.APIRouter
and overriding APIRouter.__call__
with a change to this line:
https://github.com/encode/starlette/blob/master/starlette/routing.py#L610
Then use the subclassed router to decorate your endpoints.
But it shouldn't be so awkward to specify a modified redirect path in this way. I think you should create an issue for this in starlette, I think it would probably be well-received, and based on the fact that that method isn't overridden at all in fastapi, fixing it in starlette would probably be a prerequisite for incorporating the fix into fastapi.
from fastapi.
Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs.
from fastapi.
Related Issues (20)
- No streaming interface can not support concurrency for two fastapi servers
- Using pydantic Json Type as Form data type doesn't work HOT 1
- Raw docstring (leading `r`) defeats form feed `\f` truncation HOT 3
- OpenAPI Example with multipart/form-data not showing up HOT 5
- [BUG] Using Nested Pydantic models and `params: MyModel = Depends()` forces OpenAPI docs GET methods to require a request body. HOT 6
- How to fix this bug? HOT 2
- [BUG] Upgrade python-mulipart==0.0.7 from low version fastapi upload file may be 400 HOT 4
- Use `RootModel` as query parameter HOT 2
- Context managers in `Depends` are broken after 0.106 HOT 16
- Middleware runs twice HOT 8
- Support for Pydantic deprecated fields HOT 1
- axios can't receive error response status code
- Potential footgun when using custom `Response(background=<Task()>)` in conjunction with injected `BackgroundTasks` - the custom response overwrites the tasks HOT 3
- lifespan
- Breaking change with path parameters when updating to pydantic>=2 from pydantic<2 HOT 1
- trying to live video stream using Fastapi
- Package on test.pypi.org is broken
- middleware type
- It throws an exception when I specify return Http status code
- When backend restart the frontend request a protected api cause an unhandle exception: Exception in ASGI application HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fastapi.