mirror of
https://github.com/fastapi/fastapi.git
synced 2026-01-04 04:00:27 -05:00
* Updated .py files with Optional tag (up to body_nested_models) * Update optionals * docs_src/ all updates, few I was unsure of * Updated markdown files with Optional param * es: Add Optional typing to index.md * Last of markdown files updated with Optional param * Update highlight lines * it: Add Optional typings * README.md: Update with Optional typings * Update more highlight increments * Update highlights * schema-extra-example.md: Update highlights * updating highlighting on website to reflect .py changes * Update highlighting for query-params & response-directly * Address PR comments * Get rid of unnecessary comment * ⏪ Revert Optional in Chinese docs as it probably also requires changes in text * 🎨 Apply format * ⏪ Revert modified example * ♻️ Simplify example in docs * 📝 Update OpenAPI callback example to use Optional * ✨ Add Optional types to tests * 📝 Update docs about query params, default to using Optional * 🎨 Update code examples line highlighting * 📝 Update nested models docs to use "type parameters" instead of "subtypes" * 📝 Add notes about FastAPI usage of None including: = None and = Query(None) and clarify relationship with Optional[str] * 📝 Add note about response_model_by_alias * ♻️ Simplify query param list example * 🔥 Remove test for removed example * ✅ Update test for updated example Co-authored-by: Christopher Nguyen <chrisngyn99@gmail.com> Co-authored-by: yk396 <yk396@cornell.edu> Co-authored-by: Kai Chen <kaichen120@gmail.com>
155 lines
4.2 KiB
Python
155 lines
4.2 KiB
Python
from typing import Dict, List, Optional
|
|
|
|
from fastapi import FastAPI
|
|
from pydantic import BaseModel, Field
|
|
from starlette.testclient import TestClient
|
|
|
|
app = FastAPI()
|
|
|
|
|
|
class Item(BaseModel):
|
|
name: str = Field(..., alias="aliased_name")
|
|
price: Optional[float] = None
|
|
owner_ids: List[int] = None
|
|
|
|
|
|
@app.get("/items/valid", response_model=Item)
|
|
def get_valid():
|
|
return Item(aliased_name="valid", price=1.0)
|
|
|
|
|
|
@app.get("/items/coerce", response_model=Item)
|
|
def get_coerce():
|
|
return Item(aliased_name="coerce", price="1.0")
|
|
|
|
|
|
@app.get("/items/validlist", response_model=List[Item])
|
|
def get_validlist():
|
|
return [
|
|
Item(aliased_name="foo"),
|
|
Item(aliased_name="bar", price=1.0),
|
|
Item(aliased_name="baz", price=2.0, owner_ids=[1, 2, 3]),
|
|
]
|
|
|
|
|
|
@app.get("/items/validdict", response_model=Dict[str, Item])
|
|
def get_validdict():
|
|
return {
|
|
"k1": Item(aliased_name="foo"),
|
|
"k2": Item(aliased_name="bar", price=1.0),
|
|
"k3": Item(aliased_name="baz", price=2.0, owner_ids=[1, 2, 3]),
|
|
}
|
|
|
|
|
|
@app.get(
|
|
"/items/valid-exclude-unset", response_model=Item, response_model_exclude_unset=True
|
|
)
|
|
def get_valid_exclude_unset():
|
|
return Item(aliased_name="valid", price=1.0)
|
|
|
|
|
|
@app.get(
|
|
"/items/coerce-exclude-unset",
|
|
response_model=Item,
|
|
response_model_exclude_unset=True,
|
|
)
|
|
def get_coerce_exclude_unset():
|
|
return Item(aliased_name="coerce", price="1.0")
|
|
|
|
|
|
@app.get(
|
|
"/items/validlist-exclude-unset",
|
|
response_model=List[Item],
|
|
response_model_exclude_unset=True,
|
|
)
|
|
def get_validlist_exclude_unset():
|
|
return [
|
|
Item(aliased_name="foo"),
|
|
Item(aliased_name="bar", price=1.0),
|
|
Item(aliased_name="baz", price=2.0, owner_ids=[1, 2, 3]),
|
|
]
|
|
|
|
|
|
@app.get(
|
|
"/items/validdict-exclude-unset",
|
|
response_model=Dict[str, Item],
|
|
response_model_exclude_unset=True,
|
|
)
|
|
def get_validdict_exclude_unset():
|
|
return {
|
|
"k1": Item(aliased_name="foo"),
|
|
"k2": Item(aliased_name="bar", price=1.0),
|
|
"k3": Item(aliased_name="baz", price=2.0, owner_ids=[1, 2, 3]),
|
|
}
|
|
|
|
|
|
client = TestClient(app)
|
|
|
|
|
|
def test_valid():
|
|
response = client.get("/items/valid")
|
|
response.raise_for_status()
|
|
assert response.json() == {"aliased_name": "valid", "price": 1.0, "owner_ids": None}
|
|
|
|
|
|
def test_coerce():
|
|
response = client.get("/items/coerce")
|
|
response.raise_for_status()
|
|
assert response.json() == {
|
|
"aliased_name": "coerce",
|
|
"price": 1.0,
|
|
"owner_ids": None,
|
|
}
|
|
|
|
|
|
def test_validlist():
|
|
response = client.get("/items/validlist")
|
|
response.raise_for_status()
|
|
assert response.json() == [
|
|
{"aliased_name": "foo", "price": None, "owner_ids": None},
|
|
{"aliased_name": "bar", "price": 1.0, "owner_ids": None},
|
|
{"aliased_name": "baz", "price": 2.0, "owner_ids": [1, 2, 3]},
|
|
]
|
|
|
|
|
|
def test_validdict():
|
|
response = client.get("/items/validdict")
|
|
response.raise_for_status()
|
|
assert response.json() == {
|
|
"k1": {"aliased_name": "foo", "price": None, "owner_ids": None},
|
|
"k2": {"aliased_name": "bar", "price": 1.0, "owner_ids": None},
|
|
"k3": {"aliased_name": "baz", "price": 2.0, "owner_ids": [1, 2, 3]},
|
|
}
|
|
|
|
|
|
def test_valid_exclude_unset():
|
|
response = client.get("/items/valid-exclude-unset")
|
|
response.raise_for_status()
|
|
assert response.json() == {"aliased_name": "valid", "price": 1.0}
|
|
|
|
|
|
def test_coerce_exclude_unset():
|
|
response = client.get("/items/coerce-exclude-unset")
|
|
response.raise_for_status()
|
|
assert response.json() == {"aliased_name": "coerce", "price": 1.0}
|
|
|
|
|
|
def test_validlist_exclude_unset():
|
|
response = client.get("/items/validlist-exclude-unset")
|
|
response.raise_for_status()
|
|
assert response.json() == [
|
|
{"aliased_name": "foo"},
|
|
{"aliased_name": "bar", "price": 1.0},
|
|
{"aliased_name": "baz", "price": 2.0, "owner_ids": [1, 2, 3]},
|
|
]
|
|
|
|
|
|
def test_validdict_exclude_unset():
|
|
response = client.get("/items/validdict-exclude-unset")
|
|
response.raise_for_status()
|
|
assert response.json() == {
|
|
"k1": {"aliased_name": "foo"},
|
|
"k2": {"aliased_name": "bar", "price": 1.0},
|
|
"k3": {"aliased_name": "baz", "price": 2.0, "owner_ids": [1, 2, 3]},
|
|
}
|