diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml
index 8176602a7..322b6536a 100644
--- a/.github/ISSUE_TEMPLATE/feature-request.yml
+++ b/.github/ISSUE_TEMPLATE/feature-request.yml
@@ -8,9 +8,9 @@ body:
Thanks for your interest in FastAPI! 🚀
Please follow these instructions, fill every question, and do every step. 🙏
-
+
I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time.
-
+
I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues.
All that, on top of all the incredible help provided by a bunch of community members, the [FastAPI Experts](https://fastapi.tiangolo.com/fastapi-people/#experts), that give a lot of their time to come here and help others.
@@ -18,7 +18,7 @@ body:
That's a lot of work they are doing, but if more FastAPI users came to help others like them just a little bit more, it would be much less effort for them (and you and me 😅).
By asking questions in a structured way (following this) it will be much easier to help you.
-
+
And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎
As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓
@@ -50,7 +50,7 @@ body:
label: Commit to Help
description: |
After submitting this, I commit to one of:
-
+
* Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
* I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.
* Implement a Pull Request for a confirmed bug.
diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml
index 5c76fd17e..3b16b4ad0 100644
--- a/.github/ISSUE_TEMPLATE/question.yml
+++ b/.github/ISSUE_TEMPLATE/question.yml
@@ -8,9 +8,9 @@ body:
Thanks for your interest in FastAPI! 🚀
Please follow these instructions, fill every question, and do every step. 🙏
-
+
I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time.
-
+
I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues.
All that, on top of all the incredible help provided by a bunch of community members, the [FastAPI Experts](https://fastapi.tiangolo.com/fastapi-people/#experts), that give a lot of their time to come here and help others.
@@ -18,7 +18,7 @@ body:
That's a lot of work they are doing, but if more FastAPI users came to help others like them just a little bit more, it would be much less effort for them (and you and me 😅).
By asking questions in a structured way (following this) it will be much easier to help you.
-
+
And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎
As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓
@@ -50,7 +50,7 @@ body:
label: Commit to Help
description: |
After submitting this, I commit to one of:
-
+
* Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
* I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.
* Implement a Pull Request for a confirmed bug.
diff --git a/.github/actions/comment-docs-preview-in-pr/app/main.py b/.github/actions/comment-docs-preview-in-pr/app/main.py
index 3b10e0ee0..68914fdb9 100644
--- a/.github/actions/comment-docs-preview-in-pr/app/main.py
+++ b/.github/actions/comment-docs-preview-in-pr/app/main.py
@@ -1,7 +1,7 @@
import logging
import sys
from pathlib import Path
-from typing import Optional
+from typing import Union
import httpx
from github import Github
@@ -14,7 +14,7 @@ github_api = "https://api.github.com"
class Settings(BaseSettings):
github_repository: str
github_event_path: Path
- github_event_name: Optional[str] = None
+ github_event_name: Union[str, None] = None
input_token: SecretStr
input_deploy_url: str
@@ -42,15 +42,13 @@ if __name__ == "__main__":
except ValidationError as e:
logging.error(f"Error parsing event file: {e.errors()}")
sys.exit(0)
- use_pr: Optional[PullRequest] = None
+ use_pr: Union[PullRequest, None] = None
for pr in repo.get_pulls():
if pr.head.sha == event.workflow_run.head_commit.id:
use_pr = pr
break
if not use_pr:
- logging.error(
- f"No PR found for hash: {event.workflow_run.head_commit.id}"
- )
+ logging.error(f"No PR found for hash: {event.workflow_run.head_commit.id}")
sys.exit(0)
github_headers = {
"Authorization": f"token {settings.input_token.get_secret_value()}"
diff --git a/.github/actions/notify-translations/app/main.py b/.github/actions/notify-translations/app/main.py
index 7d6c1a4d2..d4ba0ecfc 100644
--- a/.github/actions/notify-translations/app/main.py
+++ b/.github/actions/notify-translations/app/main.py
@@ -1,8 +1,8 @@
import logging
+import random
import time
from pathlib import Path
-import random
-from typing import Dict, Optional
+from typing import Dict, Union
import yaml
from github import Github
@@ -18,8 +18,8 @@ class Settings(BaseSettings):
github_repository: str
input_token: SecretStr
github_event_path: Path
- github_event_name: Optional[str] = None
- input_debug: Optional[bool] = False
+ github_event_name: Union[str, None] = None
+ input_debug: Union[bool, None] = False
class PartialGitHubEventIssue(BaseModel):
@@ -54,7 +54,7 @@ if __name__ == "__main__":
)
if pr.state == "open":
logging.debug(f"PR is open: {pr.number}")
- label_strs = set([label.name for label in pr.get_labels()])
+ label_strs = {label.name for label in pr.get_labels()}
if lang_all_label in label_strs and awaiting_label in label_strs:
logging.info(
f"This PR seems to be a language translation and awaiting reviews: {pr.number}"
diff --git a/.github/actions/notify-translations/app/translations.yml b/.github/actions/notify-translations/app/translations.yml
index decd63498..d283ef9f7 100644
--- a/.github/actions/notify-translations/app/translations.yml
+++ b/.github/actions/notify-translations/app/translations.yml
@@ -8,8 +8,12 @@ uk: 1748
tr: 1892
fr: 1972
ko: 2017
-sq: 2041
+fa: 2041
pl: 3169
de: 3716
id: 3717
az: 3994
+nl: 4701
+uz: 4883
+sv: 5146
+he: 5157
diff --git a/.github/actions/people/app/main.py b/.github/actions/people/app/main.py
index dc0bbc4c0..1455d01ca 100644
--- a/.github/actions/people/app/main.py
+++ b/.github/actions/people/app/main.py
@@ -4,7 +4,7 @@ import sys
from collections import Counter, defaultdict
from datetime import datetime, timedelta, timezone
from pathlib import Path
-from typing import Container, DefaultDict, Dict, List, Optional, Set
+from typing import Container, DefaultDict, Dict, List, Set, Union
import httpx
import yaml
@@ -14,7 +14,7 @@ from pydantic import BaseModel, BaseSettings, SecretStr
github_graphql_url = "https://api.github.com/graphql"
issues_query = """
-query Q($after: String) {
+query Q($after: String) {
repository(name: "fastapi", owner: "tiangolo") {
issues(first: 100, after: $after) {
edges {
@@ -47,7 +47,7 @@ query Q($after: String) {
"""
prs_query = """
-query Q($after: String) {
+query Q($after: String) {
repository(name: "fastapi", owner: "tiangolo") {
pullRequests(first: 100, after: $after) {
edges {
@@ -133,7 +133,7 @@ class Author(BaseModel):
class CommentsNode(BaseModel):
createdAt: datetime
- author: Optional[Author] = None
+ author: Union[Author, None] = None
class Comments(BaseModel):
@@ -142,7 +142,7 @@ class Comments(BaseModel):
class IssuesNode(BaseModel):
number: int
- author: Optional[Author] = None
+ author: Union[Author, None] = None
title: str
createdAt: datetime
state: str
@@ -179,7 +179,7 @@ class Labels(BaseModel):
class ReviewNode(BaseModel):
- author: Optional[Author] = None
+ author: Union[Author, None] = None
state: str
@@ -190,7 +190,7 @@ class Reviews(BaseModel):
class PullRequestNode(BaseModel):
number: int
labels: Labels
- author: Optional[Author] = None
+ author: Union[Author, None] = None
title: str
createdAt: datetime
state: str
@@ -263,7 +263,7 @@ class Settings(BaseSettings):
def get_graphql_response(
- *, settings: Settings, query: str, after: Optional[str] = None
+ *, settings: Settings, query: str, after: Union[str, None] = None
):
headers = {"Authorization": f"token {settings.input_token.get_secret_value()}"}
variables = {"after": after}
@@ -280,19 +280,19 @@ def get_graphql_response(
return data
-def get_graphql_issue_edges(*, settings: Settings, after: Optional[str] = None):
+def get_graphql_issue_edges(*, settings: Settings, after: Union[str, None] = None):
data = get_graphql_response(settings=settings, query=issues_query, after=after)
graphql_response = IssuesResponse.parse_obj(data)
return graphql_response.data.repository.issues.edges
-def get_graphql_pr_edges(*, settings: Settings, after: Optional[str] = None):
+def get_graphql_pr_edges(*, settings: Settings, after: Union[str, None] = None):
data = get_graphql_response(settings=settings, query=prs_query, after=after)
graphql_response = PRsResponse.parse_obj(data)
return graphql_response.data.repository.pullRequests.edges
-def get_graphql_sponsor_edges(*, settings: Settings, after: Optional[str] = None):
+def get_graphql_sponsor_edges(*, settings: Settings, after: Union[str, None] = None):
data = get_graphql_response(settings=settings, query=sponsors_query, after=after)
graphql_response = SponsorsResponse.parse_obj(data)
return graphql_response.data.user.sponsorshipsAsMaintainer.edges
@@ -501,9 +501,16 @@ if __name__ == "__main__":
github_sponsors_path = Path("./docs/en/data/github_sponsors.yml")
people_old_content = people_path.read_text(encoding="utf-8")
github_sponsors_old_content = github_sponsors_path.read_text(encoding="utf-8")
- new_people_content = yaml.dump(people, sort_keys=False, width=200, allow_unicode=True)
- new_github_sponsors_content = yaml.dump(github_sponsors, sort_keys=False, width=200, allow_unicode=True)
- if people_old_content == new_people_content and github_sponsors_old_content == new_github_sponsors_content:
+ new_people_content = yaml.dump(
+ people, sort_keys=False, width=200, allow_unicode=True
+ )
+ new_github_sponsors_content = yaml.dump(
+ github_sponsors, sort_keys=False, width=200, allow_unicode=True
+ )
+ if (
+ people_old_content == new_people_content
+ and github_sponsors_old_content == new_github_sponsors_content
+ ):
logging.info("The FastAPI People data hasn't changed, finishing.")
sys.exit(0)
people_path.write_text(new_people_content, encoding="utf-8")
@@ -517,7 +524,9 @@ if __name__ == "__main__":
logging.info(f"Creating a new branch {branch_name}")
subprocess.run(["git", "checkout", "-b", branch_name], check=True)
logging.info("Adding updated file")
- subprocess.run(["git", "add", str(people_path)], check=True)
+ subprocess.run(
+ ["git", "add", str(people_path), str(github_sponsors_path)], check=True
+ )
logging.info("Committing updated file")
message = "👥 Update FastAPI People"
result = subprocess.run(["git", "commit", "-m", message], check=True)
diff --git a/.github/actions/watch-previews/app/main.py b/.github/actions/watch-previews/app/main.py
index 3b3520599..51285d02b 100644
--- a/.github/actions/watch-previews/app/main.py
+++ b/.github/actions/watch-previews/app/main.py
@@ -1,7 +1,7 @@
import logging
from datetime import datetime
from pathlib import Path
-from typing import List, Optional
+from typing import List, Union
import httpx
from github import Github
@@ -16,7 +16,7 @@ class Settings(BaseSettings):
input_token: SecretStr
github_repository: str
github_event_path: Path
- github_event_name: Optional[str] = None
+ github_event_name: Union[str, None] = None
class Artifact(BaseModel):
@@ -74,7 +74,7 @@ if __name__ == "__main__":
logging.info(f"Docs preview was notified: {notified}")
if not notified:
artifact_name = f"docs-zip-{commit}"
- use_artifact: Optional[Artifact] = None
+ use_artifact: Union[Artifact, None] = None
for artifact in artifacts_response.artifacts:
if artifact.name == artifact_name:
use_artifact = artifact
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..cd972a0ba
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,16 @@
+version: 2
+updates:
+ # GitHub Actions
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "daily"
+ commit-message:
+ prefix: ⬆
+ # Python
+ - package-ecosystem: "pip"
+ directory: "/"
+ schedule:
+ interval: "daily"
+ commit-message:
+ prefix: ⬆
diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml
index 2482660f3..0d666b82a 100644
--- a/.github/workflows/build-docs.yml
+++ b/.github/workflows/build-docs.yml
@@ -13,16 +13,16 @@ jobs:
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set up Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: "3.7"
- - uses: actions/cache@v2
+ - uses: actions/cache@v3
id: cache
with:
path: ${{ env.pythonLocation }}
- key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-docs-v2
+ key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-v03
- name: Install Flit
if: steps.cache.outputs.cache-hit != 'true'
run: python3.7 -m pip install flit
@@ -30,18 +30,18 @@ jobs:
if: steps.cache.outputs.cache-hit != 'true'
run: python3.7 -m flit install --deps production --extras doc
- name: Install Material for MkDocs Insiders
- if: github.event.pull_request.head.repo.fork == false && steps.cache.outputs.cache-hit != 'true'
+ if: ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false ) && steps.cache.outputs.cache-hit != 'true'
run: pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git
- name: Build Docs
run: python3.7 ./scripts/docs.py build-all
- name: Zip docs
run: bash ./scripts/zip-docs.sh
- - uses: actions/upload-artifact@v2
+ - uses: actions/upload-artifact@v3
with:
name: docs-zip
path: ./docs.zip
- name: Deploy to Netlify
- uses: nwtgck/actions-netlify@v1.1.5
+ uses: nwtgck/actions-netlify@v1.2.3
with:
publish-dir: './site'
production-branch: master
diff --git a/.github/workflows/latest-changes.yml b/.github/workflows/latest-changes.yml
index 42236beba..4aa8475b6 100644
--- a/.github/workflows/latest-changes.yml
+++ b/.github/workflows/latest-changes.yml
@@ -12,7 +12,7 @@ on:
description: PR number
required: true
debug_enabled:
- description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
+ description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false
default: false
@@ -20,7 +20,7 @@ jobs:
latest-changes:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# To allow latest-changes to commit to master
token: ${{ secrets.ACTIONS_TOKEN }}
diff --git a/.github/workflows/notify-translations.yml b/.github/workflows/notify-translations.yml
index 7e414ab95..2fcb7595e 100644
--- a/.github/workflows/notify-translations.yml
+++ b/.github/workflows/notify-translations.yml
@@ -9,7 +9,7 @@ jobs:
notify-translations:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
diff --git a/.github/workflows/people.yml b/.github/workflows/people.yml
index 970813da7..4b47b4072 100644
--- a/.github/workflows/people.yml
+++ b/.github/workflows/people.yml
@@ -6,7 +6,7 @@ on:
workflow_dispatch:
inputs:
debug_enabled:
- description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
+ description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false
default: false
@@ -14,7 +14,7 @@ jobs:
fastapi-people:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
diff --git a/.github/workflows/preview-docs.yml b/.github/workflows/preview-docs.yml
index 0c0d2ac59..9e71a461a 100644
--- a/.github/workflows/preview-docs.yml
+++ b/.github/workflows/preview-docs.yml
@@ -3,16 +3,16 @@ on:
workflow_run:
workflows:
- Build Docs
- types:
+ types:
- completed
jobs:
preview-docs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Download Artifact Docs
- uses: dawidd6/action-download-artifact@v2.9.0
+ uses: dawidd6/action-download-artifact@v2.21.1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
workflow: build-docs.yml
@@ -25,7 +25,7 @@ jobs:
rm -f docs.zip
- name: Deploy to Netlify
id: netlify
- uses: nwtgck/actions-netlify@v1.1.5
+ uses: nwtgck/actions-netlify@v1.2.3
with:
publish-dir: './site'
production-deploy: false
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 9dde4e066..02846cefd 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -13,12 +13,12 @@ jobs:
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set up Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: "3.6"
- - uses: actions/cache@v2
+ - uses: actions/cache@v3
id: cache
with:
path: ${{ env.pythonLocation }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 21ea7c1a8..14dc141d9 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -16,16 +16,16 @@ jobs:
fail-fast: false
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set up Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- - uses: actions/cache@v2
+ - uses: actions/cache@v3
id: cache
with:
path: ${{ env.pythonLocation }}
- key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test
+ key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test-v02
- name: Install Flit
if: steps.cache.outputs.cache-hit != 'true'
run: pip install flit
@@ -38,4 +38,4 @@ jobs:
- name: Test
run: bash scripts/test.sh
- name: Upload coverage
- uses: codecov/codecov-action@v1
+ uses: codecov/codecov-action@v3
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 000000000..6944e4a25
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,51 @@
+# See https://pre-commit.com for more information
+# See https://pre-commit.com/hooks.html for more hooks
+repos:
+- repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.3.0
+ hooks:
+ - id: check-added-large-files
+ - id: check-toml
+ - id: check-yaml
+ args:
+ - --unsafe
+ - id: end-of-file-fixer
+ - id: trailing-whitespace
+- repo: https://github.com/asottile/pyupgrade
+ rev: v2.37.1
+ hooks:
+ - id: pyupgrade
+ args:
+ - --py3-plus
+ - --keep-runtime-typing
+- repo: https://github.com/myint/autoflake
+ rev: v1.4
+ hooks:
+ - id: autoflake
+ args:
+ - --recursive
+ - --in-place
+ - --remove-all-unused-imports
+ - --remove-unused-variables
+ - --expand-star-imports
+ - --exclude
+ - __init__.py
+ - --remove-duplicate-keys
+- repo: https://github.com/pycqa/isort
+ rev: 5.10.1
+ hooks:
+ - id: isort
+ name: isort (python)
+ - id: isort
+ name: isort (cython)
+ types: [cython]
+ - id: isort
+ name: isort (pyi)
+ types: [pyi]
+- repo: https://github.com/psf/black
+ rev: 22.6.0
+ hooks:
+ - id: black
+ci:
+ autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
+ autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate
diff --git a/README.md b/README.md
index bec58aad1..bcea9fe73 100644
--- a/README.md
+++ b/README.md
@@ -47,16 +47,17 @@ The key features are:
-
+ فریمورک FastAPI، کارایی بالا، یادگیری آسان، کدنویسی سریع، آماده برای استفاده در محیط پروداکشن
+
+ תשתית FastAPI, ביצועים גבוהים, קלה ללמידה, מהירה לתכנות, מוכנה לסביבת ייצור
+
+
-
-
+
+
-
-
+
+
+
@@ -150,7 +151,7 @@ $ pip install "uvicorn[standard]"
* Create a file `main.py` with:
```Python
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -163,7 +164,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -173,7 +174,7 @@ def read_item(item_id: int, q: Optional[str] = None):
If your code uses `async` / `await`, use `async def`:
```Python hl_lines="9 14"
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -186,7 +187,7 @@ async def read_root():
@app.get("/items/{item_id}")
-async def read_item(item_id: int, q: Optional[str] = None):
+async def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -265,7 +266,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
Declare the body using standard Python types, thanks to Pydantic.
```Python hl_lines="4 9-12 25-27"
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
@@ -276,7 +277,7 @@ app = FastAPI()
class Item(BaseModel):
name: str
price: float
- is_offer: Optional[bool] = None
+ is_offer: Union[bool, None] = None
@app.get("/")
@@ -285,7 +286,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml
index 66220f63e..90ee0bb82 100644
--- a/docs/az/mkdocs.yml
+++ b/docs/az/mkdocs.yml
@@ -5,13 +5,15 @@ theme:
name: material
custom_dir: overrides
palette:
- - scheme: default
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
primary: teal
accent: amber
toggle:
icon: material/lightbulb
name: Switch to light mode
- - scheme: slate
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
primary: teal
accent: amber
toggle:
@@ -40,15 +42,19 @@ nav:
- az: /az/
- de: /de/
- es: /es/
+ - fa: /fa/
- fr: /fr/
+ - he: /he/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
+ - sv: /sv/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -97,8 +103,12 @@ extra:
name: de
- link: /es/
name: es - español
+ - link: /fa/
+ name: fa
- link: /fr/
name: fr - français
+ - link: /he/
+ name: he
- link: /id/
name: id
- link: /it/
@@ -107,6 +117,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /nl/
+ name: nl
- link: /pl/
name: pl
- link: /pt/
@@ -115,6 +127,8 @@ extra:
name: ru - русский язык
- link: /sq/
name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/de/docs/features.md b/docs/de/docs/features.md
index f56257e7e..d99ade402 100644
--- a/docs/de/docs/features.md
+++ b/docs/de/docs/features.md
@@ -13,7 +13,7 @@
### Automatische Dokumentation
-Mit einer interaktiven API-Dokumentation und explorativen webbasierten Benutzerschnittstellen. Da FastAPI auf OpenAPI basiert, gibt es hierzu mehrere Optionen, wobei zwei standartmäßig vorhanden sind.
+Mit einer interaktiven API-Dokumentation und explorativen webbasierten Benutzerschnittstellen. Da FastAPI auf OpenAPI basiert, gibt es hierzu mehrere Optionen, wobei zwei standardmäßig vorhanden sind.
* Swagger UI, bietet interaktive Exploration: testen und rufen Sie ihre API direkt vom Webbrowser auf.
@@ -27,7 +27,7 @@ Mit einer interaktiven API-Dokumentation und explorativen webbasierten Benutzers
Alles basiert auf **Python 3.6 Typ**-Deklarationen (dank Pydantic). Es muss keine neue Syntax gelernt werden, nur standardisiertes modernes Python.
-
+
Wenn Sie eine kurze, zweiminütige, Auffrischung in der Benutzung von Python Typ-Deklarationen benötigen (auch wenn Sie FastAPI nicht nutzen), schauen Sie sich diese kurze Einführung an (Englisch): Python Types{.internal-link target=_blank}.
@@ -97,9 +97,9 @@ Hierdurch werden Sie nie wieder einen falschen Schlüsselnamen benutzen und spar
### Kompakt
-FastAPI nutzt für alles sensible **Standard-Einstellungen**, welche optional überall konfiguriert werden können. Alle Parameter können ganz genau an Ihre Bedürfnisse angepasst werden, sodass sie genau die API definieren können, die sie brachen.
+FastAPI nutzt für alles sinnvolle **Standard-Einstellungen**, welche optional überall konfiguriert werden können. Alle Parameter können ganz genau an Ihre Bedürfnisse angepasst werden, sodass sie genau die API definieren können, die sie brauchen.
-Aber standartmäßig, **"funktioniert einfach"** alles.
+Aber standardmäßig, **"funktioniert einfach"** alles.
### Validierung
@@ -109,7 +109,7 @@ Aber standartmäßig, **"funktioniert einfach"** alles.
* Zeichenketten (`str`), mit definierter minimaler und maximaler Länge.
* Zahlen (`int`, `float`) mit minimaler und maximaler Größe, usw.
-* Validierung für ungewögnliche Typen, wie:
+* Validierung für ungewöhnliche Typen, wie:
* URL.
* Email.
* UUID.
@@ -142,8 +142,8 @@ FastAPI enthält ein extrem einfaches, aber extrem mächtiges Starlette. Das bedeutet, auch ihr eigner Starlett Quellcode funktioniert.
+**FastAPI** ist vollkommen kompatibel (und basiert auf) Starlette. Das bedeutet, auch ihr eigener Starlette Quellcode funktioniert.
-`FastAPI` ist eigentlich eine Unterklasse von `Starlette`. Wenn sie also bereits Starlette kennen oder benutzen, können Sie das meiste Ihres Wissen direkt anwenden.
+`FastAPI` ist eigentlich eine Unterklasse von `Starlette`. Wenn Sie also bereits Starlette kennen oder benutzen, können Sie das meiste Ihres Wissens direkt anwenden.
Mit **FastAPI** bekommen Sie viele von **Starlette**'s Funktionen (da FastAPI nur Starlette auf Steroiden ist):
@@ -193,11 +193,11 @@ Mit **FastAPI** bekommen Sie alle Funktionen von **Pydantic** (da FastAPI für d
* Gutes Zusammenspiel mit Ihrer/Ihrem **IDE/linter/Gehirn**:
* Weil Datenstrukturen von Pydantic einfach nur Instanzen ihrer definierten Klassen sind, sollten Autovervollständigung, Linting, mypy und ihre Intuition einwandfrei funktionieren.
* **Schnell**:
- * In Vergleichen ist Pydantic schneller als jede andere getestete Bibliothek.
+ * In Vergleichen ist Pydantic schneller als jede andere getestete Bibliothek.
* Validierung von **komplexen Strukturen**:
* Benutzung von hierachischen Pydantic Schemata, Python `typing`’s `List` und `Dict`, etc.
* Validierungen erlauben klare und einfache Datenschemadefinition, überprüft und dokumentiert als JSON Schema.
* Sie können stark **verschachtelte JSON** Objekte haben und diese sind trotzdem validiert und annotiert.
* **Erweiterbar**:
- * Pydantic erlaubt die Definition von eigenen Datentypen oder sie können die Validierung mit einer `validator` dekorierten Methode erweitern..
+ * Pydantic erlaubt die Definition von eigenen Datentypen oder Sie können die Validierung mit einer `validator` dekorierten Methode erweitern..
* 100% Testabdeckung.
diff --git a/docs/de/docs/index.md b/docs/de/docs/index.md
index d09ce70a0..929754462 100644
--- a/docs/de/docs/index.md
+++ b/docs/de/docs/index.md
@@ -149,7 +149,7 @@ $ pip install uvicorn[standard]
* Create a file `main.py` with:
```Python
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -162,7 +162,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -172,7 +172,7 @@ def read_item(item_id: int, q: Optional[str] = None):
If your code uses `async` / `await`, use `async def`:
```Python hl_lines="9 14"
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -185,7 +185,7 @@ async def read_root():
@app.get("/items/{item_id}")
-async def read_item(item_id: int, q: Optional[str] = None):
+async def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -264,7 +264,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
Declare the body using standard Python types, thanks to Pydantic.
```Python hl_lines="4 9-12 25-27"
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
@@ -275,7 +275,7 @@ app = FastAPI()
class Item(BaseModel):
name: str
price: float
- is_offer: Optional[bool] = None
+ is_offer: Union[bool, None] = None
@app.get("/")
@@ -284,7 +284,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
@@ -321,7 +321,7 @@ And now, go to
requests
- Required if you want to use the `TestClient`.
-* aiofiles
- Required if you want to use `FileResponse` or `StaticFiles`.
* jinja2
- Required if you want to use the default template configuration.
* python-multipart
- Required if you want to support form "parsing", with `request.form()`.
* itsdangerous
- Required for `SessionMiddleware` support.
diff --git a/docs/de/mkdocs.yml b/docs/de/mkdocs.yml
index 360fa8c4a..6009dd2fe 100644
--- a/docs/de/mkdocs.yml
+++ b/docs/de/mkdocs.yml
@@ -5,13 +5,15 @@ theme:
name: material
custom_dir: overrides
palette:
- - scheme: default
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
primary: teal
accent: amber
toggle:
icon: material/lightbulb
name: Switch to light mode
- - scheme: slate
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
primary: teal
accent: amber
toggle:
@@ -40,15 +42,19 @@ nav:
- az: /az/
- de: /de/
- es: /es/
+ - fa: /fa/
- fr: /fr/
+ - he: /he/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
+ - sv: /sv/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -98,8 +104,12 @@ extra:
name: de
- link: /es/
name: es - español
+ - link: /fa/
+ name: fa
- link: /fr/
name: fr - français
+ - link: /he/
+ name: he
- link: /id/
name: id
- link: /it/
@@ -108,6 +118,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /nl/
+ name: nl
- link: /pl/
name: pl
- link: /pt/
@@ -116,6 +128,8 @@ extra:
name: ru - русский язык
- link: /sq/
name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml
index 0850d9788..4a5791a43 100644
--- a/docs/en/data/external_links.yml
+++ b/docs/en/data/external_links.yml
@@ -1,5 +1,17 @@
articles:
english:
+ - author: Jean-Baptiste Rocher
+ author_link: https://hashnode.com/@jibrocher
+ link: https://dev.indooroutdoor.io/series/fastapi-react-poll-app
+ title: Building the Poll App From Django Tutorial With FastAPI And React
+ - author: Silvan Melchior
+ author_link: https://github.com/silvanmelchior
+ link: https://blog.devgenius.io/seamless-fastapi-configuration-with-confz-90949c14ea12
+ title: Seamless FastAPI Configuration with ConfZ
+ - author: Kaustubh Gupta
+ author_link: https://medium.com/@kaustubhgupta1828/
+ link: https://levelup.gitconnected.com/5-advance-features-of-fastapi-you-should-try-7c0ac7eebb3e
+ title: 5 Advanced Features of FastAPI You Should Try
- author: Kaustubh Gupta
author_link: https://medium.com/@kaustubhgupta1828/
link: https://www.analyticsvidhya.com/blog/2021/06/deploying-ml-models-as-api-using-fastapi-and-heroku/
@@ -12,6 +24,10 @@ articles:
author_link: https://pystar.substack.com/
link: https://pystar.substack.com/p/how-to-create-a-fake-certificate
title: How to Create A Fake Certificate Authority And Generate TLS Certs for FastAPI
+ - author: Ben Gamble
+ author_link: https://uk.linkedin.com/in/bengamble7
+ link: https://ably.com/blog/realtime-ticket-booking-solution-kafka-fastapi-ably
+ title: Building a realtime ticket booking solution with Kafka, FastAPI, and Ably
- author: Shahriyar(Shako) Rzayev
author_link: https://www.linkedin.com/in/shahriyar-rzayev/
link: https://www.azepug.az/posts/fastapi/#building-simple-e-commerce-with-nuxtjs-and-fastapi-series
@@ -20,6 +36,10 @@ articles:
author_link: https://rodrigo-arenas.medium.com/
link: https://medium.com/analytics-vidhya/serve-a-machine-learning-model-using-sklearn-fastapi-and-docker-85aabf96729b
title: "Serve a machine learning model using Sklearn, FastAPI and Docker"
+ - author: Yashasvi Singh
+ author_link: https://hashnode.com/@aUnicornDev
+ link: https://aunicorndev.hashnode.dev/series/supafast-api
+ title: "Building an API with FastAPI and Supabase and Deploying on Deta"
- author: Navule Pavan Kumar Rao
author_link: https://www.linkedin.com/in/navule/
link: https://www.tutlinks.com/deploy-fastapi-on-ubuntu-gunicorn-caddy-2/
@@ -27,7 +47,7 @@ articles:
- author: Patrick Ladon
author_link: https://dev.to/factorlive
link: https://dev.to/factorlive/python-facebook-messenger-webhook-with-fastapi-on-glitch-4n90
- title: Python Facebook messenger webhook with FastAPI on Glitch
+ title: Python Facebook messenger webhook with FastAPI on Glitch
- author: Dom Patmore
author_link: https://twitter.com/dompatmore
link: https://dompatmore.com/blog/authenticate-your-fastapi-app-with-auth0
@@ -188,11 +208,19 @@ articles:
author_link: https://medium.com/@williamhayes
link: https://medium.com/@williamhayes/fastapi-starlette-debug-vs-prod-5f7561db3a59
title: FastAPI/Starlette debug vs prod
+ - author: Mukul Mantosh
+ author_link: https://twitter.com/MantoshMukul
+ link: https://www.jetbrains.com/pycharm/guide/tutorials/fastapi-aws-kubernetes/
+ title: Developing FastAPI Application using K8s & AWS
german:
- author: Nico Axtmann
author_link: https://twitter.com/_nicoax
link: https://blog.codecentric.de/2019/08/inbetriebnahme-eines-scikit-learn-modells-mit-onnx-und-fastapi/
title: Inbetriebnahme eines scikit-learn-Modells mit ONNX und FastAPI
+ - author: Felix Schürmeyer
+ author_link: https://hellocoding.de/autor/felix-schuermeyer/
+ link: https://hellocoding.de/blog/coding-language/python/fastapi
+ title: REST-API Programmieren mittels Python und dem FastAPI Modul
japanese:
- author: '@bee2'
author_link: https://qiita.com/bee2
diff --git a/docs/en/data/github_sponsors.yml b/docs/en/data/github_sponsors.yml
index 162a8dbe2..6c1efcbbd 100644
--- a/docs/en/data/github_sponsors.yml
+++ b/docs/en/data/github_sponsors.yml
@@ -1,88 +1,148 @@
sponsors:
-- - login: jina-ai
+- - login: github
+ avatarUrl: https://avatars.githubusercontent.com/u/9919?v=4
+ url: https://github.com/github
+- - login: Doist
+ avatarUrl: https://avatars.githubusercontent.com/u/2565372?v=4
+ url: https://github.com/Doist
+ - login: cryptapi
+ avatarUrl: https://avatars.githubusercontent.com/u/44925437?u=61369138589bc7fee6c417f3fbd50fbd38286cc4&v=4
+ url: https://github.com/cryptapi
+ - login: BLUE-DEVIL1134
+ avatarUrl: https://avatars.githubusercontent.com/u/55914808?u=f283d674fce31be7fb3ed2665b0f20d89958e541&v=4
+ url: https://github.com/BLUE-DEVIL1134
+ - login: jina-ai
avatarUrl: https://avatars.githubusercontent.com/u/60539444?v=4
url: https://github.com/jina-ai
+ - login: DropbaseHQ
+ avatarUrl: https://avatars.githubusercontent.com/u/85367855?v=4
+ url: https://github.com/DropbaseHQ
+- - login: ObliviousAI
+ avatarUrl: https://avatars.githubusercontent.com/u/65656077?v=4
+ url: https://github.com/ObliviousAI
+ - login: chaserowbotham
+ avatarUrl: https://avatars.githubusercontent.com/u/97751084?v=4
+ url: https://github.com/chaserowbotham
- - login: mikeckennedy
- avatarUrl: https://avatars.githubusercontent.com/u/2035561?v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/2035561?u=1bb18268bcd4d9249e1f783a063c27df9a84c05b&v=4
url: https://github.com/mikeckennedy
- - login: RodneyU215
- avatarUrl: https://avatars.githubusercontent.com/u/3329665?u=ec6a9adf8e7e8e306eed7d49687c398608d1604f&v=4
- url: https://github.com/RodneyU215
- login: Trivie
avatarUrl: https://avatars.githubusercontent.com/u/8161763?v=4
url: https://github.com/Trivie
- login: deta
avatarUrl: https://avatars.githubusercontent.com/u/47275976?v=4
url: https://github.com/deta
+ - login: deepset-ai
+ avatarUrl: https://avatars.githubusercontent.com/u/51827949?v=4
+ url: https://github.com/deepset-ai
- login: investsuite
avatarUrl: https://avatars.githubusercontent.com/u/73833632?v=4
url: https://github.com/investsuite
- - login: vimsoHQ
- avatarUrl: https://avatars.githubusercontent.com/u/77627231?v=4
- url: https://github.com/vimsoHQ
-- - login: newrelic
- avatarUrl: https://avatars.githubusercontent.com/u/31739?v=4
- url: https://github.com/newrelic
+ - login: VincentParedes
+ avatarUrl: https://avatars.githubusercontent.com/u/103889729?v=4
+ url: https://github.com/VincentParedes
+- - login: InesIvanova
+ avatarUrl: https://avatars.githubusercontent.com/u/22920417?u=409882ec1df6dbd77455788bb383a8de223dbf6f&v=4
+ url: https://github.com/InesIvanova
+- - login: SendCloud
+ avatarUrl: https://avatars.githubusercontent.com/u/7831959?v=4
+ url: https://github.com/SendCloud
- login: qaas
avatarUrl: https://avatars.githubusercontent.com/u/8503759?u=10a6b4391ad6ab4cf9487ce54e3fcb61322d1efc&v=4
url: https://github.com/qaas
-- - login: johnadjei
+ - login: xoflare
+ avatarUrl: https://avatars.githubusercontent.com/u/74335107?v=4
+ url: https://github.com/xoflare
+ - login: Striveworks
+ avatarUrl: https://avatars.githubusercontent.com/u/45523576?v=4
+ url: https://github.com/Striveworks
+ - login: BoostryJP
+ avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4
+ url: https://github.com/BoostryJP
+- - login: nnfuzzy
+ avatarUrl: https://avatars.githubusercontent.com/u/687670?v=4
+ url: https://github.com/nnfuzzy
+ - login: johnadjei
avatarUrl: https://avatars.githubusercontent.com/u/767860?v=4
url: https://github.com/johnadjei
+ - login: HiredScore
+ avatarUrl: https://avatars.githubusercontent.com/u/3908850?v=4
+ url: https://github.com/HiredScore
- login: wdwinslow
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4
url: https://github.com/wdwinslow
-- - login: kamalgill
- avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4
- url: https://github.com/kamalgill
- - login: grillazz
- avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=16d7d0ffa5dfb99f8834f8f76d90e138ba09b94a&v=4
- url: https://github.com/grillazz
+- - login: moellenbeck
+ avatarUrl: https://avatars.githubusercontent.com/u/169372?v=4
+ url: https://github.com/moellenbeck
+ - login: RodneyU215
+ avatarUrl: https://avatars.githubusercontent.com/u/3329665?u=ec6a9adf8e7e8e306eed7d49687c398608d1604f&v=4
+ url: https://github.com/RodneyU215
- login: tizz98
avatarUrl: https://avatars.githubusercontent.com/u/5739698?u=f095a3659e3a8e7c69ccd822696990b521ea25f9&v=4
url: https://github.com/tizz98
- login: jmaralc
avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4
url: https://github.com/jmaralc
- - login: AlexandruSimion
- avatarUrl: https://avatars.githubusercontent.com/u/71321732?v=4
- url: https://github.com/AlexandruSimion
-- - login: samuelcolvin
+ - login: marutoraman
+ avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4
+ url: https://github.com/marutoraman
+ - login: leynier
+ avatarUrl: https://avatars.githubusercontent.com/u/36774373?u=2284831c821307de562ebde5b59014d5416c7e0d&v=4
+ url: https://github.com/leynier
+ - login: mainframeindustries
+ avatarUrl: https://avatars.githubusercontent.com/u/55092103?v=4
+ url: https://github.com/mainframeindustries
+ - login: A-Edge
+ avatarUrl: https://avatars.githubusercontent.com/u/59514131?v=4
+ url: https://github.com/A-Edge
+ - login: DelfinaCare
+ avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4
+ url: https://github.com/DelfinaCare
+- - login: povilasb
+ avatarUrl: https://avatars.githubusercontent.com/u/1213442?u=b11f58ed6ceea6e8297c9b310030478ebdac894d&v=4
+ url: https://github.com/povilasb
+- - login: Kludex
+ avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
+ url: https://github.com/Kludex
+ - login: samuelcolvin
avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4
url: https://github.com/samuelcolvin
- - login: jokull
- avatarUrl: https://avatars.githubusercontent.com/u/701?u=0532b62166893d5160ef795c4c8b7512d971af05&v=4
- url: https://github.com/jokull
+ - login: jefftriplett
+ avatarUrl: https://avatars.githubusercontent.com/u/50527?u=af1ddfd50f6afd6d99f333ba2ac8d0a5b245ea74&v=4
+ url: https://github.com/jefftriplett
+ - login: medecau
+ avatarUrl: https://avatars.githubusercontent.com/u/59870?u=f9341c95adaba780828162fd4c7442357ecfcefa&v=4
+ url: https://github.com/medecau
+ - login: kamalgill
+ avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4
+ url: https://github.com/kamalgill
+ - login: deserat
+ avatarUrl: https://avatars.githubusercontent.com/u/299332?v=4
+ url: https://github.com/deserat
+ - login: ericof
+ avatarUrl: https://avatars.githubusercontent.com/u/306014?u=cf7c8733620397e6584a451505581c01c5d842d7&v=4
+ url: https://github.com/ericof
- login: wshayes
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
url: https://github.com/wshayes
- login: koxudaxi
avatarUrl: https://avatars.githubusercontent.com/u/630670?u=507d8577b4b3670546b449c4c2ccbc5af40d72f7&v=4
url: https://github.com/koxudaxi
- - login: falkben
- avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4
- url: https://github.com/falkben
- login: jqueguiner
- avatarUrl: https://avatars.githubusercontent.com/u/690878?u=e4835b2a985a0f2d52018e4926cb5a58c26a62e8&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/690878?u=bd65cc1f228ce6455e56dfaca3ef47c33bc7c3b0&v=4
url: https://github.com/jqueguiner
- - login: Mazyod
- avatarUrl: https://avatars.githubusercontent.com/u/860511?v=4
- url: https://github.com/Mazyod
+ - login: alexsantos
+ avatarUrl: https://avatars.githubusercontent.com/u/932219?v=4
+ url: https://github.com/alexsantos
+ - login: tcsmith
+ avatarUrl: https://avatars.githubusercontent.com/u/989034?u=7d8d741552b3279e8f4d3878679823a705a46f8f&v=4
+ url: https://github.com/tcsmith
- login: ltieman
avatarUrl: https://avatars.githubusercontent.com/u/1084689?u=e69b17de17cb3ca141a17daa7ccbe173ceb1eb17&v=4
url: https://github.com/ltieman
- - login: mrmattwright
- avatarUrl: https://avatars.githubusercontent.com/u/1277725?v=4
- url: https://github.com/mrmattwright
- - login: westonsteimel
- avatarUrl: https://avatars.githubusercontent.com/u/1593939?u=0f2c0e3647f916fe295d62fa70da7a4c177115e3&v=4
- url: https://github.com/westonsteimel
- - login: timdrijvers
- avatarUrl: https://avatars.githubusercontent.com/u/1694939?v=4
- url: https://github.com/timdrijvers
- - login: mrgnw
- avatarUrl: https://avatars.githubusercontent.com/u/2504532?u=7ec43837a6d0afa80f96f0788744ea6341b89f97&v=4
- url: https://github.com/mrgnw
+ - login: corleyma
+ avatarUrl: https://avatars.githubusercontent.com/u/2080732?u=aed2ff652294a87d666b1c3f6dbe98104db76d26&v=4
+ url: https://github.com/corleyma
- login: madisonmay
avatarUrl: https://avatars.githubusercontent.com/u/2645393?u=f22b93c6ea345a4d26a90a3834dfc7f0789fcb63&v=4
url: https://github.com/madisonmay
@@ -93,149 +153,212 @@ sponsors:
avatarUrl: https://avatars.githubusercontent.com/u/3148093?v=4
url: https://github.com/andre1sk
- login: Shark009
- avatarUrl: https://avatars.githubusercontent.com/u/3163309?v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/3163309?u=0c6f4091b0eda05c44c390466199826e6dc6e431&v=4
url: https://github.com/Shark009
+ - login: grillazz
+ avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=0b32b7073ae1ab8b7f6d2db0188c2e1e357ff451&v=4
+ url: https://github.com/grillazz
+ - login: dblackrun
+ avatarUrl: https://avatars.githubusercontent.com/u/3528486?v=4
+ url: https://github.com/dblackrun
+ - login: zsinx6
+ avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4
+ url: https://github.com/zsinx6
+ - login: anomaly
+ avatarUrl: https://avatars.githubusercontent.com/u/3654837?v=4
+ url: https://github.com/anomaly
- login: peterHoburg
avatarUrl: https://avatars.githubusercontent.com/u/3860655?u=f55f47eb2d6a9b495e806ac5a044e3ae01ccc1fa&v=4
url: https://github.com/peterHoburg
+ - login: gorhack
+ avatarUrl: https://avatars.githubusercontent.com/u/4141690?u=ec119ebc4bdf00a7bc84657a71aa17834f4f27f3&v=4
+ url: https://github.com/gorhack
- login: jaredtrog
avatarUrl: https://avatars.githubusercontent.com/u/4381365?v=4
url: https://github.com/jaredtrog
+ - login: oliverxchen
+ avatarUrl: https://avatars.githubusercontent.com/u/4471774?u=534191f25e32eeaadda22dfab4b0a428733d5489&v=4
+ url: https://github.com/oliverxchen
- login: CINOAdam
- avatarUrl: https://avatars.githubusercontent.com/u/4728508?u=34c3d58cb900fed475d0172b436c66a94ad739ed&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/4728508?u=76ef23f06ae7c604e009873bc27cf0ea9ba738c9&v=4
url: https://github.com/CINOAdam
- - login: dudil
- avatarUrl: https://avatars.githubusercontent.com/u/4785835?u=58b7ea39123e0507f3b2996448a27256b16fd697&v=4
- url: https://github.com/dudil
+ - login: ScrimForever
+ avatarUrl: https://avatars.githubusercontent.com/u/5040124?u=091ec38bfe16d6e762099e91309b59f248616a65&v=4
+ url: https://github.com/ScrimForever
- login: ennui93
avatarUrl: https://avatars.githubusercontent.com/u/5300907?u=5b5452725ddb391b2caaebf34e05aba873591c3a&v=4
url: https://github.com/ennui93
- login: MacroPower
avatarUrl: https://avatars.githubusercontent.com/u/5648814?u=e13991efd1e03c44c911f919872e750530ded633&v=4
url: https://github.com/MacroPower
- - login: ginomempin
- avatarUrl: https://avatars.githubusercontent.com/u/6091865?v=4
- url: https://github.com/ginomempin
+ - login: Yaleesa
+ avatarUrl: https://avatars.githubusercontent.com/u/6135475?v=4
+ url: https://github.com/Yaleesa
- login: iwpnd
avatarUrl: https://avatars.githubusercontent.com/u/6152183?u=b2286006daafff5f991557344fee20b5da59639a&v=4
url: https://github.com/iwpnd
+ - login: simw
+ avatarUrl: https://avatars.githubusercontent.com/u/6322526?v=4
+ url: https://github.com/simw
+ - login: pkucmus
+ avatarUrl: https://avatars.githubusercontent.com/u/6347418?u=98f5918b32e214a168a2f5d59b0b8ebdf57dca0d&v=4
+ url: https://github.com/pkucmus
+ - login: ioalloc
+ avatarUrl: https://avatars.githubusercontent.com/u/6737824?u=6c3a31449f1c92064287171aa9ebe6363a0c9b7b&v=4
+ url: https://github.com/ioalloc
- login: s3ich4n
avatarUrl: https://avatars.githubusercontent.com/u/6926298?u=ba3025d698e1c986655e776ae383a3d60d9d578e&v=4
url: https://github.com/s3ich4n
- login: Rehket
avatarUrl: https://avatars.githubusercontent.com/u/7015688?u=3afb0ba200feebbc7f958950e92db34df2a3c172&v=4
url: https://github.com/Rehket
- - login: christippett
- avatarUrl: https://avatars.githubusercontent.com/u/7218120?u=434b9d29287d7de25772d94ddc74a9bd6d969284&v=4
- url: https://github.com/christippett
- - login: Kludex
- avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4
- url: https://github.com/Kludex
+ - login: hiancdtrsnm
+ avatarUrl: https://avatars.githubusercontent.com/u/7343177?v=4
+ url: https://github.com/hiancdtrsnm
- login: Shackelford-Arden
avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4
url: https://github.com/Shackelford-Arden
- - login: cristeaadrian
- avatarUrl: https://avatars.githubusercontent.com/u/9112724?v=4
- url: https://github.com/cristeaadrian
- - login: otivvormes
- avatarUrl: https://avatars.githubusercontent.com/u/11317418?u=6de1edefb6afd0108c0ad2816bd6efc4464a9c44&v=4
- url: https://github.com/otivvormes
- - login: iambobmae
- avatarUrl: https://avatars.githubusercontent.com/u/12390270?u=c9a35c2ee5092a9b4135ebb1f91b7f521c467031&v=4
- url: https://github.com/iambobmae
- - login: ronaldnwilliams
- avatarUrl: https://avatars.githubusercontent.com/u/13632749?u=ac41a086d0728bf66a9d2bee9e5e377041ff44a4&v=4
- url: https://github.com/ronaldnwilliams
+ - login: Vikka
+ avatarUrl: https://avatars.githubusercontent.com/u/9381120?u=4bfc7032a824d1ed1994aa8256dfa597c8f187ad&v=4
+ url: https://github.com/Vikka
+ - login: Ge0f3
+ avatarUrl: https://avatars.githubusercontent.com/u/11887760?u=ccd80f1ac36dcb8517ef5c4e702e8cc5a80cad2f&v=4
+ url: https://github.com/Ge0f3
+ - login: svats2k
+ avatarUrl: https://avatars.githubusercontent.com/u/12378398?u=ecf28c19f61052e664bdfeb2391f8107d137915c&v=4
+ url: https://github.com/svats2k
+ - login: gokulyc
+ avatarUrl: https://avatars.githubusercontent.com/u/13468848?u=269f269d3e70407b5fb80138c52daba7af783997&v=4
+ url: https://github.com/gokulyc
+ - login: dannywade
+ avatarUrl: https://avatars.githubusercontent.com/u/13680237?u=418ee985bd41577b20fde81417fb2d901e875e8a&v=4
+ url: https://github.com/dannywade
- login: pablonnaoji
avatarUrl: https://avatars.githubusercontent.com/u/15187159?u=afc15bd5a4ba9c5c7206bbb1bcaeef606a0932e0&v=4
url: https://github.com/pablonnaoji
- - login: natenka
- avatarUrl: https://avatars.githubusercontent.com/u/15850513?u=00d1083c980d0b4ce32835dc07eee7f43f34fd2f&v=4
- url: https://github.com/natenka
- - login: la-mar
- avatarUrl: https://avatars.githubusercontent.com/u/16618300?u=7755c0521d2bb0d704f35a51464b15c1e2e6c4da&v=4
- url: https://github.com/la-mar
- login: robintully
avatarUrl: https://avatars.githubusercontent.com/u/17059673?u=862b9bb01513f5acd30df97433cb97a24dbfb772&v=4
url: https://github.com/robintully
- - login: ShaulAb
- avatarUrl: https://avatars.githubusercontent.com/u/18129076?u=2c8d48e47f2dbee15c3f89c3d17d4c356504386c&v=4
- url: https://github.com/ShaulAb
- login: wedwardbeck
avatarUrl: https://avatars.githubusercontent.com/u/19333237?u=1de4ae2bf8d59eb4c013f21d863cbe0f2010575f&v=4
url: https://github.com/wedwardbeck
- - login: linusg
- avatarUrl: https://avatars.githubusercontent.com/u/19366641?u=125e390abef8fff3b3b0d370c369cba5d7fd4c67&v=4
- url: https://github.com/linusg
+ - login: stradivari96
+ avatarUrl: https://avatars.githubusercontent.com/u/19752586?u=255f5f06a768f518b20cebd6963e840ac49294fd&v=4
+ url: https://github.com/stradivari96
- login: RedCarpetUp
avatarUrl: https://avatars.githubusercontent.com/u/20360440?v=4
url: https://github.com/RedCarpetUp
- login: Filimoa
avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=75e02d102d2ee3e3d793e555fa5c63045913ccb0&v=4
url: https://github.com/Filimoa
- - login: raminsj13
- avatarUrl: https://avatars.githubusercontent.com/u/24259406?u=d51f2a526312ebba150a06936ed187ca0727d329&v=4
- url: https://github.com/raminsj13
- - login: comoelcometa
- avatarUrl: https://avatars.githubusercontent.com/u/25950317?u=c6751efa038561b9bc5fa56d1033d5174e10cd65&v=4
- url: https://github.com/comoelcometa
+ - login: shuheng-liu
+ avatarUrl: https://avatars.githubusercontent.com/u/22414322?u=813c45f30786c6b511b21a661def025d8f7b609e&v=4
+ url: https://github.com/shuheng-liu
+ - login: Joeriksson
+ avatarUrl: https://avatars.githubusercontent.com/u/25037079?v=4
+ url: https://github.com/Joeriksson
+ - login: cometa-haley
+ avatarUrl: https://avatars.githubusercontent.com/u/25950317?u=cec1a3e0643b785288ae8260cc295a85ab344995&v=4
+ url: https://github.com/cometa-haley
+ - login: LarryGF
+ avatarUrl: https://avatars.githubusercontent.com/u/26148349?u=431bb34d36d41c172466252242175281ae132152&v=4
+ url: https://github.com/LarryGF
- login: veprimk
avatarUrl: https://avatars.githubusercontent.com/u/29689749?u=f8cb5a15a286e522e5b189bc572d5a1a90217fb2&v=4
url: https://github.com/veprimk
- - login: orihomie
- avatarUrl: https://avatars.githubusercontent.com/u/29889683?u=6bc2135a52fcb3a49e69e7d50190796618185fda&v=4
- url: https://github.com/orihomie
- - login: SaltyCoco
- avatarUrl: https://avatars.githubusercontent.com/u/31451104?u=6ee4e17c07d21b7054f54a12fa9cc377a1b24ff9&v=4
- url: https://github.com/SaltyCoco
+ - login: meysam81
+ avatarUrl: https://avatars.githubusercontent.com/u/30233243?u=64dc9fc62d039892c6fb44d804251cad5537132b&v=4
+ url: https://github.com/meysam81
- login: mauroalejandrojm
avatarUrl: https://avatars.githubusercontent.com/u/31569442?u=cdada990a1527926a36e95f62c30a8b48bbc49a1&v=4
url: https://github.com/mauroalejandrojm
- - login: bulkw4r3
- avatarUrl: https://avatars.githubusercontent.com/u/35562532?u=0b812a14a02de14bf73d05fb2b2760a67bacffc2&v=4
- url: https://github.com/bulkw4r3
+ - login: Leay15
+ avatarUrl: https://avatars.githubusercontent.com/u/32212558?u=c4aa9c1737e515959382a5515381757b1fd86c53&v=4
+ url: https://github.com/Leay15
+ - login: AlrasheedA
+ avatarUrl: https://avatars.githubusercontent.com/u/33544979?u=7fe66bf62b47682612b222e3e8f4795ef3be769b&v=4
+ url: https://github.com/AlrasheedA
+ - login: ProteinQure
+ avatarUrl: https://avatars.githubusercontent.com/u/33707203?v=4
+ url: https://github.com/ProteinQure
+ - login: guligon90
+ avatarUrl: https://avatars.githubusercontent.com/u/35070513?u=b48c05f669d1ea1d329f90dc70e45f10b569ef55&v=4
+ url: https://github.com/guligon90
- login: ybressler
- avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=6621dc9ab53b697912ab2a32211bb29ae90a9112&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=41e2c00f1eebe3c402635f0325e41b4e6511462c&v=4
url: https://github.com/ybressler
+ - login: ddilidili
+ avatarUrl: https://avatars.githubusercontent.com/u/42176885?u=c0a849dde06987434653197b5f638d3deb55fc6c&v=4
+ url: https://github.com/ddilidili
- login: dbanty
- avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=0cf33e4f40efc2ea206a1189fd63a11344eb88ed&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4
url: https://github.com/dbanty
+ - login: VictorCalderon
+ avatarUrl: https://avatars.githubusercontent.com/u/44529243?u=cea69884f826a29aff1415493405209e0706d07a&v=4
+ url: https://github.com/VictorCalderon
+ - login: arthuRHD
+ avatarUrl: https://avatars.githubusercontent.com/u/48015496?u=05a0d5b8b9320eeb7990d35c9337b823f269d2ff&v=4
+ url: https://github.com/arthuRHD
+ - login: rafsaf
+ avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
+ url: https://github.com/rafsaf
- login: dudikbender
avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=494f85229115076121b3639a3806bbac1c6ae7f6&v=4
url: https://github.com/dudikbender
+ - login: daisuke8000
+ avatarUrl: https://avatars.githubusercontent.com/u/55035595?u=23a3f2f2925ad3efc27c7420041622b7f5fd2b79&v=4
+ url: https://github.com/daisuke8000
+ - login: dazeddd
+ avatarUrl: https://avatars.githubusercontent.com/u/59472056?u=7a1b668449bf8b448db13e4c575576d24d7d658b&v=4
+ url: https://github.com/dazeddd
+ - login: yakkonaut
+ avatarUrl: https://avatars.githubusercontent.com/u/60633704?u=90a71fd631aa998ba4a96480788f017c9904e07b&v=4
+ url: https://github.com/yakkonaut
- login: primer-io
avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4
url: https://github.com/primer-io
- - login: tkrestiankova
- avatarUrl: https://avatars.githubusercontent.com/u/67013045?v=4
- url: https://github.com/tkrestiankova
+ - login: around
+ avatarUrl: https://avatars.githubusercontent.com/u/62425723?v=4
+ url: https://github.com/around
+ - login: predictionmachine
+ avatarUrl: https://avatars.githubusercontent.com/u/63719559?v=4
+ url: https://github.com/predictionmachine
- login: daverin
avatarUrl: https://avatars.githubusercontent.com/u/70378377?u=6d1814195c0de7162820eaad95a25b423a3869c0&v=4
url: https://github.com/daverin
- login: anthonycepeda
- avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=4252c6b6dc5024af502a823a3ac5e7a03a69963f&v=4
url: https://github.com/anthonycepeda
- - login: an-tho-ny
- avatarUrl: https://avatars.githubusercontent.com/u/74874159?v=4
- url: https://github.com/an-tho-ny
+ - login: dotlas
+ avatarUrl: https://avatars.githubusercontent.com/u/88832003?v=4
+ url: https://github.com/dotlas
+ - login: pyt3h
+ avatarUrl: https://avatars.githubusercontent.com/u/99658549?v=4
+ url: https://github.com/pyt3h
- - login: linux-china
avatarUrl: https://avatars.githubusercontent.com/u/46711?v=4
url: https://github.com/linux-china
+ - login: ddanier
+ avatarUrl: https://avatars.githubusercontent.com/u/113563?v=4
+ url: https://github.com/ddanier
- login: jhb
avatarUrl: https://avatars.githubusercontent.com/u/142217?v=4
url: https://github.com/jhb
+ - login: justinrmiller
+ avatarUrl: https://avatars.githubusercontent.com/u/143998?u=b507a940394d4fc2bc1c27cea2ca9c22538874bd&v=4
+ url: https://github.com/justinrmiller
+ - login: bryanculbertson
+ avatarUrl: https://avatars.githubusercontent.com/u/144028?u=defda4f90e93429221cc667500944abde60ebe4a&v=4
+ url: https://github.com/bryanculbertson
- login: yourkin
- avatarUrl: https://avatars.githubusercontent.com/u/178984?v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/178984?u=fa7c3503b47bf16405b96d21554bc59f07a65523&v=4
url: https://github.com/yourkin
- - login: jmagnusson
- avatarUrl: https://avatars.githubusercontent.com/u/190835?v=4
- url: https://github.com/jmagnusson
- - login: sakti
- avatarUrl: https://avatars.githubusercontent.com/u/196178?u=0110be74c4270244546f1b610334042cd16bb8ad&v=4
- url: https://github.com/sakti
- login: slafs
avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4
url: https://github.com/slafs
+ - login: assem-ch
+ avatarUrl: https://avatars.githubusercontent.com/u/315228?u=e0c5ab30726d3243a40974bb9bae327866e42d9b&v=4
+ url: https://github.com/assem-ch
- login: adamghill
avatarUrl: https://avatars.githubusercontent.com/u/317045?u=f1349d5ffe84a19f324e204777859fbf69ddf633&v=4
url: https://github.com/adamghill
@@ -245,71 +368,83 @@ sponsors:
- login: dmig
avatarUrl: https://avatars.githubusercontent.com/u/388564?v=4
url: https://github.com/dmig
- - login: hongqn
- avatarUrl: https://avatars.githubusercontent.com/u/405587?u=470b4c04832e45141fd5264d3354845cc9fc6466&v=4
- url: https://github.com/hongqn
- login: rinckd
avatarUrl: https://avatars.githubusercontent.com/u/546002?u=1fcc7e664dc86524a0af6837a0c222829c3fd4e5&v=4
url: https://github.com/rinckd
+ - login: securancy
+ avatarUrl: https://avatars.githubusercontent.com/u/606673?v=4
+ url: https://github.com/securancy
+ - login: falkben
+ avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4
+ url: https://github.com/falkben
- login: hardbyte
avatarUrl: https://avatars.githubusercontent.com/u/855189?u=aa29e92f34708814d6b67fcd47ca4cf2ce1c04ed&v=4
url: https://github.com/hardbyte
+ - login: browniebroke
+ avatarUrl: https://avatars.githubusercontent.com/u/861044?u=5abfca5588f3e906b31583d7ee62f6de4b68aa24&v=4
+ url: https://github.com/browniebroke
+ - login: janfilips
+ avatarUrl: https://avatars.githubusercontent.com/u/870699?u=6034d81731ecb41ae5c717e56a901ed46fc039a8&v=4
+ url: https://github.com/janfilips
+ - login: woodrad
+ avatarUrl: https://avatars.githubusercontent.com/u/1410765?u=86707076bb03d143b3b11afc1743d2aa496bd8bf&v=4
+ url: https://github.com/woodrad
- login: Pytlicek
avatarUrl: https://avatars.githubusercontent.com/u/1430522?u=169dba3bfbc04ed214a914640ff435969f19ddb3&v=4
url: https://github.com/Pytlicek
- - login: okken
- avatarUrl: https://avatars.githubusercontent.com/u/1568356?u=0a991a21bdc62e2bea9ad311652f2c45f453dc84&v=4
- url: https://github.com/okken
+ - login: allen0125
+ avatarUrl: https://avatars.githubusercontent.com/u/1448456?u=d4feb3d06a61baa4a69857ce371cc53fb4dffd2c&v=4
+ url: https://github.com/allen0125
+ - login: WillHogan
+ avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=7036c064cf29781470573865264ec8e60b6b809f&v=4
+ url: https://github.com/WillHogan
- login: cbonoz
avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4
url: https://github.com/cbonoz
- - login: Abbe98
- avatarUrl: https://avatars.githubusercontent.com/u/2631719?u=8a064aba9a710229ad28c616549d81a24191a5df&v=4
- url: https://github.com/Abbe98
- login: rglsk
avatarUrl: https://avatars.githubusercontent.com/u/2768101?u=e349c88673f2155fe021331377c656a9d74bcc25&v=4
url: https://github.com/rglsk
- - login: Atem18
- avatarUrl: https://avatars.githubusercontent.com/u/2875254?v=4
- url: https://github.com/Atem18
- login: paul121
avatarUrl: https://avatars.githubusercontent.com/u/3116995?u=6e2d8691cc345e63ee02e4eb4d7cef82b1fcbedc&v=4
url: https://github.com/paul121
- login: igorcorrea
avatarUrl: https://avatars.githubusercontent.com/u/3438238?u=c57605077c31a8f7b2341fc4912507f91b4a5621&v=4
url: https://github.com/igorcorrea
- - login: anthcor
+ - login: anthonycorletti
avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4
- url: https://github.com/anthcor
- - login: zsinx6
- avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4
- url: https://github.com/zsinx6
+ url: https://github.com/anthonycorletti
- login: pawamoy
avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4
url: https://github.com/pawamoy
- - login: spyker77
- avatarUrl: https://avatars.githubusercontent.com/u/4953435?u=03c724c6f8fbab5cd6575b810c0c91c652fa4f79&v=4
- url: https://github.com/spyker77
- - login: JonasKs
- avatarUrl: https://avatars.githubusercontent.com/u/5310116?u=98a049f3e1491bffb91e1feb7e93def6881a9389&v=4
- url: https://github.com/JonasKs
+ - login: Alisa-lisa
+ avatarUrl: https://avatars.githubusercontent.com/u/4137964?u=e7e393504f554f4ff15863a1e01a5746863ef9ce&v=4
+ url: https://github.com/Alisa-lisa
+ - login: danielunderwood
+ avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4
+ url: https://github.com/danielunderwood
+ - login: unredundant
+ avatarUrl: https://avatars.githubusercontent.com/u/5607577?u=57dd0023365bec03f4fc566df6b81bc0a264a47d&v=4
+ url: https://github.com/unredundant
- login: holec
avatarUrl: https://avatars.githubusercontent.com/u/6438041?u=f5af71ec85b3a9d7b8139cb5af0512b02fa9ab1e&v=4
url: https://github.com/holec
- - login: BartlomiejRasztabiga
- avatarUrl: https://avatars.githubusercontent.com/u/8852711?u=ed213d60f7a423df31ceb1004aa3ec60e612cb98&v=4
- url: https://github.com/BartlomiejRasztabiga
+ - login: moonape1226
+ avatarUrl: https://avatars.githubusercontent.com/u/8532038?u=d9f8b855a429fff9397c3833c2ff83849ebf989d&v=4
+ url: https://github.com/moonape1226
- login: davanstrien
avatarUrl: https://avatars.githubusercontent.com/u/8995957?u=fb2aad2b52bb4e7b56db6d7c8ecc9ae1eac1b984&v=4
url: https://github.com/davanstrien
- - login: and-semakin
- avatarUrl: https://avatars.githubusercontent.com/u/9129071?u=ea77ddf7de4bc375d546bf2825ed420eaddb7666&v=4
- url: https://github.com/and-semakin
- - login: VivianSolide
- avatarUrl: https://avatars.githubusercontent.com/u/9358572?u=ffb2e2ec522a15dcd3f0af1f9fd1df4afe418afa&v=4
- url: https://github.com/VivianSolide
+ - login: yenchenLiu
+ avatarUrl: https://avatars.githubusercontent.com/u/9199638?u=8cdf5ae507448430d90f6f3518d1665a23afe99b&v=4
+ url: https://github.com/yenchenLiu
+ - login: xncbf
+ avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=866a1311e4bd3ec5ae84185c4fcc99f397c883d7&v=4
+ url: https://github.com/xncbf
+ - login: DMantis
+ avatarUrl: https://avatars.githubusercontent.com/u/9536869?v=4
+ url: https://github.com/DMantis
- login: hard-coders
- avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4
url: https://github.com/hard-coders
- login: satwikkansal
avatarUrl: https://avatars.githubusercontent.com/u/10217535?u=b12d6ef74ea297de9e46da6933b1a5b7ba9e6a61&v=4
@@ -317,63 +452,120 @@ sponsors:
- login: pheanex
avatarUrl: https://avatars.githubusercontent.com/u/10408624?u=5b6bab6ee174aa6e991333e06eb29f628741013d&v=4
url: https://github.com/pheanex
- - login: wotori
- avatarUrl: https://avatars.githubusercontent.com/u/10486621?u=0044c295b91694b8c9bccc0a805681f794250f7b&v=4
- url: https://github.com/wotori
- login: JimFawkes
avatarUrl: https://avatars.githubusercontent.com/u/12075115?u=dc58ecfd064d72887c34bf500ddfd52592509acd&v=4
url: https://github.com/JimFawkes
- login: logan-connolly
avatarUrl: https://avatars.githubusercontent.com/u/16244943?u=8ae66dfbba936463cc8aa0dd7a6d2b4c0cc757eb&v=4
url: https://github.com/logan-connolly
- - login: iPr0ger
- avatarUrl: https://avatars.githubusercontent.com/u/19322290?v=4
- url: https://github.com/iPr0ger
+ - login: sanghunka
+ avatarUrl: https://avatars.githubusercontent.com/u/16280020?u=960f5426ae08303229f045b9cc2ed463dcd41c15&v=4
+ url: https://github.com/sanghunka
+ - login: stevenayers
+ avatarUrl: https://avatars.githubusercontent.com/u/16361214?u=098b797d8d48afb8cd964b717847943b61d24a6d&v=4
+ url: https://github.com/stevenayers
+ - login: cdsre
+ avatarUrl: https://avatars.githubusercontent.com/u/16945936?v=4
+ url: https://github.com/cdsre
+ - login: aprilcoskun
+ avatarUrl: https://avatars.githubusercontent.com/u/17393603?u=29145243b4c7fadc80c7099471309cc2c04b6bcc&v=4
+ url: https://github.com/aprilcoskun
+ - login: jangia
+ avatarUrl: https://avatars.githubusercontent.com/u/17927101?u=9261b9bb0c3e3bb1ecba43e8915dc58d8c9a077e&v=4
+ url: https://github.com/jangia
+ - login: yannicschroeer
+ avatarUrl: https://avatars.githubusercontent.com/u/22749683?u=4df05a7296c207b91c5d7c7a11c29df5ab313e2b&v=4
+ url: https://github.com/yannicschroeer
- login: ghandic
avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
url: https://github.com/ghandic
- - login: MoronVV
- avatarUrl: https://avatars.githubusercontent.com/u/24293616?v=4
- url: https://github.com/MoronVV
- login: fstau
avatarUrl: https://avatars.githubusercontent.com/u/24669867?u=60e7c8c09f8dafabee8fc3edcd6f9e19abbff918&v=4
url: https://github.com/fstau
- login: mertguvencli
avatarUrl: https://avatars.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4
url: https://github.com/mertguvencli
- - login: rgreen32
- avatarUrl: https://avatars.githubusercontent.com/u/35779241?u=c9d64ad1ab364b6a1ec8e3d859da9ca802d681d8&v=4
- url: https://github.com/rgreen32
- - login: askurihin
- avatarUrl: https://avatars.githubusercontent.com/u/37978981?v=4
- url: https://github.com/askurihin
- - login: JitPackJoyride
- avatarUrl: https://avatars.githubusercontent.com/u/40203625?u=9638bfeacfa5940358188f8205ce662bba022b53&v=4
- url: https://github.com/JitPackJoyride
- - login: es3n1n
- avatarUrl: https://avatars.githubusercontent.com/u/40367813?u=e881a3880f1e342d19a1ea7c8e1b6d76c52dc294&v=4
- url: https://github.com/es3n1n
+ - login: elisoncrum
+ avatarUrl: https://avatars.githubusercontent.com/u/30413278?u=531190845bb0935dbc1e4f017cda3cb7b4dd0e54&v=4
+ url: https://github.com/elisoncrum
+ - login: HosamAlmoghraby
+ avatarUrl: https://avatars.githubusercontent.com/u/32025281?u=aa1b09feabccbf9dc506b81c71155f32d126cefa&v=4
+ url: https://github.com/HosamAlmoghraby
+ - login: kitaramu0401
+ avatarUrl: https://avatars.githubusercontent.com/u/33246506?u=929e6efa2c518033b8097ba524eb5347a069bb3b&v=4
+ url: https://github.com/kitaramu0401
+ - login: engineerjoe440
+ avatarUrl: https://avatars.githubusercontent.com/u/33275230?u=eb223cad27017bb1e936ee9b429b450d092d0236&v=4
+ url: https://github.com/engineerjoe440
+ - login: declon
+ avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4
+ url: https://github.com/declon
+ - login: alvarobartt
+ avatarUrl: https://avatars.githubusercontent.com/u/36760800?u=ac9ccb8b9164eb5fe7d5276142591aa1b8080daf&v=4
+ url: https://github.com/alvarobartt
+ - login: d-e-h-i-o
+ avatarUrl: https://avatars.githubusercontent.com/u/36816716?v=4
+ url: https://github.com/d-e-h-i-o
+ - login: ww-daniel-mora
+ avatarUrl: https://avatars.githubusercontent.com/u/38921751?u=ae14bc1e40f2dd5a9c5741fc0b0dffbd416a5fa9&v=4
+ url: https://github.com/ww-daniel-mora
+ - login: rwxd
+ avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=9ddf8023ca3326381ba8fb77285ae36598a15de3&v=4
+ url: https://github.com/rwxd
- login: ilias-ant
avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4
url: https://github.com/ilias-ant
- login: arrrrrmin
- avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=05600727f1cfe75f440bb3fddd49bfea84b1e894&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=fee5739394fea074cb0b66929d070114a5067aae&v=4
url: https://github.com/arrrrrmin
+ - login: BomGard
+ avatarUrl: https://avatars.githubusercontent.com/u/47395385?u=8e9052f54e0b8dc7285099c438fa29c55a7d6407&v=4
+ url: https://github.com/BomGard
- login: akanz1
avatarUrl: https://avatars.githubusercontent.com/u/51492342?u=2280f57134118714645e16b535c1a37adf6b369b&v=4
url: https://github.com/akanz1
-- - login: leogregianin
- avatarUrl: https://avatars.githubusercontent.com/u/1684053?u=94ddd387601bd1805034dbe83e6eba0491c15323&v=4
- url: https://github.com/leogregianin
- - login: sadikkuzu
- avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=765ed469c44c004560079210ccdad5b29938eaa9&v=4
- url: https://github.com/sadikkuzu
+ - login: shidenko97
+ avatarUrl: https://avatars.githubusercontent.com/u/54946990?u=3fdc0caea36af9217dacf1cc7760c7ed9d67dcfe&v=4
+ url: https://github.com/shidenko97
+ - login: data-djinn
+ avatarUrl: https://avatars.githubusercontent.com/u/56449985?u=42146e140806908d49bd59ccc96f222abf587886&v=4
+ url: https://github.com/data-djinn
+ - login: leo-jp-edwards
+ avatarUrl: https://avatars.githubusercontent.com/u/58213433?u=2c128e8b0794b7a66211cd7d8ebe05db20b7e9c0&v=4
+ url: https://github.com/leo-jp-edwards
+ - login: apar-tiwari
+ avatarUrl: https://avatars.githubusercontent.com/u/61064197?v=4
+ url: https://github.com/apar-tiwari
+ - login: Vyvy-vi
+ avatarUrl: https://avatars.githubusercontent.com/u/62864373?u=1a9b0b28779abc2bc9b62cb4d2e44d453973c9c3&v=4
+ url: https://github.com/Vyvy-vi
+ - login: 0417taehyun
+ avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4
+ url: https://github.com/0417taehyun
+ - login: realabja
+ avatarUrl: https://avatars.githubusercontent.com/u/66185192?u=001e2dd9297784f4218997981b4e6fa8357bb70b&v=4
+ url: https://github.com/realabja
+ - login: alessio-proietti
+ avatarUrl: https://avatars.githubusercontent.com/u/67370599?u=8ac73db1e18e946a7681f173abdb640516f88515&v=4
+ url: https://github.com/alessio-proietti
+ - login: Mr-Sunglasses
+ avatarUrl: https://avatars.githubusercontent.com/u/81439109?u=a5d0762fdcec26e18a028aef05323de3c6fb195c&v=4
+ url: https://github.com/Mr-Sunglasses
+- - login: backbord
+ avatarUrl: https://avatars.githubusercontent.com/u/6814946?v=4
+ url: https://github.com/backbord
- login: gabrielmbmb
- avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=92084ed7242160dee4d20aece923a10c59758ee5&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=6d1e00b5d558e96718312ff910a2318f47cc3145&v=4
url: https://github.com/gabrielmbmb
- - login: starhype
- avatarUrl: https://avatars.githubusercontent.com/u/36908028?u=6df41f7b62f0f673f1ecbc87e9cbadaa4fcb0767&v=4
- url: https://github.com/starhype
- - login: pixel365
- avatarUrl: https://avatars.githubusercontent.com/u/53819609?u=9e0309c5420ec4624aececd3ca2d7105f7f68133&v=4
- url: https://github.com/pixel365
+ - login: danburonline
+ avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4
+ url: https://github.com/danburonline
+ - login: zachspar
+ avatarUrl: https://avatars.githubusercontent.com/u/41600414?u=edf29c197137f51bace3f19a2ba759662640771f&v=4
+ url: https://github.com/zachspar
+ - login: sownt
+ avatarUrl: https://avatars.githubusercontent.com/u/44340502?u=c06e3c45fb00a403075172770805fe57ff17b1cf&v=4
+ url: https://github.com/sownt
+ - login: aahouzi
+ avatarUrl: https://avatars.githubusercontent.com/u/75032370?u=82677ee9cd86b3ccf4e13d9cb6765d8de5713e1e&v=4
+ url: https://github.com/aahouzi
diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml
index ebbe446ee..031c1ca4d 100644
--- a/docs/en/data/people.yml
+++ b/docs/en/data/people.yml
@@ -1,13 +1,13 @@
maintainers:
- login: tiangolo
- answers: 1237
- prs: 280
- avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=5cad72c846b7aba2e960546af490edc7375dafc4&v=4
+ answers: 1248
+ prs: 318
+ avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4
url: https://github.com/tiangolo
experts:
- login: Kludex
- count: 319
- avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4
+ count: 352
+ avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: dmontagu
count: 262
@@ -29,20 +29,24 @@ experts:
count: 130
avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4
url: https://github.com/phy25
+- login: raphaelauv
+ count: 77
+ avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
+ url: https://github.com/raphaelauv
- login: ArcLightSlavik
count: 71
- avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4
url: https://github.com/ArcLightSlavik
-- login: raphaelauv
+- login: JarroVGIT
count: 68
- avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
- url: https://github.com/raphaelauv
+ avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
+ url: https://github.com/JarroVGIT
- login: falkben
count: 58
avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4
url: https://github.com/falkben
- login: sm-Fifteen
- count: 48
+ count: 49
avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4
url: https://github.com/sm-Fifteen
- login: insomnes
@@ -50,11 +54,19 @@ experts:
avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4
url: https://github.com/insomnes
- login: Dustyposa
- count: 42
+ count: 43
avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4
url: https://github.com/Dustyposa
+- login: adriangb
+ count: 40
+ avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4
+ url: https://github.com/adriangb
+- login: jgould22
+ count: 40
+ avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
+ url: https://github.com/jgould22
- login: includeamin
- count: 38
+ count: 39
avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4
url: https://github.com/includeamin
- login: STeveShary
@@ -65,26 +77,30 @@ experts:
count: 33
avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4
url: https://github.com/prostomarkeloff
+- login: frankie567
+ count: 31
+ avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
+ url: https://github.com/frankie567
- login: krishnardt
count: 31
avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4
url: https://github.com/krishnardt
-- login: adriangb
+- login: chbndrhnns
count: 30
- avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=81f0262df34e1460ca546fbd0c211169c2478532&v=4
- url: https://github.com/adriangb
+ avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4
+ url: https://github.com/chbndrhnns
- login: wshayes
count: 29
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
url: https://github.com/wshayes
-- login: frankie567
- count: 29
- avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
- url: https://github.com/frankie567
-- login: chbndrhnns
+- login: panla
+ count: 27
+ avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4
+ url: https://github.com/panla
+- login: acidjunk
count: 25
- avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4
- url: https://github.com/chbndrhnns
+ avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
+ url: https://github.com/acidjunk
- login: ghandic
count: 25
avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
@@ -93,10 +109,6 @@ experts:
count: 25
avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4
url: https://github.com/dbanty
-- login: panla
- count: 25
- avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4
- url: https://github.com/panla
- login: SirTelemak
count: 24
avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4
@@ -117,10 +129,18 @@ experts:
count: 19
avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4
url: https://github.com/retnikt
+- login: odiseo0
+ count: 19
+ avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=ab724eae71c3fe1cf81e8dc76e73415da926ef7d&v=4
+ url: https://github.com/odiseo0
- login: Hultner
count: 18
avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4
url: https://github.com/Hultner
+- login: rafsaf
+ count: 18
+ avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
+ url: https://github.com/rafsaf
- login: jorgerpo
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4
@@ -129,10 +149,10 @@ experts:
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/28262306?u=66ee21316275ef356081c2efc4ed7a4572e690dc&v=4
url: https://github.com/nkhitrov
-- login: acidjunk
- count: 16
- avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
- url: https://github.com/acidjunk
+- login: harunyasar
+ count: 17
+ avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4
+ url: https://github.com/harunyasar
- login: waynerv
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
@@ -141,26 +161,34 @@ experts:
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4
url: https://github.com/dstlny
-- login: jgould22
- count: 14
- avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
- url: https://github.com/jgould22
-- login: harunyasar
+- login: jonatasoli
+ count: 15
+ avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4
+ url: https://github.com/jonatasoli
+- login: hellocoldworld
count: 14
- avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4
- url: https://github.com/harunyasar
+ avatarUrl: https://avatars.githubusercontent.com/u/47581948?u=3d2186796434c507a6cb6de35189ab0ad27c356f&v=4
+ url: https://github.com/hellocoldworld
- login: haizaar
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4
url: https://github.com/haizaar
-- login: hellocoldworld
- count: 12
- avatarUrl: https://avatars.githubusercontent.com/u/47581948?v=4
- url: https://github.com/hellocoldworld
+- login: valentin994
+ count: 13
+ avatarUrl: https://avatars.githubusercontent.com/u/42819267?u=fdeeaa9242a59b243f8603496b00994f6951d5a2&v=4
+ url: https://github.com/valentin994
- login: David-Lor
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/17401854?u=474680c02b94cba810cb9032fb7eb787d9cc9d22&v=4
url: https://github.com/David-Lor
+- login: yinziyan1206
+ count: 12
+ avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4
+ url: https://github.com/yinziyan1206
+- login: n8sty
+ count: 12
+ avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4
+ url: https://github.com/n8sty
- login: lowercase00
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/21188280?v=4
@@ -169,63 +197,31 @@ experts:
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/40475662?u=e58ef61034e8d0d6a312cc956fb09b9c3332b449&v=4
url: https://github.com/zamiramir
-- login: juntatalor
- count: 11
- avatarUrl: https://avatars.githubusercontent.com/u/8134632?v=4
- url: https://github.com/juntatalor
-- login: valentin994
- count: 11
- avatarUrl: https://avatars.githubusercontent.com/u/42819267?u=fdeeaa9242a59b243f8603496b00994f6951d5a2&v=4
- url: https://github.com/valentin994
-- login: aalifadv
- count: 11
- avatarUrl: https://avatars.githubusercontent.com/u/78442260?v=4
- url: https://github.com/aalifadv
-- login: stefanondisponibile
- count: 10
- avatarUrl: https://avatars.githubusercontent.com/u/20441825?u=ee1e59446b98f8ec2363caeda4c17164d0d9cc7d&v=4
- url: https://github.com/stefanondisponibile
-- login: oligond
- count: 10
- avatarUrl: https://avatars.githubusercontent.com/u/2858306?u=1bb1182a5944e93624b7fb26585f22c8f7a9d76e&v=4
- url: https://github.com/oligond
last_month_active:
-- login: harunyasar
- count: 10
- avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4
- url: https://github.com/harunyasar
-- login: jgould22
- count: 10
- avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
- url: https://github.com/jgould22
-- login: rafsaf
+- login: JarroVGIT
+ count: 30
+ avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
+ url: https://github.com/JarroVGIT
+- login: zoliknemet
count: 9
- avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=be9f06b8ced2d2b677297decc781fa8ce4f7ddbd&v=4
- url: https://github.com/rafsaf
-- login: STeveShary
+ avatarUrl: https://avatars.githubusercontent.com/u/22326718?u=31ba446ac290e23e56eea8e4f0c558aaf0b40779&v=4
+ url: https://github.com/zoliknemet
+- login: iudeen
count: 5
- avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4
- url: https://github.com/STeveShary
-- login: ahnaf-zamil
- count: 3
- avatarUrl: https://avatars.githubusercontent.com/u/57180217?u=849128b146771ace47beca5b5ff68eb82905dd6d&v=4
- url: https://github.com/ahnaf-zamil
-- login: lucastosetto
- count: 3
- avatarUrl: https://avatars.githubusercontent.com/u/89307132?u=56326696423df7126c9e7c702ee58f294db69a2a&v=4
- url: https://github.com/lucastosetto
-- login: blokje
- count: 3
- avatarUrl: https://avatars.githubusercontent.com/u/851418?v=4
- url: https://github.com/blokje
-- login: MatthijsKok
- count: 3
- avatarUrl: https://avatars.githubusercontent.com/u/7658129?u=1243e32d57e13abc45e3f5235ed5b9197e0d2b41&v=4
- url: https://github.com/MatthijsKok
+ avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
+ url: https://github.com/iudeen
- login: Kludex
- count: 3
- avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4
+ count: 5
+ avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
+- login: odiseo0
+ count: 4
+ avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=ab724eae71c3fe1cf81e8dc76e73415da926ef7d&v=4
+ url: https://github.com/odiseo0
+- login: jonatasoli
+ count: 3
+ avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4
+ url: https://github.com/jonatasoli
top_contributors:
- login: waynerv
count: 25
@@ -251,8 +247,12 @@ top_contributors:
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
url: https://github.com/mariacamilagl
+- login: Kludex
+ count: 11
+ avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
+ url: https://github.com/Kludex
- login: Smlep
- count: 9
+ count: 10
avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4
url: https://github.com/Smlep
- login: Serrones
@@ -261,12 +261,8 @@ top_contributors:
url: https://github.com/Serrones
- login: RunningIkkyu
count: 7
- avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=efb5b45b55584450507834f279ce48d4d64dea2f&v=4
url: https://github.com/RunningIkkyu
-- login: Kludex
- count: 7
- avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4
- url: https://github.com/Kludex
- login: hard-coders
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4
@@ -283,6 +279,10 @@ top_contributors:
count: 5
avatarUrl: https://avatars.githubusercontent.com/u/1175560?v=4
url: https://github.com/Attsun1031
+- login: dependabot
+ count: 5
+ avatarUrl: https://avatars.githubusercontent.com/in/29110?v=4
+ url: https://github.com/apps/dependabot
- login: jekirl
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4
@@ -299,15 +299,31 @@ top_contributors:
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4
url: https://github.com/komtaki
+- login: hitrust
+ count: 4
+ avatarUrl: https://avatars.githubusercontent.com/u/3360631?u=5fa1f475ad784d64eb9666bdd43cc4d285dcc773&v=4
+ url: https://github.com/hitrust
+- login: lsglucas
+ count: 4
+ avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
+ url: https://github.com/lsglucas
+- login: ComicShrimp
+ count: 4
+ avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4
+ url: https://github.com/ComicShrimp
- login: NinaHwang
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4
url: https://github.com/NinaHwang
top_reviewers:
- login: Kludex
- count: 93
- avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=3682d9b9b93bef272f379ab623dc031c8d71432e&v=4
+ count: 95
+ avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
+- login: tokusumi
+ count: 49
+ avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
+ url: https://github.com/tokusumi
- login: waynerv
count: 47
avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
@@ -316,34 +332,38 @@ top_reviewers:
count: 47
avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4
url: https://github.com/Laineyzhang55
-- login: tokusumi
- count: 46
- avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
- url: https://github.com/tokusumi
+- login: BilalAlpaslan
+ count: 45
+ avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4
+ url: https://github.com/BilalAlpaslan
- login: ycd
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4
url: https://github.com/ycd
+- login: cikay
+ count: 41
+ avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4
+ url: https://github.com/cikay
+- login: yezz123
+ count: 34
+ avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4
+ url: https://github.com/yezz123
- login: AdrianDeAnda
count: 33
- avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=bb7f8a0d6c9de4e9d0320a9f271210206e202250&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=b2ea249c6b41ddf98679c8d110d0f67d4a3ebf93&v=4
url: https://github.com/AdrianDeAnda
- login: ArcLightSlavik
count: 31
- avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4
+ avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4
url: https://github.com/ArcLightSlavik
-- login: cikay
- count: 24
- avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4
- url: https://github.com/cikay
+- login: cassiobotaro
+ count: 25
+ avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4
+ url: https://github.com/cassiobotaro
- login: dmontagu
count: 23
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
url: https://github.com/dmontagu
-- login: cassiobotaro
- count: 23
- avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4
- url: https://github.com/cassiobotaro
- login: komtaki
count: 21
avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4
@@ -356,18 +376,30 @@ top_reviewers:
count: 19
avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4
url: https://github.com/0417taehyun
+- login: lsglucas
+ count: 18
+ avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
+ url: https://github.com/lsglucas
+- login: JarroVGIT
+ count: 18
+ avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
+ url: https://github.com/JarroVGIT
+- login: zy7y
+ count: 17
+ avatarUrl: https://avatars.githubusercontent.com/u/67154681?u=5d634834cc514028ea3f9115f7030b99a1f4d5a4&v=4
+ url: https://github.com/zy7y
- login: yanever
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/21978760?v=4
url: https://github.com/yanever
-- login: lsglucas
- count: 16
- avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
- url: https://github.com/lsglucas
- login: SwftAlpc
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4
url: https://github.com/SwftAlpc
+- login: rjNemo
+ count: 16
+ avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
+ url: https://github.com/rjNemo
- login: Smlep
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4
@@ -384,22 +416,18 @@ top_reviewers:
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4
url: https://github.com/delhi09
-- login: rjNemo
- count: 14
- avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
- url: https://github.com/rjNemo
-- login: RunningIkkyu
- count: 12
- avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4
- url: https://github.com/RunningIkkyu
-- login: yezz123
- count: 12
- avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4
- url: https://github.com/yezz123
- login: sh0nk
- count: 12
+ count: 13
avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4
url: https://github.com/sh0nk
+- login: RunningIkkyu
+ count: 12
+ avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=efb5b45b55584450507834f279ce48d4d64dea2f&v=4
+ url: https://github.com/RunningIkkyu
+- login: solomein-sv
+ count: 11
+ avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4
+ url: https://github.com/solomein-sv
- login: mariacamilagl
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
@@ -412,6 +440,10 @@ top_reviewers:
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/7887703?v=4
url: https://github.com/maoyibo
+- login: odiseo0
+ count: 10
+ avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=ab724eae71c3fe1cf81e8dc76e73415da926ef7d&v=4
+ url: https://github.com/odiseo0
- login: graingert
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/413772?v=4
@@ -424,26 +456,34 @@ top_reviewers:
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/49435654?v=4
url: https://github.com/kty4119
-- login: zy7y
- count: 9
- avatarUrl: https://avatars.githubusercontent.com/u/67154681?u=5d634834cc514028ea3f9115f7030b99a1f4d5a4&v=4
- url: https://github.com/zy7y
- login: bezaca
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4
url: https://github.com/bezaca
-- login: solomein-sv
- count: 9
- avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4
- url: https://github.com/solomein-sv
+- login: raphaelauv
+ count: 8
+ avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
+ url: https://github.com/raphaelauv
- login: blt232018
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/43393471?u=172b0e0391db1aa6c1706498d6dfcb003c8a4857&v=4
url: https://github.com/blt232018
+- login: rogerbrinkmann
+ count: 8
+ avatarUrl: https://avatars.githubusercontent.com/u/5690226?v=4
+ url: https://github.com/rogerbrinkmann
- login: ComicShrimp
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4
url: https://github.com/ComicShrimp
+- login: NinaHwang
+ count: 8
+ avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4
+ url: https://github.com/NinaHwang
+- login: dimaqq
+ count: 8
+ avatarUrl: https://avatars.githubusercontent.com/u/662249?v=4
+ url: https://github.com/dimaqq
- login: Serrones
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4
@@ -452,14 +492,6 @@ top_reviewers:
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/36391432?u=094eec0cfddd5013f76f31e55e56147d78b19553&v=4
url: https://github.com/ryuckel
-- login: raphaelauv
- count: 7
- avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
- url: https://github.com/raphaelauv
-- login: BilalAlpaslan
- count: 7
- avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4
- url: https://github.com/BilalAlpaslan
- login: NastasiaSaby
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/8245071?u=b3afd005f9e4bf080c219ef61a592b3a8004b764&v=4
@@ -468,35 +500,15 @@ top_reviewers:
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4
url: https://github.com/Mause
+- login: wakabame
+ count: 7
+ avatarUrl: https://avatars.githubusercontent.com/u/35513518?v=4
+ url: https://github.com/wakabame
+- login: AlexandreBiguet
+ count: 7
+ avatarUrl: https://avatars.githubusercontent.com/u/1483079?u=ff926455cd4cab03c6c49441aa5dc2b21df3e266&v=4
+ url: https://github.com/AlexandreBiguet
- login: krocdort
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/34248814?v=4
url: https://github.com/krocdort
-- login: dimaqq
- count: 7
- avatarUrl: https://avatars.githubusercontent.com/u/662249?v=4
- url: https://github.com/dimaqq
-- login: jovicon
- count: 6
- avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4
- url: https://github.com/jovicon
-- login: NinaHwang
- count: 6
- avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4
- url: https://github.com/NinaHwang
-- login: diogoduartec
- count: 5
- avatarUrl: https://avatars.githubusercontent.com/u/31852339?u=b50fc11c531e9b77922e19edfc9e7233d4d7b92e&v=4
- url: https://github.com/diogoduartec
-- login: n25a
- count: 5
- avatarUrl: https://avatars.githubusercontent.com/u/49960770?u=eb3c95338741c78fff7d9d5d7ace9617e53eee4a&v=4
- url: https://github.com/n25a
-- login: izaguerreiro
- count: 5
- avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4
- url: https://github.com/izaguerreiro
-- login: israteneda
- count: 5
- avatarUrl: https://avatars.githubusercontent.com/u/20668624?u=d7b2961d330aca65fbce5bdb26a0800a3d23ed2d&v=4
- url: https://github.com/israteneda
diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml
index 4d63a7288..7aa50b111 100644
--- a/docs/en/data/sponsors.yml
+++ b/docs/en/data/sponsors.yml
@@ -1,16 +1,16 @@
gold:
- - url: https://bit.ly/2QSouzH
- title: "Jina: build neural search-as-a-service for any kind of data in just minutes."
- img: https://fastapi.tiangolo.com/img/sponsors/jina.svg
+ - url: https://bit.ly/3PjOZqc
+ title: "DiscoArt: Create compelling Disco Diffusion artworks in just one line"
+ img: https://fastapi.tiangolo.com/img/sponsors/jina-ai.png
- url: https://cryptapi.io/
title: "CryptAPI: Your easy to use, secure and privacy oriented payment gateway."
img: https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg
- - url: https://www.dropbase.io/careers
- title: Dropbase - seamlessly collect, clean, and centralize data.
- img: https://fastapi.tiangolo.com/img/sponsors/dropbase.svg
- - url: https://striveworks.us/careers?utm_source=fastapi&utm_medium=sponsor_banner&utm_campaign=feb_march#openings
- title: https://striveworks.us/careers
- img: https://fastapi.tiangolo.com/img/sponsors/striveworks.png
+ - url: https://app.imgwhale.xyz/
+ title: The ultimate solution to unlimited and forever cloud storage.
+ img: https://fastapi.tiangolo.com/img/sponsors/imgwhale.svg
+ - url: https://doist.com/careers/9B437B1615-wa-senior-backend-engineer-python
+ title: Help us migrate doist to FastAPI
+ img: https://fastapi.tiangolo.com/img/sponsors/doist.svg
silver:
- url: https://www.deta.sh/?ref=fastapi
title: The launchpad for all your (team's) ideas
@@ -18,10 +18,7 @@ silver:
- url: https://www.investsuite.com/jobs
title: Wealthtech jobs with FastAPI
img: https://fastapi.tiangolo.com/img/sponsors/investsuite.svg
- - url: https://www.vim.so/?utm_source=FastAPI
- title: We help you master vim with interactive exercises
- img: https://fastapi.tiangolo.com/img/sponsors/vimso.png
- - url: https://talkpython.fm/fastapi-sponsor
+ - url: https://training.talkpython.fm/fastapi-courses
title: FastAPI video courses on demand from people you trust
img: https://fastapi.tiangolo.com/img/sponsors/talkpython.png
- url: https://testdriven.io/courses/tdd-fastapi/
@@ -30,7 +27,16 @@ silver:
- url: https://github.com/deepset-ai/haystack/
title: Build powerful search from composable, open source building blocks
img: https://fastapi.tiangolo.com/img/sponsors/haystack-fastapi.svg
+ - url: https://www.udemy.com/course/fastapi-rest/
+ title: Learn FastAPI by building a complete project. Extend your knowledge on advanced web development-AWS, Payments, Emails.
+ img: https://fastapi.tiangolo.com/img/sponsors/ines-course.jpg
+ - url: https://careers.budget-insight.com/
+ title: Budget Insight is hiring!
+ img: https://fastapi.tiangolo.com/img/sponsors/budget-insight.svg
bronze:
- - url: https://calmcode.io
- title: Code. Simply. Clearly. Calmly.
- img: https://fastapi.tiangolo.com/img/sponsors/calmcode.jpg
+ - url: https://www.exoflare.com/open-source/?utm_source=FastAPI&utm_campaign=open_source
+ title: Biosecurity risk assessments made easy.
+ img: https://fastapi.tiangolo.com/img/sponsors/exoflare.png
+ - url: https://bit.ly/3ccLCmM
+ title: https://striveworks.us/careers
+ img: https://fastapi.tiangolo.com/img/sponsors/striveworks2.png
diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml
index dbf69c1b3..a8bfb0b1b 100644
--- a/docs/en/data/sponsors_badge.yml
+++ b/docs/en/data/sponsors_badge.yml
@@ -2,10 +2,14 @@ logins:
- jina-ai
- deta
- investsuite
- - vimsoHQ
- mikeckennedy
- - koaning
- deepset-ai
- cryptapi
- - DropbaseHQ
- Striveworks
+ - xoflare
+ - InesIvanova
+ - DropbaseHQ
+ - VincentParedes
+ - BLUE-DEVIL1134
+ - ObliviousAI
+ - Doist
diff --git a/docs/en/docs/advanced/additional-responses.md b/docs/en/docs/advanced/additional-responses.md
index 4b8b3b71e..5d136da41 100644
--- a/docs/en/docs/advanced/additional-responses.md
+++ b/docs/en/docs/advanced/additional-responses.md
@@ -36,7 +36,7 @@ For example, to declare another response with a status code `404` and a Pydantic
**FastAPI** will take the Pydantic model from there, generate the `JSON Schema`, and put it in the correct place.
The correct place is:
-
+
* In the key `content`, that has as value another JSON object (`dict`) that contains:
* A key with the media type, e.g. `application/json`, that contains as value another JSON object, that contains:
* A key `schema`, that has as the value the JSON Schema from the model, here's the correct place.
diff --git a/docs/en/docs/advanced/additional-status-codes.md b/docs/en/docs/advanced/additional-status-codes.md
index eb6031953..b61f88b93 100644
--- a/docs/en/docs/advanced/additional-status-codes.md
+++ b/docs/en/docs/advanced/additional-status-codes.md
@@ -14,7 +14,7 @@ But you also want it to accept new items. And when the items didn't exist before
To achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want:
-```Python hl_lines="4 23"
+```Python hl_lines="4 25"
{!../../../docs_src/additional_status_codes/tutorial001.py!}
```
@@ -22,7 +22,7 @@ To achieve that, import `JSONResponse`, and return your content there directly,
When you return a `Response` directly, like in the example above, it will be returned directly.
It won't be serialized with a model, etc.
-
+
Make sure it has the data you want it to have, and that the values are valid JSON (if you are using `JSONResponse`).
!!! note "Technical Details"
diff --git a/docs/en/docs/advanced/extending-openapi.md b/docs/en/docs/advanced/extending-openapi.md
index d1b14bc00..36619696b 100644
--- a/docs/en/docs/advanced/extending-openapi.md
+++ b/docs/en/docs/advanced/extending-openapi.md
@@ -132,8 +132,8 @@ You can probably right-click each link and select an option similar to `Save lin
**Swagger UI** uses the files:
-* `swagger-ui-bundle.js`
-* `swagger-ui.css`
+* `swagger-ui-bundle.js`
+* `swagger-ui.css`
And **ReDoc** uses the file:
diff --git a/docs/en/docs/advanced/generate-clients.md b/docs/en/docs/advanced/generate-clients.md
new file mode 100644
index 000000000..f31a248d0
--- /dev/null
+++ b/docs/en/docs/advanced/generate-clients.md
@@ -0,0 +1,267 @@
+# Generate Clients
+
+As **FastAPI** is based on the OpenAPI specification, you get automatic compatibility with many tools, including the automatic API docs (provided by Swagger UI).
+
+One particular advantage that is not necessarily obvious is that you can **generate clients** (sometimes called **SDKs** ) for your API, for many different **programming languages**.
+
+## OpenAPI Client Generators
+
+There are many tools to generate clients from **OpenAPI**.
+
+A common tool is OpenAPI Generator.
+
+If you are building a **frontend**, a very interesting alternative is openapi-typescript-codegen.
+
+## Generate a TypeScript Frontend Client
+
+Let's start with a simple FastAPI application:
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="9-11 14-15 18 19 23"
+ {!> ../../../docs_src/generate_clients/tutorial001.py!}
+ ```
+
+=== "Python 3.9 and above"
+
+ ```Python hl_lines="7-9 12-13 16-17 21"
+ {!> ../../../docs_src/generate_clients/tutorial001_py39.py!}
+ ```
+
+Notice that the *path operations* define the models they use for request payload and response payload, using the models `Item` and `ResponseMessage`.
+
+### API Docs
+
+If you go to the API docs, you will see that it has the **schemas** for the data to be sent in requests and received in responses:
+
+
+
+You can see those schemas because they were declared with the models in the app.
+
+That information is available in the app's **OpenAPI schema**, and then shown in the API docs (by Swagger UI).
+
+And that same information from the models that is included in OpenAPI is what can be used to **generate the client code**.
+
+### Generate a TypeScript Client
+
+Now that we have the app with the models, we can generate the client code for the frontend.
+
+#### Install `openapi-typescript-codegen`
+
+You can install `openapi-typescript-codegen` in your frontend code with:
+
+
+
+You will also get autocompletion for the payload to send:
+
+
+
+!!! tip
+ Notice the autocompletion for `name` and `price`, that was defined in the FastAPI application, in the `Item` model.
+
+You will have inline errors for the data that you send:
+
+
+
+The response object will also have autocompletion:
+
+
+
+## FastAPI App with Tags
+
+In many cases your FastAPI app will be bigger, and you will probably use tags to separate different groups of *path operations*.
+
+For example, you could have a section for **items** and another section for **users**, and they could be separated by tags:
+
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="23 28 36"
+ {!> ../../../docs_src/generate_clients/tutorial002.py!}
+ ```
+
+=== "Python 3.9 and above"
+
+ ```Python hl_lines="21 26 34"
+ {!> ../../../docs_src/generate_clients/tutorial002_py39.py!}
+ ```
+
+### Generate a TypeScript Client with Tags
+
+If you generate a client for a FastAPI app using tags, it will normally also separate the client code based on the tags.
+
+This way you will be able to have things ordered and grouped correctly for the client code:
+
+
+
+In this case you have:
+
+* `ItemsService`
+* `UsersService`
+
+### Client Method Names
+
+Right now the generated method names like `createItemItemsPost` don't look very clean:
+
+```TypeScript
+ItemsService.createItemItemsPost({name: "Plumbus", price: 5})
+```
+
+...that's because the client generator uses the OpenAPI internal **operation ID** for each *path operation*.
+
+OpenAPI requires that each operation ID is unique across all the *path operations*, so FastAPI uses the **function name**, the **path**, and the **HTTP method/operation** to generate that operation ID, because that way it can make sure that the operation IDs are unique.
+
+But I'll show you how to improve that next. 🤓
+
+## Custom Operation IDs and Better Method Names
+
+You can **modify** the way these operation IDs are **generated** to make them simpler and have **simpler method names** in the clients.
+
+In this case you will have to ensure that each operation ID is **unique** in some other way.
+
+For example, you could make sure that each *path operation* has a tag, and then generate the operation ID based on the **tag** and the *path operation* **name** (the function name).
+
+### Custom Generate Unique ID Function
+
+FastAPI uses a **unique ID** for each *path operation*, it is used for the **operation ID** and also for the names of any needed custom models, for requests or responses.
+
+You can customize that function. It takes an `APIRoute` and outputs a string.
+
+For example, here it is using the first tag (you will probably have only one tag) and the *path operation* name (the function name).
+
+You can then pass that custom function to **FastAPI** as the `generate_unique_id_function` parameter:
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="8-9 12"
+ {!> ../../../docs_src/generate_clients/tutorial003.py!}
+ ```
+
+=== "Python 3.9 and above"
+
+ ```Python hl_lines="6-7 10"
+ {!> ../../../docs_src/generate_clients/tutorial003_py39.py!}
+ ```
+
+### Generate a TypeScript Client with Custom Operation IDs
+
+Now if you generate the client again, you will see that it has the improved method names:
+
+
+
+As you see, the method names now have the tag and then the function name, now they don't include information from the URL path and the HTTP operation.
+
+### Preprocess the OpenAPI Specification for the Client Generator
+
+The generated code still has some **duplicated information**.
+
+We already know that this method is related to the **items** because that word is in the `ItemsService` (taken from the tag), but we still have the tag name prefixed in the method name too. 😕
+
+We will probably still want to keep it for OpenAPI in general, as that will ensure that the operation IDs are **unique**.
+
+But for the generated client we could **modify** the OpenAPI operation IDs right before generating the clients, just to make those method names nicer and **cleaner**.
+
+We could download the OpenAPI JSON to a file `openapi.json` and then we could **remove that prefixed tag** with a script like this:
+
+```Python
+{!../../../docs_src/generate_clients/tutorial004.py!}
+```
+
+With that, the operation IDs would be renamed from things like `items-get_items` to just `get_items`, that way the client generator can generate simpler method names.
+
+### Generate a TypeScript Client with the Preprocessed OpenAPI
+
+Now as the end result is in a file `openapi.json`, you would modify the `package.json` to use that local file, for example:
+
+```JSON hl_lines="7"
+{
+ "name": "frontend-app",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "generate-client": "openapi --input ./openapi.json --output ./src/client --client axios"
+ },
+ "author": "",
+ "license": "",
+ "devDependencies": {
+ "openapi-typescript-codegen": "^0.20.1",
+ "typescript": "^4.6.2"
+ }
+}
+```
+
+After generating the new client, you would now have **clean method names**, with all the **autocompletion**, **inline errors**, etc:
+
+
+
+## Benefits
+
+When using the automatically generated clients you would **autocompletion** for:
+
+* Methods.
+* Request payloads in the body, query parameters, etc.
+* Response payloads.
+
+You would also have **inline errors** for everything.
+
+And whenever you update the backend code, and **regenerate** the frontend, it would have any new *path operations* available as methods, the old ones removed, and any other change would be reflected on the generated code. 🤓
+
+This also means that if something changed it will be **reflected** on the client code automatically. And if you **build** the client it will error out if you have any **mismatch** in the data used.
+
+So, you would **detect many errors** very early in the development cycle instead of having to wait for the errors to show up to your final users in production and then trying to debug where the problem is. ✨
diff --git a/docs/en/docs/advanced/security/oauth2-scopes.md b/docs/en/docs/advanced/security/oauth2-scopes.md
index 4bd9cfd04..be51325cd 100644
--- a/docs/en/docs/advanced/security/oauth2-scopes.md
+++ b/docs/en/docs/advanced/security/oauth2-scopes.md
@@ -16,11 +16,11 @@ In this section you will see how to manage authentication and authorization with
You don't necessarily need OAuth2 scopes, and you can handle authentication and authorization however you want.
But OAuth2 with scopes can be nicely integrated into your API (with OpenAPI) and your API docs.
-
+
Nevertheless, you still enforce those scopes, or any other security/authorization requirement, however you need, in your code.
In many cases, OAuth2 with scopes can be an overkill.
-
+
But if you know you need it, or you are curious, keep reading.
## OAuth2 scopes and OpenAPI
@@ -47,7 +47,7 @@ They are normally used to declare specific security permissions, for example:
In OAuth2 a "scope" is just a string that declares a specific permission required.
It doesn't matter if it has other characters like `:` or if it is a URL.
-
+
Those details are implementation specific.
For OAuth2 they are just strings.
@@ -115,7 +115,7 @@ In this case, it requires the scope `me` (it could require more than one scope).
!!! note
You don't necessarily need to add different scopes in different places.
-
+
We are doing it here to demonstrate how **FastAPI** handles scopes declared at different levels.
```Python hl_lines="4 139 166"
diff --git a/docs/en/docs/advanced/sql-databases-peewee.md b/docs/en/docs/advanced/sql-databases-peewee.md
index 48514d1e2..b4ea61367 100644
--- a/docs/en/docs/advanced/sql-databases-peewee.md
+++ b/docs/en/docs/advanced/sql-databases-peewee.md
@@ -182,7 +182,7 @@ Now let's check the file `sql_app/schemas.py`.
To avoid confusion between the Peewee *models* and the Pydantic *models*, we will have the file `models.py` with the Peewee models, and the file `schemas.py` with the Pydantic models.
These Pydantic models define more or less a "schema" (a valid data shape).
-
+
So this will help us avoiding confusion while using both.
### Create the Pydantic *models* / schemas
diff --git a/docs/en/docs/advanced/testing-dependencies.md b/docs/en/docs/advanced/testing-dependencies.md
index 79208e8dc..7bba82fb7 100644
--- a/docs/en/docs/advanced/testing-dependencies.md
+++ b/docs/en/docs/advanced/testing-dependencies.md
@@ -28,7 +28,7 @@ To override a dependency for testing, you put as a key the original dependency (
And then **FastAPI** will call that override instead of the original dependency.
-```Python hl_lines="26-27 30"
+```Python hl_lines="28-29 32"
{!../../../docs_src/dependency_testing/tutorial001.py!}
```
diff --git a/docs/en/docs/alternatives.md b/docs/en/docs/alternatives.md
index 28d0be8cc..68aa3150d 100644
--- a/docs/en/docs/alternatives.md
+++ b/docs/en/docs/alternatives.md
@@ -235,7 +235,7 @@ It was one of the first extremely fast Python frameworks based on `asyncio`. It
!!! check "Inspired **FastAPI** to"
Find a way to have a crazy performance.
-
+
That's why **FastAPI** is based on Starlette, as it is the fastest framework available (tested by third-party benchmarks).
### Falcon
@@ -333,7 +333,7 @@ Now APIStar is a set of tools to validate OpenAPI specifications, not a web fram
Exist.
The idea of declaring multiple things (data validation, serialization and documentation) with the same Python types, that at the same time provided great editor support, was something I considered a brilliant idea.
-
+
And after searching for a long time for a similar framework and testing many different alternatives, APIStar was the best option available.
Then APIStar stopped to exist as a server and Starlette was created, and was a new better foundation for such a system. That was the final inspiration to build **FastAPI**.
@@ -391,7 +391,7 @@ That's one of the main things that **FastAPI** adds on top, all based on Python
Handle all the core web parts. Adding features on top.
The class `FastAPI` itself inherits directly from the class `Starlette`.
-
+
So, anything that you can do with Starlette, you can do it directly with **FastAPI**, as it is basically Starlette on steroids.
### Uvicorn
diff --git a/docs/en/docs/async.md b/docs/en/docs/async.md
index 8194650fd..71f2e7502 100644
--- a/docs/en/docs/async.md
+++ b/docs/en/docs/async.md
@@ -116,7 +116,7 @@ The cashier 💁 gives you the number of your turn.
While you are waiting, you go with your crush 😍 and pick a table, you sit and talk with your crush 😍 for a long time (as your burgers are very fancy and take some time to prepare ✨🍔✨).
-As you are sitting on the table with your crush 😍, while you wait for the burgers 🍔, you can spend that time admiring how awesome, cute and smart your crush is ✨😍✨.
+As you are sitting at the table with your crush 😍, while you wait for the burgers 🍔, you can spend that time admiring how awesome, cute and smart your crush is ✨😍✨.
While waiting and talking to your crush 😍, from time to time, you check the number displayed on the counter to see if it's your turn already.
@@ -134,7 +134,7 @@ Then, when it's your turn, you do actual "productive" work 🤓, you process the
But then, even though you still don't have your burgers 🍔, your work with the cashier 💁 is "on pause" ⏸, because you have to wait 🕙 for your burgers to be ready.
-But as you go away from the counter and sit on the table with a number for your turn, you can switch 🔀 your attention to your crush 😍, and "work" ⏯ 🤓 on that. Then you are again doing something very "productive" 🤓, as is flirting with your crush 😍.
+But as you go away from the counter and sit at the table with a number for your turn, you can switch 🔀 your attention to your crush 😍, and "work" ⏯ 🤓 on that. Then you are again doing something very "productive" 🤓, as is flirting with your crush 😍.
Then the cashier 💁 says "I'm finished with doing the burgers" 🍔 by putting your number on the counter's display, but you don't jump like crazy immediately when the displayed number changes to your turn number. You know no one will steal your burgers 🍔 because you have the number of your turn, and they have theirs.
diff --git a/docs/en/docs/css/custom.css b/docs/en/docs/css/custom.css
index 7d3503e49..226ca2b11 100644
--- a/docs/en/docs/css/custom.css
+++ b/docs/en/docs/css/custom.css
@@ -4,10 +4,21 @@
display: block;
}
+.termy {
+ /* For right to left languages */
+ direction: ltr;
+}
+
.termy [data-termynal] {
white-space: pre-wrap;
}
+a.external-link {
+ /* For right to left languages */
+ direction: ltr;
+ display: inline-block;
+}
+
a.external-link::after {
/* \00A0 is a non-breaking space
to make the mark be on the same line as the link
@@ -94,7 +105,7 @@ a.announce-link:hover {
.announce-wrapper .sponsor-badge {
display: block;
position: absolute;
- top: -5px;
+ top: -10px;
right: 0;
font-size: 0.5rem;
color: #999;
@@ -118,3 +129,13 @@ a.announce-link:hover {
.twitter {
color: #00acee;
}
+
+/* Right to left languages */
+code {
+ direction: ltr;
+ display: inline-block;
+}
+
+.md-content__inner h1 {
+ direction: ltr !important;
+}
diff --git a/docs/en/docs/deployment/docker.md b/docs/en/docs/deployment/docker.md
index 3f86efcce..8a542622e 100644
--- a/docs/en/docs/deployment/docker.md
+++ b/docs/en/docs/deployment/docker.md
@@ -142,7 +142,7 @@ Successfully installed fastapi pydantic uvicorn
* Create a `main.py` file with:
```Python
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -155,7 +155,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -350,7 +350,7 @@ If your FastAPI is a single file, for example, `main.py` without an `./app` dire
Then you would just have to change the corresponding paths to copy the file inside the `Dockerfile`:
```{ .dockerfile .annotate hl_lines="10 13" }
-FROM python:3.9
+FROM python:3.9
WORKDIR /code
diff --git a/docs/en/docs/deployment/manually.md b/docs/en/docs/deployment/manually.md
index 7fd1f4d4f..d6892b2c1 100644
--- a/docs/en/docs/deployment/manually.md
+++ b/docs/en/docs/deployment/manually.md
@@ -38,7 +38,7 @@ You can install an ASGI compatible server with:
!!! tip
By adding the `standard`, Uvicorn will install and use some recommended extra dependencies.
-
+
That including `uvloop`, the high-performance drop-in replacement for `asyncio`, that provides the big concurrency performance boost.
=== "Hypercorn"
@@ -59,7 +59,7 @@ You can install an ASGI compatible server with:
## Run the Server Program
-You can then your application the same way you have done in the tutorials, but without the `--reload` option, e.g.:
+You can then run your application the same way you have done in the tutorials, but without the `--reload` option, e.g.:
=== "Uvicorn"
@@ -89,7 +89,7 @@ You can then your application the same way you have done in the tutorials, but w
Remember to remove the `--reload` option if you were using it.
The `--reload` option consumes much more resources, is more unstable, etc.
-
+
It helps a lot during **development**, but you **shouldn't** use it in **production**.
## Hypercorn with Trio
diff --git a/docs/en/docs/features.md b/docs/en/docs/features.md
index 36f80783a..e4672d532 100644
--- a/docs/en/docs/features.md
+++ b/docs/en/docs/features.md
@@ -190,7 +190,7 @@ With **FastAPI** you get all of **Pydantic**'s features (as FastAPI is based on
* Plays nicely with your **IDE/linter/brain**:
* Because pydantic data structures are just instances of classes you define; auto-completion, linting, mypy and your intuition should all work properly with your validated data.
* **Fast**:
- * in benchmarks Pydantic is faster than all other tested libraries.
+ * in benchmarks Pydantic is faster than all other tested libraries.
* Validate **complex structures**:
* Use of hierarchical Pydantic models, Python `typing`’s `List` and `Dict`, etc.
* And validators allow complex data schemas to be clearly and easily defined, checked and documented as JSON Schema.
diff --git a/docs/en/docs/img/deployment/concepts/process-ram.drawio b/docs/en/docs/img/deployment/concepts/process-ram.drawio
index 51fc30ed3..b29c8a342 100644
--- a/docs/en/docs/img/deployment/concepts/process-ram.drawio
+++ b/docs/en/docs/img/deployment/concepts/process-ram.drawio
@@ -103,4 +103,4 @@
-
\ No newline at end of file
+
diff --git a/docs/en/docs/img/deployment/concepts/process-ram.svg b/docs/en/docs/img/deployment/concepts/process-ram.svg
index cd086c36b..c1bf0d589 100644
--- a/docs/en/docs/img/deployment/concepts/process-ram.svg
+++ b/docs/en/docs/img/deployment/concepts/process-ram.svg
@@ -56,4 +56,4 @@
}
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126
123.124.125.126kwargs
. Even if they don't have a default value.
-```Python hl_lines="8"
+```Python hl_lines="7"
{!../../../docs_src/path_params_numeric_validations/tutorial003.py!}
```
diff --git a/docs/en/docs/tutorial/path-params.md b/docs/en/docs/tutorial/path-params.md
index 9c458844d..a0d70692e 100644
--- a/docs/en/docs/tutorial/path-params.md
+++ b/docs/en/docs/tutorial/path-params.md
@@ -115,6 +115,14 @@ Because *path operations* are evaluated in order, you need to make sure that the
Otherwise, the path for `/users/{user_id}` would match also for `/users/me`, "thinking" that it's receiving a parameter `user_id` with a value of `"me"`.
+Similarly, you cannot redefine a path operation:
+
+```Python hl_lines="6 11"
+{!../../../docs_src/path_params/tutorial003b.py!}
+```
+
+The first one will always be used since the path matches first.
+
## Predefined values
If you have a *path operation* that receives a *path parameter*, but you want the possible valid *path parameter* values to be predefined, you can use a standard Python `Enum`.
diff --git a/docs/en/docs/tutorial/query-params-str-validations.md b/docs/en/docs/tutorial/query-params-str-validations.md
index ee62b9718..c5fc35b88 100644
--- a/docs/en/docs/tutorial/query-params-str-validations.md
+++ b/docs/en/docs/tutorial/query-params-str-validations.md
@@ -16,12 +16,12 @@ Let's take this application as example:
{!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!}
```
-The query parameter `q` is of type `Optional[str]` (or `str | None` in Python 3.10), that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required.
+The query parameter `q` is of type `Union[str, None]` (or `str | None` in Python 3.10), that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required.
!!! note
FastAPI will know that the value of `q` is not required because of the default value `= None`.
- The `Optional` in `Optional[str]` is not used by FastAPI, but will allow your editor to give you better support and detect errors.
+ The `Union` in `Union[str, None]` will allow your editor to give you better support and detect errors.
## Additional validation
@@ -59,24 +59,24 @@ And now use it as the default value of your parameter, setting the parameter `ma
{!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!}
```
-As we have to replace the default value `None` with `Query(None)`, the first parameter to `Query` serves the same purpose of defining that default value.
+As we have to replace the default value `None` in the function with `Query()`, we can now set the default value with the parameter `Query(default=None)`, it serves the same purpose of defining that default value.
So:
```Python
-q: Optional[str] = Query(None)
+q: Union[str, None] = Query(default=None)
```
...makes the parameter optional, the same as:
```Python
-q: Optional[str] = None
+q: Union[str, None] = None
```
And in Python 3.10 and above:
```Python
-q: str | None = Query(None)
+q: str | None = Query(default=None)
```
...makes the parameter optional, the same as:
@@ -97,17 +97,17 @@ But it declares it explicitly as being a query parameter.
or the:
```Python
- = Query(None)
+ = Query(default=None)
```
as it will use that `None` as the default value, and that way make the parameter **not required**.
- The `Optional` part allows your editor to provide better support, but it is not what tells FastAPI that this parameter is not required.
+ The `Union[str, None]` part allows your editor to provide better support, but it is not what tells FastAPI that this parameter is not required.
Then, we can pass more parameters to `Query`. In this case, the `max_length` parameter that applies to strings:
```Python
-q: str = Query(None, max_length=50)
+q: Union[str, None] = Query(default=None, max_length=50)
```
This will validate the data, show a clear error when the data is not valid, and document the parameter in the OpenAPI schema *path operation*.
@@ -118,7 +118,7 @@ You can also add a parameter `min_length`:
=== "Python 3.6 and above"
- ```Python hl_lines="9"
+ ```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial003.py!}
```
@@ -134,13 +134,13 @@ You can define a ../../../docs_src/query_params_str_validations/tutorial004.py!}
```
=== "Python 3.10 and above"
- ```Python hl_lines="8"
+ ```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial004_py310.py!}
```
@@ -156,7 +156,7 @@ But whenever you need them and go and learn them, know that you can already use
## Default values
-The same way that you can pass `None` as the first argument to be used as the default value, you can pass other values.
+The same way that you can pass `None` as the value for the `default` parameter, you can pass other values.
Let's say that you want to declare the `q` query parameter to have a `min_length` of `3`, and to have a default value of `"fixedquery"`:
@@ -178,26 +178,68 @@ q: str
instead of:
```Python
-q: Optional[str] = None
+q: Union[str, None] = None
```
But we are now declaring it with `Query`, for example like:
```Python
-q: Optional[str] = Query(None, min_length=3)
+q: Union[str, None] = Query(default=None, min_length=3)
```
-So, when you need to declare a value as required while using `Query`, you can use `...` as the first argument:
+So, when you need to declare a value as required while using `Query`, you can simply not declare a default value:
```Python hl_lines="7"
{!../../../docs_src/query_params_str_validations/tutorial006.py!}
```
+### Required with Ellipsis (`...`)
+
+There's an alternative way to explicitly declare that a value is required. You can set the `default` parameter to the literal value `...`:
+
+```Python hl_lines="7"
+{!../../../docs_src/query_params_str_validations/tutorial006b.py!}
+```
+
!!! info
If you hadn't seen that `...` before: it is a special single value, it is part of Python and is called "Ellipsis".
+ It is used by Pydantic and FastAPI to explicitly declare that a value is required.
+
This will let **FastAPI** know that this parameter is required.
+### Required with `None`
+
+You can declare that a parameter can accept `None`, but that it's still required. This would force clients to send a value, even if the value is `None`.
+
+To do that, you can declare that `None` is a valid type but still use `default=...`:
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c.py!}
+ ```
+
+=== "Python 3.10 and above"
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c_py310.py!}
+ ```
+
+!!! tip
+ Pydantic, which is what powers all the data validation and serialization in FastAPI, has a special behavior when you use `Optional` or `Union[Something, None]` without a default value, you can read more about it in the Pydantic docs about Required Optional fields.
+
+### Use Pydantic's `Required` instead of Ellipsis (`...`)
+
+If you feel uncomfortable using `...`, you can also import and use `Required` from Pydantic:
+
+```Python hl_lines="2 8"
+{!../../../docs_src/query_params_str_validations/tutorial006d.py!}
+```
+
+!!! tip
+ Remember that in most of the cases, when something is required, you can simply omit the `default` parameter, so you normally don't have to use `...` nor `Required`.
+
## Query parameter list / multiple values
When you define a query parameter explicitly with `Query` you can also declare it to receive a list of values, or said in other way, to receive multiple values.
@@ -315,7 +357,7 @@ You can add a `title`:
=== "Python 3.10 and above"
- ```Python hl_lines="7"
+ ```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial007_py310.py!}
```
@@ -399,7 +441,7 @@ To exclude a query parameter from the generated OpenAPI schema (and thus, from t
=== "Python 3.10 and above"
- ```Python hl_lines="7"
+ ```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial014_py310.py!}
```
diff --git a/docs/en/docs/tutorial/request-files.md b/docs/en/docs/tutorial/request-files.md
index 3ca471a91..664a1102f 100644
--- a/docs/en/docs/tutorial/request-files.md
+++ b/docs/en/docs/tutorial/request-files.md
@@ -106,7 +106,7 @@ The way HTML forms (``) sends the data to the server normally uses
Data from forms is normally encoded using the "media type" `application/x-www-form-urlencoded` when it doesn't include files.
But when the form includes files, it is encoded as `multipart/form-data`. If you use `File`, **FastAPI** will know it has to get the files from the correct part of the body.
-
+
If you want to read more about these encodings and form fields, head to the MDN web docs for POST
.
!!! warning
diff --git a/docs/en/docs/tutorial/request-forms.md b/docs/en/docs/tutorial/request-forms.md
index b5495a400..2021a098f 100644
--- a/docs/en/docs/tutorial/request-forms.md
+++ b/docs/en/docs/tutorial/request-forms.md
@@ -45,7 +45,7 @@ The way HTML forms (``) sends the data to the server normally uses
Data from forms is normally encoded using the "media type" `application/x-www-form-urlencoded`.
But when the form includes files, it is encoded as `multipart/form-data`. You'll read about handling files in the next chapter.
-
+
If you want to read more about these encodings and form fields, head to the MDN web docs for POST
.
!!! warning
diff --git a/docs/en/docs/tutorial/response-model.md b/docs/en/docs/tutorial/response-model.md
index c751a9256..e371e86e4 100644
--- a/docs/en/docs/tutorial/response-model.md
+++ b/docs/en/docs/tutorial/response-model.md
@@ -162,7 +162,7 @@ Your response model could have default values, like:
{!> ../../../docs_src/response_model/tutorial004_py310.py!}
```
-* `description: Optional[str] = None` has a default of `None`.
+* `description: Union[str, None] = None` has a default of `None`.
* `tax: float = 10.5` has a default of `10.5`.
* `tags: List[str] = []` as a default of an empty list: `[]`.
diff --git a/docs/en/docs/tutorial/schema-extra-example.md b/docs/en/docs/tutorial/schema-extra-example.md
index c69df51dc..94347018d 100644
--- a/docs/en/docs/tutorial/schema-extra-example.md
+++ b/docs/en/docs/tutorial/schema-extra-example.md
@@ -68,13 +68,13 @@ Here we pass an `example` of the data expected in `Body()`:
=== "Python 3.6 and above"
- ```Python hl_lines="21-26"
+ ```Python hl_lines="20-25"
{!> ../../../docs_src/schema_extra_example/tutorial003.py!}
```
=== "Python 3.10 and above"
- ```Python hl_lines="19-24"
+ ```Python hl_lines="18-23"
{!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!}
```
@@ -99,13 +99,13 @@ Each specific example `dict` in the `examples` can contain:
=== "Python 3.6 and above"
- ```Python hl_lines="22-48"
+ ```Python hl_lines="21-47"
{!> ../../../docs_src/schema_extra_example/tutorial004.py!}
```
=== "Python 3.10 and above"
- ```Python hl_lines="20-46"
+ ```Python hl_lines="19-45"
{!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!}
```
diff --git a/docs/en/docs/tutorial/security/first-steps.md b/docs/en/docs/tutorial/security/first-steps.md
index 360d85ae4..45ffaab90 100644
--- a/docs/en/docs/tutorial/security/first-steps.md
+++ b/docs/en/docs/tutorial/security/first-steps.md
@@ -121,7 +121,7 @@ When we create an instance of the `OAuth2PasswordBearer` class we pass in the `t
```
!!! tip
- here `tokenUrl="token"` refers to a relative URL `token` that we haven't created yet. As it's a relative URL, it's equivalent to `./token`.
+ Here `tokenUrl="token"` refers to a relative URL `token` that we haven't created yet. As it's a relative URL, it's equivalent to `./token`.
Because we are using a relative URL, if your API was located at `https://example.com/`, then it would refer to `https://example.com/token`. But if your API was located at `https://example.com/api/v1/`, then it would refer to `https://example.com/api/v1/token`.
diff --git a/docs/en/docs/tutorial/sql-databases.md b/docs/en/docs/tutorial/sql-databases.md
index 9dc2f64c6..3436543a5 100644
--- a/docs/en/docs/tutorial/sql-databases.md
+++ b/docs/en/docs/tutorial/sql-databases.md
@@ -317,7 +317,7 @@ Not only the IDs of those items, but all the data that we defined in the Pydanti
Now, in the Pydantic *models* for reading, `Item` and `User`, add an internal `Config` class.
-This `Config` class is used to provide configurations to Pydantic.
+This `Config` class is used to provide configurations to Pydantic.
In the `Config` class, set the attribute `orm_mode = True`.
@@ -491,7 +491,7 @@ You can find an example of Alembic in a FastAPI project in the templates from [P
### Create a dependency
-Now use the `SessionLocal` class we created in the `sql_app/databases.py` file to create a dependency.
+Now use the `SessionLocal` class we created in the `sql_app/database.py` file to create a dependency.
We need to have an independent database session/connection (`SessionLocal`) per request, use the same session through all the request and then close it after the request is finished.
@@ -616,7 +616,7 @@ And as the code related to SQLAlchemy and the SQLAlchemy models lives in separat
The same way, you would be able to use the same SQLAlchemy models and utilities in other parts of your code that are not related to **FastAPI**.
-For example, in a background task worker with Celery, RQ, or ARQ.
+For example, in a background task worker with Celery, RQ, or ARQ.
## Review all the files
diff --git a/docs/en/docs/tutorial/testing.md b/docs/en/docs/tutorial/testing.md
index 7e2ae84d0..fea5a54f5 100644
--- a/docs/en/docs/tutorial/testing.md
+++ b/docs/en/docs/tutorial/testing.md
@@ -10,7 +10,7 @@ With it, you can use
{% endblock %}
+{%- block scripts %}
+{{ super() }}
+
+
+
+
+
+
+requests
- Requerido si quieres usar el `TestClient`.
-* aiofiles
- Requerido si quieres usar `FileResponse` o `StaticFiles`.
* jinja2
- Requerido si quieres usar la configuración por defecto de templates.
* python-multipart
- Requerido si quieres dar soporte a "parsing" de formularios, con `request.form()`.
* itsdangerous
- Requerido para dar soporte a `SessionMiddleware`.
diff --git a/docs/es/docs/tutorial/first-steps.md b/docs/es/docs/tutorial/first-steps.md
index 79f0a51c0..110036e8c 100644
--- a/docs/es/docs/tutorial/first-steps.md
+++ b/docs/es/docs/tutorial/first-steps.md
@@ -254,7 +254,7 @@ El `@app.get("/")` le dice a **FastAPI** que la función que tiene justo debajo
Esa sintaxis `@algo` se llama un "decorador" en Python.
Lo pones encima de una función. Es como un lindo sombrero decorado (creo que de ahí salió el concepto).
-
+
Un "decorador" toma la función que tiene debajo y hace algo con ella.
En nuestro caso, este decorador le dice a **FastAPI** que la función que está debajo corresponde al **path** `/` con una **operación** `get`.
diff --git a/docs/es/docs/tutorial/query-params.md b/docs/es/docs/tutorial/query-params.md
index 69caee6e8..482af8dc0 100644
--- a/docs/es/docs/tutorial/query-params.md
+++ b/docs/es/docs/tutorial/query-params.md
@@ -75,7 +75,7 @@ En este caso el parámetro de la función `q` será opcional y será `None` por
!!! note "Nota"
FastAPI sabrá que `q` es opcional por el `= None`.
- El `Optional` en `Optional[str]` no es usado por FastAPI (FastAPI solo usará la parte `str`), pero el `Optional[str]` le permitirá a tu editor ayudarte a encontrar errores en tu código.
+ El `Union` en `Union[str, None]` no es usado por FastAPI (FastAPI solo usará la parte `str`), pero el `Union[str, None]` le permitirá a tu editor ayudarte a encontrar errores en tu código.
## Conversión de tipos de parámetros de query
diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml
index a4bc41154..511ea0255 100644
--- a/docs/es/mkdocs.yml
+++ b/docs/es/mkdocs.yml
@@ -5,13 +5,15 @@ theme:
name: material
custom_dir: overrides
palette:
- - scheme: default
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
primary: teal
accent: amber
toggle:
icon: material/lightbulb
name: Switch to light mode
- - scheme: slate
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
primary: teal
accent: amber
toggle:
@@ -40,15 +42,19 @@ nav:
- az: /az/
- de: /de/
- es: /es/
+ - fa: /fa/
- fr: /fr/
+ - he: /he/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
+ - sv: /sv/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -107,8 +113,12 @@ extra:
name: de
- link: /es/
name: es - español
+ - link: /fa/
+ name: fa
- link: /fr/
name: fr - français
+ - link: /he/
+ name: he
- link: /id/
name: id
- link: /it/
@@ -117,6 +127,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /nl/
+ name: nl
- link: /pl/
name: pl
- link: /pt/
@@ -125,6 +137,8 @@ extra:
name: ru - русский язык
- link: /sq/
name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/fa/docs/index.md b/docs/fa/docs/index.md
new file mode 100644
index 000000000..0f7cd569a
--- /dev/null
+++ b/docs/fa/docs/index.md
@@ -0,0 +1,462 @@
+
+
+{% endfor %}
+{% endif %}
+
+
+
+دیگر اسپانسرها
+
+## نظر دیگران در مورد FastAPI
+
+
+
+اگر در حال ساختن برنامهای برای استفاده در CLI (به جای استفاده در وب) هستید، میتوانید از **Typer**. استفاده کنید.
+
+**Typer** دوقلوی کوچکتر FastAPI است و قرار است معادلی برای FastAPI در برنامههای CLI باشد.️ 🚀
+
+## نیازمندیها
+
+پایتون +۳.۶
+
+FastAPI مبتنی بر ابزارهای قدرتمند زیر است:
+
+* فریمورک Starlette برای بخش وب.
+* کتابخانه Pydantic برای بخش داده.
+
+## نصب
+
+
همچنین میتوانید از
+
+اگر در کدتان از `async` / `await` استفاده میکنید, از `async def` برای تعریف تابع خود استفاده کنید:
+
+```Python hl_lines="9 14"
+from typing import Optional
+
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.get("/")
+async def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+async def read_item(item_id: int, q: Optional[str] = None):
+ return {"item_id": item_id, "q": q}
+```
+
+**توجه**:
+
+اگر با `async / await` آشنا نیستید، به بخش _"عجله دارید?"_ در صفحه درباره `async` و `await` در مستندات مراجعه کنید.
+
+
+async def
... نیز استفاده کنیددرباره دستور
+
+دستور `uvicorn main:app` شامل موارد زیر است:
+
+* `main`: فایل `main.py` (ماژول پایتون ایجاد شده).
+* `app`: شیء ایجاد شده در فایل `main.py` در خط `app = FastAPI()`.
+* `--reload`: ریستارت کردن سرور با تغییر کد. تنها در هنگام توسعه از این گزینه استفاده شود..
+
+uvicorn main:app --reload
...ujson
- برای "تجزیه (parse)" سریعتر JSON .
+* email_validator
- برای اعتبارسنجی آدرسهای ایمیل.
+
+استفاده شده توسط Starlette:
+
+* requests
- در صورتی که میخواهید از `TestClient` استفاده کنید.
+* aiofiles
- در صورتی که میخواهید از `FileResponse` و `StaticFiles` استفاده کنید.
+* jinja2
- در صورتی که بخواهید از پیکربندی پیشفرض برای قالبها استفاده کنید.
+* python-multipart
- در صورتی که بخواهید با استفاده از `request.form()` از قابلیت "تجزیه (parse)" فرم استفاده کنید.
+* itsdangerous
- در صورتی که بخواید از `SessionMiddleware` پشتیبانی کنید.
+* pyyaml
- برای پشتیبانی `SchemaGenerator` در Starlet (به احتمال زیاد برای کار کردن با FastAPI به آن نیازی پیدا نمیکنید.).
+* graphene
- در صورتی که از `GraphQLApp` پشتیبانی میکنید.
+* ujson
- در صورتی که بخواهید از `UJSONResponse` استفاده کنید.
+
+استفاده شده توسط FastAPI / Starlette:
+
+* uvicorn
- برای سرور اجرا کننده برنامه وب.
+* orjson
- در صورتی که بخواهید از `ORJSONResponse` استفاده کنید.
+
+میتوان همه این موارد را با استفاده از دستور `pip install fastapi[all]`. به صورت یکجا نصب کرد.
+
+## لایسنس
+
+این پروژه مشمول قوانین و مقررات لایسنس MIT است.
diff --git a/docs/fa/mkdocs.yml b/docs/fa/mkdocs.yml
new file mode 100644
index 000000000..7d74e0407
--- /dev/null
+++ b/docs/fa/mkdocs.yml
@@ -0,0 +1,143 @@
+site_name: FastAPI
+site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
+site_url: https://fastapi.tiangolo.com/fa/
+theme:
+ name: material
+ custom_dir: overrides
+ palette:
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb
+ name: Switch to light mode
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb-outline
+ name: Switch to dark mode
+ features:
+ - search.suggest
+ - search.highlight
+ - content.tabs.link
+ icon:
+ repo: fontawesome/brands/github-alt
+ logo: https://fastapi.tiangolo.com/img/icon-white.svg
+ favicon: https://fastapi.tiangolo.com/img/favicon.png
+ language: fa
+repo_name: tiangolo/fastapi
+repo_url: https://github.com/tiangolo/fastapi
+edit_uri: ''
+plugins:
+- search
+- markdownextradata:
+ data: data
+nav:
+- FastAPI: index.md
+- Languages:
+ - en: /
+ - az: /az/
+ - de: /de/
+ - es: /es/
+ - fa: /fa/
+ - fr: /fr/
+ - he: /he/
+ - id: /id/
+ - it: /it/
+ - ja: /ja/
+ - ko: /ko/
+ - nl: /nl/
+ - pl: /pl/
+ - pt: /pt/
+ - ru: /ru/
+ - sq: /sq/
+ - sv: /sv/
+ - tr: /tr/
+ - uk: /uk/
+ - zh: /zh/
+markdown_extensions:
+- toc:
+ permalink: true
+- markdown.extensions.codehilite:
+ guess_lang: false
+- mdx_include:
+ base_path: docs
+- admonition
+- codehilite
+- extra
+- pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_code_format ''
+- pymdownx.tabbed:
+ alternate_style: true
+extra:
+ analytics:
+ provider: google
+ property: UA-133183413-1
+ social:
+ - icon: fontawesome/brands/github-alt
+ link: https://github.com/tiangolo/fastapi
+ - icon: fontawesome/brands/discord
+ link: https://discord.gg/VQjSZaeJmf
+ - icon: fontawesome/brands/twitter
+ link: https://twitter.com/fastapi
+ - icon: fontawesome/brands/linkedin
+ link: https://www.linkedin.com/in/tiangolo
+ - icon: fontawesome/brands/dev
+ link: https://dev.to/tiangolo
+ - icon: fontawesome/brands/medium
+ link: https://medium.com/@tiangolo
+ - icon: fontawesome/solid/globe
+ link: https://tiangolo.com
+ alternate:
+ - link: /
+ name: en - English
+ - link: /az/
+ name: az
+ - link: /de/
+ name: de
+ - link: /es/
+ name: es - español
+ - link: /fa/
+ name: fa
+ - link: /fr/
+ name: fr - français
+ - link: /he/
+ name: he
+ - link: /id/
+ name: id
+ - link: /it/
+ name: it - italiano
+ - link: /ja/
+ name: ja - 日本語
+ - link: /ko/
+ name: ko - 한국어
+ - link: /nl/
+ name: nl
+ - link: /pl/
+ name: pl
+ - link: /pt/
+ name: pt - português
+ - link: /ru/
+ name: ru - русский язык
+ - link: /sq/
+ name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
+ - link: /tr/
+ name: tr - Türkçe
+ - link: /uk/
+ name: uk - українська мова
+ - link: /zh/
+ name: zh - 汉语
+extra_css:
+- https://fastapi.tiangolo.com/css/termynal.css
+- https://fastapi.tiangolo.com/css/custom.css
+extra_javascript:
+- https://fastapi.tiangolo.com/js/termynal.js
+- https://fastapi.tiangolo.com/js/custom.js
diff --git a/docs/fa/overrides/.gitignore b/docs/fa/overrides/.gitignore
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs/fr/docs/alternatives.md b/docs/fr/docs/alternatives.md
index bf3e7bc3c..ee20438c3 100644
--- a/docs/fr/docs/alternatives.md
+++ b/docs/fr/docs/alternatives.md
@@ -133,7 +133,7 @@ permanents qui les rendent inadaptés.
### Marshmallow
-L'une des principales fonctionnalités nécessaires aux systèmes API est la "sérialisation" des données, qui consiste à prendre les données du code (Python) et à
les convertir en quelque chose qui peut être envoyé sur le réseau. Par exemple, convertir un objet contenant des
données provenant d'une base de données en un objet JSON. Convertir des objets `datetime` en strings, etc.
@@ -147,7 +147,7 @@ Sans un système de validation des données, vous devriez effectuer toutes les v
Ces fonctionnalités sont ce pourquoi Marshmallow a été construit. C'est une excellente bibliothèque, et je l'ai déjà beaucoup utilisée.
-Mais elle a été créée avant que les type hints n'existent en Python. Ainsi, pour définir chaque schéma, vous devez utiliser des utilitaires et des classes spécifiques fournies par Marshmallow.
!!! check "A inspiré **FastAPI** à"
@@ -155,7 +155,7 @@ Utilisez du code pour définir des "schémas" qui fournissent automatiquement le
### Webargs
-Une autre grande fonctionnalité requise par les API est le parsing des données provenant des requêtes entrantes.
Webargs est un outil qui a été créé pour fournir cela par-dessus plusieurs frameworks, dont Flask.
diff --git a/docs/fr/docs/async.md b/docs/fr/docs/async.md
index 20f4ee101..71c28b703 100644
--- a/docs/fr/docs/async.md
+++ b/docs/fr/docs/async.md
@@ -220,7 +220,7 @@ Et comme on peut avoir du parallélisme et de l'asynchronicité en même temps,
Nope ! C'est ça la morale de l'histoire.
La concurrence est différente du parallélisme. C'est mieux sur des scénarios **spécifiques** qui impliquent beaucoup d'attente. À cause de ça, c'est généralement bien meilleur que le parallélisme pour le développement d'applications web. Mais pas pour tout.
-
+
Donc pour équilibrer tout ça, imaginez l'histoire suivante :
> Vous devez nettoyer une grande et sale maison.
@@ -293,7 +293,7 @@ def get_sequential_burgers(number: int):
Avec `async def`, Python sait que dans cette fonction il doit prendre en compte les expressions `await`, et qu'il peut mettre en pause ⏸ l'exécution de la fonction pour aller faire autre chose 🔀 avant de revenir.
-Pour appeler une fonction définie avec `async def`, vous devez utiliser `await`. Donc ceci ne marche pas :
+Pour appeler une fonction définie avec `async def`, vous devez utiliser `await`. Donc ceci ne marche pas :
```Python
# Ceci ne fonctionne pas, car get_burgers a été défini avec async def
@@ -375,7 +375,7 @@ Au final, dans les deux situations, il est fort probable que **FastAPI** soit to
La même chose s'applique aux dépendances. Si une dépendance est définie avec `def` plutôt que `async def`, elle est exécutée dans la threadpool externe.
-### Sous-dépendances
+### Sous-dépendances
Vous pouvez avoir de multiples dépendances et sous-dépendances dépendant les unes des autres (en tant que paramètres de la définition de la *fonction de chemin*), certaines créées avec `async def` et d'autres avec `def`. Cela fonctionnerait aussi, et celles définies avec un simple `def` seraient exécutées sur un thread externe (venant de la threadpool) plutôt que d'être "attendues".
diff --git a/docs/fr/docs/deployment/docker.md b/docs/fr/docs/deployment/docker.md
index e4b59afbf..d2dcae722 100644
--- a/docs/fr/docs/deployment/docker.md
+++ b/docs/fr/docs/deployment/docker.md
@@ -118,7 +118,7 @@ $ docker run -d --name mycontainer -p 80:80 myimage
-Vous disposez maintenant d'un serveur FastAPI optimisé dans un conteneur Docker. Configuré automatiquement pour votre
+Vous disposez maintenant d'un serveur FastAPI optimisé dans un conteneur Docker. Configuré automatiquement pour votre
serveur actuel (et le nombre de cœurs du CPU).
## Vérifier
@@ -139,7 +139,7 @@ Vous verrez la documentation interactive automatique de l'API (fournie par http://192.168.99.100/redoc ou http://127.0.0.1/redoc (ou équivalent, en utilisant votre hôte Docker).
@@ -149,7 +149,7 @@ Vous verrez la documentation automatique alternative (fournie par Traefik est un reverse proxy/load balancer
+Traefik est un reverse proxy/load balancer
haute performance. Il peut faire office de "Proxy de terminaison TLS" (entre autres fonctionnalités).
Il est intégré à Let's Encrypt. Ainsi, il peut gérer toutes les parties HTTPS, y compris l'acquisition et le renouvellement des certificats.
@@ -164,7 +164,7 @@ Avec ces informations et ces outils, passez à la section suivante pour tout com
Vous pouvez avoir un cluster en mode Docker Swarm configuré en quelques minutes (environ 20 min) avec un processus Traefik principal gérant HTTPS (y compris l'acquisition et le renouvellement des certificats).
-En utilisant le mode Docker Swarm, vous pouvez commencer par un "cluster" d'une seule machine (il peut même s'agir
+En utilisant le mode Docker Swarm, vous pouvez commencer par un "cluster" d'une seule machine (il peut même s'agir
d'un serveur à 5 USD/mois) et ensuite vous pouvez vous développer autant que vous le souhaitez en ajoutant d'autres serveurs.
Pour configurer un cluster en mode Docker Swarm avec Traefik et la gestion de HTTPS, suivez ce guide :
diff --git a/docs/fr/docs/fastapi-people.md b/docs/fr/docs/fastapi-people.md
index 9ec2718c4..945f0794e 100644
--- a/docs/fr/docs/fastapi-people.md
+++ b/docs/fr/docs/fastapi-people.md
@@ -114,6 +114,8 @@ Ce sont les **Sponsors**. 😎
Ils soutiennent mon travail avec **FastAPI** (et d'autres) avec GitHub Sponsors.
+{% if sponsors %}
+
{% if sponsors.gold %}
### Gold Sponsors
@@ -141,6 +143,7 @@ Ils soutiennent mon travail avec **FastAPI** (et d'autres) avec IDE/linter/cerveau**:
* Parce que les structures de données de pydantic consistent seulement en une instance de classe que vous définissez; l'auto-complétion, le linting, mypy et votre intuition devrait être largement suffisante pour valider vos données.
* **Rapide**:
- * Dans les benchmarks Pydantic est plus rapide que toutes les autres librairies testées.
+ * Dans les benchmarks Pydantic est plus rapide que toutes les autres librairies testées.
* Valide les **structures complexes**:
* Utilise les modèles hiérarchique de Pydantic, le `typage` Python pour les `Lists`, `Dict`, etc.
* Et les validateurs permettent aux schémas de données complexes d'être clairement et facilement définis, validés et documentés sous forme d'un schéma JSON.
diff --git a/docs/fr/docs/index.md b/docs/fr/docs/index.md
index 40e6dfdff..f713ee96b 100644
--- a/docs/fr/docs/index.md
+++ b/docs/fr/docs/index.md
@@ -149,7 +149,7 @@ $ pip install uvicorn[standard]
* Create a file `main.py` with:
```Python
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -162,7 +162,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -172,7 +172,7 @@ def read_item(item_id: int, q: Optional[str] = None):
If your code uses `async` / `await`, use `async def`:
```Python hl_lines="9 14"
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -185,7 +185,7 @@ async def read_root():
@app.get("/items/{item_id}")
-async def read_item(item_id: int, q: Optional[str] = None):
+async def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -264,7 +264,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
Declare the body using standard Python types, thanks to Pydantic.
```Python hl_lines="4 9 10 11 12 25 26 27"
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
@@ -275,7 +275,7 @@ app = FastAPI()
class Item(BaseModel):
name: str
price: float
- is_offer: Optional[bool] = None
+ is_offer: Union[bool, None] = None
@app.get("/")
@@ -284,7 +284,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
@@ -321,7 +321,7 @@ And now, go to requests
- Required if you want to use the `TestClient`.
-* aiofiles
- Required if you want to use `FileResponse` or `StaticFiles`.
* jinja2
- Required if you want to use the default template configuration.
* python-multipart
- Required if you want to support form "parsing", with `request.form()`.
* itsdangerous
- Required for `SessionMiddleware` support.
@@ -464,4 +463,4 @@ You can install all of these with `pip install fastapi[all]`.
## License
-This project is licensed under the terms of the MIT license.
\ No newline at end of file
+This project is licensed under the terms of the MIT license.
diff --git a/docs/fr/docs/tutorial/background-tasks.md b/docs/fr/docs/tutorial/background-tasks.md
index 06ef93cd7..f7cf1a6cc 100644
--- a/docs/fr/docs/tutorial/background-tasks.md
+++ b/docs/fr/docs/tutorial/background-tasks.md
@@ -9,7 +9,7 @@ Cela comprend, par exemple :
* Les notifications par email envoyées après l'exécution d'une action :
* Étant donné que se connecter à un serveur et envoyer un email a tendance à être «lent» (plusieurs secondes), vous pouvez retourner la réponse directement et envoyer la notification en arrière-plan.
* Traiter des données :
- * Par exemple, si vous recevez un fichier qui doit passer par un traitement lent, vous pouvez retourner une réponse «Accepted» (HTTP 202) puis faire le traitement en arrière-plan.
+ * Par exemple, si vous recevez un fichier qui doit passer par un traitement lent, vous pouvez retourner une réponse «Accepted» (HTTP 202) puis faire le traitement en arrière-plan.
## Utiliser `BackgroundTasks`
@@ -73,7 +73,7 @@ La classe `BackgroundTasks` provient directement de Celery.
+Si vous avez besoin de réaliser des traitements lourds en tâche d'arrière-plan et que vous n'avez pas besoin que ces traitements aient lieu dans le même process (par exemple, pas besoin de partager la mémoire, les variables, etc.), il peut s'avérer profitable d'utiliser des outils plus importants tels que Celery.
Ces outils nécessitent généralement des configurations plus complexes ainsi qu'un gestionnaire de queue de message, comme RabbitMQ ou Redis, mais ils permettent d'exécuter des tâches d'arrière-plan dans différents process, et potentiellement, sur plusieurs serveurs.
diff --git a/docs/fr/docs/tutorial/body.md b/docs/fr/docs/tutorial/body.md
index c0953f49f..1e732d336 100644
--- a/docs/fr/docs/tutorial/body.md
+++ b/docs/fr/docs/tutorial/body.md
@@ -111,7 +111,7 @@ Mais vous auriez le même support de l'éditeur avec
!!! tip "Astuce"
- Si vous utilisez PyCharm comme éditeur, vous pouvez utiliser le Plugin PyCharm.
+ Si vous utilisez PyCharm comme éditeur, vous pouvez utiliser le Plugin Pydantic PyCharm Plugin.
Ce qui améliore le support pour les modèles Pydantic avec :
@@ -162,4 +162,4 @@ Les paramètres de la fonction seront reconnus comme tel :
## Sans Pydantic
-Si vous ne voulez pas utiliser des modèles Pydantic, vous pouvez aussi utiliser des paramètres de **Corps**. Pour cela, allez voir la partie de la documentation sur [Corps de la requête - Paramètres multiples](body-multiple-params.md){.internal-link target=_blank}.
\ No newline at end of file
+Si vous ne voulez pas utiliser des modèles Pydantic, vous pouvez aussi utiliser des paramètres de **Corps**. Pour cela, allez voir la partie de la documentation sur [Corps de la requête - Paramètres multiples](body-multiple-params.md){.internal-link target=_blank}.
diff --git a/docs/fr/docs/tutorial/first-steps.md b/docs/fr/docs/tutorial/first-steps.md
index 3a81362f6..224c340c6 100644
--- a/docs/fr/docs/tutorial/first-steps.md
+++ b/docs/fr/docs/tutorial/first-steps.md
@@ -280,7 +280,7 @@ Tout comme celles les plus exotiques :
**FastAPI** n'impose pas de sens spécifique à chacune d'elle.
- Les informations qui sont présentées ici forment une directive générale, pas des obligations.
+ Les informations qui sont présentées ici forment une directive générale, pas des obligations.
Par exemple, quand l'on utilise **GraphQL**, toutes les actions sont effectuées en utilisant uniquement des opérations `POST`.
diff --git a/docs/fr/docs/tutorial/path-params.md b/docs/fr/docs/tutorial/path-params.md
index 58f53e008..894d62dd4 100644
--- a/docs/fr/docs/tutorial/path-params.md
+++ b/docs/fr/docs/tutorial/path-params.md
@@ -8,7 +8,7 @@ Vous pouvez déclarer des "paramètres" ou "variables" de chemin avec la même s
{!../../../docs_src/path_params/tutorial001.py!}
```
-La valeur du paramètre `item_id` sera transmise à la fonction dans l'argument `item_id`.
+La valeur du paramètre `item_id` sera transmise à la fonction dans l'argument `item_id`.
Donc, si vous exécutez cet exemple et allez sur http://127.0.0.1:8000/items/foo,
vous verrez comme réponse :
@@ -44,7 +44,7 @@ Si vous exécutez cet exemple et allez sur "parsing" automatique.
## Validation de données
@@ -91,7 +91,7 @@ documentation générée automatiquement et interactive :
On voit bien dans la documentation que `item_id` est déclaré comme entier.
-## Les avantages d'avoir une documentation basée sur une norme, et la documentation alternative.
+## Les avantages d'avoir une documentation basée sur une norme, et la documentation alternative.
Le schéma généré suivant la norme OpenAPI,
il existe de nombreux outils compatibles.
@@ -102,7 +102,7 @@ sur
De la même façon, il existe bien d'autres outils compatibles, y compris des outils de génération de code
-pour de nombreux langages.
+pour de nombreux langages.
## Pydantic
diff --git a/docs/fr/docs/tutorial/query-params.md b/docs/fr/docs/tutorial/query-params.md
index f1f2a605d..7bf3b9e79 100644
--- a/docs/fr/docs/tutorial/query-params.md
+++ b/docs/fr/docs/tutorial/query-params.md
@@ -6,7 +6,7 @@ Quand vous déclarez des paramètres dans votre fonction de chemin qui ne font p
{!../../../docs_src/query_params/tutorial001.py!}
```
-La partie appelée requête (ou **query**) dans une URL est l'ensemble des paires clés-valeurs placées après le `?` , séparées par des `&`.
+La partie appelée requête (ou **query**) dans une URL est l'ensemble des paires clés-valeurs placées après le `?` , séparées par des `&`.
Par exemple, dans l'URL :
@@ -120,7 +120,7 @@ ou n'importe quelle autre variation de casse (tout en majuscules, uniquement la
## Multiples paramètres de chemin et de requête
-Vous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête dans la même fonction, **FastAPI** saura comment les gérer.
+Vous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête dans la même fonction, **FastAPI** saura comment les gérer.
Et vous n'avez pas besoin de les déclarer dans un ordre spécifique.
diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml
index ff16e1d78..f790c0299 100644
--- a/docs/fr/mkdocs.yml
+++ b/docs/fr/mkdocs.yml
@@ -5,13 +5,15 @@ theme:
name: material
custom_dir: overrides
palette:
- - scheme: default
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
primary: teal
accent: amber
toggle:
icon: material/lightbulb
name: Switch to light mode
- - scheme: slate
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
primary: teal
accent: amber
toggle:
@@ -40,15 +42,19 @@ nav:
- az: /az/
- de: /de/
- es: /es/
+ - fa: /fa/
- fr: /fr/
+ - he: /he/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
+ - sv: /sv/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -112,8 +118,12 @@ extra:
name: de
- link: /es/
name: es - español
+ - link: /fa/
+ name: fa
- link: /fr/
name: fr - français
+ - link: /he/
+ name: he
- link: /id/
name: id
- link: /it/
@@ -122,6 +132,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /nl/
+ name: nl
- link: /pl/
name: pl
- link: /pt/
@@ -130,6 +142,8 @@ extra:
name: ru - русский язык
- link: /sq/
name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/he/docs/index.md b/docs/he/docs/index.md
new file mode 100644
index 000000000..fa63d8cb7
--- /dev/null
+++ b/docs/he/docs/index.md
@@ -0,0 +1,464 @@
+
+
+{% endfor -%}
+{%- for sponsor in sponsors.silver -%}
+
+{% endfor %}
+{% endif %}
+
+
+
+נותני חסות אחרים
+
+## דעות
+
+"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._"
+
+
async def
...uvicorn main:app --reload
...app = FastAPI()
.
+- --reload
: גרמו לשרת להתאתחל לאחר שינויים בקוד. עשו זאת רק בסביבת פיתוח.
+
+/items/{item_id}
.
+- שני ה _נתיבים_ מקבלים _בקשות_ `GET` (ידועות גם כ*מתודות* HTTP).
+- ה _נתיב_ /items/{item_id}
כולל \*פרמטר נתיב\_ `item_id` שאמור להיות `int`.
+- ה _נתיב_ /items/{item_id}
\*פרמטר שאילתא\_ אופציונלי `q`.
+
+### תיעוד API אינטרקטיבי
+
+כעת פנו לכתובת http://127.0.0.1:8000/docs.
+
+אתם תראו את התיעוד האוטומטי (מסופק על ידי Swagger UI):
+
+
+
+### תיעוד אלטרנטיבי
+
+כעת פנו לכתובת http://127.0.0.1:8000/redoc.
+
+אתם תראו תיעוד אלטרנטיבי (מסופק על ידי ReDoc):
+
+
+
+## שדרוג לדוגמא
+
+כעת ערכו את הקובץ `main.py` כך שיוכל לקבל גוף מבקשת `PUT`.
+
+הגדירו את הגוף בעזרת רמזי טיפוסים סטנדרטיים, הודות ל - `Pydantic`.
+
+```Python hl_lines="4 9-12 25-27"
+from typing import Union
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ price: float
+ is_offer: Union[bool, None] = None
+
+
+@app.get("/")
+def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+def read_item(item_id: int, q: Union[str, None] = None):
+ return {"item_id": item_id, "q": q}
+
+
+@app.put("/items/{item_id}")
+def update_item(item_id: int, item: Item):
+ return {"item_name": item.name, "item_id": item_id}
+```
+
+השרת אמול להתאתחל אוטומטית (מאחר והוספתם --reload
לפקודת `uvicorn` שלמעלה).
+
+### שדרוג התיעוד האינטרקטיבי
+
+כעת פנו לכתובת http://127.0.0.1:8000/docs.
+
+- התיעוד האוטומטי יתעדכן, כולל הגוף החדש:
+
+
+
+- לחצו על הכפתור "Try it out", הוא יאפשר לכם למלא את הפרמטרים ולעבוד ישירות מול ה - API.
+
+
+
+- אחר כך לחצו על הכפתור "Execute", האתר יתקשר עם ה - API שלכם, ישלח את הפרמטרים, ישיג את התוצאות ואז יראה אותן על המסך:
+
+
+
+### שדרוג התיעוד האלטרנטיבי
+
+כעת פנו לכתובת http://127.0.0.1:8000/redoc.
+
+- התיעוד האלטרנטיבי גם יראה את פרמטר השאילתא והגוף החדשים.
+
+
+
+### סיכום
+
+לסיכום, אתם מכריזים ** פעם אחת** על טיפוסי הפרמטרים, גוף וכו' כפרמטרים לפונקציה.
+
+אתם עושים את זה עם טיפוסי פייתון מודרניים.
+
+אתם לא צריכים ללמוד תחביר חדש, מתודות או מחלקות של ספרייה ספיציפית, וכו'
+
+רק **פייתון 3.6+** סטנדרטי.
+
+לדוגמא, ל - `int`:
+
+```Python
+item_id: int
+```
+
+או למודל `Item` מורכב יותר:
+
+```Python
+item: Item
+```
+
+...ועם הכרזת הטיפוס האחת הזו אתם מקבלים:
+
+- תמיכת עורך, כולל:
+ - השלמות.
+ - בדיקת טיפוסים.
+- אימות מידע:
+ - שגיאות ברורות ואטומטיות כאשר מוכנס מידע לא חוקי .
+ - אימות אפילו לאובייקטי JSON מקוננים.
+- המרה של מידע קלט: המרה של מידע שמגיע מהרשת למידע וטיפוסים של פייתון. קורא מ:
+ - JSON.
+ - פרמטרי נתיב.
+ - פרמטרי שאילתא.
+ - עוגיות.
+ - כותרות.
+ - טפסים.
+ - קבצים.
+- המרה של מידע פלט: המרה של מידע וטיפוסים מפייתון למידע רשת (כ - JSON):
+ - המירו טיפוסי פייתון (`str`, `int`, `float`, `bool`, `list`, etc).
+ - עצמי `datetime`.
+ - עצמי `UUID`.
+ - מודלי בסיסי נתונים.
+ - ...ורבים אחרים.
+- תיעוד API אוטומטי ואינטרקטיבית כולל שתי אלטרנטיבות לממשק המשתמש:
+ - Swagger UI.
+ - ReDoc.
+
+---
+
+בחזרה לדוגמאת הקוד הקודמת, **FastAPI** ידאג:
+
+- לאמת שיש `item_id` בנתיב בבקשות `GET` ו - `PUT`.
+- לאמת שה - `item_id` הוא מטיפוס `int` בבקשות `GET` ו - `PUT`.
+ - אם הוא לא, הלקוח יראה שגיאה ברורה ושימושית.
+- לבדוק האם קיים פרמטר שאילתא בשם `q` (קרי `http://127.0.0.1:8000/items/foo?q=somequery`) לבקשות `GET`.
+ - מאחר והפרמטר `q` מוגדר עם = None
, הוא אופציונלי.
+ - לולא ה - `None` הוא היה חובה (כמו הגוף במקרה של `PUT`).
+- לבקשות `PUT` לנתיב /items/{item_id}
, לקרוא את גוף הבקשה כ - JSON:
+ - לאמת שהוא כולל את מאפיין החובה `name` שאמור להיות מטיפוס `str`.
+ - לאמת שהוא כולל את מאפיין החובה `price` שחייב להיות מטיפוס `float`.
+ - לבדוק האם הוא כולל את מאפיין הרשות `is_offer` שאמור להיות מטיפוס `bool`, אם הוא נמצא.
+ - כל זה יעבוד גם לאובייקט JSON מקונן.
+- להמיר מ - JSON ול- JSON אוטומטית.
+- לתעד הכל באמצעות OpenAPI, תיעוד שבו יוכלו להשתמש:
+ - מערכות תיעוד אינטרקטיביות.
+ - מערכות ייצור קוד אוטומטיות, להרבה שפות.
+- לספק ישירות שתי מערכות תיעוד רשתיות.
+
+---
+
+רק גרדנו את קצה הקרחון, אבל כבר יש לכם רעיון של איך הכל עובד.
+
+נסו לשנות את השורה:
+
+```Python
+ return {"item_name": item.name, "item_id": item_id}
+```
+
+...מ:
+
+```Python
+ ... "item_name": item.name ...
+```
+
+...ל:
+
+```Python
+ ... "item_price": item.price ...
+```
+
+...וראו איך העורך שלכם משלים את המאפיינים ויודע את הטיפוסים שלהם:
+
+
+
+לדוגמא יותר שלמה שכוללת עוד תכונות, ראו את המדריך - למשתמש.
+
+**התראת ספוילרים**: המדריך - למשתמש כולל:
+
+- הכרזה על **פרמטרים** ממקורות אחרים ושונים כגון: **כותרות**, **עוגיות**, **טפסים** ו - **קבצים**.
+- איך לקבוע **מגבלות אימות** בעזרת `maximum_length` או `regex`.
+- דרך חזקה וקלה להשתמש ב**הזרקת תלויות**.
+- אבטחה והתאמתות, כולל תמיכה ב - **OAuth2** עם **JWT** והתאמתות **HTTP Basic**.
+- טכניקות מתקדמות (אבל קלות באותה מידה) להכרזת אובייקטי JSON מקוננים (תודות ל - Pydantic).
+- אינטרקציה עם **GraphQL** דרך Strawberry וספריות אחרות.
+- תכונות נוספות רבות (תודות ל - Starlette) כגון:
+ - **WebSockets**
+ - בדיקות קלות במיוחד מבוססות על `requests` ו - `pytest`
+ - **CORS**
+ - **Cookie Sessions**
+ - ...ועוד.
+
+## ביצועים
+
+בדיקות עצמאיות של TechEmpower הראו שאפליקציות **FastAPI** שרצות תחת Uvicorn הן מתשתיות הפייתון המהירות ביותר, רק מתחת ל - Starlette ו - Uvicorn עצמן (ש - FastAPI מבוססת עליהן). (\*)
+
+כדי להבין עוד על הנושא, ראו את הפרק Benchmarks.
+
+## תלויות אופציונליות
+
+בשימוש Pydantic:
+
+- ujson
- "פרסור" JSON.
+- email_validator
- לאימות כתובות אימייל.
+
+בשימוש Starlette:
+
+- requests
- דרוש אם ברצונכם להשתמש ב - `TestClient`.
+- jinja2
- דרוש אם ברצונכם להשתמש בברירת המחדל של תצורת הטמפלייטים.
+- python-multipart
- דרוש אם ברצונכם לתמוך ב "פרסור" טפסים, באצמעות request.form()
.
+- itsdangerous
- דרוש אם ברצונכם להשתמש ב - `SessionMiddleware`.
+- pyyaml
- דרוש אם ברצונכם להשתמש ב - `SchemaGenerator` של Starlette (כנראה שאתם לא צריכים את זה עם FastAPI).
+- ujson
- דרוש אם ברצונכם להשתמש ב - `UJSONResponse`.
+
+בשימוש FastAPI / Starlette:
+
+- uvicorn
- לשרת שטוען ומגיש את האפליקציה שלכם.
+- orjson
- דרוש אם ברצונכם להשתמש ב - `ORJSONResponse`.
+
+תוכלו להתקין את כל אלו באמצעות pip install "fastapi[all]"
.
+
+## רשיון
+
+הפרויקט הזה הוא תחת התנאים של רשיון MIT.
diff --git a/docs/he/mkdocs.yml b/docs/he/mkdocs.yml
new file mode 100644
index 000000000..532cc5cab
--- /dev/null
+++ b/docs/he/mkdocs.yml
@@ -0,0 +1,143 @@
+site_name: FastAPI
+site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
+site_url: https://fastapi.tiangolo.com/he/
+theme:
+ name: material
+ custom_dir: overrides
+ palette:
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb
+ name: Switch to light mode
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb-outline
+ name: Switch to dark mode
+ features:
+ - search.suggest
+ - search.highlight
+ - content.tabs.link
+ icon:
+ repo: fontawesome/brands/github-alt
+ logo: https://fastapi.tiangolo.com/img/icon-white.svg
+ favicon: https://fastapi.tiangolo.com/img/favicon.png
+ language: he
+repo_name: tiangolo/fastapi
+repo_url: https://github.com/tiangolo/fastapi
+edit_uri: ''
+plugins:
+- search
+- markdownextradata:
+ data: data
+nav:
+- FastAPI: index.md
+- Languages:
+ - en: /
+ - az: /az/
+ - de: /de/
+ - es: /es/
+ - fa: /fa/
+ - fr: /fr/
+ - he: /he/
+ - id: /id/
+ - it: /it/
+ - ja: /ja/
+ - ko: /ko/
+ - nl: /nl/
+ - pl: /pl/
+ - pt: /pt/
+ - ru: /ru/
+ - sq: /sq/
+ - sv: /sv/
+ - tr: /tr/
+ - uk: /uk/
+ - zh: /zh/
+markdown_extensions:
+- toc:
+ permalink: true
+- markdown.extensions.codehilite:
+ guess_lang: false
+- mdx_include:
+ base_path: docs
+- admonition
+- codehilite
+- extra
+- pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_code_format ''
+- pymdownx.tabbed:
+ alternate_style: true
+extra:
+ analytics:
+ provider: google
+ property: UA-133183413-1
+ social:
+ - icon: fontawesome/brands/github-alt
+ link: https://github.com/tiangolo/fastapi
+ - icon: fontawesome/brands/discord
+ link: https://discord.gg/VQjSZaeJmf
+ - icon: fontawesome/brands/twitter
+ link: https://twitter.com/fastapi
+ - icon: fontawesome/brands/linkedin
+ link: https://www.linkedin.com/in/tiangolo
+ - icon: fontawesome/brands/dev
+ link: https://dev.to/tiangolo
+ - icon: fontawesome/brands/medium
+ link: https://medium.com/@tiangolo
+ - icon: fontawesome/solid/globe
+ link: https://tiangolo.com
+ alternate:
+ - link: /
+ name: en - English
+ - link: /az/
+ name: az
+ - link: /de/
+ name: de
+ - link: /es/
+ name: es - español
+ - link: /fa/
+ name: fa
+ - link: /fr/
+ name: fr - français
+ - link: /he/
+ name: he
+ - link: /id/
+ name: id
+ - link: /it/
+ name: it - italiano
+ - link: /ja/
+ name: ja - 日本語
+ - link: /ko/
+ name: ko - 한국어
+ - link: /nl/
+ name: nl
+ - link: /pl/
+ name: pl
+ - link: /pt/
+ name: pt - português
+ - link: /ru/
+ name: ru - русский язык
+ - link: /sq/
+ name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
+ - link: /tr/
+ name: tr - Türkçe
+ - link: /uk/
+ name: uk - українська мова
+ - link: /zh/
+ name: zh - 汉语
+extra_css:
+- https://fastapi.tiangolo.com/css/termynal.css
+- https://fastapi.tiangolo.com/css/custom.css
+extra_javascript:
+- https://fastapi.tiangolo.com/js/termynal.js
+- https://fastapi.tiangolo.com/js/custom.js
diff --git a/docs/he/overrides/.gitignore b/docs/he/overrides/.gitignore
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs/id/docs/index.md b/docs/id/docs/index.md
index 95fb7ae21..0bb7b55e3 100644
--- a/docs/id/docs/index.md
+++ b/docs/id/docs/index.md
@@ -321,7 +321,7 @@ And now, go to requests
- Required if you want to use the `TestClient`.
-* aiofiles
- Required if you want to use `FileResponse` or `StaticFiles`.
* jinja2
- Required if you want to use the default template configuration.
* python-multipart
- Required if you want to support form "parsing", with `request.form()`.
* itsdangerous
- Required for `SessionMiddleware` support.
diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml
index d70d2b3c3..697ecd4cb 100644
--- a/docs/id/mkdocs.yml
+++ b/docs/id/mkdocs.yml
@@ -5,13 +5,15 @@ theme:
name: material
custom_dir: overrides
palette:
- - scheme: default
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
primary: teal
accent: amber
toggle:
icon: material/lightbulb
name: Switch to light mode
- - scheme: slate
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
primary: teal
accent: amber
toggle:
@@ -40,15 +42,19 @@ nav:
- az: /az/
- de: /de/
- es: /es/
+ - fa: /fa/
- fr: /fr/
+ - he: /he/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
+ - sv: /sv/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -97,8 +103,12 @@ extra:
name: de
- link: /es/
name: es - español
+ - link: /fa/
+ name: fa
- link: /fr/
name: fr - français
+ - link: /he/
+ name: he
- link: /id/
name: id
- link: /it/
@@ -107,6 +117,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /nl/
+ name: nl
- link: /pl/
name: pl
- link: /pt/
@@ -115,6 +127,8 @@ extra:
name: ru - русский язык
- link: /sq/
name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/it/docs/index.md b/docs/it/docs/index.md
index c52f07e59..6acf92552 100644
--- a/docs/it/docs/index.md
+++ b/docs/it/docs/index.md
@@ -318,7 +318,7 @@ And now, go to requests
- Required if you want to use the `TestClient`.
-* aiofiles
- Required if you want to use `FileResponse` or `StaticFiles`.
* jinja2
- Required if you want to use the default template configuration.
* python-multipart
- Required if you want to support form "parsing", with `request.form()`.
* itsdangerous
- Required for `SessionMiddleware` support.
diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml
index e6d01fbde..1f1d0016d 100644
--- a/docs/it/mkdocs.yml
+++ b/docs/it/mkdocs.yml
@@ -5,13 +5,15 @@ theme:
name: material
custom_dir: overrides
palette:
- - scheme: default
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
primary: teal
accent: amber
toggle:
icon: material/lightbulb
name: Switch to light mode
- - scheme: slate
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
primary: teal
accent: amber
toggle:
@@ -40,15 +42,19 @@ nav:
- az: /az/
- de: /de/
- es: /es/
+ - fa: /fa/
- fr: /fr/
+ - he: /he/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
+ - sv: /sv/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -97,8 +103,12 @@ extra:
name: de
- link: /es/
name: es - español
+ - link: /fa/
+ name: fa
- link: /fr/
name: fr - français
+ - link: /he/
+ name: he
- link: /id/
name: id
- link: /it/
@@ -107,6 +117,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /nl/
+ name: nl
- link: /pl/
name: pl
- link: /pt/
@@ -115,6 +127,8 @@ extra:
name: ru - русский язык
- link: /sq/
name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/ja/docs/advanced/additional-status-codes.md b/docs/ja/docs/advanced/additional-status-codes.md
index 6c03cd92b..d1f8e6451 100644
--- a/docs/ja/docs/advanced/additional-status-codes.md
+++ b/docs/ja/docs/advanced/additional-status-codes.md
@@ -14,7 +14,7 @@
これを達成するには、 `JSONResponse` をインポートし、 `status_code` を設定して直接内容を返します。
-```Python hl_lines="4 23"
+```Python hl_lines="4 25"
{!../../../docs_src/additional_status_codes/tutorial001.py!}
```
diff --git a/docs/ja/docs/advanced/conditional-openapi.md b/docs/ja/docs/advanced/conditional-openapi.md
new file mode 100644
index 000000000..b892ed6c6
--- /dev/null
+++ b/docs/ja/docs/advanced/conditional-openapi.md
@@ -0,0 +1,58 @@
+# 条件付き OpenAPI
+
+必要であれば、設定と環境変数を利用して、環境に応じて条件付きでOpenAPIを構成することが可能です。また、完全にOpenAPIを無効にすることもできます。
+
+## セキュリティとAPI、およびドキュメントについて
+
+本番環境においてドキュメントのUIを非表示にすることによって、APIを保護しようと *すべきではありません*。
+
+それは、APIのセキュリティの強化にはならず、*path operations* は依然として利用可能です。
+
+もしセキュリティ上の欠陥がソースコードにあるならば、それは存在したままです。
+
+ドキュメンテーションを非表示にするのは、単にあなたのAPIへのアクセス方法を難解にするだけでなく、同時にあなた自身の本番環境でのAPIのデバッグを困難にしてしまう可能性があります。単純に、 Security through obscurity の一つの形態として考えられるでしょう。
+
+もしあなたのAPIのセキュリティを強化したいなら、いくつかのよりよい方法があります。例を示すと、
+
+* リクエストボディとレスポンスのためのPydanticモデルの定義を見直す。
+* 依存関係に基づきすべての必要なパーミッションとロールを設定する。
+* パスワードを絶対に平文で保存しない。パスワードハッシュのみを保存する。
+* PasslibやJWTトークンに代表される、よく知られた暗号化ツールを使って実装する。
+* そして必要なところでは、もっと細かいパーミッション制御をOAuth2スコープを使って行う。
+* など
+
+それでも、例えば本番環境のような特定の環境のみで、あるいは環境変数の設定によってAPIドキュメントをどうしても無効にしたいという、非常に特殊なユースケースがあるかもしれません。
+
+## 設定と環境変数による条件付き OpenAPI
+
+生成するOpenAPIとドキュメントUIの構成は、共通のPydanticの設定を使用して簡単に切り替えられます。
+
+例えば、
+
+```Python hl_lines="6 11"
+{!../../../docs_src/conditional_openapi/tutorial001.py!}
+```
+
+ここでは `openapi_url` の設定を、デフォルトの `"/openapi.json"` のまま宣言しています。
+
+そして、これを `FastAPI` appを作る際に使います。
+
+それから、以下のように `OPENAPI_URL` という環境変数を空文字列に設定することによってOpenAPI (UIドキュメントを含む) を無効化することができます。
+
+POST
のウェブドキュメントを参照してください。
!!! warning "注意"
diff --git a/docs/ja/docs/tutorial/static-files.md b/docs/ja/docs/tutorial/static-files.md
index fcc3ba924..1d9c434c3 100644
--- a/docs/ja/docs/tutorial/static-files.md
+++ b/docs/ja/docs/tutorial/static-files.md
@@ -2,20 +2,6 @@
`StaticFiles` を使用して、ディレクトリから静的ファイルを自動的に提供できます。
-## `aiofiles` をインストール
-
-まず、`aiofiles` をインストールする必要があります:
-
-requests
- `TestClient`를 사용하려면 필요.
-* aiofiles
- `FileResponse` 또는 `StaticFiles`를 사용하려면 필요.
* jinja2
- 기본 템플릿 설정을 사용하려면 필요.
* python-multipart
- `request.form()`과 함께 "parsing"의 지원을 원하면 필요.
* itsdangerous
- `SessionMiddleware` 지원을 위해 필요.
diff --git a/docs/ko/docs/tutorial/header-params.md b/docs/ko/docs/tutorial/header-params.md
index 1c46b32ba..484554e97 100644
--- a/docs/ko/docs/tutorial/header-params.md
+++ b/docs/ko/docs/tutorial/header-params.md
@@ -57,7 +57,7 @@
타입 정의에서 리스트를 사용하여 이러한 케이스를 정의할 수 있습니다.
-중복 헤더의 모든 값을 파이썬 `list`로 수신합니다.
+중복 헤더의 모든 값을 파이썬 `list`로 수신합니다.
예를 들어, 두 번 이상 나타날 수 있는 `X-Token`헤더를 선언하려면, 다음과 같이 작성합니다:
diff --git a/docs/ko/docs/tutorial/path-params-numeric-validations.md b/docs/ko/docs/tutorial/path-params-numeric-validations.md
index abb9d03db..cadf543fc 100644
--- a/docs/ko/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/ko/docs/tutorial/path-params-numeric-validations.md
@@ -43,7 +43,7 @@
따라서 함수를 다음과 같이 선언 할 수 있습니다:
-```Python hl_lines="8"
+```Python hl_lines="7"
{!../../../docs_src/path_params_numeric_validations/tutorial002.py!}
```
@@ -55,7 +55,7 @@
파이썬은 `*`으로 아무런 행동도 하지 않지만, 따르는 매개변수들은 kwargs
로도 알려진 키워드 인자(키-값 쌍)여야 함을 인지합니다. 기본값을 가지고 있지 않더라도 그렇습니다.
-```Python hl_lines="8"
+```Python hl_lines="7"
{!../../../docs_src/path_params_numeric_validations/tutorial003.py!}
```
diff --git a/docs/ko/docs/tutorial/path-params.md b/docs/ko/docs/tutorial/path-params.md
index ede63f69d..5cf397e7a 100644
--- a/docs/ko/docs/tutorial/path-params.md
+++ b/docs/ko/docs/tutorial/path-params.md
@@ -241,4 +241,4 @@ Starlette에서 직접 옵션을 사용하면 다음과 같은 URL을 사용하
위 사항들을 그저 한번에 선언하면 됩니다.
-이는 (원래 성능과는 별개로) 대체 프레임워크와 비교했을 때 **FastAPI**의 주요 가시적 장점일 것입니다.
\ No newline at end of file
+이는 (원래 성능과는 별개로) 대체 프레임워크와 비교했을 때 **FastAPI**의 주요 가시적 장점일 것입니다.
diff --git a/docs/ko/docs/tutorial/query-params.md b/docs/ko/docs/tutorial/query-params.md
index 05f2ff9c9..bb631e6ff 100644
--- a/docs/ko/docs/tutorial/query-params.md
+++ b/docs/ko/docs/tutorial/query-params.md
@@ -75,7 +75,7 @@ http://127.0.0.1:8000/items/?skip=20
!!! note "참고"
FastAPI는 `q`가 `= None`이므로 선택적이라는 것을 인지합니다.
- `Optional[str]`에 있는 `Optional`은 FastAPI(FastAPI는 `str` 부분만 사용합니다)가 사용하는게 아니지만, `Optional[str]`은 편집기에게 코드에서 오류를 찾아낼 수 있게 도와줍니다.
+ `Union[str, None]`에 있는 `Union`은 FastAPI(FastAPI는 `str` 부분만 사용합니다)가 사용하는게 아니지만, `Union[str, None]`은 편집기에게 코드에서 오류를 찾아낼 수 있게 도와줍니다.
## 쿼리 매개변수 형변환
diff --git a/docs/ko/docs/tutorial/request-files.md b/docs/ko/docs/tutorial/request-files.md
index 769a676cd..decefe981 100644
--- a/docs/ko/docs/tutorial/request-files.md
+++ b/docs/ko/docs/tutorial/request-files.md
@@ -13,7 +13,7 @@
`fastapi` 에서 `File` 과 `UploadFile` 을 임포트 합니다:
-```Python hl_lines="1"
+```Python hl_lines="1"
{!../../../docs_src/request_files/tutorial001.py!}
```
@@ -21,7 +21,7 @@
`Body` 및 `Form` 과 동일한 방식으로 파일의 매개변수를 생성합니다:
-```Python hl_lines="7"
+```Python hl_lines="7"
{!../../../docs_src/request_files/tutorial001.py!}
```
@@ -45,7 +45,7 @@
`File` 매개변수를 `UploadFile` 타입으로 정의합니다:
-```Python hl_lines="12"
+```Python hl_lines="12"
{!../../../docs_src/request_files/tutorial001.py!}
```
@@ -97,7 +97,7 @@ contents = myfile.file.read()
## "폼 데이터"란
-HTML의 폼들(``)이 서버에 데이터를 전송하는 방식은 대개 데이터에 JSON과는 다른 "특별한" 인코딩을 사용합니다.
+HTML의 폼들(``)이 서버에 데이터를 전송하는 방식은 대개 데이터에 JSON과는 다른 "특별한" 인코딩을 사용합니다.
**FastAPI**는 JSON 대신 올바른 위치에서 데이터를 읽을 수 있도록 합니다.
@@ -121,7 +121,7 @@ HTML의 폼들(``)이 서버에 데이터를 전송하는 방식은
이 기능을 사용하기 위해 , `bytes` 의 `List` 또는 `UploadFile` 를 선언하기 바랍니다:
-```Python hl_lines="10 15"
+```Python hl_lines="10 15"
{!../../../docs_src/request_files/tutorial002.py!}
```
diff --git a/docs/ko/docs/tutorial/request-forms-and-files.md b/docs/ko/docs/tutorial/request-forms-and-files.md
index 6750c7b23..ddf232e7f 100644
--- a/docs/ko/docs/tutorial/request-forms-and-files.md
+++ b/docs/ko/docs/tutorial/request-forms-and-files.md
@@ -9,7 +9,7 @@
## `File` 및 `Form` 업로드
-```Python hl_lines="1"
+```Python hl_lines="1"
{!../../../docs_src/request_forms_and_files/tutorial001.py!}
```
@@ -17,7 +17,7 @@
`Body` 및 `Query`와 동일한 방식으로 파일과 폼의 매개변수를 생성합니다:
-```Python hl_lines="8"
+```Python hl_lines="8"
{!../../../docs_src/request_forms_and_files/tutorial001.py!}
```
diff --git a/docs/ko/docs/tutorial/response-status-code.md b/docs/ko/docs/tutorial/response-status-code.md
index d201867a1..f92c057be 100644
--- a/docs/ko/docs/tutorial/response-status-code.md
+++ b/docs/ko/docs/tutorial/response-status-code.md
@@ -8,11 +8,11 @@
* `@app.delete()`
* 기타
-```Python hl_lines="6"
+```Python hl_lines="6"
{!../../../docs_src/response_status_code/tutorial001.py!}
```
-!!! note "참고"
+!!! note "참고"
`status_code` 는 "데코레이터" 메소드(`get`, `post` 등)의 매개변수입니다. 모든 매개변수들과 본문처럼 *경로 작동 함수*가 아닙니다.
`status_code` 매개변수는 HTTP 상태 코드를 숫자로 입력받습니다.
@@ -27,7 +27,7 @@
+ FastAPI framework, high performance, easy to learn, fast to code, ready for production +
+ + +--- + +**Documentation**: https://fastapi.tiangolo.com + +**Source Code**: https://github.com/tiangolo/fastapi + +--- + +FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. + +The key features are: + +* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). + +* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * +* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * +* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. +* **Easy**: Designed to be easy to use and learn. Less time reading docs. +* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. +* **Robust**: Get production-ready code. With automatic interactive documentation. +* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. + +* estimation based on tests on an internal development team, building production applications. + +## Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} +async def
...uvicorn main:app --reload
...ujson
- for faster JSON "parsing".
+* email_validator
- for email validation.
+
+Used by Starlette:
+
+* requests
- Required if you want to use the `TestClient`.
+* jinja2
- Required if you want to use the default template configuration.
+* python-multipart
- Required if you want to support form "parsing", with `request.form()`.
+* itsdangerous
- Required for `SessionMiddleware` support.
+* pyyaml
- Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
+* ujson
- Required if you want to use `UJSONResponse`.
+
+Used by FastAPI / Starlette:
+
+* uvicorn
- for the server that loads and serves your application.
+* orjson
- Required if you want to use `ORJSONResponse`.
+
+You can install all of these with `pip install "fastapi[all]"`.
+
+## License
+
+This project is licensed under the terms of the MIT license.
diff --git a/docs/nl/mkdocs.yml b/docs/nl/mkdocs.yml
new file mode 100644
index 000000000..8831571dd
--- /dev/null
+++ b/docs/nl/mkdocs.yml
@@ -0,0 +1,143 @@
+site_name: FastAPI
+site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
+site_url: https://fastapi.tiangolo.com/nl/
+theme:
+ name: material
+ custom_dir: overrides
+ palette:
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb
+ name: Switch to light mode
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb-outline
+ name: Switch to dark mode
+ features:
+ - search.suggest
+ - search.highlight
+ - content.tabs.link
+ icon:
+ repo: fontawesome/brands/github-alt
+ logo: https://fastapi.tiangolo.com/img/icon-white.svg
+ favicon: https://fastapi.tiangolo.com/img/favicon.png
+ language: nl
+repo_name: tiangolo/fastapi
+repo_url: https://github.com/tiangolo/fastapi
+edit_uri: ''
+plugins:
+- search
+- markdownextradata:
+ data: data
+nav:
+- FastAPI: index.md
+- Languages:
+ - en: /
+ - az: /az/
+ - de: /de/
+ - es: /es/
+ - fa: /fa/
+ - fr: /fr/
+ - he: /he/
+ - id: /id/
+ - it: /it/
+ - ja: /ja/
+ - ko: /ko/
+ - nl: /nl/
+ - pl: /pl/
+ - pt: /pt/
+ - ru: /ru/
+ - sq: /sq/
+ - sv: /sv/
+ - tr: /tr/
+ - uk: /uk/
+ - zh: /zh/
+markdown_extensions:
+- toc:
+ permalink: true
+- markdown.extensions.codehilite:
+ guess_lang: false
+- mdx_include:
+ base_path: docs
+- admonition
+- codehilite
+- extra
+- pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_code_format ''
+- pymdownx.tabbed:
+ alternate_style: true
+extra:
+ analytics:
+ provider: google
+ property: UA-133183413-1
+ social:
+ - icon: fontawesome/brands/github-alt
+ link: https://github.com/tiangolo/fastapi
+ - icon: fontawesome/brands/discord
+ link: https://discord.gg/VQjSZaeJmf
+ - icon: fontawesome/brands/twitter
+ link: https://twitter.com/fastapi
+ - icon: fontawesome/brands/linkedin
+ link: https://www.linkedin.com/in/tiangolo
+ - icon: fontawesome/brands/dev
+ link: https://dev.to/tiangolo
+ - icon: fontawesome/brands/medium
+ link: https://medium.com/@tiangolo
+ - icon: fontawesome/solid/globe
+ link: https://tiangolo.com
+ alternate:
+ - link: /
+ name: en - English
+ - link: /az/
+ name: az
+ - link: /de/
+ name: de
+ - link: /es/
+ name: es - español
+ - link: /fa/
+ name: fa
+ - link: /fr/
+ name: fr - français
+ - link: /he/
+ name: he
+ - link: /id/
+ name: id
+ - link: /it/
+ name: it - italiano
+ - link: /ja/
+ name: ja - 日本語
+ - link: /ko/
+ name: ko - 한국어
+ - link: /nl/
+ name: nl
+ - link: /pl/
+ name: pl
+ - link: /pt/
+ name: pt - português
+ - link: /ru/
+ name: ru - русский язык
+ - link: /sq/
+ name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
+ - link: /tr/
+ name: tr - Türkçe
+ - link: /uk/
+ name: uk - українська мова
+ - link: /zh/
+ name: zh - 汉语
+extra_css:
+- https://fastapi.tiangolo.com/css/termynal.css
+- https://fastapi.tiangolo.com/css/custom.css
+extra_javascript:
+- https://fastapi.tiangolo.com/js/termynal.js
+- https://fastapi.tiangolo.com/js/custom.js
diff --git a/docs/nl/overrides/.gitignore b/docs/nl/overrides/.gitignore
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs/pl/docs/index.md b/docs/pl/docs/index.md
index 4a300ae63..bbe1b1ad1 100644
--- a/docs/pl/docs/index.md
+++ b/docs/pl/docs/index.md
@@ -144,7 +144,7 @@ $ pip install uvicorn[standard]
* Utwórz plik o nazwie `main.py` z:
```Python
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -157,7 +157,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -167,7 +167,7 @@ def read_item(item_id: int, q: Optional[str] = None):
Jeżeli twój kod korzysta z `async` / `await`, użyj `async def`:
```Python hl_lines="9 14"
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -180,7 +180,7 @@ async def read_root():
@app.get("/items/{item_id}")
-async def read_item(item_id: int, q: Optional[str] = None):
+async def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -258,7 +258,7 @@ Zmodyfikuj teraz plik `main.py`, aby otrzmywał treść (body) żądania `PUT`.
Zadeklaruj treść żądania, używając standardowych typów w Pythonie dzięki Pydantic.
```Python hl_lines="4 9-12 25-27"
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
@@ -269,7 +269,7 @@ app = FastAPI()
class Item(BaseModel):
name: str
price: float
- is_offer: Optional[bool] = None
+ is_offer: Union[bool, None] = None
@app.get("/")
@@ -278,7 +278,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
diff --git a/docs/pl/docs/tutorial/first-steps.md b/docs/pl/docs/tutorial/first-steps.md
new file mode 100644
index 000000000..9406d703d
--- /dev/null
+++ b/docs/pl/docs/tutorial/first-steps.md
@@ -0,0 +1,334 @@
+# Pierwsze kroki
+
+Najprostszy plik FastAPI może wyglądać tak:
+
+```Python
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Skopiuj to do pliku `main.py`.
+
+Uruchom serwer:
+
+get
+
+!!! info "`@decorator` Info"
+ Składnia `@something` jest w Pythonie nazywana "dekoratorem".
+
+ Umieszczasz to na szczycie funkcji. Jak ładną ozdobną czapkę (chyba stąd wzięła się nazwa).
+
+ "Dekorator" przyjmuje funkcję znajdującą się poniżej jego i coś z nią robi.
+
+ W naszym przypadku dekorator mówi **FastAPI**, że poniższa funkcja odpowiada **ścieżce** `/` z **operacją** `get`.
+
+ Jest to "**dekorator operacji na ścieżce**".
+
+Możesz również użyć innej operacji:
+
+* `@app.post()`
+* `@app.put()`
+* `@app.delete()`
+
+Oraz tych bardziej egzotycznych:
+
+* `@app.options()`
+* `@app.head()`
+* `@app.patch()`
+* `@app.trace()`
+
+!!! tip
+ Możesz dowolnie używać każdej operacji (metody HTTP).
+
+ **FastAPI** nie narzuca żadnego konkretnego znaczenia.
+
+ Informacje tutaj są przedstawione jako wskazówka, a nie wymóg.
+
+ Na przykład, używając GraphQL, normalnie wykonujesz wszystkie akcje używając tylko operacji `POST`.
+
+### Krok 4: zdefiniuj **funkcję obsługującą ścieżkę**
+
+To jest nasza "**funkcja obsługująca ścieżkę**":
+
+* **ścieżka**: to `/`.
+* **operacja**: to `get`.
+* **funkcja**: to funkcja poniżej "dekoratora" (poniżej `@app.get("/")`).
+
+```Python hl_lines="7"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Jest to funkcja Python.
+
+Zostanie ona wywołana przez **FastAPI** za każdym razem, gdy otrzyma żądanie do adresu URL "`/`" przy użyciu operacji `GET`.
+
+W tym przypadku jest to funkcja "asynchroniczna".
+
+---
+
+Możesz również zdefiniować to jako normalną funkcję zamiast `async def`:
+
+```Python hl_lines="7"
+{!../../../docs_src/first_steps/tutorial003.py!}
+```
+
+!!! note
+ Jeśli nie znasz różnicy, sprawdź [Async: *"In a hurry?"*](/async/#in-a-hurry){.internal-link target=_blank}.
+
+### Krok 5: zwróć zawartość
+
+```Python hl_lines="8"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Możesz zwrócić `dict`, `list`, pojedynczą wartość jako `str`, `int`, itp.
+
+Możesz również zwrócić modele Pydantic (więcej o tym później).
+
+Istnieje wiele innych obiektów i modeli, które zostaną automatycznie skonwertowane do formatu JSON (w tym ORM itp.). Spróbuj użyć swoich ulubionych, jest bardzo prawdopodobne, że są już obsługiwane.
+
+## Podsumowanie
+
+* Zaimportuj `FastAPI`.
+* Stwórz instancję `app`.
+* Dodaj **dekorator operacji na ścieżce** (taki jak `@app.get("/")`).
+* Napisz **funkcję obsługującą ścieżkę** (taką jak `def root(): ...` powyżej).
+* Uruchom serwer deweloperski (`uvicorn main:app --reload`).
diff --git a/docs/pl/docs/tutorial/index.md b/docs/pl/docs/tutorial/index.md
new file mode 100644
index 000000000..ed8752a95
--- /dev/null
+++ b/docs/pl/docs/tutorial/index.md
@@ -0,0 +1,80 @@
+# Samouczek - Wprowadzenie
+
+Ten samouczek pokaże Ci, krok po kroku, jak używać większości funkcji **FastAPI**.
+
+Każda część korzysta z poprzednich, ale jest jednocześnie osobnym tematem. Możesz przejść bezpośrednio do każdego rozdziału, jeśli szukasz rozwiązania konkretnego problemu.
+
+Samouczek jest tak zbudowany, żeby służył jako punkt odniesienia w przyszłości.
+
+Możesz wracać i sprawdzać dokładnie to czego potrzebujesz.
+
+## Wykonywanie kodu
+
+Wszystkie fragmenty kodu mogą być skopiowane bezpośrednio i użyte (są poprawnymi i przetestowanymi plikami).
+
+Żeby wykonać każdy przykład skopiuj kod to pliku `main.py` i uruchom `uvicorn` za pomocą:
+
+requests
- Necessário se você quiser utilizar o `TestClient`.
-* aiofiles
- Necessário se você quiser utilizar o `FileResponse` ou `StaticFiles`.
* jinja2
- Necessário se você quiser utilizar a configuração padrão de templates.
* python-multipart
- Necessário se você quiser suporte com "parsing" de formulário, com `request.form()`.
* itsdangerous
- Necessário para suporte a `SessionMiddleware`.
diff --git a/docs/pt/docs/python-types.md b/docs/pt/docs/python-types.md
index df70afd40..9f12211c7 100644
--- a/docs/pt/docs/python-types.md
+++ b/docs/pt/docs/python-types.md
@@ -313,4 +313,3 @@ O importante é que, usando tipos padrão de Python, em um único local (em vez
!!! info "Informação"
Se você já passou por todo o tutorial e voltou para ver mais sobre os tipos, um bom recurso é a "cheat sheet" do `mypy` .
-
diff --git a/docs/pt/docs/tutorial/background-tasks.md b/docs/pt/docs/tutorial/background-tasks.md
new file mode 100644
index 000000000..625fa2b11
--- /dev/null
+++ b/docs/pt/docs/tutorial/background-tasks.md
@@ -0,0 +1,94 @@
+# Tarefas em segundo plano
+
+Você pode definir tarefas em segundo plano a serem executadas _ após _ retornar uma resposta.
+
+Isso é útil para operações que precisam acontecer após uma solicitação, mas que o cliente realmente não precisa esperar a operação ser concluída para receber a resposta.
+
+Isso inclui, por exemplo:
+
+- Envio de notificações por email após a realização de uma ação:
+ - Como conectar-se a um servidor de e-mail e enviar um e-mail tende a ser "lento" (vários segundos), você pode retornar a resposta imediatamente e enviar a notificação por e-mail em segundo plano.
+- Processando dados:
+ - Por exemplo, digamos que você receba um arquivo que deve passar por um processo lento, você pode retornar uma resposta de "Aceito" (HTTP 202) e processá-lo em segundo plano.
+
+## Usando `BackgroundTasks`
+
+Primeiro, importe `BackgroundTasks` e defina um parâmetro em sua _função de operação de caminho_ com uma declaração de tipo de `BackgroundTasks`:
+
+```Python hl_lines="1 13"
+{!../../../docs_src/background_tasks/tutorial001.py!}
+```
+
+O **FastAPI** criará o objeto do tipo `BackgroundTasks` para você e o passará como esse parâmetro.
+
+## Criar uma função de tarefa
+
+Crie uma função a ser executada como tarefa em segundo plano.
+
+É apenas uma função padrão que pode receber parâmetros.
+
+Pode ser uma função `async def` ou `def` normal, o **FastAPI** saberá como lidar com isso corretamente.
+
+Nesse caso, a função de tarefa gravará em um arquivo (simulando o envio de um e-mail).
+
+E como a operação de gravação não usa `async` e `await`, definimos a função com `def` normal:
+
+```Python hl_lines="6-9"
+{!../../../docs_src/background_tasks/tutorial001.py!}
+```
+
+## Adicionar a tarefa em segundo plano
+
+Dentro de sua _função de operação de caminho_, passe sua função de tarefa para o objeto _tarefas em segundo plano_ com o método `.add_task()`:
+
+```Python hl_lines="14"
+{!../../../docs_src/background_tasks/tutorial001.py!}
+```
+
+`.add_task()` recebe como argumentos:
+
+- Uma função de tarefa a ser executada em segundo plano (`write_notification`).
+- Qualquer sequência de argumentos que deve ser passada para a função de tarefa na ordem (`email`).
+- Quaisquer argumentos nomeados que devem ser passados para a função de tarefa (`mensagem = "alguma notificação"`).
+
+## Injeção de dependência
+
+Usar `BackgroundTasks` também funciona com o sistema de injeção de dependência, você pode declarar um parâmetro do tipo `BackgroundTasks` em vários níveis: em uma _função de operação de caminho_, em uma dependência (confiável), em uma subdependência, etc.
+
+O **FastAPI** sabe o que fazer em cada caso e como reutilizar o mesmo objeto, de forma que todas as tarefas em segundo plano sejam mescladas e executadas em segundo plano posteriormente:
+
+```Python hl_lines="13 15 22 25"
+{!../../../docs_src/background_tasks/tutorial002.py!}
+```
+
+Neste exemplo, as mensagens serão gravadas no arquivo `log.txt` _após_ o envio da resposta.
+
+Se houver uma consulta na solicitação, ela será gravada no log em uma tarefa em segundo plano.
+
+E então outra tarefa em segundo plano gerada na _função de operação de caminho_ escreverá uma mensagem usando o parâmetro de caminho `email`.
+
+## Detalhes técnicos
+
+A classe `BackgroundTasks` vem diretamente de `starlette.background`.
+
+Ela é importada/incluída diretamente no FastAPI para que você possa importá-la do `fastapi` e evitar a importação acidental da alternativa `BackgroundTask` (sem o `s` no final) de `starlette.background`.
+
+Usando apenas `BackgroundTasks` (e não `BackgroundTask`), é então possível usá-la como um parâmetro de _função de operação de caminho_ e deixar o **FastAPI** cuidar do resto para você, assim como ao usar o objeto `Request` diretamente.
+
+Ainda é possível usar `BackgroundTask` sozinho no FastAPI, mas você deve criar o objeto em seu código e retornar uma Starlette `Response` incluindo-o.
+
+Você pode ver mais detalhes na documentação oficiais da Starlette para tarefas em segundo plano .
+
+## Ressalva
+
+Se você precisa realizar cálculos pesados em segundo plano e não necessariamente precisa que seja executado pelo mesmo processo (por exemplo, você não precisa compartilhar memória, variáveis, etc), você pode se beneficiar do uso de outras ferramentas maiores, como Celery .
+
+Eles tendem a exigir configurações mais complexas, um gerenciador de fila de mensagens/tarefas, como RabbitMQ ou Redis, mas permitem que você execute tarefas em segundo plano em vários processos e, especialmente, em vários servidores.
+
+Para ver um exemplo, verifique os [Geradores de projeto](../project-generation.md){.internal-link target=\_blank}, todos incluem celery já configurado.
+
+Mas se você precisa acessar variáveis e objetos do mesmo aplicativo **FastAPI**, ou precisa realizar pequenas tarefas em segundo plano (como enviar uma notificação por e-mail), você pode simplesmente usar `BackgroundTasks`.
+
+## Recapitulando
+
+Importe e use `BackgroundTasks` com parâmetros em _funções de operação de caminho_ e dependências para adicionar tarefas em segundo plano.
diff --git a/docs/pt/docs/tutorial/body.md b/docs/pt/docs/tutorial/body.md
new file mode 100644
index 000000000..99e05ab77
--- /dev/null
+++ b/docs/pt/docs/tutorial/body.md
@@ -0,0 +1,165 @@
+# Corpo da Requisição
+
+Quando você precisa enviar dados de um cliente (como de um navegador web) para sua API, você o envia como um **corpo da requisição**.
+
+O corpo da **requisição** é a informação enviada pelo cliente para sua API. O corpo da **resposta** é a informação que sua API envia para o cliente.
+
+Sua API quase sempre irá enviar um corpo na **resposta**. Mas os clientes não necessariamente precisam enviar um corpo em toda **requisição**.
+
+Para declarar um corpo da **requisição**, você utiliza os modelos do Pydantic com todos os seus poderes e benefícios.
+
+!!! info "Informação"
+ Para enviar dados, você deve usar utilizar um dos métodos: `POST` (Mais comum), `PUT`, `DELETE` ou `PATCH`.
+
+ Enviar um corpo em uma requisição `GET` não tem um comportamento definido nas especificações, porém é suportado pelo FastAPI, apenas para casos de uso bem complexos/extremos.
+
+ Como é desencorajado, a documentação interativa com Swagger UI não irá mostrar a documentação para o corpo da requisição para um `GET`, e proxies que intermediarem podem não suportar o corpo da requisição.
+
+## Importe o `BaseModel` do Pydantic
+
+Primeiro, você precisa importar `BaseModel` do `pydantic`:
+
+```Python hl_lines="4"
+{!../../../docs_src/body/tutorial001.py!}
+```
+
+## Crie seu modelo de dados
+
+Então você declara seu modelo de dados como uma classe que herda `BaseModel`.
+
+Utilize os tipos Python padrão para todos os atributos:
+
+```Python hl_lines="7-11"
+{!../../../docs_src/body/tutorial001.py!}
+```
+
+Assim como quando declaramos parâmetros de consulta, quando um atributo do modelo possui um valor padrão, ele se torna opcional. Caso contrário, se torna obrigatório. Use `None` para torná-lo opcional.
+
+Por exemplo, o modelo acima declara um JSON "`object`" (ou `dict` no Python) como esse:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "Uma descrição opcional",
+ "price": 45.2,
+ "tax": 3.5
+}
+```
+
+...como `description` e `tax` são opcionais (Com um valor padrão de `None`), esse JSON "`object`" também é válido:
+
+```JSON
+{
+ "name": "Foo",
+ "price": 45.2
+}
+```
+
+## Declare como um parâmetro
+
+Para adicionar o corpo na *função de operação de rota*, declare-o da mesma maneira que você declarou parâmetros de rota e consulta:
+
+```Python hl_lines="18"
+{!../../../docs_src/body/tutorial001.py!}
+```
+
+...E declare o tipo como o modelo que você criou, `Item`.
+
+## Resultados
+
+Apenas com esse declaração de tipos do Python, o **FastAPI** irá:
+
+* Ler o corpo da requisição como um JSON.
+* Converter os tipos correspondentes (se necessário).
+* Validar os dados.
+ * Se algum dados for inválido, irá retornar um erro bem claro, indicando exatamente onde e o que está incorreto.
+* Entregar a você a informação recebida no parâmetro `item`.
+ * Como você o declarou na função como do tipo `Item`, você também terá o suporte do editor (completação, etc) para todos os atributos e seus tipos.
+* Gerar um Esquema JSON com as definições do seu modelo, você também pode utilizá-lo em qualquer lugar que quiser, se fizer sentido para seu projeto.
+* Esses esquemas farão parte do esquema OpenAPI, e utilizados nas UIs de documentação automática.
+
+## Documentação automática
+
+Os esquemas JSON dos seus modelos farão parte do esquema OpenAPI gerado para sua aplicação, e aparecerão na documentação interativa da API:
+
+requests
- Required if you want to use the `TestClient`.
-* aiofiles
- Required if you want to use `FileResponse` or `StaticFiles`.
* jinja2
- Required if you want to use the default template configuration.
* python-multipart
- Required if you want to support form "parsing", with `request.form()`.
* itsdangerous
- Required for `SessionMiddleware` support.
diff --git a/docs/ru/docs/python-types.md b/docs/ru/docs/python-types.md
index 99670363c..7523083c8 100644
--- a/docs/ru/docs/python-types.md
+++ b/docs/ru/docs/python-types.md
@@ -1,6 +1,6 @@
# Введение в аннотации типов Python
-Python имеет поддержку необязательных аннотаций типов.
+Python имеет поддержку необязательных аннотаций типов.
**Аннотации типов** являются специальным синтаксисом, который позволяет определять тип переменной.
diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml
index 6e17c287e..2eb8eb935 100644
--- a/docs/ru/mkdocs.yml
+++ b/docs/ru/mkdocs.yml
@@ -5,13 +5,15 @@ theme:
name: material
custom_dir: overrides
palette:
- - scheme: default
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
primary: teal
accent: amber
toggle:
icon: material/lightbulb
name: Switch to light mode
- - scheme: slate
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
primary: teal
accent: amber
toggle:
@@ -40,18 +42,23 @@ nav:
- az: /az/
- de: /de/
- es: /es/
+ - fa: /fa/
- fr: /fr/
+ - he: /he/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
+ - sv: /sv/
- tr: /tr/
- uk: /uk/
- zh: /zh/
+- async.md
markdown_extensions:
- toc:
permalink: true
@@ -97,8 +104,12 @@ extra:
name: de
- link: /es/
name: es - español
+ - link: /fa/
+ name: fa
- link: /fr/
name: fr - français
+ - link: /he/
+ name: he
- link: /id/
name: id
- link: /it/
@@ -107,6 +118,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /nl/
+ name: nl
- link: /pl/
name: pl
- link: /pt/
@@ -115,6 +128,8 @@ extra:
name: ru - русский язык
- link: /sq/
name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/sq/docs/index.md b/docs/sq/docs/index.md
index 95fb7ae21..29f92e020 100644
--- a/docs/sq/docs/index.md
+++ b/docs/sq/docs/index.md
@@ -149,7 +149,7 @@ $ pip install uvicorn[standard]
* Create a file `main.py` with:
```Python
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -162,7 +162,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -172,7 +172,7 @@ def read_item(item_id: int, q: Optional[str] = None):
If your code uses `async` / `await`, use `async def`:
```Python hl_lines="9 14"
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -185,7 +185,7 @@ async def read_root():
@app.get("/items/{item_id}")
-async def read_item(item_id: int, q: Optional[str] = None):
+async def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -264,7 +264,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
Declare the body using standard Python types, thanks to Pydantic.
```Python hl_lines="4 9-12 25-27"
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
@@ -275,7 +275,7 @@ app = FastAPI()
class Item(BaseModel):
name: str
price: float
- is_offer: Optional[bool] = None
+ is_offer: Union[bool, None] = None
@app.get("/")
@@ -284,7 +284,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
@@ -321,7 +321,7 @@ And now, go to requests
- Required if you want to use the `TestClient`.
-* aiofiles
- Required if you want to use `FileResponse` or `StaticFiles`.
* jinja2
- Required if you want to use the default template configuration.
* python-multipart
- Required if you want to support form "parsing", with `request.form()`.
* itsdangerous
- Required for `SessionMiddleware` support.
diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml
index d9c3dad4c..1d8d9d04e 100644
--- a/docs/sq/mkdocs.yml
+++ b/docs/sq/mkdocs.yml
@@ -5,13 +5,15 @@ theme:
name: material
custom_dir: overrides
palette:
- - scheme: default
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
primary: teal
accent: amber
toggle:
icon: material/lightbulb
name: Switch to light mode
- - scheme: slate
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
primary: teal
accent: amber
toggle:
@@ -40,15 +42,19 @@ nav:
- az: /az/
- de: /de/
- es: /es/
+ - fa: /fa/
- fr: /fr/
+ - he: /he/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
+ - sv: /sv/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -97,8 +103,12 @@ extra:
name: de
- link: /es/
name: es - español
+ - link: /fa/
+ name: fa
- link: /fr/
name: fr - français
+ - link: /he/
+ name: he
- link: /id/
name: id
- link: /it/
@@ -107,6 +117,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /nl/
+ name: nl
- link: /pl/
name: pl
- link: /pt/
@@ -115,6 +127,8 @@ extra:
name: ru - русский язык
- link: /sq/
name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/sv/docs/index.md b/docs/sv/docs/index.md
new file mode 100644
index 000000000..fd52f994c
--- /dev/null
+++ b/docs/sv/docs/index.md
@@ -0,0 +1,468 @@
+
+{!../../../docs/missing-translation.md!}
+
+
+
++ FastAPI framework, high performance, easy to learn, fast to code, ready for production +
+ + +--- + +**Documentation**: https://fastapi.tiangolo.com + +**Source Code**: https://github.com/tiangolo/fastapi + +--- + +FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. + +The key features are: + +* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). + +* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * +* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * +* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. +* **Easy**: Designed to be easy to use and learn. Less time reading docs. +* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. +* **Robust**: Get production-ready code. With automatic interactive documentation. +* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. + +* estimation based on tests on an internal development team, building production applications. + +## Sponsors + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} +async def
...uvicorn main:app --reload
...ujson
- for faster JSON "parsing".
+* email_validator
- for email validation.
+
+Used by Starlette:
+
+* requests
- Required if you want to use the `TestClient`.
+* jinja2
- Required if you want to use the default template configuration.
+* python-multipart
- Required if you want to support form "parsing", with `request.form()`.
+* itsdangerous
- Required for `SessionMiddleware` support.
+* pyyaml
- Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
+* ujson
- Required if you want to use `UJSONResponse`.
+
+Used by FastAPI / Starlette:
+
+* uvicorn
- for the server that loads and serves your application.
+* orjson
- Required if you want to use `ORJSONResponse`.
+
+You can install all of these with `pip install "fastapi[all]"`.
+
+## License
+
+This project is licensed under the terms of the MIT license.
diff --git a/docs/sv/mkdocs.yml b/docs/sv/mkdocs.yml
new file mode 100644
index 000000000..4606c9349
--- /dev/null
+++ b/docs/sv/mkdocs.yml
@@ -0,0 +1,143 @@
+site_name: FastAPI
+site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
+site_url: https://fastapi.tiangolo.com/sv/
+theme:
+ name: material
+ custom_dir: overrides
+ palette:
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb
+ name: Switch to light mode
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb-outline
+ name: Switch to dark mode
+ features:
+ - search.suggest
+ - search.highlight
+ - content.tabs.link
+ icon:
+ repo: fontawesome/brands/github-alt
+ logo: https://fastapi.tiangolo.com/img/icon-white.svg
+ favicon: https://fastapi.tiangolo.com/img/favicon.png
+ language: sv
+repo_name: tiangolo/fastapi
+repo_url: https://github.com/tiangolo/fastapi
+edit_uri: ''
+plugins:
+- search
+- markdownextradata:
+ data: data
+nav:
+- FastAPI: index.md
+- Languages:
+ - en: /
+ - az: /az/
+ - de: /de/
+ - es: /es/
+ - fa: /fa/
+ - fr: /fr/
+ - he: /he/
+ - id: /id/
+ - it: /it/
+ - ja: /ja/
+ - ko: /ko/
+ - nl: /nl/
+ - pl: /pl/
+ - pt: /pt/
+ - ru: /ru/
+ - sq: /sq/
+ - sv: /sv/
+ - tr: /tr/
+ - uk: /uk/
+ - zh: /zh/
+markdown_extensions:
+- toc:
+ permalink: true
+- markdown.extensions.codehilite:
+ guess_lang: false
+- mdx_include:
+ base_path: docs
+- admonition
+- codehilite
+- extra
+- pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_code_format ''
+- pymdownx.tabbed:
+ alternate_style: true
+extra:
+ analytics:
+ provider: google
+ property: UA-133183413-1
+ social:
+ - icon: fontawesome/brands/github-alt
+ link: https://github.com/tiangolo/fastapi
+ - icon: fontawesome/brands/discord
+ link: https://discord.gg/VQjSZaeJmf
+ - icon: fontawesome/brands/twitter
+ link: https://twitter.com/fastapi
+ - icon: fontawesome/brands/linkedin
+ link: https://www.linkedin.com/in/tiangolo
+ - icon: fontawesome/brands/dev
+ link: https://dev.to/tiangolo
+ - icon: fontawesome/brands/medium
+ link: https://medium.com/@tiangolo
+ - icon: fontawesome/solid/globe
+ link: https://tiangolo.com
+ alternate:
+ - link: /
+ name: en - English
+ - link: /az/
+ name: az
+ - link: /de/
+ name: de
+ - link: /es/
+ name: es - español
+ - link: /fa/
+ name: fa
+ - link: /fr/
+ name: fr - français
+ - link: /he/
+ name: he
+ - link: /id/
+ name: id
+ - link: /it/
+ name: it - italiano
+ - link: /ja/
+ name: ja - 日本語
+ - link: /ko/
+ name: ko - 한국어
+ - link: /nl/
+ name: nl
+ - link: /pl/
+ name: pl
+ - link: /pt/
+ name: pt - português
+ - link: /ru/
+ name: ru - русский язык
+ - link: /sq/
+ name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
+ - link: /tr/
+ name: tr - Türkçe
+ - link: /uk/
+ name: uk - українська мова
+ - link: /zh/
+ name: zh - 汉语
+extra_css:
+- https://fastapi.tiangolo.com/css/termynal.css
+- https://fastapi.tiangolo.com/css/custom.css
+extra_javascript:
+- https://fastapi.tiangolo.com/js/termynal.js
+- https://fastapi.tiangolo.com/js/custom.js
diff --git a/docs/sv/overrides/.gitignore b/docs/sv/overrides/.gitignore
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs/tr/docs/features.md b/docs/tr/docs/features.md
index c06c27c16..0bcda4e9c 100644
--- a/docs/tr/docs/features.md
+++ b/docs/tr/docs/features.md
@@ -6,7 +6,7 @@
### Açık standartları temel alır
-* API oluşturma işlemlerinde OpenAPI buna path operasyonları parametreleri, body talebi, güvenlik gibi şeyler dahil olmak üzere deklare bunların deklare edilmesi.
+* API oluşturma işlemlerinde OpenAPI buna path operasyonları parametreleri, body talebi, güvenlik gibi şeyler dahil olmak üzere deklare bunların deklare edilmesi.
* Otomatik olarak data modelinin JSON Schema ile beraber dokümante edilmesi (OpenAPI'n kendisi zaten JSON Schema'ya dayanıyor).
* Titiz bir çalışmanın sonucunda yukarıdaki standartlara uygun bir framework oluşturduk. Standartları pastanın üzerine sonradan eklenmiş bir çilek olarak görmedik.
* Ayrıca bu bir çok dilde kullanılabilecek **client code generator** kullanımına da izin veriyor.
@@ -74,7 +74,7 @@ my_second_user: User = User(**second_user_data)
### Editor desteği
-Bütün framework kullanılması kolay ve sezgileri güçlü olması için tasarlandı, verilen bütün kararlar geliştiricilere en iyi geliştirme deneyimini yaşatmak üzere, bir çok editör üzerinde test edildi.
+Bütün framework kullanılması kolay ve sezgileri güçlü olması için tasarlandı, verilen bütün kararlar geliştiricilere en iyi geliştirme deneyimini yaşatmak üzere, bir çok editör üzerinde test edildi.
Son yapılan Python geliştiricileri anketinde, açık ara en çok kullanılan özellik "oto-tamamlama" idi..
@@ -135,7 +135,7 @@ Bütün güvenlik şemaları OpenAPI'da tanımlanmış durumda, kapsadıkları:
Bütün güvenlik özellikleri Starlette'den geliyor (**session cookies'de** dahil olmak üzere).
-Bütün hepsi tekrardan kullanılabilir aletler ve bileşenler olarak, kolayca sistemlerinize, data depolarınıza, ilişkisel ve NoSQL databaselerinize entegre edebileceğiniz şekilde yapıldı.
+Bütün hepsi tekrardan kullanılabilir aletler ve bileşenler olarak, kolayca sistemlerinize, data depolarınıza, ilişkisel ve NoSQL databaselerinize entegre edebileceğiniz şekilde yapıldı.
### Dependency injection
@@ -198,7 +198,7 @@ Aynı şekilde, databaseden gelen objeyi de **direkt olarak isteğe** de tamamiy
* Kullandığın geliştirme araçları ile iyi çalışır **IDE/linter/brain**:
* Pydantic'in veri yapıları aslında sadece senin tanımladığın classlar; Bu yüzden doğrulanmış dataların ile otomatik tamamlama, linting ve mypy'ı kullanarak sorunsuz bir şekilde çalışabilirsin
* **Hızlı**:
- * Benchmarklarda, Pydantic'in diğer bütün test edilmiş bütün kütüphanelerden daha hızlı.
+ * Benchmarklarda, Pydantic'in diğer bütün test edilmiş bütün kütüphanelerden daha hızlı.
* **En kompleks** yapıları bile doğrula:
* Hiyerarşik Pydantic modellerinin kullanımı ile beraber, Python `typing`’s `List` and `Dict`, vs gibi şeyleri doğrula.
* Doğrulayıcılar en kompleks data şemalarının bile temiz ve kolay bir şekilde tanımlanmasına izin veriyor, ve hepsi JSON şeması olarak dokümante ediliyor
@@ -206,4 +206,3 @@ Aynı şekilde, databaseden gelen objeyi de **direkt olarak isteğe** de tamamiy
* **Genişletilebilir**:
* Pydantic özelleştirilmiş data tiplerinin tanımlanmasının yapılmasına izin veriyor ayrıca validator decoratorü ile senin doğrulamaları genişletip, kendi doğrulayıcılarını yazmana izin veriyor.
* 100% test kapsayıcılığı.
-
diff --git a/docs/tr/docs/index.md b/docs/tr/docs/index.md
index 88660f7eb..5693029b5 100644
--- a/docs/tr/docs/index.md
+++ b/docs/tr/docs/index.md
@@ -28,7 +28,7 @@
---
-FastAPI, Python 3.6+'nın standart type hintlerine dayanan modern ve hızlı (yüksek performanslı) API'lar oluşturmak için kullanılabilecek web framework'ü.
+FastAPI, Python 3.6+'nın standart type hintlerine dayanan modern ve hızlı (yüksek performanslı) API'lar oluşturmak için kullanılabilecek web framework'ü.
Ana özellikleri:
@@ -157,7 +157,7 @@ $ pip install uvicorn[standard]
* `main.py` adında bir dosya oluştur :
```Python
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -170,7 +170,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -180,7 +180,7 @@ def read_item(item_id: int, q: Optional[str] = None):
Eğer kodunda `async` / `await` var ise, `async def` kullan:
```Python hl_lines="9 14"
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -193,7 +193,7 @@ async def read_root():
@app.get("/items/{item_id}")
-async def read_item(item_id: int, q: Optional[str] = None):
+async def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -272,7 +272,7 @@ Senin için alternatif olarak (requests
- Eğer `TestClient` kullanmak istiyorsan gerekli.
-* aiofiles
- `FileResponse` ya da `StaticFiles` kullanmak istiyorsan gerekli.
* jinja2
- Eğer kendine ait template konfigürasyonu oluşturmak istiyorsan gerekli
* python-multipart
- Form kullanmak istiyorsan gerekli ("dönüşümü").
* itsdangerous
- `SessionMiddleware` desteği için gerekli.
diff --git a/docs/tr/docs/python-types.md b/docs/tr/docs/python-types.md
index 7e46bd031..3b9ab9050 100644
--- a/docs/tr/docs/python-types.md
+++ b/docs/tr/docs/python-types.md
@@ -29,7 +29,7 @@ Programın çıktısı:
John Doe
```
-Fonksiyon sırayla şunları yapar:
+Fonksiyon sırayla şunları yapar:
* `first_name` ve `last_name` değerlerini alır.
* `title()` ile değişkenlerin ilk karakterlerini büyütür.
diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml
index f6ed7f5b9..bf66edd68 100644
--- a/docs/tr/mkdocs.yml
+++ b/docs/tr/mkdocs.yml
@@ -5,13 +5,15 @@ theme:
name: material
custom_dir: overrides
palette:
- - scheme: default
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
primary: teal
accent: amber
toggle:
icon: material/lightbulb
name: Switch to light mode
- - scheme: slate
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
primary: teal
accent: amber
toggle:
@@ -40,15 +42,19 @@ nav:
- az: /az/
- de: /de/
- es: /es/
+ - fa: /fa/
- fr: /fr/
+ - he: /he/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
+ - sv: /sv/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -100,8 +106,12 @@ extra:
name: de
- link: /es/
name: es - español
+ - link: /fa/
+ name: fa
- link: /fr/
name: fr - français
+ - link: /he/
+ name: he
- link: /id/
name: id
- link: /it/
@@ -110,6 +120,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /nl/
+ name: nl
- link: /pl/
name: pl
- link: /pt/
@@ -118,6 +130,8 @@ extra:
name: ru - русский язык
- link: /sq/
name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/uk/docs/index.md b/docs/uk/docs/index.md
index 95fb7ae21..29f92e020 100644
--- a/docs/uk/docs/index.md
+++ b/docs/uk/docs/index.md
@@ -149,7 +149,7 @@ $ pip install uvicorn[standard]
* Create a file `main.py` with:
```Python
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -162,7 +162,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -172,7 +172,7 @@ def read_item(item_id: int, q: Optional[str] = None):
If your code uses `async` / `await`, use `async def`:
```Python hl_lines="9 14"
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -185,7 +185,7 @@ async def read_root():
@app.get("/items/{item_id}")
-async def read_item(item_id: int, q: Optional[str] = None):
+async def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
@@ -264,7 +264,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
Declare the body using standard Python types, thanks to Pydantic.
```Python hl_lines="4 9-12 25-27"
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
@@ -275,7 +275,7 @@ app = FastAPI()
class Item(BaseModel):
name: str
price: float
- is_offer: Optional[bool] = None
+ is_offer: Union[bool, None] = None
@app.get("/")
@@ -284,7 +284,7 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
@@ -321,7 +321,7 @@ And now, go to requests
- Required if you want to use the `TestClient`.
-* aiofiles
- Required if you want to use `FileResponse` or `StaticFiles`.
* jinja2
- Required if you want to use the default template configuration.
* python-multipart
- Required if you want to support form "parsing", with `request.form()`.
* itsdangerous
- Required for `SessionMiddleware` support.
diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml
index d0de8cc0e..3b8475907 100644
--- a/docs/uk/mkdocs.yml
+++ b/docs/uk/mkdocs.yml
@@ -5,13 +5,15 @@ theme:
name: material
custom_dir: overrides
palette:
- - scheme: default
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
primary: teal
accent: amber
toggle:
icon: material/lightbulb
name: Switch to light mode
- - scheme: slate
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
primary: teal
accent: amber
toggle:
@@ -40,15 +42,19 @@ nav:
- az: /az/
- de: /de/
- es: /es/
+ - fa: /fa/
- fr: /fr/
+ - he: /he/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
+ - sv: /sv/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -97,8 +103,12 @@ extra:
name: de
- link: /es/
name: es - español
+ - link: /fa/
+ name: fa
- link: /fr/
name: fr - français
+ - link: /he/
+ name: he
- link: /id/
name: id
- link: /it/
@@ -107,6 +117,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /nl/
+ name: nl
- link: /pl/
name: pl
- link: /pt/
@@ -115,6 +127,8 @@ extra:
name: ru - русский язык
- link: /sq/
name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/zh/docs/advanced/additional-status-codes.md b/docs/zh/docs/advanced/additional-status-codes.md
index 1cb724f1d..54ec9775b 100644
--- a/docs/zh/docs/advanced/additional-status-codes.md
+++ b/docs/zh/docs/advanced/additional-status-codes.md
@@ -14,7 +14,7 @@
要实现它,导入 `JSONResponse`,然后在其中直接返回你的内容,并将 `status_code` 设置为为你要的值。
-```Python hl_lines="2 19"
+```Python hl_lines="4 25"
{!../../../docs_src/additional_status_codes/tutorial001.py!}
```
@@ -22,7 +22,7 @@
当你直接返回一个像上面例子中的 `Response` 对象时,它会直接返回。
FastAPI 不会用模型等对该响应进行序列化。
-
+
确保其中有你想要的数据,且返回的值为合法的 JSON(如果你使用 `JSONResponse` 的话)。
!!! note "技术细节"
diff --git a/docs/zh/docs/advanced/custom-response.md b/docs/zh/docs/advanced/custom-response.md
index 5f1a74e9e..155ce2882 100644
--- a/docs/zh/docs/advanced/custom-response.md
+++ b/docs/zh/docs/advanced/custom-response.md
@@ -60,7 +60,7 @@
正如你在 [直接返回响应](response-directly.md){.internal-link target=_blank} 中了解到的,你也可以通过直接返回响应在 *路径操作* 中直接重载响应。
和上面一样的例子,返回一个 `HTMLResponse` 看起来可能是这样:
-
+
```Python hl_lines="2 7 19"
{!../../../docs_src/custom_response/tutorial003.py!}
```
diff --git a/docs/zh/docs/advanced/response-directly.md b/docs/zh/docs/advanced/response-directly.md
index 05926a9c8..797a878eb 100644
--- a/docs/zh/docs/advanced/response-directly.md
+++ b/docs/zh/docs/advanced/response-directly.md
@@ -10,7 +10,7 @@
直接返回响应可能会有用处,比如返回自定义的响应头和 cookies。
-## 返回 `Response`
+## 返回 `Response`
事实上,你可以返回任意 `Response` 或者任意 `Response` 的子类。
@@ -62,4 +62,3 @@
但是你仍可以参考 [OpenApI 中的额外响应](additional-responses.md){.internal-link target=_blank} 给响应编写文档。
在后续的章节中你可以了解到如何使用/声明这些自定义的 `Response` 的同时还保留自动化的数据转换和文档等。
-
diff --git a/docs/zh/docs/benchmarks.md b/docs/zh/docs/benchmarks.md
index c133d51b7..8991c72cd 100644
--- a/docs/zh/docs/benchmarks.md
+++ b/docs/zh/docs/benchmarks.md
@@ -22,7 +22,7 @@
* 具有最佳性能,因为除了服务器本身外,它没有太多额外的代码。
* 您不会直接在 Uvicorn 中编写应用程序。这意味着您的代码至少必须包含 Starlette(或 **FastAPI**)提供的代码。如果您这样做了(即直接在 Uvicorn 中编写应用程序),最终的应用程序会和使用了框架并且最小化了应用代码和 bug 的情况具有相同的性能损耗。
* 如果要对比与 Uvicorn 对标的服务器,请将其与 Daphne,Hypercorn,uWSGI等应用服务器进行比较。
-* **Starlette**:
+* **Starlette**:
* 在 Uvicorn 后使用 Starlette,性能会略有下降。实际上,Starlette 使用 Uvicorn运行。因此,由于必须执行更多的代码,它只会比 Uvicorn 更慢。
* 但它为您提供了构建简单的网络程序的工具,并具有基于路径的路由等功能。
* 如果想对比与 Starlette 对标的开发框架,请将其与 Sanic,Flask,Django 等网络框架(或微框架)进行比较。
diff --git a/docs/zh/docs/contributing.md b/docs/zh/docs/contributing.md
index 402668c47..95500d12b 100644
--- a/docs/zh/docs/contributing.md
+++ b/docs/zh/docs/contributing.md
@@ -497,4 +497,4 @@ $ bash scripts/test-cov-html.sh
-该命令生成了一个 `./htmlcov/` 目录,如果你在浏览器中打开 `./htmlcov/index.html` 文件,你可以交互式地浏览被测试所覆盖的代码区块,并注意是否缺少了任何区块。
+该命令生成了一个 `./htmlcov/` 目录,如果你在浏览器中打开 `./htmlcov/index.html` 文件,你可以交互式地浏览被测试所覆盖的代码区块,并注意是否缺少了任何区块。
diff --git a/docs/zh/docs/fastapi-people.md b/docs/zh/docs/fastapi-people.md
index 75651592d..5d7b0923f 100644
--- a/docs/zh/docs/fastapi-people.md
+++ b/docs/zh/docs/fastapi-people.md
@@ -114,6 +114,8 @@ FastAPI 有一个非常棒的社区,它欢迎来自各个领域和背景的朋
他们主要通过GitHub Sponsors支持我在 **FastAPI** (和其他项目)的工作。
+{% if sponsors %}
+
{% if sponsors.gold %}
### 金牌赞助商
@@ -141,6 +143,8 @@ FastAPI 有一个非常棒的社区,它欢迎来自各个领域和背景的朋
{% endfor %}
{% endif %}
+{% endif %}
+
### 个人赞助
{% if github_sponsors %}
diff --git a/docs/zh/docs/features.md b/docs/zh/docs/features.md
index 4752947a3..fefe4b197 100644
--- a/docs/zh/docs/features.md
+++ b/docs/zh/docs/features.md
@@ -193,9 +193,9 @@ FastAPI 有一个使用非常简单,但是非常强大的 None:
self._debug: bool = debug
+ self.title = title
+ self.description = description
+ self.version = version
+ self.terms_of_service = terms_of_service
+ self.contact = contact
+ self.license_info = license_info
+ self.openapi_url = openapi_url
+ self.openapi_tags = openapi_tags
+ self.root_path_in_servers = root_path_in_servers
+ self.docs_url = docs_url
+ self.redoc_url = redoc_url
+ self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url
+ self.swagger_ui_init_oauth = swagger_ui_init_oauth
+ self.swagger_ui_parameters = swagger_ui_parameters
+ self.servers = servers or []
+ self.extra = extra
+ self.openapi_version = "3.0.2"
+ self.openapi_schema: Optional[Dict[str, Any]] = None
+ if self.openapi_url:
+ assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'"
+ assert self.version, "A version must be provided for OpenAPI, e.g.: '2.1.0'"
+ # TODO: remove when discarding the openapi_prefix parameter
+ if openapi_prefix:
+ logger.warning(
+ '"openapi_prefix" has been deprecated in favor of "root_path", which '
+ "follows more closely the ASGI standard, is simpler, and more "
+ "automatic. Check the docs at "
+ "https://fastapi.tiangolo.com/advanced/sub-applications/"
+ )
+ self.root_path = root_path or openapi_prefix
self.state: State = State()
+ self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {}
self.router: routing.APIRouter = routing.APIRouter(
routes=routes,
dependency_overrides_provider=self,
@@ -83,13 +129,11 @@ class FastAPI(Starlette):
deprecated=deprecated,
include_in_schema=include_in_schema,
responses=responses,
+ generate_unique_id_function=generate_unique_id_function,
)
self.exception_handlers: Dict[
- Union[int, Type[Exception]],
- Callable[[Request, Any], Coroutine[Any, Any, Response]],
- ] = (
- {} if exception_handlers is None else dict(exception_handlers)
- )
+ Any, Callable[[Request, Any], Union[Response, Awaitable[Response]]]
+ ] = ({} if exception_handlers is None else dict(exception_handlers))
self.exception_handlers.setdefault(HTTPException, http_exception_handler)
self.exception_handlers.setdefault(
RequestValidationError, request_validation_exception_handler
@@ -99,40 +143,6 @@ class FastAPI(Starlette):
[] if middleware is None else list(middleware)
)
self.middleware_stack: ASGIApp = self.build_middleware_stack()
-
- self.title = title
- self.description = description
- self.version = version
- self.terms_of_service = terms_of_service
- self.contact = contact
- self.license_info = license_info
- self.servers = servers or []
- self.openapi_url = openapi_url
- self.openapi_tags = openapi_tags
- # TODO: remove when discarding the openapi_prefix parameter
- if openapi_prefix:
- logger.warning(
- '"openapi_prefix" has been deprecated in favor of "root_path", which '
- "follows more closely the ASGI standard, is simpler, and more "
- "automatic. Check the docs at "
- "https://fastapi.tiangolo.com/advanced/sub-applications/"
- )
- self.root_path = root_path or openapi_prefix
- self.root_path_in_servers = root_path_in_servers
- self.docs_url = docs_url
- self.redoc_url = redoc_url
- self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url
- self.swagger_ui_init_oauth = swagger_ui_init_oauth
- self.swagger_ui_parameters = swagger_ui_parameters
- self.extra = extra
- self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {}
-
- self.openapi_version = "3.0.2"
-
- if self.openapi_url:
- assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'"
- assert self.version, "A version must be provided for OpenAPI, e.g.: '2.1.0'"
- self.openapi_schema: Optional[Dict[str, Any]] = None
self.setup()
def build_middleware_stack(self) -> ASGIApp:
@@ -286,6 +296,9 @@ class FastAPI(Starlette):
),
name: Optional[str] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> None:
self.router.add_api_route(
path,
@@ -311,6 +324,7 @@ class FastAPI(Starlette):
response_class=response_class,
name=name,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def api_route(
@@ -338,6 +352,9 @@ class FastAPI(Starlette):
response_class: Type[Response] = Default(JSONResponse),
name: Optional[str] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
def decorator(func: DecoratedCallable) -> DecoratedCallable:
self.router.add_api_route(
@@ -364,6 +381,7 @@ class FastAPI(Starlette):
response_class=response_class,
name=name,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
return func
@@ -395,6 +413,9 @@ class FastAPI(Starlette):
include_in_schema: bool = True,
default_response_class: Type[Response] = Default(JSONResponse),
callbacks: Optional[List[BaseRoute]] = None,
+ generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> None:
self.router.include_router(
router,
@@ -406,6 +427,7 @@ class FastAPI(Starlette):
include_in_schema=include_in_schema,
default_response_class=default_response_class,
callbacks=callbacks,
+ generate_unique_id_function=generate_unique_id_function,
)
def get(
@@ -433,6 +455,9 @@ class FastAPI(Starlette):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.router.get(
path,
@@ -457,6 +482,7 @@ class FastAPI(Starlette):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def put(
@@ -484,6 +510,9 @@ class FastAPI(Starlette):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.router.put(
path,
@@ -508,6 +537,7 @@ class FastAPI(Starlette):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def post(
@@ -535,6 +565,9 @@ class FastAPI(Starlette):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.router.post(
path,
@@ -559,6 +592,7 @@ class FastAPI(Starlette):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def delete(
@@ -586,6 +620,9 @@ class FastAPI(Starlette):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.router.delete(
path,
@@ -610,6 +647,7 @@ class FastAPI(Starlette):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def options(
@@ -637,6 +675,9 @@ class FastAPI(Starlette):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.router.options(
path,
@@ -661,6 +702,7 @@ class FastAPI(Starlette):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def head(
@@ -688,6 +730,9 @@ class FastAPI(Starlette):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.router.head(
path,
@@ -712,6 +757,7 @@ class FastAPI(Starlette):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def patch(
@@ -739,6 +785,9 @@ class FastAPI(Starlette):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.router.patch(
path,
@@ -763,6 +812,7 @@ class FastAPI(Starlette):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def trace(
@@ -790,6 +840,9 @@ class FastAPI(Starlette):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.router.trace(
path,
@@ -814,4 +867,5 @@ class FastAPI(Starlette):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
diff --git a/fastapi/concurrency.py b/fastapi/concurrency.py
index 04382c69e..becac3f33 100644
--- a/fastapi/concurrency.py
+++ b/fastapi/concurrency.py
@@ -25,7 +25,7 @@ async def contextmanager_in_threadpool(
try:
yield await run_in_threadpool(cm.__enter__)
except Exception as e:
- ok = await run_in_threadpool(cm.__exit__, type(e), e, None)
+ ok: bool = await run_in_threadpool(cm.__exit__, type(e), e, None)
if not ok:
raise e
else:
diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py
index d4028d067..f397e333c 100644
--- a/fastapi/dependencies/utils.py
+++ b/fastapi/dependencies/utils.py
@@ -43,6 +43,7 @@ from pydantic.fields import (
FieldInfo,
ModelField,
Required,
+ Undefined,
)
from pydantic.schema import get_annotation_from_field_info
from pydantic.typing import ForwardRef, evaluate_forwardref
@@ -316,7 +317,7 @@ def get_dependant(
field_info = param_field.field_info
assert isinstance(
field_info, params.Body
- ), f"Param: {param_field.name} can only be a request body, using Body(...)"
+ ), f"Param: {param_field.name} can only be a request body, using Body()"
dependant.body_params.append(param_field)
return dependant
@@ -353,7 +354,7 @@ def get_param_field(
force_type: Optional[params.ParamTypes] = None,
ignore_default: bool = False,
) -> ModelField:
- default_value = Required
+ default_value: Any = Undefined
had_schema = False
if not param.default == param.empty and ignore_default is False:
default_value = param.default
@@ -369,8 +370,13 @@ def get_param_field(
if force_type:
field_info.in_ = force_type # type: ignore
else:
- field_info = default_field_info(default_value)
- required = default_value == Required
+ field_info = default_field_info(default=default_value)
+ required = True
+ if default_value is Required or ignore_default:
+ required = True
+ default_value = None
+ elif default_value is not Undefined:
+ required = False
annotation: Any = Any
if not param.annotation == param.empty:
annotation = param.annotation
@@ -382,12 +388,11 @@ def get_param_field(
field = create_response_field(
name=param.name,
type_=annotation,
- default=None if required else default_value,
+ default=default_value,
alias=alias,
required=required,
field_info=field_info,
)
- field.required = required
if not had_schema and not is_scalar_field(field=field):
field.field_info = params.Body(field_info.default)
if not had_schema and lenient_issubclass(field.type_, UploadFile):
@@ -462,13 +467,10 @@ async def solve_dependencies(
]:
values: Dict[str, Any] = {}
errors: List[ErrorWrapper] = []
- response = response or Response(
- content=None,
- status_code=None, # type: ignore
- headers=None, # type: ignore # in Starlette
- media_type=None, # type: ignore # in Starlette
- background=None, # type: ignore # in Starlette
- )
+ if response is None:
+ response = Response()
+ del response.headers["content-length"]
+ response.status_code = None # type: ignore
dependency_cache = dependency_cache or {}
sub_dependant: Dependant
for sub_dependant in dependant.dependencies:
diff --git a/fastapi/exceptions.py b/fastapi/exceptions.py
index f4a837bb4..0f50acc6c 100644
--- a/fastapi/exceptions.py
+++ b/fastapi/exceptions.py
@@ -12,8 +12,7 @@ class HTTPException(StarletteHTTPException):
detail: Any = None,
headers: Optional[Dict[str, Any]] = None,
) -> None:
- super().__init__(status_code=status_code, detail=detail)
- self.headers = headers
+ super().__init__(status_code=status_code, detail=detail, headers=headers)
RequestErrorModel: Type[BaseModel] = create_model("Request")
diff --git a/fastapi/openapi/constants.py b/fastapi/openapi/constants.py
index 3e69e5524..1897ad750 100644
--- a/fastapi/openapi/constants.py
+++ b/fastapi/openapi/constants.py
@@ -1,3 +1,2 @@
METHODS_WITH_BODY = {"GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"}
-STATUS_CODES_WITH_NO_BODY = {100, 101, 102, 103, 204, 304}
REF_PREFIX = "#/components/schemas/"
diff --git a/fastapi/openapi/docs.py b/fastapi/openapi/docs.py
index 1be90d188..d6af17a85 100644
--- a/fastapi/openapi/docs.py
+++ b/fastapi/openapi/docs.py
@@ -17,8 +17,8 @@ def get_swagger_ui_html(
*,
openapi_url: str,
title: str,
- swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui-bundle.js",
- swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui.css",
+ swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui-bundle.js",
+ swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui.css",
swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
oauth2_redirect_url: Optional[str] = None,
init_oauth: Optional[Dict[str, Any]] = None,
diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py
index 9c6598d2d..35aa1672b 100644
--- a/fastapi/openapi/models.py
+++ b/fastapi/openapi/models.py
@@ -73,7 +73,7 @@ class Server(BaseModel):
class Reference(BaseModel):
- ref: str = Field(..., alias="$ref")
+ ref: str = Field(alias="$ref")
class Discriminator(BaseModel):
@@ -101,28 +101,28 @@ class ExternalDocumentation(BaseModel):
class Schema(BaseModel):
- ref: Optional[str] = Field(None, alias="$ref")
+ ref: Optional[str] = Field(default=None, alias="$ref")
title: Optional[str] = None
multipleOf: Optional[float] = None
maximum: Optional[float] = None
exclusiveMaximum: Optional[float] = None
minimum: Optional[float] = None
exclusiveMinimum: Optional[float] = None
- maxLength: Optional[int] = Field(None, gte=0)
- minLength: Optional[int] = Field(None, gte=0)
+ maxLength: Optional[int] = Field(default=None, gte=0)
+ minLength: Optional[int] = Field(default=None, gte=0)
pattern: Optional[str] = None
- maxItems: Optional[int] = Field(None, gte=0)
- minItems: Optional[int] = Field(None, gte=0)
+ maxItems: Optional[int] = Field(default=None, gte=0)
+ minItems: Optional[int] = Field(default=None, gte=0)
uniqueItems: Optional[bool] = None
- maxProperties: Optional[int] = Field(None, gte=0)
- minProperties: Optional[int] = Field(None, gte=0)
+ maxProperties: Optional[int] = Field(default=None, gte=0)
+ minProperties: Optional[int] = Field(default=None, gte=0)
required: Optional[List[str]] = None
enum: Optional[List[Any]] = None
type: Optional[str] = None
allOf: Optional[List["Schema"]] = None
oneOf: Optional[List["Schema"]] = None
anyOf: Optional[List["Schema"]] = None
- not_: Optional["Schema"] = Field(None, alias="not")
+ not_: Optional["Schema"] = Field(default=None, alias="not")
items: Optional[Union["Schema", List["Schema"]]] = None
properties: Optional[Dict[str, "Schema"]] = None
additionalProperties: Optional[Union["Schema", Reference, bool]] = None
@@ -171,7 +171,7 @@ class Encoding(BaseModel):
class MediaType(BaseModel):
- schema_: Optional[Union[Schema, Reference]] = Field(None, alias="schema")
+ schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema")
example: Optional[Any] = None
examples: Optional[Dict[str, Union[Example, Reference]]] = None
encoding: Optional[Dict[str, Encoding]] = None
@@ -188,7 +188,7 @@ class ParameterBase(BaseModel):
style: Optional[str] = None
explode: Optional[bool] = None
allowReserved: Optional[bool] = None
- schema_: Optional[Union[Schema, Reference]] = Field(None, alias="schema")
+ schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema")
example: Optional[Any] = None
examples: Optional[Dict[str, Union[Example, Reference]]] = None
# Serialization rules for more complex scenarios
@@ -200,7 +200,7 @@ class ParameterBase(BaseModel):
class Parameter(ParameterBase):
name: str
- in_: ParameterInType = Field(..., alias="in")
+ in_: ParameterInType = Field(alias="in")
class Header(ParameterBase):
@@ -258,7 +258,7 @@ class Operation(BaseModel):
class PathItem(BaseModel):
- ref: Optional[str] = Field(None, alias="$ref")
+ ref: Optional[str] = Field(default=None, alias="$ref")
summary: Optional[str] = None
description: Optional[str] = None
get: Optional[Operation] = None
@@ -284,7 +284,7 @@ class SecuritySchemeType(Enum):
class SecurityBase(BaseModel):
- type_: SecuritySchemeType = Field(..., alias="type")
+ type_: SecuritySchemeType = Field(alias="type")
description: Optional[str] = None
class Config:
@@ -299,7 +299,7 @@ class APIKeyIn(Enum):
class APIKey(SecurityBase):
type_ = Field(SecuritySchemeType.apiKey, alias="type")
- in_: APIKeyIn = Field(..., alias="in")
+ in_: APIKeyIn = Field(alias="in")
name: str
diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py
index aff76b15e..5d3d95c24 100644
--- a/fastapi/openapi/utils.py
+++ b/fastapi/openapi/utils.py
@@ -1,5 +1,6 @@
import http.client
import inspect
+import warnings
from enum import Enum
from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast
@@ -8,11 +9,7 @@ from fastapi.datastructures import DefaultPlaceholder
from fastapi.dependencies.models import Dependant
from fastapi.dependencies.utils import get_flat_dependant, get_flat_params
from fastapi.encoders import jsonable_encoder
-from fastapi.openapi.constants import (
- METHODS_WITH_BODY,
- REF_PREFIX,
- STATUS_CODES_WITH_NO_BODY,
-)
+from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX
from fastapi.openapi.models import OpenAPI
from fastapi.params import Body, Param
from fastapi.responses import Response
@@ -20,6 +17,7 @@ from fastapi.utils import (
deep_dict_update,
generate_operation_id_for_path,
get_model_definitions,
+ is_body_allowed_for_status_code,
)
from pydantic import BaseModel
from pydantic.fields import ModelField, Undefined
@@ -37,7 +35,11 @@ validation_error_definition = {
"title": "ValidationError",
"type": "object",
"properties": {
- "loc": {"title": "Location", "type": "array", "items": {"type": "string"}},
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ },
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
@@ -140,7 +142,15 @@ def get_openapi_operation_request_body(
return request_body_oai
-def generate_operation_id(*, route: routing.APIRoute, method: str) -> str:
+def generate_operation_id(
+ *, route: routing.APIRoute, method: str
+) -> str: # pragma: nocover
+ warnings.warn(
+ "fastapi.openapi.utils.generate_operation_id() was deprecated, "
+ "it is not used internally, and will be removed soon",
+ DeprecationWarning,
+ stacklevel=2,
+ )
if route.operation_id:
return route.operation_id
path: str = route.path_format
@@ -154,7 +164,7 @@ def generate_operation_summary(*, route: routing.APIRoute, method: str) -> str:
def get_openapi_operation_metadata(
- *, route: routing.APIRoute, method: str
+ *, route: routing.APIRoute, method: str, operation_ids: Set[str]
) -> Dict[str, Any]:
operation: Dict[str, Any] = {}
if route.tags:
@@ -162,14 +172,25 @@ def get_openapi_operation_metadata(
operation["summary"] = generate_operation_summary(route=route, method=method)
if route.description:
operation["description"] = route.description
- operation["operationId"] = generate_operation_id(route=route, method=method)
+ operation_id = route.operation_id or route.unique_id
+ if operation_id in operation_ids:
+ message = (
+ f"Duplicate Operation ID {operation_id} for function "
+ + f"{route.endpoint.__name__}"
+ )
+ file_name = getattr(route.endpoint, "__globals__", {}).get("__file__")
+ if file_name:
+ message += f" at {file_name}"
+ warnings.warn(message)
+ operation_ids.add(operation_id)
+ operation["operationId"] = operation_id
if route.deprecated:
operation["deprecated"] = route.deprecated
return operation
def get_openapi_path(
- *, route: routing.APIRoute, model_name_map: Dict[type, str]
+ *, route: routing.APIRoute, model_name_map: Dict[type, str], operation_ids: Set[str]
) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:
path = {}
security_schemes: Dict[str, Any] = {}
@@ -183,7 +204,9 @@ def get_openapi_path(
route_response_media_type: Optional[str] = current_response_class.media_type
if route.include_in_schema:
for method in route.methods:
- operation = get_openapi_operation_metadata(route=route, method=method)
+ operation = get_openapi_operation_metadata(
+ route=route, method=method, operation_ids=operation_ids
+ )
parameters: List[Dict[str, Any]] = []
flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True)
security_definitions, operation_security = get_openapi_security_definitions(
@@ -217,7 +240,9 @@ def get_openapi_path(
cb_security_schemes,
cb_definitions,
) = get_openapi_path(
- route=callback, model_name_map=model_name_map
+ route=callback,
+ model_name_map=model_name_map,
+ operation_ids=operation_ids,
)
callbacks[callback.name] = {callback.path: cb_path}
operation["callbacks"] = callbacks
@@ -237,9 +262,8 @@ def get_openapi_path(
operation.setdefault("responses", {}).setdefault(status_code, {})[
"description"
] = route.response_description
- if (
- route_response_media_type
- and route.status_code not in STATUS_CODES_WITH_NO_BODY
+ if route_response_media_type and is_body_allowed_for_status_code(
+ route.status_code
):
response_schema = {"type": "string"}
if lenient_issubclass(current_response_class, JSONResponse):
@@ -384,6 +408,7 @@ def get_openapi(
output["servers"] = servers
components: Dict[str, Dict[str, Any]] = {}
paths: Dict[str, Dict[str, Any]] = {}
+ operation_ids: Set[str] = set()
flat_models = get_flat_models_from_routes(routes)
model_name_map = get_model_name_map(flat_models)
definitions = get_model_definitions(
@@ -391,7 +416,9 @@ def get_openapi(
)
for route in routes:
if isinstance(route, routing.APIRoute):
- result = get_openapi_path(route=route, model_name_map=model_name_map)
+ result = get_openapi_path(
+ route=route, model_name_map=model_name_map, operation_ids=operation_ids
+ )
if result:
path, security_schemes, path_definitions = result
if path:
diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py
index a553a1461..1932ef065 100644
--- a/fastapi/param_functions.py
+++ b/fastapi/param_functions.py
@@ -5,7 +5,7 @@ from pydantic.fields import Undefined
def Path( # noqa: N802
- default: Any,
+ default: Any = Undefined,
*,
alias: Optional[str] = None,
title: Optional[str] = None,
@@ -44,7 +44,7 @@ def Path( # noqa: N802
def Query( # noqa: N802
- default: Any,
+ default: Any = Undefined,
*,
alias: Optional[str] = None,
title: Optional[str] = None,
@@ -63,7 +63,7 @@ def Query( # noqa: N802
**extra: Any,
) -> Any:
return params.Query(
- default,
+ default=default,
alias=alias,
title=title,
description=description,
@@ -83,7 +83,7 @@ def Query( # noqa: N802
def Header( # noqa: N802
- default: Any,
+ default: Any = Undefined,
*,
alias: Optional[str] = None,
convert_underscores: bool = True,
@@ -103,7 +103,7 @@ def Header( # noqa: N802
**extra: Any,
) -> Any:
return params.Header(
- default,
+ default=default,
alias=alias,
convert_underscores=convert_underscores,
title=title,
@@ -124,7 +124,7 @@ def Header( # noqa: N802
def Cookie( # noqa: N802
- default: Any,
+ default: Any = Undefined,
*,
alias: Optional[str] = None,
title: Optional[str] = None,
@@ -143,7 +143,7 @@ def Cookie( # noqa: N802
**extra: Any,
) -> Any:
return params.Cookie(
- default,
+ default=default,
alias=alias,
title=title,
description=description,
@@ -163,7 +163,7 @@ def Cookie( # noqa: N802
def Body( # noqa: N802
- default: Any,
+ default: Any = Undefined,
*,
embed: bool = False,
media_type: str = "application/json",
@@ -182,7 +182,7 @@ def Body( # noqa: N802
**extra: Any,
) -> Any:
return params.Body(
- default,
+ default=default,
embed=embed,
media_type=media_type,
alias=alias,
@@ -202,7 +202,7 @@ def Body( # noqa: N802
def Form( # noqa: N802
- default: Any,
+ default: Any = Undefined,
*,
media_type: str = "application/x-www-form-urlencoded",
alias: Optional[str] = None,
@@ -220,7 +220,7 @@ def Form( # noqa: N802
**extra: Any,
) -> Any:
return params.Form(
- default,
+ default=default,
media_type=media_type,
alias=alias,
title=title,
@@ -239,7 +239,7 @@ def Form( # noqa: N802
def File( # noqa: N802
- default: Any,
+ default: Any = Undefined,
*,
media_type: str = "multipart/form-data",
alias: Optional[str] = None,
@@ -257,7 +257,7 @@ def File( # noqa: N802
**extra: Any,
) -> Any:
return params.File(
- default,
+ default=default,
media_type=media_type,
alias=alias,
title=title,
diff --git a/fastapi/params.py b/fastapi/params.py
index 042bbd42f..5395b98a3 100644
--- a/fastapi/params.py
+++ b/fastapi/params.py
@@ -16,7 +16,7 @@ class Param(FieldInfo):
def __init__(
self,
- default: Any,
+ default: Any = Undefined,
*,
alias: Optional[str] = None,
title: Optional[str] = None,
@@ -39,7 +39,7 @@ class Param(FieldInfo):
self.examples = examples
self.include_in_schema = include_in_schema
super().__init__(
- default,
+ default=default,
alias=alias,
title=title,
description=description,
@@ -62,7 +62,7 @@ class Path(Param):
def __init__(
self,
- default: Any,
+ default: Any = Undefined,
*,
alias: Optional[str] = None,
title: Optional[str] = None,
@@ -82,7 +82,7 @@ class Path(Param):
):
self.in_ = self.in_
super().__init__(
- ...,
+ default=...,
alias=alias,
title=title,
description=description,
@@ -106,7 +106,7 @@ class Query(Param):
def __init__(
self,
- default: Any,
+ default: Any = Undefined,
*,
alias: Optional[str] = None,
title: Optional[str] = None,
@@ -125,7 +125,7 @@ class Query(Param):
**extra: Any,
):
super().__init__(
- default,
+ default=default,
alias=alias,
title=title,
description=description,
@@ -149,7 +149,7 @@ class Header(Param):
def __init__(
self,
- default: Any,
+ default: Any = Undefined,
*,
alias: Optional[str] = None,
convert_underscores: bool = True,
@@ -170,7 +170,7 @@ class Header(Param):
):
self.convert_underscores = convert_underscores
super().__init__(
- default,
+ default=default,
alias=alias,
title=title,
description=description,
@@ -194,7 +194,7 @@ class Cookie(Param):
def __init__(
self,
- default: Any,
+ default: Any = Undefined,
*,
alias: Optional[str] = None,
title: Optional[str] = None,
@@ -213,7 +213,7 @@ class Cookie(Param):
**extra: Any,
):
super().__init__(
- default,
+ default=default,
alias=alias,
title=title,
description=description,
@@ -235,7 +235,7 @@ class Cookie(Param):
class Body(FieldInfo):
def __init__(
self,
- default: Any,
+ default: Any = Undefined,
*,
embed: bool = False,
media_type: str = "application/json",
@@ -258,7 +258,7 @@ class Body(FieldInfo):
self.example = example
self.examples = examples
super().__init__(
- default,
+ default=default,
alias=alias,
title=title,
description=description,
@@ -297,7 +297,7 @@ class Form(Body):
**extra: Any,
):
super().__init__(
- default,
+ default=default,
embed=True,
media_type=media_type,
alias=alias,
@@ -337,7 +337,7 @@ class File(Form):
**extra: Any,
):
super().__init__(
- default,
+ default=default,
media_type=media_type,
alias=alias,
title=title,
diff --git a/fastapi/routing.py b/fastapi/routing.py
index 7dae04521..6f1a8e900 100644
--- a/fastapi/routing.py
+++ b/fastapi/routing.py
@@ -29,13 +29,13 @@ from fastapi.dependencies.utils import (
)
from fastapi.encoders import DictIntStrAny, SetIntStr, jsonable_encoder
from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
-from fastapi.openapi.constants import STATUS_CODES_WITH_NO_BODY
from fastapi.types import DecoratedCallable
from fastapi.utils import (
create_cloned_field,
create_response_field,
- generate_operation_id_for_path,
+ generate_unique_id,
get_value_or_default,
+ is_body_allowed_for_status_code,
)
from pydantic import BaseModel
from pydantic.error_wrappers import ErrorWrapper, ValidationError
@@ -127,7 +127,7 @@ async def serialize_response(
if is_coroutine:
value, errors_ = field.validate(response_content, {}, loc=("response",))
else:
- value, errors_ = await run_in_threadpool(
+ value, errors_ = await run_in_threadpool( # type: ignore[misc]
field.validate, response_content, {}, loc=("response",)
)
if isinstance(errors_, ErrorWrapper):
@@ -232,7 +232,17 @@ def get_request_handler(
if raw_response.background is None:
raw_response.background = background_tasks
return raw_response
- response_data = await serialize_response(
+ response_args: Dict[str, Any] = {"background": background_tasks}
+ # If status_code was set, use it, otherwise use the default from the
+ # response class, in the case of redirect it's 307
+ current_status_code = (
+ status_code if status_code else sub_response.status_code
+ )
+ if current_status_code is not None:
+ response_args["status_code"] = current_status_code
+ if sub_response.status_code:
+ response_args["status_code"] = sub_response.status_code
+ content = await serialize_response(
field=response_field,
response_content=raw_response,
include=response_model_include,
@@ -243,15 +253,10 @@ def get_request_handler(
exclude_none=response_model_exclude_none,
is_coroutine=is_coroutine,
)
- response_args: Dict[str, Any] = {"background": background_tasks}
- # If status_code was set, use it, otherwise use the default from the
- # response class, in the case of redirect it's 307
- if status_code is not None:
- response_args["status_code"] = status_code
- response = actual_response_class(response_data, **response_args)
+ response = actual_response_class(content, **response_args)
+ if not is_body_allowed_for_status_code(status_code):
+ response.body = b""
response.headers.raw.extend(sub_response.headers.raw)
- if sub_response.status_code:
- response.status_code = sub_response.status_code
return response
return app
@@ -335,24 +340,50 @@ class APIRoute(routing.Route):
dependency_overrides_provider: Optional[Any] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Union[
+ Callable[["APIRoute"], str], DefaultPlaceholder
+ ] = Default(generate_unique_id),
) -> None:
- # normalise enums e.g. http.HTTPStatus
- if isinstance(status_code, IntEnum):
- status_code = int(status_code)
self.path = path
self.endpoint = endpoint
+ self.response_model = response_model
+ self.summary = summary
+ self.response_description = response_description
+ self.deprecated = deprecated
+ self.operation_id = operation_id
+ self.response_model_include = response_model_include
+ self.response_model_exclude = response_model_exclude
+ self.response_model_by_alias = response_model_by_alias
+ self.response_model_exclude_unset = response_model_exclude_unset
+ self.response_model_exclude_defaults = response_model_exclude_defaults
+ self.response_model_exclude_none = response_model_exclude_none
+ self.include_in_schema = include_in_schema
+ self.response_class = response_class
+ self.dependency_overrides_provider = dependency_overrides_provider
+ self.callbacks = callbacks
+ self.openapi_extra = openapi_extra
+ self.generate_unique_id_function = generate_unique_id_function
+ self.tags = tags or []
+ self.responses = responses or {}
self.name = get_name(endpoint) if name is None else name
self.path_regex, self.path_format, self.param_convertors = compile_path(path)
if methods is None:
methods = ["GET"]
- self.methods: Set[str] = set([method.upper() for method in methods])
- self.unique_id = generate_operation_id_for_path(
- name=self.name, path=self.path_format, method=list(methods)[0]
- )
- self.response_model = response_model
+ self.methods: Set[str] = {method.upper() for method in methods}
+ if isinstance(generate_unique_id_function, DefaultPlaceholder):
+ current_generate_unique_id: Callable[
+ ["APIRoute"], str
+ ] = generate_unique_id_function.value
+ else:
+ current_generate_unique_id = generate_unique_id_function
+ self.unique_id = self.operation_id or current_generate_unique_id(self)
+ # normalize enums e.g. http.HTTPStatus
+ if isinstance(status_code, IntEnum):
+ status_code = int(status_code)
+ self.status_code = status_code
if self.response_model:
- assert (
- status_code not in STATUS_CODES_WITH_NO_BODY
+ assert is_body_allowed_for_status_code(
+ status_code
), f"Status code {status_code} must not have a response body"
response_name = "Response_" + self.unique_id
self.response_field = create_response_field(
@@ -371,26 +402,21 @@ class APIRoute(routing.Route):
else:
self.response_field = None # type: ignore
self.secure_cloned_response_field = None
- self.status_code = status_code
- self.tags = tags or []
if dependencies:
self.dependencies = list(dependencies)
else:
self.dependencies = []
- self.summary = summary
self.description = description or inspect.cleandoc(self.endpoint.__doc__ or "")
# if a "form feed" character (page break) is found in the description text,
# truncate description text to the content preceding the first "form feed"
self.description = self.description.split("\f")[0]
- self.response_description = response_description
- self.responses = responses or {}
response_fields = {}
for additional_status_code, response in self.responses.items():
assert isinstance(response, dict), "An additional response must be a dict"
model = response.get("model")
if model:
- assert (
- additional_status_code not in STATUS_CODES_WITH_NO_BODY
+ assert is_body_allowed_for_status_code(
+ additional_status_code
), f"Status code {additional_status_code} must not have a response body"
response_name = f"Response_{additional_status_code}_{self.unique_id}"
response_field = create_response_field(name=response_name, type_=model)
@@ -399,16 +425,6 @@ class APIRoute(routing.Route):
self.response_fields: Dict[Union[int, str], ModelField] = response_fields
else:
self.response_fields = {}
- self.deprecated = deprecated
- self.operation_id = operation_id
- self.response_model_include = response_model_include
- self.response_model_exclude = response_model_exclude
- self.response_model_by_alias = response_model_by_alias
- self.response_model_exclude_unset = response_model_exclude_unset
- self.response_model_exclude_defaults = response_model_exclude_defaults
- self.response_model_exclude_none = response_model_exclude_none
- self.include_in_schema = include_in_schema
- self.response_class = response_class
assert callable(endpoint), "An endpoint must be a callable"
self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
@@ -418,10 +434,7 @@ class APIRoute(routing.Route):
get_parameterless_sub_dependant(depends=depends, path=self.path_format),
)
self.body_field = get_body_field(dependant=self.dependant, name=self.unique_id)
- self.dependency_overrides_provider = dependency_overrides_provider
- self.callbacks = callbacks
self.app = request_response(self.get_route_handler())
- self.openapi_extra = openapi_extra
def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]:
return get_request_handler(
@@ -465,13 +478,16 @@ class APIRouter(routing.Router):
on_shutdown: Optional[Sequence[Callable[[], Any]]] = None,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
+ generate_unique_id_function: Callable[[APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> None:
super().__init__(
- routes=routes, # type: ignore # in Starlette
+ routes=routes,
redirect_slashes=redirect_slashes,
- default=default, # type: ignore # in Starlette
- on_startup=on_startup, # type: ignore # in Starlette
- on_shutdown=on_shutdown, # type: ignore # in Starlette
+ default=default,
+ on_startup=on_startup,
+ on_shutdown=on_shutdown,
)
if prefix:
assert prefix.startswith("/"), "A path prefix must start with '/'"
@@ -488,6 +504,7 @@ class APIRouter(routing.Router):
self.dependency_overrides_provider = dependency_overrides_provider
self.route_class = route_class
self.default_response_class = default_response_class
+ self.generate_unique_id_function = generate_unique_id_function
def add_api_route(
self,
@@ -519,6 +536,9 @@ class APIRouter(routing.Router):
route_class_override: Optional[Type[APIRoute]] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Union[
+ Callable[[APIRoute], str], DefaultPlaceholder
+ ] = Default(generate_unique_id),
) -> None:
route_class = route_class_override or self.route_class
responses = responses or {}
@@ -535,6 +555,9 @@ class APIRouter(routing.Router):
current_callbacks = self.callbacks.copy()
if callbacks:
current_callbacks.extend(callbacks)
+ current_generate_unique_id = get_value_or_default(
+ generate_unique_id_function, self.generate_unique_id_function
+ )
route = route_class(
self.prefix + path,
endpoint=endpoint,
@@ -561,6 +584,7 @@ class APIRouter(routing.Router):
dependency_overrides_provider=self.dependency_overrides_provider,
callbacks=current_callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=current_generate_unique_id,
)
self.routes.append(route)
@@ -590,6 +614,9 @@ class APIRouter(routing.Router):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
def decorator(func: DecoratedCallable) -> DecoratedCallable:
self.add_api_route(
@@ -617,6 +644,7 @@ class APIRouter(routing.Router):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
return func
@@ -626,7 +654,7 @@ class APIRouter(routing.Router):
self, path: str, endpoint: Callable[..., Any], name: Optional[str] = None
) -> None:
route = APIWebSocketRoute(
- path,
+ self.prefix + path,
endpoint=endpoint,
name=name,
dependency_overrides_provider=self.dependency_overrides_provider,
@@ -654,6 +682,9 @@ class APIRouter(routing.Router):
callbacks: Optional[List[BaseRoute]] = None,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
+ generate_unique_id_function: Callable[[APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> None:
if prefix:
assert prefix.startswith("/"), "A path prefix must start with '/'"
@@ -694,6 +725,12 @@ class APIRouter(routing.Router):
current_callbacks.extend(callbacks)
if route.callbacks:
current_callbacks.extend(route.callbacks)
+ current_generate_unique_id = get_value_or_default(
+ route.generate_unique_id_function,
+ router.generate_unique_id_function,
+ generate_unique_id_function,
+ self.generate_unique_id_function,
+ )
self.add_api_route(
prefix + route.path,
route.endpoint,
@@ -722,9 +759,10 @@ class APIRouter(routing.Router):
route_class_override=type(route),
callbacks=current_callbacks,
openapi_extra=route.openapi_extra,
+ generate_unique_id_function=current_generate_unique_id,
)
elif isinstance(route, routing.Route):
- methods = list(route.methods or []) # type: ignore # in Starlette
+ methods = list(route.methods or [])
self.add_route(
prefix + route.path,
route.endpoint,
@@ -770,6 +808,9 @@ class APIRouter(routing.Router):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.api_route(
path=path,
@@ -795,6 +836,7 @@ class APIRouter(routing.Router):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def put(
@@ -822,6 +864,9 @@ class APIRouter(routing.Router):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.api_route(
path=path,
@@ -847,6 +892,7 @@ class APIRouter(routing.Router):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def post(
@@ -874,6 +920,9 @@ class APIRouter(routing.Router):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.api_route(
path=path,
@@ -899,6 +948,7 @@ class APIRouter(routing.Router):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def delete(
@@ -926,6 +976,9 @@ class APIRouter(routing.Router):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.api_route(
path=path,
@@ -951,6 +1004,7 @@ class APIRouter(routing.Router):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def options(
@@ -978,6 +1032,9 @@ class APIRouter(routing.Router):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.api_route(
path=path,
@@ -1003,6 +1060,7 @@ class APIRouter(routing.Router):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def head(
@@ -1030,6 +1088,9 @@ class APIRouter(routing.Router):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.api_route(
path=path,
@@ -1055,6 +1116,7 @@ class APIRouter(routing.Router):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def patch(
@@ -1082,6 +1144,9 @@ class APIRouter(routing.Router):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.api_route(
path=path,
@@ -1107,6 +1172,7 @@ class APIRouter(routing.Router):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
def trace(
@@ -1134,6 +1200,9 @@ class APIRouter(routing.Router):
name: Optional[str] = None,
callbacks: Optional[List[BaseRoute]] = None,
openapi_extra: Optional[Dict[str, Any]] = None,
+ generate_unique_id_function: Callable[[APIRoute], str] = Default(
+ generate_unique_id
+ ),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
return self.api_route(
@@ -1160,4 +1229,5 @@ class APIRouter(routing.Router):
name=name,
callbacks=callbacks,
openapi_extra=openapi_extra,
+ generate_unique_id_function=generate_unique_id_function,
)
diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py
index bdc6e2ea9..888208c15 100644
--- a/fastapi/security/oauth2.py
+++ b/fastapi/security/oauth2.py
@@ -45,12 +45,12 @@ class OAuth2PasswordRequestForm:
def __init__(
self,
- grant_type: str = Form(None, regex="password"),
- username: str = Form(...),
- password: str = Form(...),
- scope: str = Form(""),
- client_id: Optional[str] = Form(None),
- client_secret: Optional[str] = Form(None),
+ grant_type: str = Form(default=None, regex="password"),
+ username: str = Form(),
+ password: str = Form(),
+ scope: str = Form(default=""),
+ client_id: Optional[str] = Form(default=None),
+ client_secret: Optional[str] = Form(default=None),
):
self.grant_type = grant_type
self.username = username
@@ -95,12 +95,12 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
def __init__(
self,
- grant_type: str = Form(..., regex="password"),
- username: str = Form(...),
- password: str = Form(...),
- scope: str = Form(""),
- client_id: Optional[str] = Form(None),
- client_secret: Optional[str] = Form(None),
+ grant_type: str = Form(regex="password"),
+ username: str = Form(),
+ password: str = Form(),
+ scope: str = Form(default=""),
+ client_id: Optional[str] = Form(default=None),
+ client_secret: Optional[str] = Form(default=None),
):
super().__init__(
grant_type=grant_type,
diff --git a/fastapi/utils.py b/fastapi/utils.py
index 8913d85b2..887d57c90 100644
--- a/fastapi/utils.py
+++ b/fastapi/utils.py
@@ -1,8 +1,9 @@
import functools
import re
+import warnings
from dataclasses import is_dataclass
from enum import Enum
-from typing import Any, Dict, Optional, Set, Type, Union, cast
+from typing import TYPE_CHECKING, Any, Dict, Optional, Set, Type, Union, cast
import fastapi
from fastapi.datastructures import DefaultPlaceholder, DefaultType
@@ -13,6 +14,16 @@ from pydantic.fields import FieldInfo, ModelField, UndefinedType
from pydantic.schema import model_process_schema
from pydantic.utils import lenient_issubclass
+if TYPE_CHECKING: # pragma: nocover
+ from .routing import APIRoute
+
+
+def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool:
+ if status_code is None:
+ return True
+ current_status_code = int(status_code)
+ return not (current_status_code < 200 or current_status_code in {204, 304})
+
def get_model_definitions(
*,
@@ -48,7 +59,7 @@ def create_response_field(
Create a new response field. Raises if type_ is invalid.
"""
class_validators = class_validators or {}
- field_info = field_info or FieldInfo(None)
+ field_info = field_info or FieldInfo()
response_field = functools.partial(
ModelField,
@@ -119,23 +130,39 @@ def create_cloned_field(
return new_field
-def generate_operation_id_for_path(*, name: str, path: str, method: str) -> str:
+def generate_operation_id_for_path(
+ *, name: str, path: str, method: str
+) -> str: # pragma: nocover
+ warnings.warn(
+ "fastapi.utils.generate_operation_id_for_path() was deprecated, "
+ "it is not used internally, and will be removed soon",
+ DeprecationWarning,
+ stacklevel=2,
+ )
operation_id = name + path
operation_id = re.sub("[^0-9a-zA-Z_]", "_", operation_id)
operation_id = operation_id + "_" + method.lower()
return operation_id
+def generate_unique_id(route: "APIRoute") -> str:
+ operation_id = route.name + route.path_format
+ operation_id = re.sub("[^0-9a-zA-Z_]", "_", operation_id)
+ assert route.methods
+ operation_id = operation_id + "_" + list(route.methods)[0].lower()
+ return operation_id
+
+
def deep_dict_update(main_dict: Dict[Any, Any], update_dict: Dict[Any, Any]) -> None:
- for key in update_dict:
+ for key, value in update_dict.items():
if (
key in main_dict
and isinstance(main_dict[key], dict)
- and isinstance(update_dict[key], dict)
+ and isinstance(value, dict)
):
- deep_dict_update(main_dict[key], update_dict[key])
+ deep_dict_update(main_dict[key], value)
else:
- main_dict[key] = update_dict[key]
+ main_dict[key] = value
def get_value_or_default(
diff --git a/pending_tests/main.py b/pending_tests/main.py
deleted file mode 100644
index 5e919f1bc..000000000
--- a/pending_tests/main.py
+++ /dev/null
@@ -1,118 +0,0 @@
-from fastapi import (
- Body,
- Cookie,
- Depends,
- FastAPI,
- File,
- Form,
- Header,
- Path,
- Query,
- Security,
-)
-from fastapi.security import (
- HTTPBasic,
- OAuth2,
- OAuth2PasswordBearer,
- OAuth2PasswordRequestForm,
-)
-from pydantic import BaseModel
-from starlette.responses import HTMLResponse, JSONResponse, PlainTextResponse
-from starlette.status import HTTP_202_ACCEPTED
-
-app = FastAPI()
-
-
-@app.get("/security")
-def get_security(sec=Security(HTTPBasic())):
- return sec
-
-
-reusable_oauth2 = OAuth2(
- flows={
- "password": {
- "tokenUrl": "token",
- "scopes": {"read:user": "Read a User", "write:user": "Create a user"},
- }
- }
-)
-
-
-@app.get("/security/oauth2")
-def get_security_oauth2(sec=Security(reusable_oauth2, scopes=["read:user"])):
- return sec
-
-
-@app.post("/token")
-def post_token(request_data: OAuth2PasswordRequestForm = Form(...)):
- data = request_data.parse()
- access_token = data.username + ":" + data.password
- return {"access_token": access_token}
-
-
-class Item(BaseModel):
- name: str
- price: float
- is_offer: bool
-
-
-class FakeDB:
- def __init__(self):
- self.data = {
- "johndoe": {
- "username": "johndoe",
- "password": "shouldbehashed",
- "first_name": "John",
- "last_name": "Doe",
- }
- }
-
-
-class DBConnectionManager:
- def __init__(self):
- self.db = FakeDB()
-
- def __call__(self):
- return self.db
-
-
-connection_manager = DBConnectionManager()
-
-
-class TokenUserData(BaseModel):
- username: str
- password: str
-
-
-class UserInDB(BaseModel):
- username: str
- password: str
- first_name: str
- last_name: str
-
-
-def require_token(
- token: str = Security(reusable_oauth2, scopes=["read:user", "write:user"])
-):
- raw_token = token.replace("Bearer ", "")
- # Never do this plaintext password usage in production
- username, password = raw_token.split(":")
- return TokenUserData(username=username, password=password)
-
-
-def require_user(
- db: FakeDB = Depends(connection_manager),
- user_data: TokenUserData = Depends(require_token),
-):
- return db.data[user_data.username]
-
-
-class UserOut(BaseModel):
- username: str
- first_name: str
- last_name: str
-
-
-@app.get("/dependency", response_model=UserOut)
-def get_dependency(user: UserInDB = Depends(require_user)):
- return user
diff --git a/pyproject.toml b/pyproject.toml
index 77c01322f..5ffdf93ad 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -35,7 +35,7 @@ classifiers = [
"Topic :: Internet :: WWW/HTTP",
]
requires = [
- "starlette ==0.17.1",
+ "starlette==0.19.1",
"pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0",
]
description-file = "README.md"
@@ -50,7 +50,7 @@ test = [
"pytest-cov >=2.12.0,<4.0.0",
"mypy ==0.910",
"flake8 >=3.8.3,<4.0.0",
- "black ==21.9b0",
+ "black == 22.3.0",
"isort >=5.0.6,<6.0.0",
"requests >=2.24.0,<3.0.0",
"httpx >=0.14.0,<0.19.0",
@@ -59,41 +59,44 @@ test = [
"peewee >=3.13.3,<4.0.0",
"databases[sqlite] >=0.3.2,<0.6.0",
"orjson >=3.2.1,<4.0.0",
- "ujson >=4.0.1,<5.0.0",
+ "ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0",
"python-multipart >=0.0.5,<0.0.6",
"flask >=1.1.2,<3.0.0",
"anyio[trio] >=3.2.1,<4.0.0",
# types
- "types-ujson ==0.1.1",
- "types-orjson ==3.6.0",
- "types-dataclasses ==0.1.7; python_version<'3.7'",
+ "types-ujson ==4.2.1",
+ "types-orjson ==3.6.2",
+ "types-dataclasses ==0.6.5; python_version<'3.7'",
]
doc = [
"mkdocs >=1.1.2,<2.0.0",
"mkdocs-material >=8.1.4,<9.0.0",
"mdx-include >=1.4.1,<2.0.0",
"mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0",
- "typer-cli >=0.0.12,<0.0.13",
- "pyyaml >=5.3.1,<6.0.0"
+ # TODO: upgrade and enable typer-cli once it supports Click 8.x.x
+ # "typer-cli >=0.0.12,<0.0.13",
+ "typer >=0.4.1,<0.5.0",
+ "pyyaml >=5.3.1,<7.0.0",
]
dev = [
"python-jose[cryptography] >=3.3.0,<4.0.0",
"passlib[bcrypt] >=1.7.2,<2.0.0",
"autoflake >=1.4.0,<2.0.0",
"flake8 >=3.8.3,<4.0.0",
- "uvicorn[standard] >=0.12.0,<0.16.0",
+ "uvicorn[standard] >=0.12.0,<0.18.0",
+ "pre-commit >=2.17.0,<3.0.0",
]
all = [
"requests >=2.24.0,<3.0.0",
"jinja2 >=2.11.2,<4.0.0",
"python-multipart >=0.0.5,<0.0.6",
"itsdangerous >=1.1.0,<3.0.0",
- "pyyaml >=5.3.1,<6.0.0",
- "ujson >=4.0.1,<5.0.0",
+ "pyyaml >=5.3.1,<7.0.0",
+ "ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0",
"orjson >=3.2.1,<4.0.0",
"email_validator >=1.1.1,<2.0.0",
- "uvicorn[standard] >=0.12.0,<0.16.0",
+ "uvicorn[standard] >=0.12.0,<0.18.0",
]
[tool.isort]
@@ -138,4 +141,7 @@ filterwarnings = [
"error",
# TODO: needed by asyncio in Python 3.9.7 https://bugs.python.org/issue45097, try to remove on 3.9.8
'ignore:The loop argument is deprecated since Python 3\.8, and scheduled for removal in Python 3\.10:DeprecationWarning:asyncio',
+ 'ignore:starlette.middleware.wsgi is deprecated and will be removed in a future release\..*:DeprecationWarning:starlette',
+ # TODO: remove after dropping support for Python 3.6
+ 'ignore:Python 3.6 is no longer supported by the Python core team. Therefore, support for it is deprecated in cryptography and will be removed in a future release.:UserWarning:jose',
]
diff --git a/tests/main.py b/tests/main.py
index d5603d0e6..f70496db8 100644
--- a/tests/main.py
+++ b/tests/main.py
@@ -49,97 +49,97 @@ def get_bool_id(item_id: bool):
@app.get("/path/param/{item_id}")
-def get_path_param_id(item_id: Optional[str] = Path(None)):
+def get_path_param_id(item_id: str = Path()):
return item_id
@app.get("/path/param-required/{item_id}")
-def get_path_param_required_id(item_id: str = Path(...)):
+def get_path_param_required_id(item_id: str = Path()):
return item_id
@app.get("/path/param-minlength/{item_id}")
-def get_path_param_min_length(item_id: str = Path(..., min_length=3)):
+def get_path_param_min_length(item_id: str = Path(min_length=3)):
return item_id
@app.get("/path/param-maxlength/{item_id}")
-def get_path_param_max_length(item_id: str = Path(..., max_length=3)):
+def get_path_param_max_length(item_id: str = Path(max_length=3)):
return item_id
@app.get("/path/param-min_maxlength/{item_id}")
-def get_path_param_min_max_length(item_id: str = Path(..., max_length=3, min_length=2)):
+def get_path_param_min_max_length(item_id: str = Path(max_length=3, min_length=2)):
return item_id
@app.get("/path/param-gt/{item_id}")
-def get_path_param_gt(item_id: float = Path(..., gt=3)):
+def get_path_param_gt(item_id: float = Path(gt=3)):
return item_id
@app.get("/path/param-gt0/{item_id}")
-def get_path_param_gt0(item_id: float = Path(..., gt=0)):
+def get_path_param_gt0(item_id: float = Path(gt=0)):
return item_id
@app.get("/path/param-ge/{item_id}")
-def get_path_param_ge(item_id: float = Path(..., ge=3)):
+def get_path_param_ge(item_id: float = Path(ge=3)):
return item_id
@app.get("/path/param-lt/{item_id}")
-def get_path_param_lt(item_id: float = Path(..., lt=3)):
+def get_path_param_lt(item_id: float = Path(lt=3)):
return item_id
@app.get("/path/param-lt0/{item_id}")
-def get_path_param_lt0(item_id: float = Path(..., lt=0)):
+def get_path_param_lt0(item_id: float = Path(lt=0)):
return item_id
@app.get("/path/param-le/{item_id}")
-def get_path_param_le(item_id: float = Path(..., le=3)):
+def get_path_param_le(item_id: float = Path(le=3)):
return item_id
@app.get("/path/param-lt-gt/{item_id}")
-def get_path_param_lt_gt(item_id: float = Path(..., lt=3, gt=1)):
+def get_path_param_lt_gt(item_id: float = Path(lt=3, gt=1)):
return item_id
@app.get("/path/param-le-ge/{item_id}")
-def get_path_param_le_ge(item_id: float = Path(..., le=3, ge=1)):
+def get_path_param_le_ge(item_id: float = Path(le=3, ge=1)):
return item_id
@app.get("/path/param-lt-int/{item_id}")
-def get_path_param_lt_int(item_id: int = Path(..., lt=3)):
+def get_path_param_lt_int(item_id: int = Path(lt=3)):
return item_id
@app.get("/path/param-gt-int/{item_id}")
-def get_path_param_gt_int(item_id: int = Path(..., gt=3)):
+def get_path_param_gt_int(item_id: int = Path(gt=3)):
return item_id
@app.get("/path/param-le-int/{item_id}")
-def get_path_param_le_int(item_id: int = Path(..., le=3)):
+def get_path_param_le_int(item_id: int = Path(le=3)):
return item_id
@app.get("/path/param-ge-int/{item_id}")
-def get_path_param_ge_int(item_id: int = Path(..., ge=3)):
+def get_path_param_ge_int(item_id: int = Path(ge=3)):
return item_id
@app.get("/path/param-lt-gt-int/{item_id}")
-def get_path_param_lt_gt_int(item_id: int = Path(..., lt=3, gt=1)):
+def get_path_param_lt_gt_int(item_id: int = Path(lt=3, gt=1)):
return item_id
@app.get("/path/param-le-ge-int/{item_id}")
-def get_path_param_le_ge_int(item_id: int = Path(..., le=3, ge=1)):
+def get_path_param_le_ge_int(item_id: int = Path(le=3, ge=1)):
return item_id
@@ -173,19 +173,19 @@ def get_query_type_int_default(query: int = 10):
@app.get("/query/param")
-def get_query_param(query=Query(None)):
+def get_query_param(query=Query(default=None)):
if query is None:
return "foo bar"
return f"foo bar {query}"
@app.get("/query/param-required")
-def get_query_param_required(query=Query(...)):
+def get_query_param_required(query=Query()):
return f"foo bar {query}"
@app.get("/query/param-required/int")
-def get_query_param_required_type(query: int = Query(...)):
+def get_query_param_required_type(query: int = Query()):
return f"foo bar {query}"
diff --git a/tests/test_additional_properties.py b/tests/test_additional_properties.py
index 9e15e6ed0..016c1f734 100644
--- a/tests/test_additional_properties.py
+++ b/tests/test_additional_properties.py
@@ -76,7 +76,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_additional_responses_custom_model_in_callback.py b/tests/test_additional_responses_custom_model_in_callback.py
index 36dd0d6db..a1072cc56 100644
--- a/tests/test_additional_responses_custom_model_in_callback.py
+++ b/tests/test_additional_responses_custom_model_in_callback.py
@@ -119,7 +119,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_additional_responses_default_validationerror.py b/tests/test_additional_responses_default_validationerror.py
index 6ea372ce8..cabb536d7 100644
--- a/tests/test_additional_responses_default_validationerror.py
+++ b/tests/test_additional_responses_default_validationerror.py
@@ -54,7 +54,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_application.py b/tests/test_application.py
index 5ba737307..d9194c15c 100644
--- a/tests/test_application.py
+++ b/tests/test_application.py
@@ -1101,7 +1101,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_dependency_duplicates.py b/tests/test_dependency_duplicates.py
index 5e15812b6..33899134e 100644
--- a/tests/test_dependency_duplicates.py
+++ b/tests/test_dependency_duplicates.py
@@ -177,7 +177,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_dependency_normal_exceptions.py b/tests/test_dependency_normal_exceptions.py
index 49a19f460..23c366d5d 100644
--- a/tests/test_dependency_normal_exceptions.py
+++ b/tests/test_dependency_normal_exceptions.py
@@ -26,14 +26,14 @@ async def get_database():
@app.put("/invalid-user/{user_id}")
def put_invalid_user(
- user_id: str, name: str = Body(...), db: dict = Depends(get_database)
+ user_id: str, name: str = Body(), db: dict = Depends(get_database)
):
db[user_id] = name
raise HTTPException(status_code=400, detail="Invalid user")
@app.put("/user/{user_id}")
-def put_user(user_id: str, name: str = Body(...), db: dict = Depends(get_database)):
+def put_user(user_id: str, name: str = Body(), db: dict = Depends(get_database)):
db[user_id] = name
return {"message": "OK"}
diff --git a/tests/test_extra_routes.py b/tests/test_extra_routes.py
index 6aba3e8dd..491ba61c6 100644
--- a/tests/test_extra_routes.py
+++ b/tests/test_extra_routes.py
@@ -32,12 +32,12 @@ def delete_item(item_id: str, item: Item):
@app.head("/items/{item_id}")
def head_item(item_id: str):
- return JSONResponse(headers={"x-fastapi-item-id": item_id})
+ return JSONResponse(None, headers={"x-fastapi-item-id": item_id})
@app.options("/items/{item_id}")
def options_item(item_id: str):
- return JSONResponse(headers={"x-fastapi-item-id": item_id})
+ return JSONResponse(None, headers={"x-fastapi-item-id": item_id})
@app.patch("/items/{item_id}")
@@ -47,7 +47,7 @@ def patch_item(item_id: str, item: Item):
@app.trace("/items/{item_id}")
def trace_item(item_id: str):
- return JSONResponse(media_type="message/http")
+ return JSONResponse(None, media_type="message/http")
client = TestClient(app)
@@ -292,7 +292,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_filter_pydantic_sub_model.py b/tests/test_filter_pydantic_sub_model.py
index 90a372976..8814356a1 100644
--- a/tests/test_filter_pydantic_sub_model.py
+++ b/tests/test_filter_pydantic_sub_model.py
@@ -116,7 +116,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_forms_from_non_typing_sequences.py b/tests/test_forms_from_non_typing_sequences.py
index be917eab7..52ce24753 100644
--- a/tests/test_forms_from_non_typing_sequences.py
+++ b/tests/test_forms_from_non_typing_sequences.py
@@ -5,17 +5,17 @@ app = FastAPI()
@app.post("/form/python-list")
-def post_form_param_list(items: list = Form(...)):
+def post_form_param_list(items: list = Form()):
return items
@app.post("/form/python-set")
-def post_form_param_set(items: set = Form(...)):
+def post_form_param_set(items: set = Form()):
return items
@app.post("/form/python-tuple")
-def post_form_param_tuple(items: tuple = Form(...)):
+def post_form_param_tuple(items: tuple = Form()):
return items
diff --git a/tests/test_generate_unique_id_function.py b/tests/test_generate_unique_id_function.py
new file mode 100644
index 000000000..0b519f859
--- /dev/null
+++ b/tests/test_generate_unique_id_function.py
@@ -0,0 +1,1631 @@
+import warnings
+from typing import List
+
+from fastapi import APIRouter, FastAPI
+from fastapi.routing import APIRoute
+from fastapi.testclient import TestClient
+from pydantic import BaseModel
+
+
+def custom_generate_unique_id(route: APIRoute):
+ return f"foo_{route.name}"
+
+
+def custom_generate_unique_id2(route: APIRoute):
+ return f"bar_{route.name}"
+
+
+def custom_generate_unique_id3(route: APIRoute):
+ return f"baz_{route.name}"
+
+
+class Item(BaseModel):
+ name: str
+ price: float
+
+
+class Message(BaseModel):
+ title: str
+ description: str
+
+
+def test_top_level_generate_unique_id():
+ app = FastAPI(generate_unique_id_function=custom_generate_unique_id)
+ router = APIRouter()
+
+ @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}})
+ def post_root(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ @router.post(
+ "/router", response_model=List[Item], responses={404: {"model": List[Message]}}
+ )
+ def post_router(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ app.include_router(router)
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ data = response.json()
+ assert data == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "post": {
+ "summary": "Post Root",
+ "operationId": "foo_post_root",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_foo_post_root"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Foo Post Root",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Foo Post Root",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/router": {
+ "post": {
+ "summary": "Post Router",
+ "operationId": "foo_post_router",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_foo_post_router"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Foo Post Router",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Foo Post Router",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_foo_post_root": {
+ "title": "Body_foo_post_root",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "Body_foo_post_router": {
+ "title": "Body_foo_post_router",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ },
+ },
+ "Message": {
+ "title": "Message",
+ "required": ["title", "description"],
+ "type": "object",
+ "properties": {
+ "title": {"title": "Title", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
+
+
+def test_router_overrides_generate_unique_id():
+ app = FastAPI(generate_unique_id_function=custom_generate_unique_id)
+ router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)
+
+ @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}})
+ def post_root(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ @router.post(
+ "/router", response_model=List[Item], responses={404: {"model": List[Message]}}
+ )
+ def post_router(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ app.include_router(router)
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ data = response.json()
+ assert data == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "post": {
+ "summary": "Post Root",
+ "operationId": "foo_post_root",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_foo_post_root"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Foo Post Root",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Foo Post Root",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/router": {
+ "post": {
+ "summary": "Post Router",
+ "operationId": "bar_post_router",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_bar_post_router"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Bar Post Router",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Bar Post Router",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_bar_post_router": {
+ "title": "Body_bar_post_router",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "Body_foo_post_root": {
+ "title": "Body_foo_post_root",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ },
+ },
+ "Message": {
+ "title": "Message",
+ "required": ["title", "description"],
+ "type": "object",
+ "properties": {
+ "title": {"title": "Title", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
+
+
+def test_router_include_overrides_generate_unique_id():
+ app = FastAPI(generate_unique_id_function=custom_generate_unique_id)
+ router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)
+
+ @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}})
+ def post_root(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ @router.post(
+ "/router", response_model=List[Item], responses={404: {"model": List[Message]}}
+ )
+ def post_router(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ app.include_router(router, generate_unique_id_function=custom_generate_unique_id3)
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ data = response.json()
+ assert data == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "post": {
+ "summary": "Post Root",
+ "operationId": "foo_post_root",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_foo_post_root"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Foo Post Root",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Foo Post Root",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/router": {
+ "post": {
+ "summary": "Post Router",
+ "operationId": "bar_post_router",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_bar_post_router"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Bar Post Router",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Bar Post Router",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_bar_post_router": {
+ "title": "Body_bar_post_router",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "Body_foo_post_root": {
+ "title": "Body_foo_post_root",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ },
+ },
+ "Message": {
+ "title": "Message",
+ "required": ["title", "description"],
+ "type": "object",
+ "properties": {
+ "title": {"title": "Title", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
+
+
+def test_subrouter_top_level_include_overrides_generate_unique_id():
+ app = FastAPI(generate_unique_id_function=custom_generate_unique_id)
+ router = APIRouter()
+ sub_router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)
+
+ @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}})
+ def post_root(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ @router.post(
+ "/router", response_model=List[Item], responses={404: {"model": List[Message]}}
+ )
+ def post_router(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ @sub_router.post(
+ "/subrouter",
+ response_model=List[Item],
+ responses={404: {"model": List[Message]}},
+ )
+ def post_subrouter(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ router.include_router(sub_router)
+ app.include_router(router, generate_unique_id_function=custom_generate_unique_id3)
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ data = response.json()
+ assert data == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "post": {
+ "summary": "Post Root",
+ "operationId": "foo_post_root",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_foo_post_root"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Foo Post Root",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Foo Post Root",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/router": {
+ "post": {
+ "summary": "Post Router",
+ "operationId": "baz_post_router",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_baz_post_router"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Baz Post Router",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Baz Post Router",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/subrouter": {
+ "post": {
+ "summary": "Post Subrouter",
+ "operationId": "bar_post_subrouter",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_bar_post_subrouter"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Bar Post Subrouter",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Bar Post Subrouter",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_bar_post_subrouter": {
+ "title": "Body_bar_post_subrouter",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "Body_baz_post_router": {
+ "title": "Body_baz_post_router",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "Body_foo_post_root": {
+ "title": "Body_foo_post_root",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ },
+ },
+ "Message": {
+ "title": "Message",
+ "required": ["title", "description"],
+ "type": "object",
+ "properties": {
+ "title": {"title": "Title", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
+
+
+def test_router_path_operation_overrides_generate_unique_id():
+ app = FastAPI(generate_unique_id_function=custom_generate_unique_id)
+ router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)
+
+ @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}})
+ def post_root(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ @router.post(
+ "/router",
+ response_model=List[Item],
+ responses={404: {"model": List[Message]}},
+ generate_unique_id_function=custom_generate_unique_id3,
+ )
+ def post_router(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ app.include_router(router)
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ data = response.json()
+ assert data == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "post": {
+ "summary": "Post Root",
+ "operationId": "foo_post_root",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_foo_post_root"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Foo Post Root",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Foo Post Root",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/router": {
+ "post": {
+ "summary": "Post Router",
+ "operationId": "baz_post_router",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_baz_post_router"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Baz Post Router",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Baz Post Router",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_baz_post_router": {
+ "title": "Body_baz_post_router",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "Body_foo_post_root": {
+ "title": "Body_foo_post_root",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ },
+ },
+ "Message": {
+ "title": "Message",
+ "required": ["title", "description"],
+ "type": "object",
+ "properties": {
+ "title": {"title": "Title", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
+
+
+def test_app_path_operation_overrides_generate_unique_id():
+ app = FastAPI(generate_unique_id_function=custom_generate_unique_id)
+ router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)
+
+ @app.post(
+ "/",
+ response_model=List[Item],
+ responses={404: {"model": List[Message]}},
+ generate_unique_id_function=custom_generate_unique_id3,
+ )
+ def post_root(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ @router.post(
+ "/router",
+ response_model=List[Item],
+ responses={404: {"model": List[Message]}},
+ )
+ def post_router(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ app.include_router(router)
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ data = response.json()
+ assert data == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "post": {
+ "summary": "Post Root",
+ "operationId": "baz_post_root",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_baz_post_root"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Baz Post Root",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Baz Post Root",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/router": {
+ "post": {
+ "summary": "Post Router",
+ "operationId": "bar_post_router",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_bar_post_router"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Bar Post Router",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Bar Post Router",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_bar_post_router": {
+ "title": "Body_bar_post_router",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "Body_baz_post_root": {
+ "title": "Body_baz_post_root",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ },
+ },
+ "Message": {
+ "title": "Message",
+ "required": ["title", "description"],
+ "type": "object",
+ "properties": {
+ "title": {"title": "Title", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
+
+
+def test_callback_override_generate_unique_id():
+ app = FastAPI(generate_unique_id_function=custom_generate_unique_id)
+ callback_router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)
+
+ @callback_router.post(
+ "/post-callback",
+ response_model=List[Item],
+ responses={404: {"model": List[Message]}},
+ generate_unique_id_function=custom_generate_unique_id3,
+ )
+ def post_callback(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ @app.post(
+ "/",
+ response_model=List[Item],
+ responses={404: {"model": List[Message]}},
+ generate_unique_id_function=custom_generate_unique_id3,
+ callbacks=callback_router.routes,
+ )
+ def post_root(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ @app.post(
+ "/tocallback",
+ response_model=List[Item],
+ responses={404: {"model": List[Message]}},
+ )
+ def post_with_callback(item1: Item, item2: Item):
+ return item1, item2 # pragma: nocover
+
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ data = response.json()
+ assert data == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "post": {
+ "summary": "Post Root",
+ "operationId": "baz_post_root",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_baz_post_root"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Baz Post Root",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Baz Post Root",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "callbacks": {
+ "post_callback": {
+ "/post-callback": {
+ "post": {
+ "summary": "Post Callback",
+ "operationId": "baz_post_callback",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_baz_post_callback"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Baz Post Callback",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Item"
+ },
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Baz Post Callback",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ }
+ },
+ }
+ },
+ "/tocallback": {
+ "post": {
+ "summary": "Post With Callback",
+ "operationId": "foo_post_with_callback",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_foo_post_with_callback"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Foo Post With Callback",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ },
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 404 Foo Post With Callback",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Message"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_baz_post_callback": {
+ "title": "Body_baz_post_callback",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "Body_baz_post_root": {
+ "title": "Body_baz_post_root",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "Body_foo_post_with_callback": {
+ "title": "Body_foo_post_with_callback",
+ "required": ["item1", "item2"],
+ "type": "object",
+ "properties": {
+ "item1": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ },
+ },
+ "Message": {
+ "title": "Message",
+ "required": ["title", "description"],
+ "type": "object",
+ "properties": {
+ "title": {"title": "Title", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
+
+
+def test_warn_duplicate_operation_id():
+ def broken_operation_id(route: APIRoute):
+ return "foo"
+
+ app = FastAPI(generate_unique_id_function=broken_operation_id)
+
+ @app.post("/")
+ def post_root(item1: Item):
+ return item1 # pragma: nocover
+
+ @app.post("/second")
+ def post_second(item1: Item):
+ return item1 # pragma: nocover
+
+ @app.post("/third")
+ def post_third(item1: Item):
+ return item1 # pragma: nocover
+
+ client = TestClient(app)
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter("always")
+ client.get("/openapi.json")
+ assert len(w) == 2
+ assert issubclass(w[-1].category, UserWarning)
+ assert "Duplicate Operation ID" in str(w[-1].message)
diff --git a/tests/test_get_request_body.py b/tests/test_get_request_body.py
index b12f499eb..88b9d839f 100644
--- a/tests/test_get_request_body.py
+++ b/tests/test_get_request_body.py
@@ -85,7 +85,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_include_router_defaults_overrides.py b/tests/test_include_router_defaults_overrides.py
index c46cb6701..ccb6c7229 100644
--- a/tests/test_include_router_defaults_overrides.py
+++ b/tests/test_include_router_defaults_overrides.py
@@ -1,3 +1,5 @@
+import warnings
+
import pytest
from fastapi import APIRouter, Depends, FastAPI, Response
from fastapi.responses import JSONResponse
@@ -343,7 +345,11 @@ client = TestClient(app)
def test_openapi():
client = TestClient(app)
- response = client.get("/openapi.json")
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter("always")
+ response = client.get("/openapi.json")
+ assert issubclass(w[-1].category, UserWarning)
+ assert "Duplicate Operation ID" in str(w[-1].message)
assert response.json() == openapi_schema
@@ -6606,7 +6612,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_invalid_sequence_param.py b/tests/test_invalid_sequence_param.py
index f00dd7b93..475786adb 100644
--- a/tests/test_invalid_sequence_param.py
+++ b/tests/test_invalid_sequence_param.py
@@ -13,7 +13,7 @@ def test_invalid_sequence():
title: str
@app.get("/items/")
- def read_items(q: List[Item] = Query(None)):
+ def read_items(q: List[Item] = Query(default=None)):
pass # pragma: no cover
@@ -25,7 +25,7 @@ def test_invalid_tuple():
title: str
@app.get("/items/")
- def read_items(q: Tuple[Item, Item] = Query(None)):
+ def read_items(q: Tuple[Item, Item] = Query(default=None)):
pass # pragma: no cover
@@ -37,7 +37,7 @@ def test_invalid_dict():
title: str
@app.get("/items/")
- def read_items(q: Dict[str, Item] = Query(None)):
+ def read_items(q: Dict[str, Item] = Query(default=None)):
pass # pragma: no cover
@@ -49,5 +49,5 @@ def test_invalid_simple_dict():
title: str
@app.get("/items/")
- def read_items(q: Optional[dict] = Query(None)):
+ def read_items(q: Optional[dict] = Query(default=None)):
pass # pragma: no cover
diff --git a/tests/test_jsonable_encoder.py b/tests/test_jsonable_encoder.py
index fa82b5ea8..ed35fd32e 100644
--- a/tests/test_jsonable_encoder.py
+++ b/tests/test_jsonable_encoder.py
@@ -67,7 +67,7 @@ class ModelWithConfig(BaseModel):
class ModelWithAlias(BaseModel):
- foo: str = Field(..., alias="Foo")
+ foo: str = Field(alias="Foo")
class ModelWithDefault(BaseModel):
diff --git a/tests/test_modules_same_name_body/app/a.py b/tests/test_modules_same_name_body/app/a.py
index 3c86c1865..377236890 100644
--- a/tests/test_modules_same_name_body/app/a.py
+++ b/tests/test_modules_same_name_body/app/a.py
@@ -4,5 +4,5 @@ router = APIRouter()
@router.post("/compute")
-def compute(a: int = Body(...), b: str = Body(...)):
+def compute(a: int = Body(), b: str = Body()):
return {"a": a, "b": b}
diff --git a/tests/test_modules_same_name_body/app/b.py b/tests/test_modules_same_name_body/app/b.py
index f7c7fdfc6..b62118f84 100644
--- a/tests/test_modules_same_name_body/app/b.py
+++ b/tests/test_modules_same_name_body/app/b.py
@@ -4,5 +4,5 @@ router = APIRouter()
@router.post("/compute/")
-def compute(a: int = Body(...), b: str = Body(...)):
+def compute(a: int = Body(), b: str = Body()):
return {"a": a, "b": b}
diff --git a/tests/test_modules_same_name_body/test_main.py b/tests/test_modules_same_name_body/test_main.py
index b0d3330c7..8b1aea031 100644
--- a/tests/test_modules_same_name_body/test_main.py
+++ b/tests/test_modules_same_name_body/test_main.py
@@ -101,7 +101,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_multi_body_errors.py b/tests/test_multi_body_errors.py
index c1be82806..31308ea85 100644
--- a/tests/test_multi_body_errors.py
+++ b/tests/test_multi_body_errors.py
@@ -79,7 +79,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_multi_query_errors.py b/tests/test_multi_query_errors.py
index 69ea87a9b..3da461af5 100644
--- a/tests/test_multi_query_errors.py
+++ b/tests/test_multi_query_errors.py
@@ -7,7 +7,7 @@ app = FastAPI()
@app.get("/items/")
-def read_items(q: List[int] = Query(None)):
+def read_items(q: List[int] = Query(default=None)):
return {"q": q}
@@ -63,7 +63,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_multipart_installation.py b/tests/test_multipart_installation.py
index c8a6fd942..788d9ef5a 100644
--- a/tests/test_multipart_installation.py
+++ b/tests/test_multipart_installation.py
@@ -12,7 +12,7 @@ def test_incorrect_multipart_installed_form(monkeypatch):
app = FastAPI()
@app.post("/")
- async def root(username: str = Form(...)):
+ async def root(username: str = Form()):
return username # pragma: nocover
@@ -22,7 +22,7 @@ def test_incorrect_multipart_installed_file_upload(monkeypatch):
app = FastAPI()
@app.post("/")
- async def root(f: UploadFile = File(...)):
+ async def root(f: UploadFile = File()):
return f # pragma: nocover
@@ -32,7 +32,7 @@ def test_incorrect_multipart_installed_file_bytes(monkeypatch):
app = FastAPI()
@app.post("/")
- async def root(f: bytes = File(...)):
+ async def root(f: bytes = File()):
return f # pragma: nocover
@@ -42,7 +42,7 @@ def test_incorrect_multipart_installed_multi_form(monkeypatch):
app = FastAPI()
@app.post("/")
- async def root(username: str = Form(...), password: str = Form(...)):
+ async def root(username: str = Form(), password: str = Form()):
return username # pragma: nocover
@@ -52,7 +52,7 @@ def test_incorrect_multipart_installed_form_file(monkeypatch):
app = FastAPI()
@app.post("/")
- async def root(username: str = Form(...), f: UploadFile = File(...)):
+ async def root(username: str = Form(), f: UploadFile = File()):
return username # pragma: nocover
@@ -62,7 +62,7 @@ def test_no_multipart_installed(monkeypatch):
app = FastAPI()
@app.post("/")
- async def root(username: str = Form(...)):
+ async def root(username: str = Form()):
return username # pragma: nocover
@@ -72,7 +72,7 @@ def test_no_multipart_installed_file(monkeypatch):
app = FastAPI()
@app.post("/")
- async def root(f: UploadFile = File(...)):
+ async def root(f: UploadFile = File()):
return f # pragma: nocover
@@ -82,7 +82,7 @@ def test_no_multipart_installed_file_bytes(monkeypatch):
app = FastAPI()
@app.post("/")
- async def root(f: bytes = File(...)):
+ async def root(f: bytes = File()):
return f # pragma: nocover
@@ -92,7 +92,7 @@ def test_no_multipart_installed_multi_form(monkeypatch):
app = FastAPI()
@app.post("/")
- async def root(username: str = Form(...), password: str = Form(...)):
+ async def root(username: str = Form(), password: str = Form()):
return username # pragma: nocover
@@ -102,5 +102,5 @@ def test_no_multipart_installed_form_file(monkeypatch):
app = FastAPI()
@app.post("/")
- async def root(username: str = Form(...), f: UploadFile = File(...)):
+ async def root(username: str = Form(), f: UploadFile = File()):
return username # pragma: nocover
diff --git a/tests/test_param_class.py b/tests/test_param_class.py
index f5767ec96..1fd40dcd2 100644
--- a/tests/test_param_class.py
+++ b/tests/test_param_class.py
@@ -8,7 +8,7 @@ app = FastAPI()
@app.get("/items/")
-def read_items(q: Optional[str] = Param(None)): # type: ignore
+def read_items(q: Optional[str] = Param(default=None)): # type: ignore
return {"q": q}
diff --git a/tests/test_param_in_path_and_dependency.py b/tests/test_param_in_path_and_dependency.py
index 0a94c2151..4d85afbce 100644
--- a/tests/test_param_in_path_and_dependency.py
+++ b/tests/test_param_in_path_and_dependency.py
@@ -71,7 +71,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_param_include_in_schema.py b/tests/test_param_include_in_schema.py
index 4eaac72d8..214f039b6 100644
--- a/tests/test_param_include_in_schema.py
+++ b/tests/test_param_include_in_schema.py
@@ -9,26 +9,26 @@ app = FastAPI()
@app.get("/hidden_cookie")
async def hidden_cookie(
- hidden_cookie: Optional[str] = Cookie(None, include_in_schema=False)
+ hidden_cookie: Optional[str] = Cookie(default=None, include_in_schema=False)
):
return {"hidden_cookie": hidden_cookie}
@app.get("/hidden_header")
async def hidden_header(
- hidden_header: Optional[str] = Header(None, include_in_schema=False)
+ hidden_header: Optional[str] = Header(default=None, include_in_schema=False)
):
return {"hidden_header": hidden_header}
@app.get("/hidden_path/{hidden_path}")
-async def hidden_path(hidden_path: str = Path(..., include_in_schema=False)):
+async def hidden_path(hidden_path: str = Path(include_in_schema=False)):
return {"hidden_path": hidden_path}
@app.get("/hidden_query")
async def hidden_query(
- hidden_query: Optional[str] = Query(None, include_in_schema=False)
+ hidden_query: Optional[str] = Query(default=None, include_in_schema=False)
):
return {"hidden_query": hidden_query}
@@ -149,7 +149,7 @@ openapi_shema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_put_no_body.py b/tests/test_put_no_body.py
index 1c2cfac89..3da294ccf 100644
--- a/tests/test_put_no_body.py
+++ b/tests/test_put_no_body.py
@@ -57,7 +57,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_repeated_dependency_schema.py b/tests/test_repeated_dependency_schema.py
index fd616e12a..ca0305184 100644
--- a/tests/test_repeated_dependency_schema.py
+++ b/tests/test_repeated_dependency_schema.py
@@ -4,7 +4,7 @@ from fastapi.testclient import TestClient
app = FastAPI()
-def get_header(*, someheader: str = Header(...)):
+def get_header(*, someheader: str = Header()):
return someheader
@@ -36,7 +36,7 @@ schema = {
"ValidationError": {
"properties": {
"loc": {
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
"title": "Location",
"type": "array",
},
diff --git a/tests/test_request_body_parameters_media_type.py b/tests/test_request_body_parameters_media_type.py
index ace6bdef7..e9cf4006d 100644
--- a/tests/test_request_body_parameters_media_type.py
+++ b/tests/test_request_body_parameters_media_type.py
@@ -21,14 +21,14 @@ class Shop(BaseModel):
@app.post("/products")
-async def create_product(data: Product = Body(..., media_type=media_type, embed=True)):
+async def create_product(data: Product = Body(media_type=media_type, embed=True)):
pass # pragma: no cover
@app.post("/shops")
async def create_shop(
- data: Shop = Body(..., media_type=media_type),
- included: typing.List[Product] = Body([], media_type=media_type),
+ data: Shop = Body(media_type=media_type),
+ included: typing.List[Product] = Body(default=[], media_type=media_type),
):
pass # pragma: no cover
diff --git a/tests/test_required_noneable.py b/tests/test_required_noneable.py
new file mode 100644
index 000000000..5da8cd4d0
--- /dev/null
+++ b/tests/test_required_noneable.py
@@ -0,0 +1,62 @@
+from typing import Union
+
+from fastapi import Body, FastAPI, Query
+from fastapi.testclient import TestClient
+
+app = FastAPI()
+
+
+@app.get("/query")
+def read_query(q: Union[str, None]):
+ return q
+
+
+@app.get("/explicit-query")
+def read_explicit_query(q: Union[str, None] = Query()):
+ return q
+
+
+@app.post("/body-embed")
+def send_body_embed(b: Union[str, None] = Body(embed=True)):
+ return b
+
+
+client = TestClient(app)
+
+
+def test_required_nonable_query_invalid():
+ response = client.get("/query")
+ assert response.status_code == 422
+
+
+def test_required_noneable_query_value():
+ response = client.get("/query", params={"q": "foo"})
+ assert response.status_code == 200
+ assert response.json() == "foo"
+
+
+def test_required_nonable_explicit_query_invalid():
+ response = client.get("/explicit-query")
+ assert response.status_code == 422
+
+
+def test_required_nonable_explicit_query_value():
+ response = client.get("/explicit-query", params={"q": "foo"})
+ assert response.status_code == 200
+ assert response.json() == "foo"
+
+
+def test_required_nonable_body_embed_no_content():
+ response = client.post("/body-embed")
+ assert response.status_code == 422
+
+
+def test_required_nonable_body_embed_invalid():
+ response = client.post("/body-embed", json={"invalid": "invalid"})
+ assert response.status_code == 422
+
+
+def test_required_noneable_body_embed_value():
+ response = client.post("/body-embed", json={"b": "foo"})
+ assert response.status_code == 200
+ assert response.json() == "foo"
diff --git a/tests/test_response_code_no_body.py b/tests/test_response_code_no_body.py
index 45e2fabc7..6d9b5c333 100644
--- a/tests/test_response_code_no_body.py
+++ b/tests/test_response_code_no_body.py
@@ -28,7 +28,7 @@ class JsonApiError(BaseModel):
responses={500: {"description": "Error", "model": JsonApiError}},
)
async def a():
- pass # pragma: no cover
+ pass
@app.get("/b", responses={204: {"description": "No Content"}})
@@ -106,3 +106,10 @@ def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == openapi_schema
+
+
+def test_get_response():
+ response = client.get("/a")
+ assert response.status_code == 204, response.text
+ assert "content-length" not in response.headers
+ assert response.content == b""
diff --git a/tests/test_schema_extra_examples.py b/tests/test_schema_extra_examples.py
index 3e0d846cd..5047aeaa4 100644
--- a/tests/test_schema_extra_examples.py
+++ b/tests/test_schema_extra_examples.py
@@ -1,3 +1,5 @@
+from typing import Union
+
from fastapi import Body, Cookie, FastAPI, Header, Path, Query
from fastapi.testclient import TestClient
from pydantic import BaseModel
@@ -18,14 +20,13 @@ def schema_extra(item: Item):
@app.post("/example/")
-def example(item: Item = Body(..., example={"data": "Data in Body example"})):
+def example(item: Item = Body(example={"data": "Data in Body example"})):
return item
@app.post("/examples/")
def examples(
item: Item = Body(
- ...,
examples={
"example1": {
"summary": "example1 summary",
@@ -41,7 +42,6 @@ def examples(
@app.post("/example_examples/")
def example_examples(
item: Item = Body(
- ...,
example={"data": "Overriden example"},
examples={
"example1": {"value": {"data": "examples example_examples 1"}},
@@ -55,7 +55,7 @@ def example_examples(
# TODO: enable these tests once/if Form(embed=False) is supported
# TODO: In that case, define if File() should support example/examples too
# @app.post("/form_example")
-# def form_example(firstname: str = Form(..., example="John")):
+# def form_example(firstname: str = Form(example="John")):
# return firstname
@@ -89,7 +89,6 @@ def example_examples(
@app.get("/path_example/{item_id}")
def path_example(
item_id: str = Path(
- ...,
example="item_1",
),
):
@@ -99,7 +98,6 @@ def path_example(
@app.get("/path_examples/{item_id}")
def path_examples(
item_id: str = Path(
- ...,
examples={
"example1": {"summary": "item ID summary", "value": "item_1"},
"example2": {"value": "item_2"},
@@ -112,7 +110,6 @@ def path_examples(
@app.get("/path_example_examples/{item_id}")
def path_example_examples(
item_id: str = Path(
- ...,
example="item_overriden",
examples={
"example1": {"summary": "item ID summary", "value": "item_1"},
@@ -125,8 +122,8 @@ def path_example_examples(
@app.get("/query_example/")
def query_example(
- data: str = Query(
- None,
+ data: Union[str, None] = Query(
+ default=None,
example="query1",
),
):
@@ -135,8 +132,8 @@ def query_example(
@app.get("/query_examples/")
def query_examples(
- data: str = Query(
- None,
+ data: Union[str, None] = Query(
+ default=None,
examples={
"example1": {"summary": "Query example 1", "value": "query1"},
"example2": {"value": "query2"},
@@ -148,8 +145,8 @@ def query_examples(
@app.get("/query_example_examples/")
def query_example_examples(
- data: str = Query(
- None,
+ data: Union[str, None] = Query(
+ default=None,
example="query_overriden",
examples={
"example1": {"summary": "Qeury example 1", "value": "query1"},
@@ -162,8 +159,8 @@ def query_example_examples(
@app.get("/header_example/")
def header_example(
- data: str = Header(
- None,
+ data: Union[str, None] = Header(
+ default=None,
example="header1",
),
):
@@ -172,8 +169,8 @@ def header_example(
@app.get("/header_examples/")
def header_examples(
- data: str = Header(
- None,
+ data: Union[str, None] = Header(
+ default=None,
examples={
"example1": {"summary": "header example 1", "value": "header1"},
"example2": {"value": "header2"},
@@ -185,8 +182,8 @@ def header_examples(
@app.get("/header_example_examples/")
def header_example_examples(
- data: str = Header(
- None,
+ data: Union[str, None] = Header(
+ default=None,
example="header_overriden",
examples={
"example1": {"summary": "Qeury example 1", "value": "header1"},
@@ -199,8 +196,8 @@ def header_example_examples(
@app.get("/cookie_example/")
def cookie_example(
- data: str = Cookie(
- None,
+ data: Union[str, None] = Cookie(
+ default=None,
example="cookie1",
),
):
@@ -209,8 +206,8 @@ def cookie_example(
@app.get("/cookie_examples/")
def cookie_examples(
- data: str = Cookie(
- None,
+ data: Union[str, None] = Cookie(
+ default=None,
examples={
"example1": {"summary": "cookie example 1", "value": "cookie1"},
"example2": {"value": "cookie2"},
@@ -222,8 +219,8 @@ def cookie_examples(
@app.get("/cookie_example_examples/")
def cookie_example_examples(
- data: str = Cookie(
- None,
+ data: Union[str, None] = Cookie(
+ default=None,
example="cookie_overriden",
examples={
"example1": {"summary": "Qeury example 1", "value": "cookie1"},
@@ -830,7 +827,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_security_oauth2.py b/tests/test_security_oauth2.py
index b7ada7caf..b9ac488ee 100644
--- a/tests/test_security_oauth2.py
+++ b/tests/test_security_oauth2.py
@@ -117,7 +117,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_security_oauth2_optional.py b/tests/test_security_oauth2_optional.py
index ecc766511..a5fd49b8c 100644
--- a/tests/test_security_oauth2_optional.py
+++ b/tests/test_security_oauth2_optional.py
@@ -121,7 +121,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_security_oauth2_optional_description.py b/tests/test_security_oauth2_optional_description.py
index 011db65ec..171f96b76 100644
--- a/tests/test_security_oauth2_optional_description.py
+++ b/tests/test_security_oauth2_optional_description.py
@@ -122,7 +122,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_serialize_response_model.py b/tests/test_serialize_response_model.py
index 295667437..3bb46b2e9 100644
--- a/tests/test_serialize_response_model.py
+++ b/tests/test_serialize_response_model.py
@@ -8,7 +8,7 @@ app = FastAPI()
class Item(BaseModel):
- name: str = Field(..., alias="aliased_name")
+ name: str = Field(alias="aliased_name")
price: Optional[float] = None
owner_ids: Optional[List[int]] = None
diff --git a/tests/test_starlette_exception.py b/tests/test_starlette_exception.py
index 5759a93f4..859169d3c 100644
--- a/tests/test_starlette_exception.py
+++ b/tests/test_starlette_exception.py
@@ -102,7 +102,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_starlette_urlconvertors.py b/tests/test_starlette_urlconvertors.py
index 2320c7005..5a980cbf6 100644
--- a/tests/test_starlette_urlconvertors.py
+++ b/tests/test_starlette_urlconvertors.py
@@ -5,17 +5,17 @@ app = FastAPI()
@app.get("/int/{param:int}")
-def int_convertor(param: int = Path(...)):
+def int_convertor(param: int = Path()):
return {"int": param}
@app.get("/float/{param:float}")
-def float_convertor(param: float = Path(...)):
+def float_convertor(param: float = Path()):
return {"float": param}
@app.get("/path/{param:path}")
-def path_convertor(param: str = Path(...)):
+def path_convertor(param: str = Path()):
return {"path": param}
diff --git a/tests/test_sub_callbacks.py b/tests/test_sub_callbacks.py
index 16644b556..7574d6fbc 100644
--- a/tests/test_sub_callbacks.py
+++ b/tests/test_sub_callbacks.py
@@ -256,7 +256,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tuples.py b/tests/test_tuples.py
index 4cd5ee3af..18ec2d048 100644
--- a/tests/test_tuples.py
+++ b/tests/test_tuples.py
@@ -27,7 +27,7 @@ def post_tuple_of_models(square: Tuple[Coordinate, Coordinate]):
@app.post("/tuple-form/")
-def hello(values: Tuple[int, int] = Form(...)):
+def hello(values: Tuple[int, int] = Form()):
return values
@@ -200,7 +200,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial001.py b/tests/test_tutorial/test_additional_responses/test_tutorial001.py
index 8342dd787..1a8acb523 100644
--- a/tests/test_tutorial/test_additional_responses/test_tutorial001.py
+++ b/tests/test_tutorial/test_additional_responses/test_tutorial001.py
@@ -76,7 +76,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial002.py b/tests/test_tutorial/test_additional_responses/test_tutorial002.py
index 57f877978..2adcf15d0 100644
--- a/tests/test_tutorial/test_additional_responses/test_tutorial002.py
+++ b/tests/test_tutorial/test_additional_responses/test_tutorial002.py
@@ -72,7 +72,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial003.py b/tests/test_tutorial/test_additional_responses/test_tutorial003.py
index 37190b36a..8b2167de0 100644
--- a/tests/test_tutorial/test_additional_responses/test_tutorial003.py
+++ b/tests/test_tutorial/test_additional_responses/test_tutorial003.py
@@ -77,7 +77,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial004.py b/tests/test_tutorial/test_additional_responses/test_tutorial004.py
index c44a18f68..990d5235a 100644
--- a/tests/test_tutorial/test_additional_responses/test_tutorial004.py
+++ b/tests/test_tutorial/test_additional_responses/test_tutorial004.py
@@ -75,7 +75,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py
index 90feb0172..1ad625db6 100644
--- a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py
+++ b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py
@@ -88,7 +88,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_bigger_applications/test_main.py b/tests/test_tutorial/test_bigger_applications/test_main.py
index 7eb675179..cd6d7b5c8 100644
--- a/tests/test_tutorial/test_bigger_applications/test_main.py
+++ b/tests/test_tutorial/test_bigger_applications/test_main.py
@@ -323,7 +323,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_body/test_tutorial001.py b/tests/test_tutorial/test_body/test_tutorial001.py
index 7bf62c907..8dbaf15db 100644
--- a/tests/test_tutorial/test_body/test_tutorial001.py
+++ b/tests/test_tutorial/test_body/test_tutorial001.py
@@ -63,7 +63,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_body/test_tutorial001_py310.py b/tests/test_tutorial/test_body/test_tutorial001_py310.py
index e292b5346..dd9d9911e 100644
--- a/tests/test_tutorial/test_body/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_body/test_tutorial001_py310.py
@@ -61,7 +61,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001.py b/tests/test_tutorial/test_body_fields/test_tutorial001.py
index 9de4907c2..fe5a270f3 100644
--- a/tests/test_tutorial/test_body_fields/test_tutorial001.py
+++ b/tests/test_tutorial/test_body_fields/test_tutorial001.py
@@ -87,7 +87,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py b/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py
index d7a525ea7..993e2a91d 100644
--- a/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py
@@ -84,7 +84,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py
index b11ecddab..8dc710d75 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py
@@ -79,7 +79,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py
index 85ba41ce6..5114ccea2 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py
@@ -77,7 +77,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
index d98e3e419..64aa9c43b 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
@@ -90,7 +90,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py
index f896f7bf5..fc019d8bb 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py
@@ -88,7 +88,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py
index 8eb0ad130..c56d41b5b 100644
--- a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py
+++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py
@@ -53,7 +53,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py
index 17ca29ce5..5b8d82861 100644
--- a/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py
+++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py
@@ -52,7 +52,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001.py b/tests/test_tutorial/test_body_updates/test_tutorial001.py
index 5e92ef7ea..efd0e4676 100644
--- a/tests/test_tutorial/test_body_updates/test_tutorial001.py
+++ b/tests/test_tutorial/test_body_updates/test_tutorial001.py
@@ -109,7 +109,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py
index ca1d8c585..49279b320 100644
--- a/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py
@@ -108,7 +108,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py
index f2b184c4f..872530bcf 100644
--- a/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py
+++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py
@@ -108,7 +108,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001.py b/tests/test_tutorial/test_cookie_params/test_tutorial001.py
index 3451dc19e..edccffec1 100644
--- a/tests/test_tutorial/test_cookie_params/test_tutorial001.py
+++ b/tests/test_tutorial/test_cookie_params/test_tutorial001.py
@@ -50,7 +50,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py
index 587a328da..5caa5c440 100644
--- a/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py
@@ -48,7 +48,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial001.py b/tests/test_tutorial/test_dataclasses/test_tutorial001.py
index 3e3fc9acf..bf1564194 100644
--- a/tests/test_tutorial/test_dataclasses/test_tutorial001.py
+++ b/tests/test_tutorial/test_dataclasses/test_tutorial001.py
@@ -71,7 +71,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial003.py b/tests/test_tutorial/test_dataclasses/test_tutorial003.py
index dd0f1f2c0..2d86f7b9a 100644
--- a/tests/test_tutorial/test_dataclasses/test_tutorial003.py
+++ b/tests/test_tutorial/test_dataclasses/test_tutorial003.py
@@ -118,7 +118,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001.py b/tests/test_tutorial/test_dependencies/test_tutorial001.py
index 8b53157cd..c3bca5d5b 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial001.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial001.py
@@ -104,7 +104,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py
index a7991170e..32a61c821 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py
@@ -102,7 +102,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004.py b/tests/test_tutorial/test_dependencies/test_tutorial004.py
index eb21f6524..f2b1878d5 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial004.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial004.py
@@ -62,7 +62,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py
index f66a36a99..e3ae0c741 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py
@@ -60,7 +60,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006.py b/tests/test_tutorial/test_dependencies/test_tutorial006.py
index c08992ec8..2916577a2 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial006.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial006.py
@@ -55,7 +55,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012.py b/tests/test_tutorial/test_dependencies/test_tutorial012.py
index ada83c626..e4e07395d 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial012.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial012.py
@@ -102,7 +102,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_events/test_tutorial001.py b/tests/test_tutorial/test_events/test_tutorial001.py
index e3587a0e8..d52dd1a04 100644
--- a/tests/test_tutorial/test_events/test_tutorial001.py
+++ b/tests/test_tutorial/test_events/test_tutorial001.py
@@ -47,7 +47,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
index 68b7d61dc..8522d7b9d 100644
--- a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
@@ -89,7 +89,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py
index 3d4c1d07d..4efdecc53 100644
--- a/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py
@@ -87,7 +87,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003.py b/tests/test_tutorial/test_extra_models/test_tutorial003.py
index a2a325c77..f1433470c 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial003.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial003.py
@@ -78,7 +78,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py b/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py
index 185bc3a37..56fd83ad3 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py
@@ -77,7 +77,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_generate_clients/__init__.py b/tests/test_tutorial/test_generate_clients/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial003.py b/tests/test_tutorial/test_generate_clients/test_tutorial003.py
new file mode 100644
index 000000000..128fcea30
--- /dev/null
+++ b/tests/test_tutorial/test_generate_clients/test_tutorial003.py
@@ -0,0 +1,188 @@
+from fastapi.testclient import TestClient
+
+from docs_src.generate_clients.tutorial003 import app
+
+client = TestClient(app)
+
+openapi_schema = {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "tags": ["items"],
+ "summary": "Get Items",
+ "operationId": "items-get_items",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Items-Get Items",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ }
+ },
+ },
+ "post": {
+ "tags": ["items"],
+ "summary": "Create Item",
+ "operationId": "items-create_item",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ResponseMessage"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/users/": {
+ "post": {
+ "tags": ["users"],
+ "summary": "Create User",
+ "operationId": "users-create_user",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ResponseMessage"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ },
+ },
+ "ResponseMessage": {
+ "title": "ResponseMessage",
+ "required": ["message"],
+ "type": "object",
+ "properties": {"message": {"title": "Message", "type": "string"}},
+ },
+ "User": {
+ "title": "User",
+ "required": ["username", "email"],
+ "type": "object",
+ "properties": {
+ "username": {"title": "Username", "type": "string"},
+ "email": {"title": "Email", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+}
+
+
+def test_openapi():
+ with client:
+ response = client.get("/openapi.json")
+
+ assert response.json() == openapi_schema
+
+
+def test_post_items():
+ response = client.post("/items/", json={"name": "Foo", "price": 5})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "Item received"}
+
+
+def test_post_users():
+ response = client.post(
+ "/users/", json={"username": "Foo", "email": "foo@example.com"}
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "User received"}
+
+
+def test_get_items():
+ response = client.get("/items/")
+ assert response.status_code == 200, response.text
+ assert response.json() == [
+ {"name": "Plumbus", "price": 3},
+ {"name": "Portal Gun", "price": 9001},
+ ]
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial001.py b/tests/test_tutorial/test_handling_errors/test_tutorial001.py
index 6b62293d8..ffd79ccff 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial001.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial001.py
@@ -49,7 +49,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial002.py b/tests/test_tutorial/test_handling_errors/test_tutorial002.py
index d2ce0bf9d..e678499c6 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial002.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial002.py
@@ -49,7 +49,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial003.py b/tests/test_tutorial/test_handling_errors/test_tutorial003.py
index ca9d94e3c..a01726dc2 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial003.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial003.py
@@ -49,7 +49,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial004.py b/tests/test_tutorial/test_handling_errors/test_tutorial004.py
index d95debf37..0b5f74798 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial004.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial004.py
@@ -49,7 +49,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial005.py b/tests/test_tutorial/test_handling_errors/test_tutorial005.py
index cedcaae70..253f3d006 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial005.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial005.py
@@ -69,7 +69,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial006.py b/tests/test_tutorial/test_handling_errors/test_tutorial006.py
index 8b6c1e7ed..21233d7bb 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial006.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial006.py
@@ -49,7 +49,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_header_params/test_tutorial001.py b/tests/test_tutorial/test_header_params/test_tutorial001.py
index 0f05b9e8c..273cf3249 100644
--- a/tests/test_tutorial/test_header_params/test_tutorial001.py
+++ b/tests/test_tutorial/test_header_params/test_tutorial001.py
@@ -51,7 +51,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_header_params/test_tutorial001_py310.py b/tests/test_tutorial/test_header_params/test_tutorial001_py310.py
index f5ee17428..77a60eb9d 100644
--- a/tests/test_tutorial/test_header_params/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_header_params/test_tutorial001_py310.py
@@ -48,7 +48,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py
index b30427d08..e773e7f8f 100644
--- a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py
+++ b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py
@@ -143,7 +143,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
index f2ec2c7e5..456e509d5 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
@@ -72,7 +72,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
index d21640946..e587519a0 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
@@ -72,7 +72,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py
index 1f617da70..43a7a610d 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py
@@ -71,7 +71,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py
index ffdf05081..62aa73ac5 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py
@@ -71,7 +71,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_path_params/test_tutorial004.py b/tests/test_tutorial/test_path_params/test_tutorial004.py
index 131bf773b..7f0227ecf 100644
--- a/tests/test_tutorial/test_path_params/test_tutorial004.py
+++ b/tests/test_tutorial/test_path_params/test_tutorial004.py
@@ -49,7 +49,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_path_params/test_tutorial005.py b/tests/test_tutorial/test_path_params/test_tutorial005.py
index ed9d2032b..eae3637be 100644
--- a/tests/test_tutorial/test_path_params/test_tutorial005.py
+++ b/tests/test_tutorial/test_path_params/test_tutorial005.py
@@ -54,7 +54,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
@@ -138,7 +138,7 @@ openapi_schema2 = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_query_params/test_tutorial005.py b/tests/test_tutorial/test_query_params/test_tutorial005.py
index aabc0af4f..07178f8a6 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial005.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial005.py
@@ -56,7 +56,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_query_params/test_tutorial006.py b/tests/test_tutorial/test_query_params/test_tutorial006.py
index 042a0e1f8..73c5302e7 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial006.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial006.py
@@ -68,7 +68,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_query_params/test_tutorial006_py310.py b/tests/test_tutorial/test_query_params/test_tutorial006_py310.py
index 1986d27d0..141525f15 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial006_py310.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial006_py310.py
@@ -66,7 +66,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py
index 709bf6956..f8d7f85c8 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py
@@ -59,7 +59,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py
index 66b24017e..298b5d616 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py
@@ -57,7 +57,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py
index 6ae10296f..ad3645f31 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py
@@ -53,7 +53,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py
index 8894ee1b5..9330037ed 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py
@@ -52,7 +52,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py
index b10e70af7..11f23be27 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py
@@ -52,7 +52,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py
index 724c975f8..d69139dda 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py
@@ -54,7 +54,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py
index a9cbce02a..b25bb2847 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py
@@ -53,7 +53,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py
index ad5597913..1b2e36354 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py
@@ -54,7 +54,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py
index 98ae5a684..57b8b9d94 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py
@@ -53,7 +53,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py
index 33f3d5f77..fe54fc080 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py
@@ -51,7 +51,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001.py b/tests/test_tutorial/test_request_files/test_tutorial001.py
index 841116e30..166014c71 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001.py
@@ -99,7 +99,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02.py b/tests/test_tutorial/test_request_files/test_tutorial001_02.py
index e852a1b31..a254bf3e8 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001_02.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_02.py
@@ -106,7 +106,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py b/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py
index 62e9f98d0..15b6a8d53 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py
@@ -107,7 +107,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_03.py b/tests/test_tutorial/test_request_files/test_tutorial001_03.py
index ec7509ea2..c34165f18 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001_03.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_03.py
@@ -120,7 +120,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_request_files/test_tutorial002.py b/tests/test_tutorial/test_request_files/test_tutorial002.py
index 4e33ef464..73d1179a1 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial002.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial002.py
@@ -119,7 +119,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_request_files/test_tutorial002_py39.py b/tests/test_tutorial/test_request_files/test_tutorial002_py39.py
index bbdf25cd9..de4127057 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial002_py39.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial002_py39.py
@@ -119,7 +119,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_request_files/test_tutorial003.py b/tests/test_tutorial/test_request_files/test_tutorial003.py
index 943b235ab..83aea66cd 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial003.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial003.py
@@ -132,7 +132,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_request_files/test_tutorial003_py39.py b/tests/test_tutorial/test_request_files/test_tutorial003_py39.py
index d5fbd7889..56aeb54cd 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial003_py39.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial003_py39.py
@@ -132,7 +132,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_request_forms/test_tutorial001.py b/tests/test_tutorial/test_request_forms/test_tutorial001.py
index 3d271b531..215260ffa 100644
--- a/tests/test_tutorial/test_request_forms/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_forms/test_tutorial001.py
@@ -61,7 +61,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py
index 10cce5e61..09e232b8e 100644
--- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py
@@ -61,7 +61,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial003.py b/tests/test_tutorial/test_response_model/test_tutorial003.py
index 44f2fb7ca..e1bde5d13 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial003.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial003.py
@@ -74,7 +74,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_py310.py b/tests/test_tutorial/test_response_model/test_tutorial003_py310.py
index ffba11662..9827dab8a 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial003_py310.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial003_py310.py
@@ -73,7 +73,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial004.py b/tests/test_tutorial/test_response_model/test_tutorial004.py
index 19303982b..8c98c6de3 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial004.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial004.py
@@ -71,7 +71,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial004_py310.py b/tests/test_tutorial/test_response_model/test_tutorial004_py310.py
index f1508a05d..7fc86fafa 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial004_py310.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial004_py310.py
@@ -69,7 +69,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial004_py39.py b/tests/test_tutorial/test_response_model/test_tutorial004_py39.py
index e5d9c8b5f..405fe79f5 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial004_py39.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial004_py39.py
@@ -69,7 +69,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial005.py b/tests/test_tutorial/test_response_model/test_tutorial005.py
index 9ca5463e6..476b172d3 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial005.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial005.py
@@ -98,7 +98,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial005_py310.py b/tests/test_tutorial/test_response_model/test_tutorial005_py310.py
index 6d7366f12..389a302e0 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial005_py310.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial005_py310.py
@@ -97,7 +97,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial006.py b/tests/test_tutorial/test_response_model/test_tutorial006.py
index 25eb6e333..38eb31e54 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial006.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial006.py
@@ -98,7 +98,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_response_model/test_tutorial006_py310.py b/tests/test_tutorial/test_response_model/test_tutorial006_py310.py
index a3d8d204e..f870f3926 100644
--- a/tests/test_tutorial/test_response_model/test_tutorial006_py310.py
+++ b/tests/test_tutorial/test_response_model/test_tutorial006_py310.py
@@ -97,7 +97,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py
index 89f5b66fd..badf66b3d 100644
--- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py
+++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py
@@ -103,7 +103,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py
index 4f9a2ff57..d326a5a09 100644
--- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py
+++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py
@@ -102,7 +102,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_security/test_tutorial003.py b/tests/test_tutorial/test_security/test_tutorial003.py
index 3fc7f5f40..595107834 100644
--- a/tests/test_tutorial/test_security/test_tutorial003.py
+++ b/tests/test_tutorial/test_security/test_tutorial003.py
@@ -81,7 +81,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_security/test_tutorial003_py310.py b/tests/test_tutorial/test_security/test_tutorial003_py310.py
index e621bcd45..26f5c097f 100644
--- a/tests/test_tutorial/test_security/test_tutorial003_py310.py
+++ b/tests/test_tutorial/test_security/test_tutorial003_py310.py
@@ -80,7 +80,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_security/test_tutorial005.py b/tests/test_tutorial/test_security/test_tutorial005.py
index a37f2d60a..e8697339f 100644
--- a/tests/test_tutorial/test_security/test_tutorial005.py
+++ b/tests/test_tutorial/test_security/test_tutorial005.py
@@ -141,7 +141,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_security/test_tutorial005_py310.py b/tests/test_tutorial/test_security/test_tutorial005_py310.py
index 0c9372e2a..3144a2365 100644
--- a/tests/test_tutorial/test_security/test_tutorial005_py310.py
+++ b/tests/test_tutorial/test_security/test_tutorial005_py310.py
@@ -134,7 +134,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_security/test_tutorial005_py39.py b/tests/test_tutorial/test_security/test_tutorial005_py39.py
index 099ab2526..290136e17 100644
--- a/tests/test_tutorial/test_security/test_tutorial005_py39.py
+++ b/tests/test_tutorial/test_security/test_tutorial005_py39.py
@@ -134,7 +134,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases.py b/tests/test_tutorial/test_sql_databases/test_sql_databases.py
index c88fd0bcd..09304ff87 100644
--- a/tests/test_tutorial/test_sql_databases/test_sql_databases.py
+++ b/tests/test_tutorial/test_sql_databases/test_sql_databases.py
@@ -261,7 +261,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py
index b02e1c89e..fbaa8938a 100644
--- a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py
+++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py
@@ -260,7 +260,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py
index 1d0442eb5..d131b4b6a 100644
--- a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py
+++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py
@@ -263,7 +263,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py
index 8764d07a6..470fb52fd 100644
--- a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py
+++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py
@@ -263,7 +263,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py
index f7e73dea4..dc6a1db15 100644
--- a/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py
+++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py
@@ -263,7 +263,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py
index c194c85aa..ebf55ed01 100644
--- a/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py
+++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py
@@ -263,7 +263,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py b/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py
index 2ebc31b95..d28ea5e76 100644
--- a/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py
+++ b/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py
@@ -318,7 +318,7 @@ openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_union_body.py b/tests/test_union_body.py
index d1dfd5efb..3e424de07 100644
--- a/tests/test_union_body.py
+++ b/tests/test_union_body.py
@@ -84,7 +84,7 @@ item_openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_union_inherited_body.py b/tests/test_union_inherited_body.py
index e3d0acc99..60b327ebc 100644
--- a/tests/test_union_inherited_body.py
+++ b/tests/test_union_inherited_body.py
@@ -96,7 +96,7 @@ inherited_item_openapi_schema = {
"loc": {
"title": "Location",
"type": "array",
- "items": {"type": "string"},
+ "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
diff --git a/tests/test_ws_router.py b/tests/test_ws_router.py
index bd7c3c53d..fbca104a2 100644
--- a/tests/test_ws_router.py
+++ b/tests/test_ws_router.py
@@ -3,6 +3,7 @@ from fastapi.testclient import TestClient
router = APIRouter()
prefix_router = APIRouter()
+native_prefix_route = APIRouter(prefix="/native")
app = FastAPI()
@@ -47,8 +48,16 @@ async def router_ws_decorator_depends(
await websocket.close()
+@native_prefix_route.websocket("/")
+async def router_native_prefix_ws(websocket: WebSocket):
+ await websocket.accept()
+ await websocket.send_text("Hello, router with native prefix!")
+ await websocket.close()
+
+
app.include_router(router)
app.include_router(prefix_router, prefix="/prefix")
+app.include_router(native_prefix_route)
def test_app():
@@ -72,6 +81,13 @@ def test_prefix_router():
assert data == "Hello, router with prefix!"
+def test_native_prefix_router():
+ client = TestClient(app)
+ with client.websocket_connect("/native/") as websocket:
+ data = websocket.receive_text()
+ assert data == "Hello, router with native prefix!"
+
+
def test_router2():
client = TestClient(app)
with client.websocket_connect("/router2") as websocket: