mirror of
https://github.com/fastapi/fastapi.git
synced 2025-12-27 16:21:06 -05:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a274d18b4 | ||
|
|
62626b0175 | ||
|
|
c8df3ae57c | ||
|
|
6f7f9268f6 | ||
|
|
50653e205f | ||
|
|
50a280b17b | ||
|
|
c1da3b38a3 |
@@ -1,5 +1,13 @@
|
||||
## Next release
|
||||
|
||||
## 0.12.1
|
||||
|
||||
* Fix bug: handling additional `responses` in `APIRouter.include_router()`. PR <a href="https://github.com/tiangolo/fastapi/pull/140" target="_blank">#140</a>.
|
||||
|
||||
* Fix typo in SQL tutorial. PR <a href="https://github.com/tiangolo/fastapi/pull/138" target="_blank">#138</a> by <a href="https://github.com/mostaphaRoudsari" target="_blank">@mostaphaRoudsari</a>.
|
||||
|
||||
* Fix typos in section about nested models and OAuth2 with JWT. PR <a href="https://github.com/tiangolo/fastapi/pull/127" target="_blank">#127</a> by <a href="https://github.com/mmcloud" target="_blank">@mmcloud</a>.
|
||||
|
||||
## 0.12.0
|
||||
|
||||
* Add additional `responses` parameter to *path operation decorators* to extend responses in OpenAPI (and API docs).
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from typing import Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from pydantic.types import UrlStr
|
||||
from pydantic import BaseModel, UrlStr
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from typing import List, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from pydantic.types import UrlStr
|
||||
from pydantic import BaseModel, UrlStr
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -18,7 +17,7 @@ class Item(BaseModel):
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: Set[str] = []
|
||||
image: List[Image] = None
|
||||
images: List[Image] = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from typing import List, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from pydantic.types import UrlStr
|
||||
from pydantic import BaseModel, UrlStr
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -18,7 +17,7 @@ class Item(BaseModel):
|
||||
price: float
|
||||
tax: float = None
|
||||
tags: Set[str] = []
|
||||
image: List[Image] = None
|
||||
images: List[Image] = None
|
||||
|
||||
|
||||
class Offer(BaseModel):
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from typing import List
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from pydantic.types import UrlStr
|
||||
from pydantic import BaseModel, UrlStr
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ To see all the options you have, checkout the docs for <a href="https://pydantic
|
||||
|
||||
For example, as in the `Image` model we have a `url` field, we can declare it to be instead of a `str`, a Pydantic's `UrlStr`:
|
||||
|
||||
```Python hl_lines="5 11"
|
||||
```Python hl_lines="4 10"
|
||||
{!./src/body_nested_models/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -130,7 +130,7 @@ The string will be checked to be a valid URL, and documented in JSON Schema / Op
|
||||
|
||||
You can also use Pydantic models as subtypes of `list`, `set`, etc:
|
||||
|
||||
```Python hl_lines="21"
|
||||
```Python hl_lines="20"
|
||||
{!./src/body_nested_models/tutorial006.py!}
|
||||
```
|
||||
|
||||
@@ -167,7 +167,7 @@ This will expect (convert, validate, document, etc) a JSON body like:
|
||||
|
||||
You can define arbitrarily deeply nested models:
|
||||
|
||||
```Python hl_lines="10 15 21 24 28"
|
||||
```Python hl_lines="9 14 20 23 27"
|
||||
{!./src/body_nested_models/tutorial007.py!}
|
||||
```
|
||||
|
||||
@@ -184,7 +184,7 @@ images: List[Image]
|
||||
|
||||
as in:
|
||||
|
||||
```Python hl_lines="16"
|
||||
```Python hl_lines="15"
|
||||
{!./src/body_nested_models/tutorial008.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ If you want to play with JWT tokens and see how they work, check <a href="https:
|
||||
|
||||
## Install `PyJWT`
|
||||
|
||||
We need to install `PyJWT` to generate and verity the JWT tokens in Python:
|
||||
We need to install `PyJWT` to generate and verify the JWT tokens in Python:
|
||||
|
||||
```bash
|
||||
pip install pyjwt
|
||||
@@ -198,7 +198,7 @@ Many packages that simplify it a lot have to make many compromises with the data
|
||||
|
||||
**FastAPI** doesn't make any compromise with any database, data model or tool.
|
||||
|
||||
It gives you all the flexibility to chose the ones that fit your project the best.
|
||||
It gives you all the flexibility to choose the ones that fit your project the best.
|
||||
|
||||
And you can use directly many well maintained and widely used packages like `passlib` and `pyjwt`, because **FastAPI** doesn't require any complex mechanisms to integrate external packages.
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ This object (class) is not a connection to the database yet, but once we create
|
||||
|
||||
We name it `SessionLocal` to distinguish it form the `Session` we are importing from SQLAlchemy.
|
||||
|
||||
We will use `Session` to declare types later and getter better editor support and completion.
|
||||
We will use `Session` to declare types later and to get better editor support and completion.
|
||||
|
||||
For now, create the `SessionLocal`:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
||||
|
||||
__version__ = "0.12.0"
|
||||
__version__ = "0.12.1"
|
||||
|
||||
from starlette.background import BackgroundTasks
|
||||
|
||||
|
||||
@@ -285,11 +285,11 @@ class APIRouter(routing.Router):
|
||||
assert not prefix.endswith(
|
||||
"/"
|
||||
), "A path prefix must not end with '/', as the routes will start with '/'"
|
||||
if responses is None:
|
||||
responses = {}
|
||||
for route in router.routes:
|
||||
if isinstance(route, APIRoute):
|
||||
if responses is None:
|
||||
responses = {}
|
||||
responses = {**responses, **route.responses}
|
||||
combined_responses = {**responses, **route.responses}
|
||||
self.add_api_route(
|
||||
prefix + route.path,
|
||||
route.endpoint,
|
||||
@@ -299,7 +299,7 @@ class APIRouter(routing.Router):
|
||||
summary=route.summary,
|
||||
description=route.description,
|
||||
response_description=route.response_description,
|
||||
responses=responses,
|
||||
responses=combined_responses,
|
||||
deprecated=route.deprecated,
|
||||
methods=route.methods,
|
||||
operation_id=route.operation_id,
|
||||
|
||||
95
tests/test_additional_responses_router.py
Normal file
95
tests/test_additional_responses_router.py
Normal file
@@ -0,0 +1,95 @@
|
||||
from fastapi import APIRouter, FastAPI
|
||||
from starlette.testclient import TestClient
|
||||
|
||||
app = FastAPI()
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/a", responses={501: {"description": "Error 1"}})
|
||||
async def a():
|
||||
return "a"
|
||||
|
||||
|
||||
@router.get("/b", responses={502: {"description": "Error 2"}})
|
||||
async def b():
|
||||
return "b"
|
||||
|
||||
|
||||
@router.get("/c", responses={501: {"description": "Error 3"}})
|
||||
async def c():
|
||||
return "c"
|
||||
|
||||
|
||||
app.include_router(router)
|
||||
|
||||
openapi_schema = {
|
||||
"openapi": "3.0.2",
|
||||
"info": {"title": "Fast API", "version": "0.1.0"},
|
||||
"paths": {
|
||||
"/a": {
|
||||
"get": {
|
||||
"responses": {
|
||||
"501": {"description": "Error 1"},
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {"application/json": {"schema": {}}},
|
||||
},
|
||||
},
|
||||
"summary": "A Get",
|
||||
"operationId": "a_a_get",
|
||||
}
|
||||
},
|
||||
"/b": {
|
||||
"get": {
|
||||
"responses": {
|
||||
"502": {"description": "Error 2"},
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {"application/json": {"schema": {}}},
|
||||
},
|
||||
},
|
||||
"summary": "B Get",
|
||||
"operationId": "b_b_get",
|
||||
}
|
||||
},
|
||||
"/c": {
|
||||
"get": {
|
||||
"responses": {
|
||||
"501": {"description": "Error 3"},
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {"application/json": {"schema": {}}},
|
||||
},
|
||||
},
|
||||
"summary": "C Get",
|
||||
"operationId": "c_c_get",
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
def test_openapi_schema():
|
||||
response = client.get("/openapi.json")
|
||||
assert response.status_code == 200
|
||||
assert response.json() == openapi_schema
|
||||
|
||||
|
||||
def test_a():
|
||||
response = client.get("/a")
|
||||
assert response.status_code == 200
|
||||
assert response.json() == "a"
|
||||
|
||||
|
||||
def test_b():
|
||||
response = client.get("/b")
|
||||
assert response.status_code == 200
|
||||
assert response.json() == "b"
|
||||
|
||||
|
||||
def test_c():
|
||||
response = client.get("/c")
|
||||
assert response.status_code == 200
|
||||
assert response.json() == "c"
|
||||
Reference in New Issue
Block a user