Compare commits
281 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77f7447ee8 | ||
|
|
48827eb7fc | ||
|
|
5786d2ef78 | ||
|
|
166088775a | ||
|
|
1052914c20 | ||
|
|
7bdc86b6b4 | ||
|
|
733218f199 | ||
|
|
3fb6d2982f | ||
|
|
b323726d86 | ||
|
|
2db2381b68 | ||
|
|
d31648c82e | ||
|
|
e6c2343691 | ||
|
|
ab0379ee52 | ||
|
|
790fa217f7 | ||
|
|
b892b5e028 | ||
|
|
39eedb31f7 | ||
|
|
8355832c7c | ||
|
|
5821ea8a69 | ||
|
|
3dbdc74366 | ||
|
|
939acef803 | ||
|
|
22a5960d36 | ||
|
|
8c5efe0b4b | ||
|
|
730ded2870 | ||
|
|
1a000d7e5f | ||
|
|
104ee630fc | ||
|
|
ea69c373ac | ||
|
|
9118749128 | ||
|
|
87ad6a46e8 | ||
|
|
75c64b6e4c | ||
|
|
ccd3b97f03 | ||
|
|
074d39fa17 | ||
|
|
f1419322b3 | ||
|
|
b8e6d18385 | ||
|
|
82a1300257 | ||
|
|
13d9de4a49 | ||
|
|
f931dd0717 | ||
|
|
24d2226326 | ||
|
|
0c895f1eaf | ||
|
|
c041c52d91 | ||
|
|
cc9e6b3484 | ||
|
|
dfcc6bc154 | ||
|
|
7e708f7411 | ||
|
|
e09646441d | ||
|
|
1631f981af | ||
|
|
4ce18167e7 | ||
|
|
a676899557 | ||
|
|
b299792ebf | ||
|
|
9fcec3abe9 | ||
|
|
5df00f3ec4 | ||
|
|
20ba6e8b97 | ||
|
|
a42c690496 | ||
|
|
bed0f065fa | ||
|
|
76632fcf24 | ||
|
|
32a010394f | ||
|
|
8d572faa24 | ||
|
|
f495d98fae | ||
|
|
3702cef08d | ||
|
|
9474706ec2 | ||
|
|
e1755f4fa6 | ||
|
|
c75c13c3b0 | ||
|
|
8673e1c127 | ||
|
|
360868fe25 | ||
|
|
b46b3f00bf | ||
|
|
c6e950dc9c | ||
|
|
4e74d40736 | ||
|
|
612d114f3a | ||
|
|
f88ffd1a0b | ||
|
|
cdf0f8a933 | ||
|
|
8650dee4bc | ||
|
|
dca9cc3ec5 | ||
|
|
d6f37b2138 | ||
|
|
5a13f78078 | ||
|
|
d625963cc5 | ||
|
|
142710a0f3 | ||
|
|
47fcacd4d6 | ||
|
|
00104c9259 | ||
|
|
8386e61f17 | ||
|
|
9b7125f66b | ||
|
|
68dc9bd5ac | ||
|
|
7a02d862aa | ||
|
|
479e87e467 | ||
|
|
1ea24e1813 | ||
|
|
492c0924c4 | ||
|
|
048355f01d | ||
|
|
fe889f38e8 | ||
|
|
1dd2bc7675 | ||
|
|
91ffa0ed27 | ||
|
|
6ab0f89858 | ||
|
|
bfc9733660 | ||
|
|
9c00618710 | ||
|
|
beedd199e8 | ||
|
|
ae580deaea | ||
|
|
e1231eeef1 | ||
|
|
8a1ebb38e2 | ||
|
|
e9413f2711 | ||
|
|
7434d2bec7 | ||
|
|
f2c565d8e4 | ||
|
|
cb55d7cdde | ||
|
|
d513680005 | ||
|
|
a5ee4d93d2 | ||
|
|
3a2d4434ce | ||
|
|
d1dfc812f1 | ||
|
|
0b76b675db | ||
|
|
5a776fbff5 | ||
|
|
7667605520 | ||
|
|
642762564d | ||
|
|
78ead585f8 | ||
|
|
48bf243050 | ||
|
|
0e920e6f02 | ||
|
|
afac22dfd2 | ||
|
|
2836e10e2d | ||
|
|
aa62d9212f | ||
|
|
620bffc2b4 | ||
|
|
b56cf6c08f | ||
|
|
cead6ba887 | ||
|
|
23772f3c49 | ||
|
|
45304562a6 | ||
|
|
3d767008df | ||
|
|
5c6811c4ef | ||
|
|
25e1a2602d | ||
|
|
b6272a36af | ||
|
|
db91255ede | ||
|
|
ab52e1c7e4 | ||
|
|
4924d08e7e | ||
|
|
a7c65271ac | ||
|
|
030f1f2ae2 | ||
|
|
74f13e522b | ||
|
|
a4f88f74f2 | ||
|
|
3826129b16 | ||
|
|
636f06cd6b | ||
|
|
c8365bd339 | ||
|
|
df38e53723 | ||
|
|
c606407929 | ||
|
|
f59f85d755 | ||
|
|
42bb15de22 | ||
|
|
e96b002599 | ||
|
|
75b83ce3aa | ||
|
|
ad5aa33864 | ||
|
|
952cd736ac | ||
|
|
026039cae2 | ||
|
|
e2609dff95 | ||
|
|
8486b41349 | ||
|
|
e77ea63577 | ||
|
|
097df92c1c | ||
|
|
be669059fb | ||
|
|
dfdd371c52 | ||
|
|
e1e8627168 | ||
|
|
0916c1c3ef | ||
|
|
11656f7bd5 | ||
|
|
483d092af8 | ||
|
|
60aa63b68a | ||
|
|
eb547bd4fd | ||
|
|
0dfde6e284 | ||
|
|
2d7038e03e | ||
|
|
4f0a3a9e4d | ||
|
|
1701930c86 | ||
|
|
a6897963d5 | ||
|
|
c14803e3fa | ||
|
|
cdba8481c2 | ||
|
|
64ca596a11 | ||
|
|
e1758d107e | ||
|
|
3390182fc9 | ||
|
|
912a43ee3d | ||
|
|
4020304945 | ||
|
|
0a2fc78fea | ||
|
|
b91acfb457 | ||
|
|
b9a0179a03 | ||
|
|
5ed48ccdc8 | ||
|
|
f32d67c8b9 | ||
|
|
0752c7242d | ||
|
|
be855c696b | ||
|
|
da9b5201c4 | ||
|
|
4daa6ef4e4 | ||
|
|
4ad7c55618 | ||
|
|
79e08a2541 | ||
|
|
1c9c80ba93 | ||
|
|
25cb05c876 | ||
|
|
694fbab074 | ||
|
|
2fd28434dd | ||
|
|
d15556b152 | ||
|
|
38d8bab770 | ||
|
|
52f0f8657e | ||
|
|
aedf5c895a | ||
|
|
117f9e4abe | ||
|
|
604fea9fc1 | ||
|
|
994bfd4591 | ||
|
|
02722923b1 | ||
|
|
d63a93429b | ||
|
|
b93e216dc7 | ||
|
|
95a29b6e67 | ||
|
|
272f01a153 | ||
|
|
1a345ae7fc | ||
|
|
c5c138b8eb | ||
|
|
da20e33414 | ||
|
|
7fbe3737bc | ||
|
|
f63cec9c95 | ||
|
|
3063ad83ec | ||
|
|
78680e5bee | ||
|
|
55b9faeb48 | ||
|
|
72645dfeab | ||
|
|
3223de5598 | ||
|
|
1afa4e8e75 | ||
|
|
6fd3736da2 | ||
|
|
7e043e5e6f | ||
|
|
d1585c42b9 | ||
|
|
fc494e3527 | ||
|
|
b344cc9415 | ||
|
|
38b71a9298 | ||
|
|
769ee73240 | ||
|
|
1df2f14c64 | ||
|
|
eab9a0e139 | ||
|
|
b86ac6739a | ||
|
|
9840d9e59d | ||
|
|
0ec52157df | ||
|
|
f1c5330b65 | ||
|
|
306ec8de04 | ||
|
|
6d7c9893d4 | ||
|
|
6264709054 | ||
|
|
76c2077f47 | ||
|
|
9cc4428de3 | ||
|
|
a63b1efc29 | ||
|
|
9863c3fca8 | ||
|
|
6fb97f44cf | ||
|
|
f64c448329 | ||
|
|
df6cbc5ec6 | ||
|
|
0f0af751e4 | ||
|
|
6c9dca55bc | ||
|
|
d71e807401 | ||
|
|
7df9ddfe4e | ||
|
|
4170659359 | ||
|
|
2940a7fdfa | ||
|
|
dadd6650ed | ||
|
|
c5a21354af | ||
|
|
8bafe2a482 | ||
|
|
42f1716b48 | ||
|
|
6ab2841dbb | ||
|
|
0f54657377 | ||
|
|
79e5b36551 | ||
|
|
074868d77e | ||
|
|
3dd16a9458 | ||
|
|
62c23ab5fa | ||
|
|
11c05beece | ||
|
|
7b3ef43127 | ||
|
|
e0080e5f75 | ||
|
|
e1ba54bd12 | ||
|
|
7032dfb4f1 | ||
|
|
14e7f7c1f4 | ||
|
|
9ed6f1e419 | ||
|
|
b268c39758 | ||
|
|
4dd386b807 | ||
|
|
b7251f1654 | ||
|
|
780d3e65ad | ||
|
|
cc8cac200f | ||
|
|
e7be5c8ac5 | ||
|
|
8f52864899 | ||
|
|
47a630721a | ||
|
|
10ae6de111 | ||
|
|
2b47f3e56b | ||
|
|
d60dd1b60e | ||
|
|
2822f7ca64 | ||
|
|
ff6afeaf78 | ||
|
|
74852d406c | ||
|
|
921642dc7b | ||
|
|
5c01d44ee9 | ||
|
|
135704dcc8 | ||
|
|
88793bb6c2 | ||
|
|
70a51b3aff | ||
|
|
340a582be7 | ||
|
|
5f66b5466f | ||
|
|
d2169ee567 | ||
|
|
a5c03ba1b7 | ||
|
|
e4ea6426dc | ||
|
|
8bf7cd1dc6 | ||
|
|
92feb3ade7 | ||
|
|
d0e739d8f2 | ||
|
|
4efa6bd75e | ||
|
|
600f15faa0 | ||
|
|
250fa519f9 | ||
|
|
3c6dafcc8e | ||
|
|
8447000eee | ||
|
|
fe453f80ed |
5
.flake8
Normal file
@@ -0,0 +1,5 @@
|
||||
[flake8]
|
||||
max-line-length = 88
|
||||
select = C,E,F,W,B,B9
|
||||
ignore = E203, E501, W503
|
||||
exclude = __init__.py
|
||||
7
.github/actions/comment-docs-preview-in-pr/Dockerfile
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM python:3.7
|
||||
|
||||
RUN pip install httpx "pydantic==1.5.1" pygithub
|
||||
|
||||
COPY ./app /app
|
||||
|
||||
CMD ["python", "/app/main.py"]
|
||||
13
.github/actions/comment-docs-preview-in-pr/action.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
name: Comment Docs Preview in PR
|
||||
description: Comment with the docs URL preview in the PR
|
||||
author: Sebastián Ramírez <tiangolo@gmail.com>
|
||||
inputs:
|
||||
token:
|
||||
description: Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }}
|
||||
required: true
|
||||
deploy_url:
|
||||
description: The deployment URL to comment in the PR
|
||||
required: true
|
||||
runs:
|
||||
using: docker
|
||||
image: Dockerfile
|
||||
70
.github/actions/comment-docs-preview-in-pr/app/main.py
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
import logging
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
import httpx
|
||||
from github import Github
|
||||
from github.PullRequest import PullRequest
|
||||
from pydantic import BaseModel, BaseSettings, SecretStr, ValidationError
|
||||
|
||||
github_api = "https://api.github.com"
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
github_repository: str
|
||||
github_event_path: Path
|
||||
github_event_name: Optional[str] = None
|
||||
input_token: SecretStr
|
||||
input_deploy_url: str
|
||||
|
||||
|
||||
class PartialGithubEventHeadCommit(BaseModel):
|
||||
id: str
|
||||
|
||||
|
||||
class PartialGithubEventWorkflowRun(BaseModel):
|
||||
head_commit: PartialGithubEventHeadCommit
|
||||
|
||||
|
||||
class PartialGithubEvent(BaseModel):
|
||||
workflow_run: PartialGithubEventWorkflowRun
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
settings = Settings()
|
||||
logging.info(f"Using config: {settings.json()}")
|
||||
g = Github(settings.input_token.get_secret_value())
|
||||
repo = g.get_repo(settings.github_repository)
|
||||
try:
|
||||
event = PartialGithubEvent.parse_file(settings.github_event_path)
|
||||
except ValidationError as e:
|
||||
logging.error(f"Error parsing event file: {e.errors()}")
|
||||
sys.exit(0)
|
||||
use_pr: Optional[PullRequest] = 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}"
|
||||
)
|
||||
sys.exit(0)
|
||||
github_headers = {
|
||||
"Authorization": f"token {settings.input_token.get_secret_value()}"
|
||||
}
|
||||
url = f"{github_api}/repos/{settings.github_repository}/issues/{use_pr.number}/comments"
|
||||
logging.info(f"Using comments URL: {url}")
|
||||
response = httpx.post(
|
||||
url,
|
||||
headers=github_headers,
|
||||
json={
|
||||
"body": f"📝 Docs preview for commit {use_pr.head.sha} at: {settings.input_deploy_url}"
|
||||
},
|
||||
)
|
||||
if not (200 <= response.status_code <= 300):
|
||||
logging.error(f"Error posting comment: {response.text}")
|
||||
sys.exit(1)
|
||||
logging.info("Finished")
|
||||
7
.github/actions/people/Dockerfile
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM python:3.7
|
||||
|
||||
RUN pip install httpx PyGithub "pydantic==1.5.1" "pyyaml>=5.3.1,<6.0.0"
|
||||
|
||||
COPY ./app /app
|
||||
|
||||
CMD ["python", "/app/main.py"]
|
||||
13
.github/actions/people/action.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
name: "Generate FastAPI People"
|
||||
description: "Generate the data for the FastAPI People page"
|
||||
author: "Sebastián Ramírez <tiangolo@gmail.com>"
|
||||
inputs:
|
||||
token:
|
||||
description: 'User token, to read the GitHub API. Can be passed in using {{ secrets.ACTION_TOKEN }}'
|
||||
required: true
|
||||
standard_token:
|
||||
description: 'Default GitHub Action token, used for the PR. Can be passed in using {{ secrets.GITHUB_TOKEN }}'
|
||||
required: true
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
||||
518
.github/actions/people/app/main.py
vendored
Normal file
@@ -0,0 +1,518 @@
|
||||
import logging
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import Counter
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
from typing import Container, Dict, List, Optional, Set
|
||||
|
||||
import httpx
|
||||
import yaml
|
||||
from github import Github
|
||||
from pydantic import BaseModel, BaseSettings, SecretStr
|
||||
|
||||
github_graphql_url = "https://api.github.com/graphql"
|
||||
|
||||
issues_query = """
|
||||
query Q($after: String) {
|
||||
repository(name: "fastapi", owner: "tiangolo") {
|
||||
issues(first: 100, after: $after) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
number
|
||||
author {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
title
|
||||
createdAt
|
||||
state
|
||||
comments(first: 100) {
|
||||
nodes {
|
||||
createdAt
|
||||
author {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
prs_query = """
|
||||
query Q($after: String) {
|
||||
repository(name: "fastapi", owner: "tiangolo") {
|
||||
pullRequests(first: 100, after: $after) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
number
|
||||
labels(first: 100) {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
author {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
title
|
||||
createdAt
|
||||
state
|
||||
comments(first: 100) {
|
||||
nodes {
|
||||
createdAt
|
||||
author {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
reviews(first:100) {
|
||||
nodes {
|
||||
author {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
sponsors_query = """
|
||||
query Q($after: String) {
|
||||
user(login: "tiangolo") {
|
||||
sponsorshipsAsMaintainer(first: 100, after: $after) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
sponsorEntity {
|
||||
... on Organization {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
... on User {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
}
|
||||
tier {
|
||||
name
|
||||
monthlyPriceInDollars
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class Author(BaseModel):
|
||||
login: str
|
||||
avatarUrl: str
|
||||
url: str
|
||||
|
||||
|
||||
class CommentsNode(BaseModel):
|
||||
createdAt: datetime
|
||||
author: Optional[Author] = None
|
||||
|
||||
|
||||
class Comments(BaseModel):
|
||||
nodes: List[CommentsNode]
|
||||
|
||||
|
||||
class IssuesNode(BaseModel):
|
||||
number: int
|
||||
author: Optional[Author] = None
|
||||
title: str
|
||||
createdAt: datetime
|
||||
state: str
|
||||
comments: Comments
|
||||
|
||||
|
||||
class IssuesEdge(BaseModel):
|
||||
cursor: str
|
||||
node: IssuesNode
|
||||
|
||||
|
||||
class Issues(BaseModel):
|
||||
edges: List[IssuesEdge]
|
||||
|
||||
|
||||
class IssuesRepository(BaseModel):
|
||||
issues: Issues
|
||||
|
||||
|
||||
class IssuesResponseData(BaseModel):
|
||||
repository: IssuesRepository
|
||||
|
||||
|
||||
class IssuesResponse(BaseModel):
|
||||
data: IssuesResponseData
|
||||
|
||||
|
||||
class LabelNode(BaseModel):
|
||||
name: str
|
||||
|
||||
|
||||
class Labels(BaseModel):
|
||||
nodes: List[LabelNode]
|
||||
|
||||
|
||||
class ReviewNode(BaseModel):
|
||||
author: Optional[Author] = None
|
||||
state: str
|
||||
|
||||
|
||||
class Reviews(BaseModel):
|
||||
nodes: List[ReviewNode]
|
||||
|
||||
|
||||
class PullRequestNode(BaseModel):
|
||||
number: int
|
||||
labels: Labels
|
||||
author: Optional[Author] = None
|
||||
title: str
|
||||
createdAt: datetime
|
||||
state: str
|
||||
comments: Comments
|
||||
reviews: Reviews
|
||||
|
||||
|
||||
class PullRequestEdge(BaseModel):
|
||||
cursor: str
|
||||
node: PullRequestNode
|
||||
|
||||
|
||||
class PullRequests(BaseModel):
|
||||
edges: List[PullRequestEdge]
|
||||
|
||||
|
||||
class PRsRepository(BaseModel):
|
||||
pullRequests: PullRequests
|
||||
|
||||
|
||||
class PRsResponseData(BaseModel):
|
||||
repository: PRsRepository
|
||||
|
||||
|
||||
class PRsResponse(BaseModel):
|
||||
data: PRsResponseData
|
||||
|
||||
|
||||
class SponsorEntity(BaseModel):
|
||||
login: str
|
||||
avatarUrl: str
|
||||
url: str
|
||||
|
||||
|
||||
class Tier(BaseModel):
|
||||
name: str
|
||||
monthlyPriceInDollars: float
|
||||
|
||||
|
||||
class SponsorshipAsMaintainerNode(BaseModel):
|
||||
sponsorEntity: SponsorEntity
|
||||
tier: Tier
|
||||
|
||||
|
||||
class SponsorshipAsMaintainerEdge(BaseModel):
|
||||
cursor: str
|
||||
node: SponsorshipAsMaintainerNode
|
||||
|
||||
|
||||
class SponsorshipAsMaintainer(BaseModel):
|
||||
edges: List[SponsorshipAsMaintainerEdge]
|
||||
|
||||
|
||||
class SponsorsUser(BaseModel):
|
||||
sponsorshipsAsMaintainer: SponsorshipAsMaintainer
|
||||
|
||||
|
||||
class SponsorsResponseData(BaseModel):
|
||||
user: SponsorsUser
|
||||
|
||||
|
||||
class SponsorsResponse(BaseModel):
|
||||
data: SponsorsResponseData
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
input_token: SecretStr
|
||||
input_standard_token: SecretStr
|
||||
github_repository: str
|
||||
|
||||
|
||||
def get_graphql_response(
|
||||
*, settings: Settings, query: str, after: Optional[str] = None
|
||||
):
|
||||
headers = {"Authorization": f"token {settings.input_token.get_secret_value()}"}
|
||||
variables = {"after": after}
|
||||
response = httpx.post(
|
||||
github_graphql_url,
|
||||
headers=headers,
|
||||
json={"query": query, "variables": variables, "operationName": "Q"},
|
||||
)
|
||||
if not response.status_code == 200:
|
||||
logging.error(f"Response was not 200, after: {after}")
|
||||
logging.error(response.text)
|
||||
raise RuntimeError(response.text)
|
||||
data = response.json()
|
||||
return data
|
||||
|
||||
|
||||
def get_graphql_issue_edges(*, settings: Settings, after: Optional[str] = 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):
|
||||
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):
|
||||
data = get_graphql_response(settings=settings, query=sponsors_query, after=after)
|
||||
graphql_response = SponsorsResponse.parse_obj(data)
|
||||
return graphql_response.data.user.sponsorshipsAsMaintainer.edges
|
||||
|
||||
|
||||
def get_experts(settings: Settings):
|
||||
issue_nodes: List[IssuesNode] = []
|
||||
issue_edges = get_graphql_issue_edges(settings=settings)
|
||||
|
||||
while issue_edges:
|
||||
for edge in issue_edges:
|
||||
issue_nodes.append(edge.node)
|
||||
last_edge = issue_edges[-1]
|
||||
issue_edges = get_graphql_issue_edges(settings=settings, after=last_edge.cursor)
|
||||
|
||||
commentors = Counter()
|
||||
last_month_commentors = Counter()
|
||||
authors: Dict[str, Author] = {}
|
||||
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
one_month_ago = now - timedelta(days=30)
|
||||
|
||||
for issue in issue_nodes:
|
||||
issue_author_name = None
|
||||
if issue.author:
|
||||
authors[issue.author.login] = issue.author
|
||||
issue_author_name = issue.author.login
|
||||
issue_commentors = set()
|
||||
for comment in issue.comments.nodes:
|
||||
if comment.author:
|
||||
authors[comment.author.login] = comment.author
|
||||
if comment.author.login == issue_author_name:
|
||||
continue
|
||||
issue_commentors.add(comment.author.login)
|
||||
for author_name in issue_commentors:
|
||||
commentors[author_name] += 1
|
||||
if issue.createdAt > one_month_ago:
|
||||
last_month_commentors[author_name] += 1
|
||||
return commentors, last_month_commentors, authors
|
||||
|
||||
|
||||
def get_contributors(settings: Settings):
|
||||
pr_nodes: List[PullRequestNode] = []
|
||||
pr_edges = get_graphql_pr_edges(settings=settings)
|
||||
|
||||
while pr_edges:
|
||||
for edge in pr_edges:
|
||||
pr_nodes.append(edge.node)
|
||||
last_edge = pr_edges[-1]
|
||||
pr_edges = get_graphql_pr_edges(settings=settings, after=last_edge.cursor)
|
||||
|
||||
contributors = Counter()
|
||||
commentors = Counter()
|
||||
reviewers = Counter()
|
||||
authors: Dict[str, Author] = {}
|
||||
|
||||
for pr in pr_nodes:
|
||||
author_name = None
|
||||
if pr.author:
|
||||
authors[pr.author.login] = pr.author
|
||||
author_name = pr.author.login
|
||||
pr_commentors: Set[str] = set()
|
||||
pr_reviewers: Set[str] = set()
|
||||
for comment in pr.comments.nodes:
|
||||
if comment.author:
|
||||
authors[comment.author.login] = comment.author
|
||||
if comment.author.login == author_name:
|
||||
continue
|
||||
pr_commentors.add(comment.author.login)
|
||||
for author_name in pr_commentors:
|
||||
commentors[author_name] += 1
|
||||
for review in pr.reviews.nodes:
|
||||
if review.author:
|
||||
authors[review.author.login] = review.author
|
||||
pr_reviewers.add(review.author.login)
|
||||
for reviewer in pr_reviewers:
|
||||
reviewers[reviewer] += 1
|
||||
if pr.state == "MERGED" and pr.author:
|
||||
contributors[pr.author.login] += 1
|
||||
return contributors, commentors, reviewers, authors
|
||||
|
||||
|
||||
def get_individual_sponsors(settings: Settings, max_individual_sponsor: int = 5):
|
||||
nodes: List[SponsorshipAsMaintainerNode] = []
|
||||
edges = get_graphql_sponsor_edges(settings=settings)
|
||||
|
||||
while edges:
|
||||
for edge in edges:
|
||||
nodes.append(edge.node)
|
||||
last_edge = edges[-1]
|
||||
edges = get_graphql_sponsor_edges(settings=settings, after=last_edge.cursor)
|
||||
|
||||
entities: Dict[str, SponsorEntity] = {}
|
||||
for node in nodes:
|
||||
if node.tier.monthlyPriceInDollars > max_individual_sponsor:
|
||||
continue
|
||||
entities[node.sponsorEntity.login] = node.sponsorEntity
|
||||
return entities
|
||||
|
||||
|
||||
def get_top_users(
|
||||
*,
|
||||
counter: Counter,
|
||||
min_count: int,
|
||||
authors: Dict[str, Author],
|
||||
skip_users: Container[str],
|
||||
):
|
||||
users = []
|
||||
for commentor, count in counter.most_common(50):
|
||||
if commentor in skip_users:
|
||||
continue
|
||||
if count >= min_count:
|
||||
author = authors[commentor]
|
||||
users.append(
|
||||
{
|
||||
"login": commentor,
|
||||
"count": count,
|
||||
"avatarUrl": author.avatarUrl,
|
||||
"url": author.url,
|
||||
}
|
||||
)
|
||||
return users
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
settings = Settings()
|
||||
logging.info(f"Using config: {settings.json()}")
|
||||
g = Github(settings.input_standard_token.get_secret_value())
|
||||
repo = g.get_repo(settings.github_repository)
|
||||
issue_commentors, issue_last_month_commentors, issue_authors = get_experts(
|
||||
settings=settings
|
||||
)
|
||||
contributors, pr_commentors, reviewers, pr_authors = get_contributors(
|
||||
settings=settings
|
||||
)
|
||||
authors = {**issue_authors, **pr_authors}
|
||||
maintainers_logins = {"tiangolo"}
|
||||
bot_names = {"codecov", "github-actions"}
|
||||
maintainers = []
|
||||
for login in maintainers_logins:
|
||||
user = authors[login]
|
||||
maintainers.append(
|
||||
{
|
||||
"login": login,
|
||||
"answers": issue_commentors[login],
|
||||
"prs": contributors[login],
|
||||
"avatarUrl": user.avatarUrl,
|
||||
"url": user.url,
|
||||
}
|
||||
)
|
||||
|
||||
min_count_expert = 10
|
||||
min_count_last_month = 3
|
||||
min_count_contributor = 4
|
||||
min_count_reviewer = 4
|
||||
skip_users = maintainers_logins | bot_names
|
||||
experts = get_top_users(
|
||||
counter=issue_commentors,
|
||||
min_count=min_count_expert,
|
||||
authors=authors,
|
||||
skip_users=skip_users,
|
||||
)
|
||||
last_month_active = get_top_users(
|
||||
counter=issue_last_month_commentors,
|
||||
min_count=min_count_last_month,
|
||||
authors=authors,
|
||||
skip_users=skip_users,
|
||||
)
|
||||
top_contributors = get_top_users(
|
||||
counter=contributors,
|
||||
min_count=min_count_contributor,
|
||||
authors=authors,
|
||||
skip_users=skip_users,
|
||||
)
|
||||
top_reviewers = get_top_users(
|
||||
counter=reviewers,
|
||||
min_count=min_count_reviewer,
|
||||
authors=authors,
|
||||
skip_users=skip_users,
|
||||
)
|
||||
|
||||
sponsors_by_login = get_individual_sponsors(settings=settings)
|
||||
sponsors = []
|
||||
for login, sponsor in sponsors_by_login.items():
|
||||
sponsors.append(
|
||||
{"login": login, "avatarUrl": sponsor.avatarUrl, "url": sponsor.url}
|
||||
)
|
||||
|
||||
people = {
|
||||
"maintainers": maintainers,
|
||||
"experts": experts,
|
||||
"last_month_active": last_month_active,
|
||||
"top_contributors": top_contributors,
|
||||
"top_reviewers": top_reviewers,
|
||||
"sponsors": sponsors,
|
||||
}
|
||||
people_path = Path("./docs/en/data/people.yml")
|
||||
people_old_content = people_path.read_text(encoding="utf-8")
|
||||
new_content = yaml.dump(people, sort_keys=False, width=200, allow_unicode=True)
|
||||
if people_old_content == new_content:
|
||||
logging.info("The FastAPI People data hasn't changed, finishing.")
|
||||
sys.exit(0)
|
||||
people_path.write_text(new_content, encoding="utf-8")
|
||||
logging.info("Setting up GitHub Actions git user")
|
||||
subprocess.run(["git", "config", "user.name", "github-actions"], check=True)
|
||||
subprocess.run(
|
||||
["git", "config", "user.email", "github-actions@github.com"], check=True
|
||||
)
|
||||
branch_name = "fastapi-people"
|
||||
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)
|
||||
logging.info("Committing updated file")
|
||||
message = "👥 Update FastAPI People"
|
||||
result = subprocess.run(["git", "commit", "-m", message], check=True)
|
||||
logging.info("Pushing branch")
|
||||
subprocess.run(["git", "push", "origin", branch_name], check=True)
|
||||
logging.info("Creating PR")
|
||||
pr = repo.create_pull(title=message, body=message, base="master", head=branch_name)
|
||||
logging.info(f"Created PR: {pr.number}")
|
||||
logging.info("Finished")
|
||||
7
.github/actions/watch-previews/Dockerfile
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM python:3.7
|
||||
|
||||
RUN pip install httpx PyGithub "pydantic==1.5.1"
|
||||
|
||||
COPY ./app /app
|
||||
|
||||
CMD ["python", "/app/main.py"]
|
||||
10
.github/actions/watch-previews/action.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
name: "Watch docs previews in PRs"
|
||||
description: "Check PRs and trigger new docs deploys"
|
||||
author: "Sebastián Ramírez <tiangolo@gmail.com>"
|
||||
inputs:
|
||||
token:
|
||||
description: 'Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }}'
|
||||
required: true
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
||||
101
.github/actions/watch-previews/app/main.py
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
import httpx
|
||||
from github import Github
|
||||
from github.NamedUser import NamedUser
|
||||
from pydantic import BaseModel, BaseSettings, SecretStr
|
||||
|
||||
github_api = "https://api.github.com"
|
||||
netlify_api = "https://api.netlify.com"
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
input_token: SecretStr
|
||||
github_repository: str
|
||||
github_event_path: Path
|
||||
github_event_name: Optional[str] = None
|
||||
|
||||
|
||||
class Artifact(BaseModel):
|
||||
id: int
|
||||
node_id: str
|
||||
name: str
|
||||
size_in_bytes: int
|
||||
url: str
|
||||
archive_download_url: str
|
||||
expired: bool
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class ArtifactResponse(BaseModel):
|
||||
total_count: int
|
||||
artifacts: List[Artifact]
|
||||
|
||||
|
||||
def get_message(commit: str) -> str:
|
||||
return f"Docs preview for commit {commit} at"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
settings = Settings()
|
||||
logging.info(f"Using config: {settings.json()}")
|
||||
g = Github(settings.input_token.get_secret_value())
|
||||
repo = g.get_repo(settings.github_repository)
|
||||
owner: NamedUser = repo.owner
|
||||
headers = {"Authorization": f"token {settings.input_token.get_secret_value()}"}
|
||||
prs = list(repo.get_pulls(state="open"))
|
||||
response = httpx.get(
|
||||
f"{github_api}/repos/{settings.github_repository}/actions/artifacts",
|
||||
headers=headers,
|
||||
)
|
||||
data = response.json()
|
||||
artifacts_response = ArtifactResponse.parse_obj(data)
|
||||
for pr in prs:
|
||||
logging.info("-----")
|
||||
logging.info(f"Processing PR #{pr.number}: {pr.title}")
|
||||
pr_comments = list(pr.get_issue_comments())
|
||||
pr_commits = list(pr.get_commits())
|
||||
last_commit = pr_commits[0]
|
||||
for pr_commit in pr_commits:
|
||||
if pr_commit.commit.author.date > last_commit.commit.author.date:
|
||||
last_commit = pr_commit
|
||||
commit = last_commit.commit.sha
|
||||
logging.info(f"Last commit: {commit}")
|
||||
message = get_message(commit)
|
||||
notified = False
|
||||
for pr_comment in pr_comments:
|
||||
if message in pr_comment.body:
|
||||
notified = True
|
||||
logging.info(f"Docs preview was notified: {notified}")
|
||||
if not notified:
|
||||
artifact_name = f"docs-zip-{commit}"
|
||||
use_artifact: Optional[Artifact] = None
|
||||
for artifact in artifacts_response.artifacts:
|
||||
if artifact.name == artifact_name:
|
||||
use_artifact = artifact
|
||||
break
|
||||
if not use_artifact:
|
||||
logging.info("Artifact not available")
|
||||
else:
|
||||
logging.info(f"Existing artifact: {use_artifact.name}")
|
||||
response = httpx.post(
|
||||
"https://api.github.com/repos/tiangolo/fastapi/actions/workflows/preview-docs.yml/dispatches",
|
||||
headers=headers,
|
||||
json={
|
||||
"ref": "master",
|
||||
"inputs": {
|
||||
"pr": f"{pr.number}",
|
||||
"name": artifact_name,
|
||||
"commit": commit,
|
||||
},
|
||||
},
|
||||
)
|
||||
logging.info(
|
||||
f"Trigger sent, response status: {response.status_code} - content: {response.content}"
|
||||
)
|
||||
logging.info("Finished")
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Build and Deploy to Netlify
|
||||
name: Build Docs
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
@@ -7,6 +7,10 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
@@ -18,12 +22,19 @@ jobs:
|
||||
run: python3.7 -m flit install --extras doc
|
||||
- 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
|
||||
with:
|
||||
name: docs-zip
|
||||
path: ./docs.zip
|
||||
- name: Deploy to Netlify
|
||||
uses: nwtgck/actions-netlify@v1.0.3
|
||||
uses: nwtgck/actions-netlify@v1.1.5
|
||||
with:
|
||||
publish-dir: './site'
|
||||
production-branch: master
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
enable-commit-comment: false
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
||||
13
.github/workflows/label-approved.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
name: Label Approved
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 12 * * *"
|
||||
|
||||
jobs:
|
||||
label-approved:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: docker://tiangolo/label-approved:0.0.2
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
25
.github/workflows/latest-changes.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Latest Changes
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
branches:
|
||||
- master
|
||||
types:
|
||||
- closed
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
number:
|
||||
description: PR number
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
latest-changes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: docker://tiangolo/latest-changes:0.0.3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
latest_changes_file: docs/en/docs/release-notes.md
|
||||
latest_changes_header: '## Latest Changes\n\n'
|
||||
debug_logs: true
|
||||
16
.github/workflows/people.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
name: FastAPI People
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 14 1 * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
fastapi-people:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/people
|
||||
with:
|
||||
token: ${{ secrets.ACTIONS_TOKEN }}
|
||||
standard_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
14
.github/workflows/pr-approvals.yml
vendored
@@ -1,14 +0,0 @@
|
||||
name: Label approved pull requests
|
||||
on: pull_request_review
|
||||
jobs:
|
||||
labelWhenApproved:
|
||||
name: Label when approved
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Label when approved
|
||||
uses: pullreminders/label-when-approved-action@v1.0.7
|
||||
env:
|
||||
APPROVALS: "2"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ADD_LABEL: "approved-2"
|
||||
REMOVE_LABEL: "awaiting%20review"
|
||||
41
.github/workflows/preview-docs.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Preview Docs
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- Build Docs
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Download Artifact Docs
|
||||
uses: dawidd6/action-download-artifact@v2.9.0
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
workflow: build-docs.yml
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
name: docs-zip
|
||||
- name: Unzip docs
|
||||
run: |
|
||||
rm -rf ./site
|
||||
unzip docs.zip
|
||||
rm -f docs.zip
|
||||
- name: Deploy to Netlify
|
||||
id: netlify
|
||||
uses: nwtgck/actions-netlify@v1.1.5
|
||||
with:
|
||||
publish-dir: './site'
|
||||
production-deploy: false
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
enable-commit-comment: false
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
||||
- name: Comment Deploy
|
||||
uses: ./.github/actions/comment-docs-preview-in-pr
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
deploy_url: "${{ steps.netlify.outputs.deploy-url }}"
|
||||
39
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: Publish
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: "3.6"
|
||||
- name: Install Flit
|
||||
run: pip install flit
|
||||
- name: Install Dependencies
|
||||
run: flit install --symlink
|
||||
- name: Publish
|
||||
env:
|
||||
FLIT_USERNAME: ${{ secrets.FLIT_USERNAME }}
|
||||
FLIT_PASSWORD: ${{ secrets.FLIT_PASSWORD }}
|
||||
run: bash scripts/publish.sh
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
# - name: Notify
|
||||
# env:
|
||||
# GITTER_TOKEN: ${{ secrets.GITTER_TOKEN }}
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# TAG: ${{ github.event.release.name }}
|
||||
# run: bash scripts/notify.sh
|
||||
29
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.6, 3.7, 3.8]
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install Flit
|
||||
run: pip install flit
|
||||
- name: Install Dependencies
|
||||
run: flit install --symlink
|
||||
- name: Test
|
||||
run: bash scripts/test.sh
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
2
.gitignore
vendored
@@ -17,6 +17,8 @@ env3.*
|
||||
env
|
||||
docs_build
|
||||
venv
|
||||
docs.zip
|
||||
archive.zip
|
||||
|
||||
# vim temporary files
|
||||
*~
|
||||
|
||||
32
.travis.yml
@@ -1,32 +0,0 @@
|
||||
dist: xenial
|
||||
|
||||
language: python
|
||||
|
||||
cache: pip
|
||||
|
||||
python:
|
||||
- "3.6"
|
||||
- "3.7"
|
||||
- "3.8"
|
||||
- "nightly"
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- python: "nightly"
|
||||
|
||||
install:
|
||||
- pip install flit
|
||||
- flit install --symlink
|
||||
|
||||
script:
|
||||
- bash scripts/test.sh
|
||||
|
||||
after_script:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
deploy:
|
||||
provider: script
|
||||
script: bash scripts/deploy.sh
|
||||
on:
|
||||
tags: true
|
||||
python: "3.6"
|
||||
34
README.md
@@ -5,14 +5,14 @@
|
||||
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.com/tiangolo/fastapi" target="_blank">
|
||||
<img src="https://travis-ci.com/tiangolo/fastapi.svg?branch=master" alt="Build Status">
|
||||
<a href="https://github.com/tiangolo/fastapi/actions?query=workflow%3ATest" target="_blank">
|
||||
<img src="https://github.com/tiangolo/fastapi/workflows/Test/badge.svg" alt="Test">
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/tiangolo/fastapi" target="_blank">
|
||||
<img src="https://img.shields.io/codecov/c/github/tiangolo/fastapi" alt="Coverage">
|
||||
<img src="https://img.shields.io/codecov/c/github/tiangolo/fastapi?color=%2334D058" alt="Coverage">
|
||||
</a>
|
||||
<a href="https://pypi.org/project/fastapi" target="_blank">
|
||||
<img src="https://badge.fury.io/py/fastapi.svg" alt="Package version">
|
||||
<img src="https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package" alt="Package version">
|
||||
</a>
|
||||
<a href="https://gitter.im/tiangolo/fastapi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge" target="_blank">
|
||||
<img src="https://badges.gitter.im/tiangolo/fastapi.svg" alt="Join the chat at https://gitter.im/tiangolo/fastapi">
|
||||
@@ -39,10 +39,20 @@ The key features are:
|
||||
* **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: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
|
||||
<small>* estimation based on tests on an internal development team, building production applications.</small>
|
||||
|
||||
## Gold Sponsors
|
||||
|
||||
<!-- sponsors -->
|
||||
|
||||
<a href="https://www.deta.sh/?ref=fastapi" target="_blank" title="The launchpad for all your (team's) ideas"><img src="https://fastapi.tiangolo.com/img/sponsors/deta.svg"></a>
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">Other sponsors</a>
|
||||
|
||||
## Opinions
|
||||
|
||||
"_[...] 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._"
|
||||
@@ -71,7 +81,7 @@ The key features are:
|
||||
|
||||
"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="http://www.hug.rest/" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://www.hug.rest/" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
@@ -112,7 +122,7 @@ $ pip install fastapi
|
||||
|
||||
</div>
|
||||
|
||||
You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
|
||||
You will also need an ASGI server, for production such as <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -153,7 +163,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"
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
@@ -245,7 +255,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"
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
@@ -428,9 +438,9 @@ Used by Pydantic:
|
||||
|
||||
Used by Starlette:
|
||||
|
||||
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
||||
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
|
||||
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
||||
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
|
||||
@@ -439,7 +449,7 @@ Used by Starlette:
|
||||
|
||||
Used by FastAPI / Starlette:
|
||||
|
||||
* <a href="http://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - for the server that loads and serves your application.
|
||||
* <a href="https://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - for the server that loads and serves your application.
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Required if you want to use `ORJSONResponse`.
|
||||
|
||||
You can install all of these with `pip install fastapi[all]`.
|
||||
|
||||
238
docs/en/data/external_links.yml
Normal file
@@ -0,0 +1,238 @@
|
||||
articles:
|
||||
english:
|
||||
- link: https://medium.com/@williamhayes/fastapi-starlette-debug-vs-prod-5f7561db3a59
|
||||
title: FastAPI/Starlette debug vs prod
|
||||
author_link: https://medium.com/@williamhayes
|
||||
author: William Hayes
|
||||
- link: https://medium.com/data-rebels/fastapi-google-as-an-external-authentication-provider-3a527672cf33
|
||||
title: FastAPI — Google as an external authentication provider
|
||||
author_link: https://medium.com/@nilsdebruin
|
||||
author: Nils de Bruin
|
||||
- link: https://medium.com/data-rebels/fastapi-how-to-add-basic-and-cookie-authentication-a45c85ef47d3
|
||||
title: FastAPI — How to add basic and cookie authentication
|
||||
author_link: https://medium.com/@nilsdebruin
|
||||
author: Nils de Bruin
|
||||
- link: https://dev.to/errietta/introduction-to-the-fastapi-python-framework-2n10
|
||||
title: Introduction to the fastapi python framework
|
||||
author_link: https://dev.to/errietta
|
||||
author: Errieta Kostala
|
||||
- link: https://nickc1.github.io/api,/scikit-learn/2019/01/10/scikit-fastapi.html
|
||||
title: "FastAPI and Scikit-Learn: Easily Deploy Models"
|
||||
author_link: https://nickc1.github.io/
|
||||
author: Nick Cortale
|
||||
- link: https://medium.com/data-rebels/fastapi-authentication-revisited-enabling-api-key-authentication-122dc5975680
|
||||
title: "FastAPI authentication revisited: Enabling API key authentication"
|
||||
author_link: https://medium.com/@nilsdebruin
|
||||
author: Nils de Bruin
|
||||
- link: https://medium.com/@nico.axtmann95/deploying-a-scikit-learn-model-with-onnx-und-fastapi-1af398268915
|
||||
title: Deploying a scikit-learn model with ONNX and FastAPI
|
||||
author_link: https://www.linkedin.com/in/nico-axtmann
|
||||
author: Nico Axtmann
|
||||
- link: https://geekflare.com/python-asynchronous-web-frameworks/
|
||||
title: Top 5 Asynchronous Web Frameworks for Python
|
||||
author_link: https://geekflare.com/author/ankush/
|
||||
author: Ankush Thakur
|
||||
- link: https://medium.com/@gntrm/jwt-authentication-with-fastapi-and-aws-cognito-1333f7f2729e
|
||||
title: JWT Authentication with FastAPI and AWS Cognito
|
||||
author_link: https://twitter.com/gntrm
|
||||
author: Johannes Gontrum
|
||||
- link: https://towardsdatascience.com/how-to-deploy-a-machine-learning-model-dc51200fe8cf
|
||||
title: How to Deploy a Machine Learning Model
|
||||
author_link: https://www.linkedin.com/in/mgrootendorst/
|
||||
author: Maarten Grootendorst
|
||||
- link: https://eng.uber.com/ludwig-v0-2/
|
||||
title: "Uber: Ludwig v0.2 Adds New Features and Other Improvements to its Deep Learning Toolbox [including a FastAPI server]"
|
||||
author_link: https://eng.uber.com
|
||||
author: Uber Engineering
|
||||
- link: https://gitlab.com/euri10/fastapi_cheatsheet
|
||||
title: A FastAPI and Swagger UI visual cheatsheet
|
||||
author_link: https://gitlab.com/euri10
|
||||
author: "@euri10"
|
||||
- link: https://medium.com/@mike.p.moritz/using-docker-compose-to-deploy-a-lightweight-python-rest-api-with-a-job-queue-37e6072a209b
|
||||
title: Using Docker Compose to deploy a lightweight Python REST API with a job queue
|
||||
author_link: https://medium.com/@mike.p.moritz
|
||||
author: Mike Moritz
|
||||
- link: https://robwagner.dev/tortoise-fastapi-setup/
|
||||
title: Setting up Tortoise ORM with FastAPI
|
||||
author_link: https://robwagner.dev/
|
||||
author: Rob Wagner
|
||||
- link: https://dev.to/dbanty/why-i-m-leaving-flask-3ki6
|
||||
title: Why I'm Leaving Flask
|
||||
author_link: https://dev.to/dbanty
|
||||
author: Dylan Anthony
|
||||
- link: https://medium.com/python-data/how-to-deploy-tensorflow-2-0-models-as-an-api-service-with-fastapi-docker-128b177e81f3
|
||||
title: How To Deploy Tensorflow 2.0 Models As An API Service With FastAPI & Docker
|
||||
author_link: https://medium.com/@bbrenyah
|
||||
author: Bernard Brenyah
|
||||
- link: https://testdriven.io/blog/fastapi-crud/
|
||||
title: "TestDriven.io: Developing and Testing an Asynchronous API with FastAPI and Pytest"
|
||||
author_link: https://testdriven.io/authors/herman
|
||||
author: Michael Herman
|
||||
- link: https://towardsdatascience.com/deploying-iris-classifications-with-fastapi-and-docker-7c9b83fdec3a
|
||||
title: "Towards Data Science: Deploying Iris Classifications with FastAPI and Docker"
|
||||
author_link: https://towardsdatascience.com/@mandygu
|
||||
author: Mandy Gu
|
||||
- link: https://medium.com/analytics-vidhya/deploy-machine-learning-models-with-keras-fastapi-redis-and-docker-4940df614ece
|
||||
title: Deploy Machine Learning Models with Keras, FastAPI, Redis and Docker
|
||||
author_link: https://medium.com/@shane.soh
|
||||
author: Shane Soh
|
||||
- link: https://medium.com/@arthur393/another-boilerplate-to-fastapi-azure-pipeline-ci-pytest-3c8d9a4be0bb
|
||||
title: "Another Boilerplate to FastAPI: Azure Pipeline CI + Pytest"
|
||||
author_link: https://twitter.com/arthurheinrique
|
||||
author: Arthur Henrique
|
||||
- link: https://iwpnd.pw/articles/2020-01/deploy-fastapi-to-aws-lambda
|
||||
title: How to continuously deploy a FastAPI to AWS Lambda with AWS SAM
|
||||
author_link: https://iwpnd.pw
|
||||
author: Benjamin Ramser
|
||||
- link: https://www.tutlinks.com/create-and-deploy-fastapi-app-to-heroku/
|
||||
title: Create and Deploy FastAPI app to Heroku without using Docker
|
||||
author_link: https://www.linkedin.com/in/navule/
|
||||
author: Navule Pavan Kumar Rao
|
||||
- link: https://iwpnd.pw/articles/2020-03/apache-kafka-fastapi-geostream
|
||||
title: Apache Kafka producer and consumer with FastAPI and aiokafka
|
||||
author_link: https://iwpnd.pw
|
||||
author: Benjamin Ramser
|
||||
- link: https://wuilly.com/2019/10/real-time-notifications-with-python-and-postgres/
|
||||
title: Real-time Notifications with Python and Postgres
|
||||
author_link: https://wuilly.com/
|
||||
author: Guillermo Cruz
|
||||
- link: https://dev.to/paurakhsharma/microservice-in-python-using-fastapi-24cc
|
||||
title: Microservice in Python using FastAPI
|
||||
author_link: https://twitter.com/PaurakhSharma
|
||||
author: Paurakh Sharma Humagain
|
||||
- link: https://dev.to/cuongld2/build-simple-api-service-with-python-fastapi-part-1-581o
|
||||
title: Build simple API service with Python FastAPI — Part 1
|
||||
author_link: https://dev.to/cuongld2
|
||||
author: cuongld2
|
||||
- link: https://paulsec.github.io/posts/fastapi_plus_zeit_serverless_fu/
|
||||
title: FastAPI + Zeit.co = 🚀
|
||||
author_link: https://twitter.com/PaulWebSec
|
||||
author: Paul Sec
|
||||
- link: https://dev.to/tiangolo/build-a-web-api-from-scratch-with-fastapi-the-workshop-2ehe
|
||||
title: Build a web API from scratch with FastAPI - the workshop
|
||||
author_link: https://twitter.com/tiangolo
|
||||
author: Sebastián Ramírez (tiangolo)
|
||||
- link: https://www.twilio.com/blog/build-secure-twilio-webhook-python-fastapi
|
||||
title: Build a Secure Twilio Webhook with Python and FastAPI
|
||||
author_link: https://www.twilio.com
|
||||
author: Twilio
|
||||
- link: https://www.stavros.io/posts/fastapi-with-django/
|
||||
title: Using FastAPI with Django
|
||||
author_link: https://twitter.com/Stavros
|
||||
author: Stavros Korokithakis
|
||||
- link: https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072
|
||||
title: Introducing Dispatch
|
||||
author_link: https://netflixtechblog.com/
|
||||
author: Netflix
|
||||
- link: https://davidefiocco.github.io/2020/06/27/streamlit-fastapi-ml-serving.html
|
||||
title: Machine learning model serving in Python using FastAPI and streamlit
|
||||
author_link: https://github.com/davidefiocco
|
||||
author: Davide Fiocco
|
||||
- link: https://www.tutlinks.com/deploy-fastapi-on-azure/
|
||||
title: Deploy FastAPI on Azure App Service
|
||||
author_link: https://www.linkedin.com/in/navule/
|
||||
author: Navule Pavan Kumar Rao
|
||||
- link: https://towardsdatascience.com/build-and-host-fast-data-science-applications-using-fastapi-823be8a1d6a0
|
||||
title: Build And Host Fast Data Science Applications Using FastAPI
|
||||
author_link: https://medium.com/@farhadmalik
|
||||
author: Farhad Malik
|
||||
- link: https://medium.com/@gabbyprecious2000/creating-a-crud-app-with-fastapi-part-one-7c049292ad37
|
||||
title: Creating a CRUD App with FastAPI (Part one)
|
||||
author_link: https://medium.com/@gabbyprecious2000
|
||||
author: Precious Ndubueze
|
||||
- link: https://julienharbulot.com/notification-server.html
|
||||
title: HTTP server to display desktop notifications
|
||||
author_link: https://julienharbulot.com/
|
||||
author: Julien Harbulot
|
||||
japanese:
|
||||
- link: https://qiita.com/mtitg/items/47770e9a562dd150631d
|
||||
title: FastAPI|DB接続してCRUDするPython製APIサーバーを構築
|
||||
author_link: https://qiita.com/mtitg
|
||||
author: "@mtitg"
|
||||
- link: https://qiita.com/ryoryomaru/items/59958ed385b3571d50de
|
||||
title: python製の最新APIフレームワーク FastAPI を触ってみた
|
||||
author_link: https://qiita.com/ryoryomaru
|
||||
author: "@ryoryomaru"
|
||||
- link: https://qiita.com/angel_katayoku/items/0e1f5dbbe62efc612a78
|
||||
title: FastAPIでCORSを回避
|
||||
author_link: https://qiita.com/angel_katayoku
|
||||
author: "@angel_katayoku"
|
||||
- link: https://qiita.com/angel_katayoku/items/4fbc1a4e2b33fa2237d2
|
||||
title: FastAPIをMySQLと接続してDockerで管理してみる
|
||||
author_link: https://qiita.com/angel_katayoku
|
||||
author: "@angel_katayoku"
|
||||
- link: https://qiita.com/angel_katayoku/items/8a458a8952f50b73f420
|
||||
title: FastAPIでPOSTされたJSONのレスポンスbodyを受け取る
|
||||
author_link: https://qiita.com/angel_katayoku
|
||||
author: "@angel_katayoku"
|
||||
- link: https://qiita.com/hikarut/items/b178af2e2440c67c6ac4
|
||||
title: フロントエンド開発者向けのDockerによるPython開発環境構築
|
||||
author_link: https://qiita.com/hikarut
|
||||
author: Hikaru Takahashi
|
||||
- link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-environment
|
||||
title: "【第1回】FastAPIチュートリアル: ToDoアプリを作ってみよう【環境構築編】"
|
||||
author_link: https://rightcode.co.jp/author/jun
|
||||
author: ライトコードメディア編集部
|
||||
- link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-model-building
|
||||
title: "【第2回】FastAPIチュートリアル: ToDoアプリを作ってみよう【モデル構築編】"
|
||||
author_link: https://rightcode.co.jp/author/jun
|
||||
author: ライトコードメディア編集部
|
||||
- link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-authentication-user-registration
|
||||
title: "【第3回】FastAPIチュートリアル: toDoアプリを作ってみよう【認証・ユーザ登録編】"
|
||||
author_link: https://rightcode.co.jp/author/jun
|
||||
author: ライトコードメディア編集部
|
||||
- link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-admin-page-improvement
|
||||
title: "【第4回】FastAPIチュートリアル: toDoアプリを作ってみよう【管理者ページ改良編】"
|
||||
author_link: https://rightcode.co.jp/author/jun
|
||||
author: ライトコードメディア編集部
|
||||
- link: https://qiita.com/bee2/items/0ad260ab9835a2087dae
|
||||
title: PythonのWeb frameworkのパフォーマンス比較 (Django, Flask, responder, FastAPI, japronto)
|
||||
author_link: https://qiita.com/bee2
|
||||
author: "@bee2"
|
||||
- link: https://qiita.com/bee2/items/75d9c0d7ba20e7a4a0e9
|
||||
title: "[FastAPI] Python製のASGI Web フレームワーク FastAPIに入門する"
|
||||
author_link: https://qiita.com/bee2
|
||||
author: "@bee2"
|
||||
vietnamese:
|
||||
- link: https://fullstackstation.com/fastapi-trien-khai-bang-docker/
|
||||
title: "FASTAPI: TRIỂN KHAI BẰNG DOCKER"
|
||||
author_link: https://fullstackstation.com/author/figonking/
|
||||
author: Nguyễn Nhân
|
||||
russian:
|
||||
- link: https://habr.com/ru/post/454440/
|
||||
title: "Мелкая питонячая радость #2: Starlette - Солидная примочка – FastAPI"
|
||||
author_link: https://habr.com/ru/users/57uff3r/
|
||||
author: Andrey Korchak
|
||||
- link: https://habr.com/ru/post/478620/
|
||||
title: Почему Вы должны попробовать FastAPI?
|
||||
author_link: https://github.com/prostomarkeloff
|
||||
author: prostomarkeloff
|
||||
german:
|
||||
- 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_link: https://twitter.com/_nicoax
|
||||
author: Nico Axtmann
|
||||
podcasts:
|
||||
english:
|
||||
- link: https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855
|
||||
title: FastAPI on PythonBytes
|
||||
author_link: https://pythonbytes.fm/
|
||||
author: Python Bytes FM
|
||||
- link: https://www.pythonpodcast.com/fastapi-web-application-framework-episode-259/
|
||||
title: "Build The Next Generation Of Python Web Applications With FastAPI - Episode 259 - interview to Sebastían Ramírez (tiangolo)"
|
||||
author_link: https://www.pythonpodcast.com/
|
||||
author: Podcast.`__init__`
|
||||
talks:
|
||||
english:
|
||||
- link: https://www.youtube.com/watch?v=3DLwPcrE5mA
|
||||
title: "PyCon UK 2019: FastAPI from the ground up"
|
||||
author_link: https://twitter.com/chriswithers13
|
||||
author: Chris Withers
|
||||
- link: https://www.youtube.com/watch?v=z9K5pwb0rt8
|
||||
title: "PyConBY 2020: Serve ML models easily with FastAPI"
|
||||
author_link: https://twitter.com/tiangolo
|
||||
author: "Sebastián Ramírez (tiangolo)"
|
||||
- link: https://www.youtube.com/watch?v=PnpTY1f4k2U
|
||||
title: "[VIRTUAL] Py.Amsterdam's flying Software Circus: Intro to FastAPI"
|
||||
author_link: https://twitter.com/tiangolo
|
||||
author: "Sebastián Ramírez (tiangolo)"
|
||||
368
docs/en/data/people.yml
Normal file
@@ -0,0 +1,368 @@
|
||||
maintainers:
|
||||
- login: tiangolo
|
||||
answers: 979
|
||||
prs: 189
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/1326112?u=05f95ca7fdead36edd9c86be46b4ef6c3c71f876&v=4
|
||||
url: https://github.com/tiangolo
|
||||
experts:
|
||||
- login: dmontagu
|
||||
count: 262
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
|
||||
url: https://github.com/dmontagu
|
||||
- login: euri10
|
||||
count: 166
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/1104190?u=ffd411da5d3b7ad3aa18261317f7ddc76f763c33&v=4
|
||||
url: https://github.com/euri10
|
||||
- login: phy25
|
||||
count: 129
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/331403?v=4
|
||||
url: https://github.com/phy25
|
||||
- login: Kludex
|
||||
count: 104
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: ycd
|
||||
count: 61
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/62724709?u=496a800351ea1009678e40b26288a2a6c0dfa8bd&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: sm-Fifteen
|
||||
count: 39
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4
|
||||
url: https://github.com/sm-Fifteen
|
||||
- login: ArcLightSlavik
|
||||
count: 35
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/31127044?u=b81d0c33b056152513fb14749a9fe00f39887a8e&v=4
|
||||
url: https://github.com/ArcLightSlavik
|
||||
- login: prostomarkeloff
|
||||
count: 33
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4
|
||||
url: https://github.com/prostomarkeloff
|
||||
- login: Mause
|
||||
count: 32
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/1405026?v=4
|
||||
url: https://github.com/Mause
|
||||
- login: wshayes
|
||||
count: 29
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
|
||||
url: https://github.com/wshayes
|
||||
- login: dbanty
|
||||
count: 25
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/43723790?u=0cf33e4f40efc2ea206a1189fd63a11344eb88ed&v=4
|
||||
url: https://github.com/dbanty
|
||||
- login: SirTelemak
|
||||
count: 23
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4
|
||||
url: https://github.com/SirTelemak
|
||||
- login: nsidnev
|
||||
count: 22
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4
|
||||
url: https://github.com/nsidnev
|
||||
- login: chris-allnutt
|
||||
count: 21
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/565544?v=4
|
||||
url: https://github.com/chris-allnutt
|
||||
- login: Dustyposa
|
||||
count: 21
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4
|
||||
url: https://github.com/Dustyposa
|
||||
- login: acnebs
|
||||
count: 19
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/9054108?u=bfd127b3e6200f4d00afd714f0fc95c2512df19b&v=4
|
||||
url: https://github.com/acnebs
|
||||
- login: retnikt
|
||||
count: 19
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/24581770?v=4
|
||||
url: https://github.com/retnikt
|
||||
- login: raphaelauv
|
||||
count: 18
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
url: https://github.com/raphaelauv
|
||||
- login: jorgerpo
|
||||
count: 17
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4
|
||||
url: https://github.com/jorgerpo
|
||||
- login: includeamin
|
||||
count: 17
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4
|
||||
url: https://github.com/includeamin
|
||||
- login: Slyfoxy
|
||||
count: 17
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/28262306?u=66ee21316275ef356081c2efc4ed7a4572e690dc&v=4
|
||||
url: https://github.com/Slyfoxy
|
||||
- login: haizaar
|
||||
count: 13
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4
|
||||
url: https://github.com/haizaar
|
||||
- login: zamiramir
|
||||
count: 11
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/40475662?u=e58ef61034e8d0d6a312cc956fb09b9c3332b449&v=4
|
||||
url: https://github.com/zamiramir
|
||||
- login: stefanondisponibile
|
||||
count: 10
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/20441825?u=ee1e59446b98f8ec2363caeda4c17164d0d9cc7d&v=4
|
||||
url: https://github.com/stefanondisponibile
|
||||
last_month_active:
|
||||
- login: ycd
|
||||
count: 19
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/62724709?u=496a800351ea1009678e40b26288a2a6c0dfa8bd&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: Mause
|
||||
count: 18
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/1405026?v=4
|
||||
url: https://github.com/Mause
|
||||
- login: Kludex
|
||||
count: 11
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: includeamin
|
||||
count: 11
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4
|
||||
url: https://github.com/includeamin
|
||||
- login: eseglem
|
||||
count: 7
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/5920492?u=208d419cf667b8ac594c82a8db01932c7e50d057&v=4
|
||||
url: https://github.com/eseglem
|
||||
- login: ArcLightSlavik
|
||||
count: 5
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/31127044?u=b81d0c33b056152513fb14749a9fe00f39887a8e&v=4
|
||||
url: https://github.com/ArcLightSlavik
|
||||
- login: SirTelemak
|
||||
count: 4
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4
|
||||
url: https://github.com/SirTelemak
|
||||
- login: clmno
|
||||
count: 3
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/17064666?v=4
|
||||
url: https://github.com/clmno
|
||||
top_contributors:
|
||||
- login: dmontagu
|
||||
count: 16
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
|
||||
url: https://github.com/dmontagu
|
||||
- login: waynerv
|
||||
count: 16
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
- login: euri10
|
||||
count: 13
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/1104190?u=ffd411da5d3b7ad3aa18261317f7ddc76f763c33&v=4
|
||||
url: https://github.com/euri10
|
||||
- login: tokusumi
|
||||
count: 10
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
|
||||
url: https://github.com/tokusumi
|
||||
- login: mariacamilagl
|
||||
count: 8
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
|
||||
url: https://github.com/mariacamilagl
|
||||
- login: Serrones
|
||||
count: 6
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4
|
||||
url: https://github.com/Serrones
|
||||
- login: wshayes
|
||||
count: 5
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
|
||||
url: https://github.com/wshayes
|
||||
- login: jekirl
|
||||
count: 4
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/2546697?v=4
|
||||
url: https://github.com/jekirl
|
||||
top_reviewers:
|
||||
- login: Kludex
|
||||
count: 53
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: tokusumi
|
||||
count: 40
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
|
||||
url: https://github.com/tokusumi
|
||||
- login: dmontagu
|
||||
count: 23
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
|
||||
url: https://github.com/dmontagu
|
||||
- login: ycd
|
||||
count: 17
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/62724709?u=496a800351ea1009678e40b26288a2a6c0dfa8bd&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: AdrianDeAnda
|
||||
count: 16
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/1024932?u=bb7f8a0d6c9de4e9d0320a9f271210206e202250&v=4
|
||||
url: https://github.com/AdrianDeAnda
|
||||
- login: SwftAlpc
|
||||
count: 16
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4
|
||||
url: https://github.com/SwftAlpc
|
||||
- login: cassiobotaro
|
||||
count: 14
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4
|
||||
url: https://github.com/cassiobotaro
|
||||
- login: Laineyzhang55
|
||||
count: 12
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/59285379?v=4
|
||||
url: https://github.com/Laineyzhang55
|
||||
- login: yanever
|
||||
count: 11
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/21978760?v=4
|
||||
url: https://github.com/yanever
|
||||
- login: waynerv
|
||||
count: 10
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
- login: mariacamilagl
|
||||
count: 10
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
|
||||
url: https://github.com/mariacamilagl
|
||||
- login: Attsun1031
|
||||
count: 10
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/1175560?v=4
|
||||
url: https://github.com/Attsun1031
|
||||
- login: RunningIkkyu
|
||||
count: 9
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4
|
||||
url: https://github.com/RunningIkkyu
|
||||
- login: komtaki
|
||||
count: 9
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/39375566?v=4
|
||||
url: https://github.com/komtaki
|
||||
- login: Serrones
|
||||
count: 7
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4
|
||||
url: https://github.com/Serrones
|
||||
- login: ryuckel
|
||||
count: 7
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/36391432?u=094eec0cfddd5013f76f31e55e56147d78b19553&v=4
|
||||
url: https://github.com/ryuckel
|
||||
- login: MashhadiNima
|
||||
count: 5
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/49960770?u=e39b11d47188744ee07b2a1c7ce1a1bdf3c80760&v=4
|
||||
url: https://github.com/MashhadiNima
|
||||
- login: euri10
|
||||
count: 4
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/1104190?u=ffd411da5d3b7ad3aa18261317f7ddc76f763c33&v=4
|
||||
url: https://github.com/euri10
|
||||
- login: rkbeatss
|
||||
count: 4
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/23391143?u=56ab6bff50be950fa8cae5cf736f2ae66e319ff3&v=4
|
||||
url: https://github.com/rkbeatss
|
||||
- login: raphaelauv
|
||||
count: 4
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
url: https://github.com/raphaelauv
|
||||
sponsors:
|
||||
- login: samuelcolvin
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4
|
||||
url: https://github.com/samuelcolvin
|
||||
- login: mkeen
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/38221?u=03e076e08a10a4de0d48a348f1aab0223c5cf24a&v=4
|
||||
url: https://github.com/mkeen
|
||||
- login: wshayes
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
|
||||
url: https://github.com/wshayes
|
||||
- login: ltieman
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/1084689?u=c9bf77f5e57f98b49694870219b9bd9d1cc862e7&v=4
|
||||
url: https://github.com/ltieman
|
||||
- login: mrmattwright
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/1277725?v=4
|
||||
url: https://github.com/mrmattwright
|
||||
- login: timdrijvers
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/1694939?v=4
|
||||
url: https://github.com/timdrijvers
|
||||
- login: abdelhai
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/1752577?u=8f8f2bce75f3ab68188cea2b5da37c784197acd8&v=4
|
||||
url: https://github.com/abdelhai
|
||||
- login: ddahan
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/1933516?u=4068dc3c5db5d3605116c4f5df6deb9fee324c33&v=4
|
||||
url: https://github.com/ddahan
|
||||
- login: cbonoz
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4
|
||||
url: https://github.com/cbonoz
|
||||
- login: mrgnw
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/2504532?u=7ec43837a6d0afa80f96f0788744ea6341b89f97&v=4
|
||||
url: https://github.com/mrgnw
|
||||
- login: paul121
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/3116995?u=6e2d8691cc345e63ee02e4eb4d7cef82b1fcbedc&v=4
|
||||
url: https://github.com/paul121
|
||||
- login: andre1sk
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/3148093?v=4
|
||||
url: https://github.com/andre1sk
|
||||
- login: igorcorrea
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/3438238?u=c57605077c31a8f7b2341fc4912507f91b4a5621&v=4
|
||||
url: https://github.com/igorcorrea
|
||||
- login: pawamoy
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4
|
||||
url: https://github.com/pawamoy
|
||||
- login: p141592
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/5256328?u=7f9fdf3329bf90017cff00c8a78781bd7a2b48aa&v=4
|
||||
url: https://github.com/p141592
|
||||
- login: fabboe
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/7251331?v=4
|
||||
url: https://github.com/fabboe
|
||||
- login: Shackelford-Arden
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/7362263?v=4
|
||||
url: https://github.com/Shackelford-Arden
|
||||
- login: macleodmac
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/8996312?u=e39c68c3e0b1d264dcba4850134a291680f46355&v=4
|
||||
url: https://github.com/macleodmac
|
||||
- login: cristeaadrian
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/9112724?u=76099d546d6ee44b3ad7269773ecb916590c6a36&v=4
|
||||
url: https://github.com/cristeaadrian
|
||||
- login: otivvormes
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/11317418?u=6de1edefb6afd0108c0ad2816bd6efc4464a9c44&v=4
|
||||
url: https://github.com/otivvormes
|
||||
- login: iambobmae
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/12390270?u=c9a35c2ee5092a9b4135ebb1f91b7f521c467031&v=4
|
||||
url: https://github.com/iambobmae
|
||||
- login: Cozmo25
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/12619962?u=679dcd6785121e14f6254e9dd0961baf3b1fef5d&v=4
|
||||
url: https://github.com/Cozmo25
|
||||
- login: la-mar
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/16618300?u=7755c0521d2bb0d704f35a51464b15c1e2e6c4da&v=4
|
||||
url: https://github.com/la-mar
|
||||
- login: robintully
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/17059673?u=862b9bb01513f5acd30df97433cb97a24dbfb772&v=4
|
||||
url: https://github.com/robintully
|
||||
- login: Duval23
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/17622958?v=4
|
||||
url: https://github.com/Duval23
|
||||
- login: wedwardbeck
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/19333237?u=1de4ae2bf8d59eb4c013f21d863cbe0f2010575f&v=4
|
||||
url: https://github.com/wedwardbeck
|
||||
- login: linusg
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/19366641?u=125e390abef8fff3b3b0d370c369cba5d7fd4c67&v=4
|
||||
url: https://github.com/linusg
|
||||
- login: SebastianLuebke
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/21161532?u=ba033c1bf6851b874cfa05a8a824b9f1ff434c37&v=4
|
||||
url: https://github.com/SebastianLuebke
|
||||
- login: raminsj13
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/24259406?u=d51f2a526312ebba150a06936ed187ca0727d329&v=4
|
||||
url: https://github.com/raminsj13
|
||||
- login: mertguvencli
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4
|
||||
url: https://github.com/mertguvencli
|
||||
- login: orihomie
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/29889683?u=6bc2135a52fcb3a49e69e7d50190796618185fda&v=4
|
||||
url: https://github.com/orihomie
|
||||
- login: dcooper01
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/32238294?u=2a83c78b7f2a5f97beeede0b604bbe44cd21b46b&v=4
|
||||
url: https://github.com/dcooper01
|
||||
- login: d3vzer0
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/34250156?u=c50c9df0e34f411f7e5f050a72e8d89696284eba&v=4
|
||||
url: https://github.com/d3vzer0
|
||||
- login: AjitZK
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/40203625?u=70c479337ab95d76ab59ae17ba0a988f1b43c0c6&v=4
|
||||
url: https://github.com/AjitZK
|
||||
- login: dbanty
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/43723790?u=0cf33e4f40efc2ea206a1189fd63a11344eb88ed&v=4
|
||||
url: https://github.com/dbanty
|
||||
- login: Brontomerus
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/61284158?u=c00d807195815014d0b6597b3801ee9c494802dd&v=4
|
||||
url: https://github.com/Brontomerus
|
||||
- login: primer-api
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/62152773?u=4549d79b0ad1d30ecfbef6c6933593e90e819c75&v=4
|
||||
url: https://github.com/primer-api
|
||||
- login: tkrestiankova
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/67013045?u=6f06d28dba7e46aa363af2840d7b028e4d7bcbd9&v=4
|
||||
url: https://github.com/tkrestiankova
|
||||
- login: daverin
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/70378377?u=6d1814195c0de7162820eaad95a25b423a3869c0&v=4
|
||||
url: https://github.com/daverin
|
||||
8
docs/en/data/sponsors.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
gold:
|
||||
- url: https://www.deta.sh/?ref=fastapi
|
||||
title: The launchpad for all your (team's) ideas
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/deta.svg
|
||||
silver:
|
||||
- url: https://testdriven.io/
|
||||
title: Learn to build high-quality web apps with best practices
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/testdriven.svg
|
||||
@@ -23,7 +23,7 @@ Each of those response `dict`s can have a key `model`, containing a Pydantic mod
|
||||
|
||||
For example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write:
|
||||
|
||||
```Python hl_lines="18 23"
|
||||
```Python hl_lines="18 23"
|
||||
{!../../../docs_src/additional_responses/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -44,7 +44,7 @@ For example, to declare another response with a status code `404` and a Pydantic
|
||||
|
||||
The generated responses in the OpenAPI for this *path operation* will be:
|
||||
|
||||
```JSON hl_lines="3 4 5 6 7 8 9 10 11 12"
|
||||
```JSON hl_lines="3-12"
|
||||
{
|
||||
"responses": {
|
||||
"404": {
|
||||
@@ -83,7 +83,7 @@ The generated responses in the OpenAPI for this *path operation* will be:
|
||||
|
||||
The schemas are referenced to another place inside the OpenAPI schema:
|
||||
|
||||
```JSON hl_lines="4 5 6 7 8 9 10 11 12 13 14 15 16"
|
||||
```JSON hl_lines="4-16"
|
||||
{
|
||||
"components": {
|
||||
"schemas": {
|
||||
@@ -168,7 +168,7 @@ You can use this same `responses` parameter to add different media types for the
|
||||
|
||||
For example, you can add an additional media type of `image/png`, declaring that your *path operation* can return a JSON object (with media type `application/json`) or a PNG image:
|
||||
|
||||
```Python hl_lines="19 20 21 22 23 24 28"
|
||||
```Python hl_lines="19-24 28"
|
||||
{!../../../docs_src/additional_responses/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -192,7 +192,7 @@ For example, you can declare a response with a status code `404` that uses a Pyd
|
||||
|
||||
And a response with a status code `200` that uses your `response_model`, but includes a custom `example`:
|
||||
|
||||
```Python hl_lines="20 21 22 23 24 25 26 27 28 29 30 31"
|
||||
```Python hl_lines="20-31"
|
||||
{!../../../docs_src/additional_responses/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -228,7 +228,7 @@ You can use that technique to re-use some predefined responses in your *path ope
|
||||
|
||||
For example:
|
||||
|
||||
```Python hl_lines="13 14 15 16 17 26"
|
||||
```Python hl_lines="13-17 26"
|
||||
{!../../../docs_src/additional_responses/tutorial004.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ Later, for your production application, you might want to use a database server
|
||||
* Create a `metadata` object.
|
||||
* Create a table `notes` using the `metadata` object.
|
||||
|
||||
```Python hl_lines="4 14 16 17 18 19 20 21 22"
|
||||
```Python hl_lines="4 14 16-22"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -38,7 +38,7 @@ Later, for your production application, you might want to use a database server
|
||||
* Create a `DATABASE_URL`.
|
||||
* Create a `database` object.
|
||||
|
||||
```Python hl_lines="3 9 12"
|
||||
```Python hl_lines="3 9 12"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -54,7 +54,7 @@ Here, this section would run directly, right before starting your **FastAPI** ap
|
||||
* Create an `engine`.
|
||||
* Create all the tables from the `metadata` object.
|
||||
|
||||
```Python hl_lines="25 26 27 28"
|
||||
```Python hl_lines="25-28"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -65,7 +65,7 @@ Create Pydantic models for:
|
||||
* Notes to be created (`NoteIn`).
|
||||
* Notes to be returned (`Note`).
|
||||
|
||||
```Python hl_lines="31 32 33 36 37 38 39"
|
||||
```Python hl_lines="31-33 36-39"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -78,7 +78,7 @@ So, you will be able to see it all in the interactive API docs.
|
||||
* Create your `FastAPI` application.
|
||||
* Create event handlers to connect and disconnect from the database.
|
||||
|
||||
```Python hl_lines="42 45 46 47 50 51 52"
|
||||
```Python hl_lines="42 45-47 50-52"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -86,7 +86,7 @@ So, you will be able to see it all in the interactive API docs.
|
||||
|
||||
Create the *path operation function* to read notes:
|
||||
|
||||
```Python hl_lines="55 56 57 58"
|
||||
```Python hl_lines="55-58"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -103,7 +103,7 @@ That documents (and validates, serializes, filters) the output data, as a `list`
|
||||
|
||||
Create the *path operation function* to create notes:
|
||||
|
||||
```Python hl_lines="61 62 63 64 65"
|
||||
```Python hl_lines="61-65"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
100
docs/en/docs/advanced/async-tests.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Async Tests
|
||||
|
||||
You have already seen how to test your **FastAPI** applications using the provided `TestClient`, but with it, you can't test or run any other `async` function in your (synchronous) pytest functions.
|
||||
|
||||
Being able to use asynchronous functions in your tests could be useful, for example, when you're querying your database asynchronously. Imagine you want to test sending requests to your FastAPI application and then verify that your backend successfully wrote the correct data in the database, while using an async database library.
|
||||
|
||||
Let's look at how we can make that work.
|
||||
|
||||
## pytest-asyncio
|
||||
|
||||
If we want to call asynchronous functions in our tests, our test functions have to be asynchronous. Pytest provides a neat library for this, called `pytest-asyncio`, that allows us to specify that some test functions are to be called asynchronously.
|
||||
|
||||
You can install it via:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install pytest-asyncio
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## HTTPX
|
||||
|
||||
Even if your **FastAPI** application uses normal `def` functions instead of `async def`, it is still an `async` application underneath.
|
||||
|
||||
The `TestClient` does some magic inside to call the asynchronous FastAPI application in your normal `def` test functions, using standard pytest. But that magic doesn't work anymore when we're using it inside asynchronous functions. By running our tests asynchronously, we can no longer use the `TestClient` inside our test functions.
|
||||
|
||||
Luckily there's a nice alternative, called <a href="https://www.python-httpx.org/" class="external-link" target="_blank">HTTPX</a>.
|
||||
|
||||
HTTPX is an HTTP client for Python 3 that allows us to query our FastAPI application similarly to how we did it with the `TestClient`.
|
||||
|
||||
If you're familiar with the <a href="https://requests.readthedocs.io/en/master/" class="external-link" target="_blank">Requests</a> library, you'll find that the API of HTTPX is almost identical.
|
||||
|
||||
The important difference for us is that with HTTPX we are not limited to synchronous, but can also make asynchronous requests.
|
||||
|
||||
## Example
|
||||
|
||||
For a simple example, let's consider the following `main.py` module:
|
||||
|
||||
```Python
|
||||
{!../../../docs_src/async_tests/main.py!}
|
||||
```
|
||||
|
||||
The `test_main.py` module that contains the tests for `main.py` could look like this now:
|
||||
|
||||
```Python
|
||||
{!../../../docs_src/async_tests/test_main.py!}
|
||||
```
|
||||
|
||||
## Run it
|
||||
|
||||
You can run your tests as usual via:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pytest
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## In Detail
|
||||
|
||||
The marker `@pytest.mark.asyncio` tells pytest that this test function should be called asynchronously:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!../../../docs_src/async_tests/test_main.py!}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Note that the test function is now `async def` instead of just `def` as before when using the `TestClient`.
|
||||
|
||||
Then we can create an `AsyncClient` with the app, and send async requests to it, using `await`.
|
||||
|
||||
```Python hl_lines="9-10"
|
||||
{!../../../docs_src/async_tests/test_main.py!}
|
||||
```
|
||||
|
||||
This is the equivalent to:
|
||||
|
||||
```Python
|
||||
response = client.get('/')
|
||||
```
|
||||
|
||||
that we used to make our requests with the `TestClient`.
|
||||
|
||||
!!! tip
|
||||
Note that we're using async/await with the new `AsyncClient` - the request is asynchronous.
|
||||
|
||||
## Other Asynchronous Function Calls
|
||||
|
||||
As the testing function is now asynchronous, you can now also call (and `await`) other `async` functions apart from sending requests to your FastAPI application in your tests, exactly as you would call them anywhere else in your code.
|
||||
|
||||
!!! tip
|
||||
If you encounter a `RuntimeError: Task attached to a different loop` when integrating asynchronous function calls in your tests (e.g. when using <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">MongoDB's MotorClient</a>) check out <a href="https://github.com/pytest-dev/pytest-asyncio/issues/38#issuecomment-264418154" class="external-link" target="_blank">this issue</a> in the pytest-asyncio repository.
|
||||
@@ -42,16 +42,19 @@ proxy --> server
|
||||
!!! tip
|
||||
The IP `0.0.0.0` is commonly used to mean that the program listens on all the IPs available in that machine/server.
|
||||
|
||||
The docs UI would also need that the JSON payload with the OpenAPI schema has the path defined as `/api/v1/app` (behind the proxy) instead of `/app`. For example, something like:
|
||||
The docs UI would also need the OpenAPI schema to declare that this API `server` is located at `/api/v1` (behind the proxy). For example:
|
||||
|
||||
```JSON hl_lines="5"
|
||||
```JSON hl_lines="4-8"
|
||||
{
|
||||
"openapi": "3.0.2",
|
||||
// More stuff here
|
||||
"paths": {
|
||||
"/api/v1/app": {
|
||||
// More stuff here
|
||||
"servers": [
|
||||
{
|
||||
"url": "/api/v1"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
// More stuff here
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -235,7 +238,7 @@ Now, if you go to the URL with the port for Uvicorn: <a href="http://127.0.0.1:8
|
||||
!!! tip
|
||||
Notice that even though you are accessing it at `http://127.0.0.1:8000/app` it shows the `root_path` of `/api/v1`, taken from the option `--root-path`.
|
||||
|
||||
And now open the URL with the port for Traefik, including the path prefix: <a href="http://127.0.0.1:9999/api/v1/app" class="external-link" target="_blank">http://127.0.0.1:9999/api/vi/app</a>.
|
||||
And now open the URL with the port for Traefik, including the path prefix: <a href="http://127.0.0.1:9999/api/v1/app" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/app</a>.
|
||||
|
||||
We get the same response:
|
||||
|
||||
@@ -264,16 +267,78 @@ You can check it at <a href="http://127.0.0.1:8000/docs" class="external-link" t
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image01.png">
|
||||
|
||||
But if we access the docs UI at the "official" URL using the proxy, at `/api/v1/docs`, it works correctly! 🎉
|
||||
|
||||
Right as we wanted it. ✔️
|
||||
|
||||
This is because FastAPI uses this `root_path` internally to tell the docs UI to use the URL for OpenAPI with the path prefix provided by `root_path`.
|
||||
But if we access the docs UI at the "official" URL using the proxy with port `9999`, at `/api/v1/docs`, it works correctly! 🎉
|
||||
|
||||
You can check it at <a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a>:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image02.png">
|
||||
|
||||
Right as we wanted it. ✔️
|
||||
|
||||
This is because FastAPI uses this `root_path` to create the default `server` in OpenAPI with the URL provided by `root_path`.
|
||||
|
||||
## Additional servers
|
||||
|
||||
!!! warning
|
||||
This is a more advanced use case. Feel free to skip it.
|
||||
|
||||
By default, **FastAPI** will create a `server` in the OpenAPI schema with the URL for the `root_path`.
|
||||
|
||||
But you can also provide other alternative `servers`, for example if you want *the same* docs UI to interact with a staging and production environments.
|
||||
|
||||
If you pass a custom list of `servers` and there's a `root_path` (because your API lives behind a proxy), **FastAPI** will insert a "server" with this `root_path` at the beginning of the list.
|
||||
|
||||
For example:
|
||||
|
||||
```Python hl_lines="4-7"
|
||||
{!../../../docs_src/behind_a_proxy/tutorial003.py!}
|
||||
```
|
||||
|
||||
Will generate an OpenAPI schema like:
|
||||
|
||||
```JSON hl_lines="5-7"
|
||||
{
|
||||
"openapi": "3.0.2",
|
||||
// More stuff here
|
||||
"servers": [
|
||||
{
|
||||
"url": "/api/v1"
|
||||
},
|
||||
{
|
||||
"url": "https://stag.example.com",
|
||||
"description": "Staging environment"
|
||||
},
|
||||
{
|
||||
"url": "https://prod.example.com",
|
||||
"description": "Production environment"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
// More stuff here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Notice the auto-generated server with a `url` value of `/api/v1`, taken from the `root_path`.
|
||||
|
||||
In the docs UI at <a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a> it would look like:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image03.png">
|
||||
|
||||
!!! tip
|
||||
The docs UI will interact with the server that you select.
|
||||
|
||||
### Disable automatic server from `root_path`
|
||||
|
||||
If you don't want **FastAPI** to include an automatic server using the `root_path`, you can use the parameter `root_path_in_servers=False`:
|
||||
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/behind_a_proxy/tutorial004.py!}
|
||||
```
|
||||
|
||||
and then it won't include it in the OpenAPI schema.
|
||||
|
||||
## Mounting a sub-application
|
||||
|
||||
If you need to mount a sub-application (as described in [Sub Applications - Mounts](./sub-applications.md){.internal-link target=_blank}) while also using a proxy with `root_path`, you can do it normally, as you would expect.
|
||||
|
||||
@@ -36,7 +36,7 @@ If there's no `gzip` in the header, it will not try to decompress the body.
|
||||
|
||||
That way, the same route class can handle gzip compressed or uncompressed requests.
|
||||
|
||||
```Python hl_lines="8 9 10 11 12 13 14 15"
|
||||
```Python hl_lines="8-15"
|
||||
{!../../../docs_src/custom_request_and_route/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -50,7 +50,7 @@ This method returns a function. And that function is what will receive a request
|
||||
|
||||
Here we use it to create a `GzipRequest` from the original request.
|
||||
|
||||
```Python hl_lines="18 19 20 21 22 23 24 25 26"
|
||||
```Python hl_lines="18-26"
|
||||
{!../../../docs_src/custom_request_and_route/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -84,13 +84,13 @@ We can also use this same approach to access the request body in an exception ha
|
||||
|
||||
All we need to do is handle the request inside a `try`/`except` block:
|
||||
|
||||
```Python hl_lines="13 15"
|
||||
```Python hl_lines="13 15"
|
||||
{!../../../docs_src/custom_request_and_route/tutorial002.py!}
|
||||
```
|
||||
|
||||
If an exception occurs, the`Request` instance will still be in scope, so we can read and make use of the request body when handling the error:
|
||||
|
||||
```Python hl_lines="16 17 18"
|
||||
```Python hl_lines="16-18"
|
||||
{!../../../docs_src/custom_request_and_route/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -104,6 +104,6 @@ You can also set the `route_class` parameter of an `APIRouter`:
|
||||
|
||||
In this example, the *path operations* under the `router` will use the custom `TimedRoute` class, and will have an extra `X-Response-Time` header in the response with the time it took to generate the response:
|
||||
|
||||
```Python hl_lines="13 14 15 16 17 18 19 20"
|
||||
```Python hl_lines="13-20"
|
||||
{!../../../docs_src/custom_request_and_route/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -21,7 +21,7 @@ For example, if you are squeezing performance, you can install and use <a href="
|
||||
|
||||
Import the `Response` class (sub-class) you want to use and declare it in the *path operation decorator*.
|
||||
|
||||
```Python hl_lines="2 7"
|
||||
```Python hl_lines="2 7"
|
||||
{!../../../docs_src/custom_response/tutorial001b.py!}
|
||||
```
|
||||
|
||||
@@ -40,9 +40,9 @@ Import the `Response` class (sub-class) you want to use and declare it in the *p
|
||||
To return a response with HTML directly from **FastAPI**, use `HTMLResponse`.
|
||||
|
||||
* Import `HTMLResponse`.
|
||||
* Pass `HTMLResponse` as the parameter `content_type` of your *path operation*.
|
||||
* Pass `HTMLResponse` as the parameter `response_class` of your *path operation decorator*.
|
||||
|
||||
```Python hl_lines="2 7"
|
||||
```Python hl_lines="2 7"
|
||||
{!../../../docs_src/custom_response/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -59,7 +59,7 @@ As seen in [Return a Response directly](response-directly.md){.internal-link tar
|
||||
|
||||
The same example from above, returning an `HTMLResponse`, could look like:
|
||||
|
||||
```Python hl_lines="2 7 19"
|
||||
```Python hl_lines="2 7 19"
|
||||
{!../../../docs_src/custom_response/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -79,7 +79,7 @@ The `response_class` will then be used only to document the OpenAPI *path operat
|
||||
|
||||
For example, it could be something like:
|
||||
|
||||
```Python hl_lines="7 23 21"
|
||||
```Python hl_lines="7 21 23"
|
||||
{!../../../docs_src/custom_response/tutorial004.py!}
|
||||
```
|
||||
|
||||
@@ -150,7 +150,7 @@ An alternative JSON response using <a href="https://github.com/ultrajson/ultrajs
|
||||
!!! warning
|
||||
`ujson` is less careful than Python's built-in implementation in how it handles some edge-cases.
|
||||
|
||||
```Python hl_lines="2 7"
|
||||
```Python hl_lines="2 7"
|
||||
{!../../../docs_src/custom_response/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -179,7 +179,7 @@ If you have a file-like object (e.g. the object returned by `open()`), you can r
|
||||
|
||||
This includes many libraries to interact with cloud storage, video processing, and others.
|
||||
|
||||
```Python hl_lines="2 10 11"
|
||||
```Python hl_lines="2 10-11"
|
||||
{!../../../docs_src/custom_response/tutorial008.py!}
|
||||
```
|
||||
|
||||
@@ -211,7 +211,7 @@ The parameter that defines this is `default_response_class`.
|
||||
|
||||
In the example below, **FastAPI** will use `ORJSONResponse` by default, in all *path operations*, instead of `JSONResponse`.
|
||||
|
||||
```Python hl_lines="2 4"
|
||||
```Python hl_lines="2 4"
|
||||
{!../../../docs_src/custom_response/tutorial010.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ And that function `get_openapi()` receives as parameters:
|
||||
* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.0.2`.
|
||||
* `description`: The description of your API.
|
||||
* `routes`: A list of routes, these are each of the registered *path operations*. They are taken from `app.routes`.
|
||||
* `openapi_prefix`: The URL prefix to be used in your OpenAPI.
|
||||
|
||||
## Overriding the defaults
|
||||
|
||||
@@ -44,7 +43,7 @@ For example, let's add <a href="https://github.com/Rebilly/ReDoc/blob/master/doc
|
||||
|
||||
First, write all your **FastAPI** application as normally:
|
||||
|
||||
```Python hl_lines="1 4 7 8 9"
|
||||
```Python hl_lines="1 4 7-9"
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -52,22 +51,15 @@ First, write all your **FastAPI** application as normally:
|
||||
|
||||
Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function:
|
||||
|
||||
```Python hl_lines="2 15 16 17 18 19 20 21"
|
||||
```Python hl_lines="2 15-20"
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
The `openapi_prefix` will contain any prefix needed for the generated OpenAPI *path operations*.
|
||||
|
||||
FastAPI will automatically use the `root_path` to pass it in the `openapi_prefix`.
|
||||
|
||||
But the important thing is that your function should receive that parameter `openapi_prefix` and pass it along.
|
||||
|
||||
### Modify the OpenAPI schema
|
||||
|
||||
Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema:
|
||||
|
||||
```Python hl_lines="22 23 24"
|
||||
```Python hl_lines="21-23"
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -79,7 +71,7 @@ That way, your application won't have to generate the schema every time a user o
|
||||
|
||||
It will be generated only once, and then the same cached schema will be used for the next requests.
|
||||
|
||||
```Python hl_lines="13 14 25 26"
|
||||
```Python hl_lines="13-14 24-25"
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -87,7 +79,7 @@ It will be generated only once, and then the same cached schema will be used for
|
||||
|
||||
Now you can replace the `.openapi()` method with your new function.
|
||||
|
||||
```Python hl_lines="29"
|
||||
```Python hl_lines="28"
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -180,7 +172,7 @@ $ pip install aiofiles
|
||||
* Import `StaticFiles`.
|
||||
* "Mount" a `StaticFiles()` instance in a specific path.
|
||||
|
||||
```Python hl_lines="7 11"
|
||||
```Python hl_lines="7 11"
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -232,7 +224,7 @@ You can re-use FastAPI's internal functions to create the HTML pages for the doc
|
||||
|
||||
And similarly for ReDoc...
|
||||
|
||||
```Python hl_lines="2 3 4 5 6 14 15 16 17 18 19 20 21 22 25 26 27 30 31 32 33 34 35 36"
|
||||
```Python hl_lines="2-6 14-22 25-27 30-36"
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -247,7 +239,7 @@ And similarly for ReDoc...
|
||||
|
||||
Now, to be able to test that everything works, create a *path operation*:
|
||||
|
||||
```Python hl_lines="39 40 41"
|
||||
```Python hl_lines="39-41"
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ GraphQL is implemented with Graphene, you can check <a href="https://docs.graphe
|
||||
|
||||
Import `graphene` and define your GraphQL data:
|
||||
|
||||
```Python hl_lines="1 6 7 8 9 10"
|
||||
```Python hl_lines="1 6-10"
|
||||
{!../../../docs_src/graphql/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -18,7 +18,7 @@ Import `graphene` and define your GraphQL data:
|
||||
|
||||
Then import and add Starlette's `GraphQLApp`:
|
||||
|
||||
```Python hl_lines="3 14"
|
||||
```Python hl_lines="3 14"
|
||||
{!../../../docs_src/graphql/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -16,3 +16,9 @@ In the next sections you will see other options, configurations, and additional
|
||||
You could still use most of the features in **FastAPI** with the knowledge from the main [Tutorial - User Guide](../tutorial/){.internal-link target=_blank}.
|
||||
|
||||
And the next sections assume you already read it, and assume that you know those main ideas.
|
||||
|
||||
## TestDriven.io course
|
||||
|
||||
If you would like to take an advanced-beginner course to complement this section of the docs, you might want to check: <a href="https://testdriven.io/courses/tdd-fastapi/" class="external-link" target="_blank">Test-Driven Development with FastAPI and Docker</a> by **TestDriven.io**.
|
||||
|
||||
They are currently donating 10% of all profits to the development of **FastAPI**. 🎉 😄
|
||||
|
||||
@@ -62,7 +62,7 @@ Any incoming requests to `http` or `ws` will be redirected to the secure scheme
|
||||
|
||||
Enforces that all incoming requests have a correctly set `Host` header, in order to guard against HTTP Host Header attacks.
|
||||
|
||||
```Python hl_lines="2 6 7 8"
|
||||
```Python hl_lines="2 6-8"
|
||||
{!../../../docs_src/advanced_middleware/tutorial002.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ You can adapt it to any other NoSQL database like:
|
||||
|
||||
For now, don't pay attention to the rest, only the imports:
|
||||
|
||||
```Python hl_lines="6 7 8"
|
||||
```Python hl_lines="3-5"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -29,7 +29,7 @@ We will use it later as a fixed field `type` in our documents.
|
||||
|
||||
This is not required by Couchbase, but is a good practice that will help you afterwards.
|
||||
|
||||
```Python hl_lines="10"
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -54,7 +54,7 @@ This utility function will:
|
||||
* Set defaults for timeouts.
|
||||
* Return it.
|
||||
|
||||
```Python hl_lines="13 14 15 16 17 18 19 20 21 22"
|
||||
```Python hl_lines="12-21"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -66,7 +66,7 @@ As **Couchbase** "documents" are actually just "JSON objects", we can model them
|
||||
|
||||
First, let's create a `User` model:
|
||||
|
||||
```Python hl_lines="25 26 27 28 29"
|
||||
```Python hl_lines="24-28"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -80,7 +80,7 @@ This will have the data that is actually stored in the database.
|
||||
|
||||
We don't create it as a subclass of Pydantic's `BaseModel` but as a subclass of our own `User`, because it will have all the attributes in `User` plus a couple more:
|
||||
|
||||
```Python hl_lines="32 33 34"
|
||||
```Python hl_lines="31-33"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -100,7 +100,7 @@ Now create a function that will:
|
||||
|
||||
By creating a function that is only dedicated to getting your user from a `username` (or any other parameter) independent of your *path operation function*, you can more easily re-use it in multiple parts and also add <abbr title="Automated test, written in code, that checks if another piece of code is working correctly.">unit tests</abbr> for it:
|
||||
|
||||
```Python hl_lines="37 38 39 40 41 42 43"
|
||||
```Python hl_lines="36-42"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -135,7 +135,7 @@ UserInDB(username="johndoe", hashed_password="some_hash")
|
||||
|
||||
### Create the `FastAPI` app
|
||||
|
||||
```Python hl_lines="47"
|
||||
```Python hl_lines="46"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -143,9 +143,9 @@ UserInDB(username="johndoe", hashed_password="some_hash")
|
||||
|
||||
As our code is calling Couchbase and we are not using the <a href="https://docs.couchbase.com/python-sdk/2.5/async-programming.html#asyncio-python-3-5" class="external-link" target="_blank">experimental Python <code>await</code> support</a>, we should declare our function with normal `def` instead of `async def`.
|
||||
|
||||
Also, Couchbase recommends not using a single `Bucket` object in multiple "<abbr title="A sequence of code being executed by the program, while at the same time, or at intervals, there can be others being executed too.">thread</abbr>s", so, we can get just get the bucket directly and pass it to our utility functions:
|
||||
Also, Couchbase recommends not using a single `Bucket` object in multiple "<abbr title="A sequence of code being executed by the program, while at the same time, or at intervals, there can be others being executed too.">thread</abbr>s", so, we can just get the bucket directly and pass it to our utility functions:
|
||||
|
||||
```Python hl_lines="50 51 52 53 54"
|
||||
```Python hl_lines="49-53"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ It will have a *path operation* that will receive an `Invoice` body, and a query
|
||||
|
||||
This part is pretty normal, most of the code is probably already familiar to you:
|
||||
|
||||
```Python hl_lines="10 11 12 13 14 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54"
|
||||
```Python hl_lines="10-14 37-54"
|
||||
{!../../../docs_src/openapi_callbacks/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -92,7 +92,7 @@ Because of that, you need to declare what will be the `default_response_class`,
|
||||
|
||||
But as we are never calling `app.include_router(some_router)`, we need to set the `default_response_class` during creation of the `APIRouter`.
|
||||
|
||||
```Python hl_lines="5 26"
|
||||
```Python hl_lines="5 26"
|
||||
{!../../../docs_src/openapi_callbacks/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -105,7 +105,7 @@ It should look just like a normal FastAPI *path operation*:
|
||||
* It should probably have a declaration of the body it should receive, e.g. `body: InvoiceEvent`.
|
||||
* And it could also have a declaration of the response it should return, e.g. `response_model=InvoiceEventReceived`.
|
||||
|
||||
```Python hl_lines="17 18 19 22 23 29 30 31 32 33"
|
||||
```Python hl_lines="17-19 22-23 29-33"
|
||||
{!../../../docs_src/openapi_callbacks/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ If you want to use your APIs' function names as `operationId`s, you can iterate
|
||||
|
||||
You should do it after adding all your *path operations*.
|
||||
|
||||
```Python hl_lines="2 12 13 14 15 16 17 18 19 20 21 24"
|
||||
```Python hl_lines="2 12-21 24"
|
||||
{!../../../docs_src/path_operation_advanced_configuration/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -47,6 +47,6 @@ Adding an `\f` (an escaped "form feed" character) causes **FastAPI** to truncate
|
||||
|
||||
It won't show up in the documentation, but other tools (such as Sphinx) will be able to use the rest.
|
||||
|
||||
```Python hl_lines="19 20 21 22 23 24 25 26 27 28 29"
|
||||
```Python hl_lines="19-29"
|
||||
{!../../../docs_src/path_operation_advanced_configuration/tutorial004.py!}
|
||||
```
|
||||
|
||||
@@ -6,7 +6,7 @@ You can declare a parameter of type `Response` in your *path operation function*
|
||||
|
||||
And then you can set cookies in that *temporal* response object.
|
||||
|
||||
```Python hl_lines="1 8 9"
|
||||
```Python hl_lines="1 8-9"
|
||||
{!../../../docs_src/response_cookies/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -26,7 +26,7 @@ To do that, you can create a response as described in [Return a Response Directl
|
||||
|
||||
Then set Cookies in it, and then return it:
|
||||
|
||||
```Python hl_lines="10 11 12"
|
||||
```Python hl_lines="10-12"
|
||||
{!../../../docs_src/response_cookies/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ For example, you cannot put a Pydantic model in a `JSONResponse` without first c
|
||||
|
||||
For those cases, you can use the `jsonable_encoder` to convert your data before passing it to a response:
|
||||
|
||||
```Python hl_lines="6 7 21 22"
|
||||
```Python hl_lines="6-7 21-22"
|
||||
{!../../../docs_src/response_directly/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ You can declare a parameter of type `Response` in your *path operation function*
|
||||
|
||||
And then you can set headers in that *temporal* response object.
|
||||
|
||||
```Python hl_lines="1 7 8"
|
||||
```Python hl_lines="1 7-8"
|
||||
{!../../../docs_src/response_headers/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -24,7 +24,7 @@ You can also add headers when you return a `Response` directly.
|
||||
|
||||
Create a response as described in [Return a Response Directly](response-directly.md){.internal-link target=_blank} and pass the headers as an additional parameter:
|
||||
|
||||
```Python hl_lines="10 11 12"
|
||||
```Python hl_lines="10-12"
|
||||
{!../../../docs_src/response_headers/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Then, when you type that username and password, the browser sends them in the he
|
||||
* It returns an object of type `HTTPBasicCredentials`:
|
||||
* It contains the `username` and `password` sent.
|
||||
|
||||
```Python hl_lines="2 6 10"
|
||||
```Python hl_lines="2 6 10"
|
||||
{!../../../docs_src/security/tutorial006.py!}
|
||||
```
|
||||
|
||||
@@ -36,7 +36,7 @@ Use a dependency to check if the username and password are correct.
|
||||
|
||||
For this, use the Python standard module <a href="https://docs.python.org/3/library/secrets.html" class="external-link" target="_blank">`secrets`</a> to check the username and password:
|
||||
|
||||
```Python hl_lines="1 11 12 13"
|
||||
```Python hl_lines="1 11-13"
|
||||
{!../../../docs_src/security/tutorial007.py!}
|
||||
```
|
||||
|
||||
@@ -54,9 +54,9 @@ But by using the `secrets.compare_digest()` it will be secure against a type of
|
||||
|
||||
But what's a "timing attack"?
|
||||
|
||||
Let's imagine an attacker is trying to guess the username and password.
|
||||
Let's imagine some attackers are trying to guess the username and password.
|
||||
|
||||
And that attacker sends a request with a username `johndoe` and a password `love123`.
|
||||
And they send a request with a username `johndoe` and a password `love123`.
|
||||
|
||||
Then the Python code in your application would be equivalent to something like:
|
||||
|
||||
@@ -67,7 +67,7 @@ if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
|
||||
|
||||
But right at the moment Python compares the first `j` in `johndoe` to the first `s` in `stanleyjobson`, it will return `False`, because it already knows that those two strings are not the same, thinking that "there's no need to waste more computation comparing the rest of the letters". And your application will say "incorrect user or password".
|
||||
|
||||
But then the attacker tries with username `stanleyjobsox` and password `love123`.
|
||||
But then the attackers try with username `stanleyjobsox` and password `love123`.
|
||||
|
||||
And your application code does something like:
|
||||
|
||||
@@ -78,17 +78,17 @@ if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
|
||||
|
||||
Python will have to compare the whole `stanleyjobso` in both `stanleyjobsox` and `stanleyjobson` before realizing that both strings are not the same. So it will take some extra microseconds to reply back "incorrect user or password".
|
||||
|
||||
#### The time to answer helps the attacker
|
||||
#### The time to answer helps the attackers
|
||||
|
||||
At that point, by noticing that the server took some microseconds longer to send the "incorrect user or password" response, the attacker will know that she/he got _something_ right, some of the initial letters were right.
|
||||
At that point, by noticing that the server took some microseconds longer to send the "incorrect user or password" response, the attackers will know that they got _something_ right, some of the initial letters were right.
|
||||
|
||||
And then she/he can try again knowing that it's probably something more similar to `stanleyjobsox` than to `johndoe`.
|
||||
And then they can try again knowing that it's probably something more similar to `stanleyjobsox` than to `johndoe`.
|
||||
|
||||
#### A "professional" attack
|
||||
|
||||
Of course, the attacker would not try all this by hand, she/he would write a program to do it, possibly with thousands or millions of tests per second. And would get just one extra correct letter at a time.
|
||||
Of course, the attackers would not try all this by hand, they would write a program to do it, possibly with thousands or millions of tests per second. And would get just one extra correct letter at a time.
|
||||
|
||||
But doing that, in some minutes or hours the attacker would have guessed the correct username and password, with the "help" of our application, just using the time taken to answer.
|
||||
But doing that, in some minutes or hours the attackers would have guessed the correct username and password, with the "help" of our application, just using the time taken to answer.
|
||||
|
||||
#### Fix it with `secrets.compare_digest()`
|
||||
|
||||
@@ -102,6 +102,6 @@ That way, using `secrets.compare_digest()` in your application code, it will be
|
||||
|
||||
After detecting that the credentials are incorrect, return an `HTTPException` with a status code 401 (the same returned when no credentials are provided) and add the header `WWW-Authenticate` to make the browser show the login prompt again:
|
||||
|
||||
```Python hl_lines="15 16 17 18 19"
|
||||
```Python hl_lines="15-19"
|
||||
{!../../../docs_src/security/tutorial007.py!}
|
||||
```
|
||||
|
||||
@@ -56,7 +56,7 @@ They are normally used to declare specific security permissions, for example:
|
||||
|
||||
First, let's quickly see the parts that change from the examples in the main **Tutorial - User Guide** for [OAuth2 with Password (and hashing), Bearer with JWT tokens](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. Now using OAuth2 scopes:
|
||||
|
||||
```Python hl_lines="2 5 9 13 47 65 106 108 109 110 111 112 113 114 115 116 122 123 124 125 129 130 131 132 133 134 135 140 154"
|
||||
```Python hl_lines="2 4 8 12 46 64 105 107-115 121-124 128-134 139 153"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -68,7 +68,7 @@ The first change is that now we are declaring the OAuth2 security scheme with tw
|
||||
|
||||
The `scopes` parameter receives a `dict` with each scope as a key and the description as the value:
|
||||
|
||||
```Python hl_lines="63 64 65 66"
|
||||
```Python hl_lines="62-65"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -93,7 +93,7 @@ And we return the scopes as part of the JWT token.
|
||||
|
||||
But in your application, for security, you should make sure you only add the scopes that the user is actually able to have, or the ones you have predefined.
|
||||
|
||||
```Python hl_lines="155"
|
||||
```Python hl_lines="153"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -118,7 +118,7 @@ In this case, it requires the scope `me` (it could require more than one scope).
|
||||
|
||||
We are doing it here to demonstrate how **FastAPI** handles scopes declared at different levels.
|
||||
|
||||
```Python hl_lines="5 140 167"
|
||||
```Python hl_lines="4 139 166"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -143,7 +143,7 @@ We also declare a special parameter of type `SecurityScopes`, imported from `fas
|
||||
|
||||
This `SecurityScopes` class is similar to `Request` (`Request` was used to get the request object directly).
|
||||
|
||||
```Python hl_lines="9 106"
|
||||
```Python hl_lines="8 105"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -159,7 +159,7 @@ We create an `HTTPException` that we can re-use (`raise`) later at several point
|
||||
|
||||
In this exception, we include the scopes required (if any) as a string separated by spaces (using `scope_str`). We put that string containing the scopes in in the `WWW-Authenticate` header (this is part of the spec).
|
||||
|
||||
```Python hl_lines="106 108 109 110 111 112 113 114 115 116"
|
||||
```Python hl_lines="105 107-115"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -177,7 +177,7 @@ Instead of, for example, a `dict`, or something else, as it could break the appl
|
||||
|
||||
We also verify that we have a user with that username, and if not, we raise that same exception we created before.
|
||||
|
||||
```Python hl_lines="47 117 118 119 120 121 122 123 124 125 126 127 128"
|
||||
```Python hl_lines="46 116-127"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -187,7 +187,7 @@ We now verify that all the scopes required, by this dependency and all the depen
|
||||
|
||||
For this, we use `security_scopes.scopes`, that contains a `list` with all these scopes as `str`.
|
||||
|
||||
```Python hl_lines="129 130 131 132 133 134 135"
|
||||
```Python hl_lines="128-134"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ The same way as with Pydantic models, you declare class attributes with type ann
|
||||
|
||||
You can use all the same validation features and tools you use for Pydantic models, like different data types and additional validations with `Field()`.
|
||||
|
||||
```Python hl_lines="2 5 6 7 8 11"
|
||||
```Python hl_lines="2 5-8 11"
|
||||
{!../../../docs_src/settings/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -150,7 +150,7 @@ Next it will convert and validate the data. So, when you use that `settings` obj
|
||||
|
||||
Then you can use the new `settings` object in your application:
|
||||
|
||||
```Python hl_lines="18 19 20"
|
||||
```Python hl_lines="18-20"
|
||||
{!../../../docs_src/settings/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -189,7 +189,7 @@ For example, you could have a file `config.py` with:
|
||||
|
||||
And then use it in a file `main.py`:
|
||||
|
||||
```Python hl_lines="3 11 12 13"
|
||||
```Python hl_lines="3 11-13"
|
||||
{!../../../docs_src/settings/app01/main.py!}
|
||||
```
|
||||
|
||||
@@ -216,7 +216,7 @@ Notice that now we don't create a default instance `settings = Settings()`.
|
||||
|
||||
Now we create a dependency that returns a new `config.Settings()`.
|
||||
|
||||
```Python hl_lines="5 11 12"
|
||||
```Python hl_lines="5 11-12"
|
||||
{!../../../docs_src/settings/app02/main.py!}
|
||||
```
|
||||
|
||||
@@ -227,7 +227,7 @@ Now we create a dependency that returns a new `config.Settings()`.
|
||||
|
||||
And then we can require it from the *path operation function* as a dependency and use it anywhere we need it.
|
||||
|
||||
```Python hl_lines="16 18 19 20"
|
||||
```Python hl_lines="16 18-20"
|
||||
{!../../../docs_src/settings/app02/main.py!}
|
||||
```
|
||||
|
||||
@@ -235,7 +235,7 @@ And then we can require it from the *path operation function* as a dependency an
|
||||
|
||||
Then it would be very easy to provide a different settings object during testing by creating a dependency override for `get_settings`:
|
||||
|
||||
```Python hl_lines="8 9 12 21"
|
||||
```Python hl_lines="8-9 12 21"
|
||||
{!../../../docs_src/settings/app02/test_main.py!}
|
||||
```
|
||||
|
||||
@@ -272,7 +272,7 @@ APP_NAME="ChimichangApp"
|
||||
|
||||
And then update your `config.py` with:
|
||||
|
||||
```Python hl_lines="9 10"
|
||||
```Python hl_lines="9-10"
|
||||
{!../../../docs_src/settings/app03/config.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
If you are starting a project from scratch, you are probably better off with SQLAlchemy ORM ([SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank}), or any other async ORM.
|
||||
|
||||
If you already have a code base that uses <a href="http://docs.peewee-orm.com/en/latest/" class="external-link" target="_blank">Peewee ORM</a>, you can check here how to use it with **FastAPI**.
|
||||
If you already have a code base that uses <a href="https://docs.peewee-orm.com/en/latest/" class="external-link" target="_blank">Peewee ORM</a>, you can check here how to use it with **FastAPI**.
|
||||
|
||||
!!! warning "Python 3.7+ required"
|
||||
You will need Python 3.7 or above to safely use Peewee with FastAPI.
|
||||
@@ -25,7 +25,7 @@ But if you need to change some of the defaults, support more than one predefined
|
||||
Nevertheless, it's possible to do it, and here you'll see exactly what code you have to add to be able to use Peewee with FastAPI.
|
||||
|
||||
!!! note "Technical Details"
|
||||
You can read more about Peewee's stand about async in Python <a href="http://docs.peewee-orm.com/en/latest/peewee/database.html#async-with-gevent" class="external-link" target="_blank">in the docs</a>, <a href="https://github.com/coleifer/peewee/issues/263#issuecomment-517347032" class="external-link" target="_blank">an issue</a>, <a href="https://github.com/coleifer/peewee/pull/2072#issuecomment-563215132" class="external-link" target="_blank">a PR</a>.
|
||||
You can read more about Peewee's stand about async in Python <a href="https://docs.peewee-orm.com/en/latest/peewee/database.html#async-with-gevent" class="external-link" target="_blank">in the docs</a>, <a href="https://github.com/coleifer/peewee/issues/263#issuecomment-517347032" class="external-link" target="_blank">an issue</a>, <a href="https://github.com/coleifer/peewee/pull/2072#issuecomment-563215132" class="external-link" target="_blank">a PR</a>.
|
||||
|
||||
## The same app
|
||||
|
||||
@@ -113,7 +113,7 @@ This might seem a bit complex (and it actually is), you don't really need to com
|
||||
|
||||
We will create a `PeeweeConnectionState`:
|
||||
|
||||
```Python hl_lines="10 11 12 13 14 15 16 17 18 19"
|
||||
```Python hl_lines="10-19"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/database.py!}
|
||||
```
|
||||
|
||||
@@ -161,7 +161,7 @@ This is the same you would do if you followed the Peewee tutorial and updated th
|
||||
|
||||
Import `db` from `database` (the file `database.py` from above) and use it here.
|
||||
|
||||
```Python hl_lines="3 6 7 8 9 10 11 12 15 16 17 18 19 20 21"
|
||||
```Python hl_lines="3 6-12 15-21"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/models.py!}
|
||||
```
|
||||
|
||||
@@ -189,7 +189,7 @@ Now let's check the file `sql_app/schemas.py`.
|
||||
|
||||
Create all the same Pydantic models as in the SQLAlchemy tutorial:
|
||||
|
||||
```Python hl_lines="16 17 18 21 22 25 26 27 28 29 30 34 35 38 39 42 43 44 45 46 47 48"
|
||||
```Python hl_lines="16-18 21-22 25-30 34-35 38-39 42-48"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/schemas.py!}
|
||||
```
|
||||
|
||||
@@ -214,7 +214,7 @@ But recent versions of Pydantic allow providing a custom class that inherits fro
|
||||
|
||||
We are going to create a custom `PeeweeGetterDict` class and use it in all the same Pydantic *models* / schemas that use `orm_mode`:
|
||||
|
||||
```Python hl_lines="3 8 9 10 11 12 13 31 49"
|
||||
```Python hl_lines="3 8-13 31 49"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/schemas.py!}
|
||||
```
|
||||
|
||||
@@ -235,7 +235,7 @@ Now let's see the file `sql_app/crud.py`.
|
||||
|
||||
Create all the same CRUD utils as in the SQLAlchemy tutorial, all the code is very similar:
|
||||
|
||||
```Python hl_lines="1 4 5 8 9 12 13 16 17 18 19 20 23 24 27 28 29 30"
|
||||
```Python hl_lines="1 4-5 8-9 12-13 16-20 23-24 27-30"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/crud.py!}
|
||||
```
|
||||
|
||||
@@ -259,7 +259,7 @@ And now in the file `sql_app/main.py` let's integrate and use all the other part
|
||||
|
||||
In a very simplistic way create the database tables:
|
||||
|
||||
```Python hl_lines="9 10 11"
|
||||
```Python hl_lines="9-11"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
|
||||
```
|
||||
|
||||
@@ -267,7 +267,7 @@ In a very simplistic way create the database tables:
|
||||
|
||||
Create a dependency that will connect the database right at the beginning of a request and disconnect it at the end:
|
||||
|
||||
```Python hl_lines="23 24 25 26 27 28 29"
|
||||
```Python hl_lines="23-29"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
|
||||
```
|
||||
|
||||
@@ -291,7 +291,7 @@ For all the `contextvars` parts to work, we need to make sure we have an indepen
|
||||
|
||||
For that, we need to create another `async` dependency `reset_db_state()` that is used as a sub-dependency in `get_db()`. It will set the value for the context variable (with just a default `dict`) that will be used as the database state for the whole request. And then the dependency `get_db()` will store in it the database state (connection, transactions, etc).
|
||||
|
||||
```Python hl_lines="18 19 20"
|
||||
```Python hl_lines="18-20"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
|
||||
```
|
||||
|
||||
@@ -306,11 +306,11 @@ For the **next request**, as we will reset that context variable again in the `a
|
||||
|
||||
#### Peewee Proxy
|
||||
|
||||
If you are using a <a href="http://docs.peewee-orm.com/en/latest/peewee/database.html#dynamically-defining-a-database" class="external-link" target="_blank">Peewee Proxy</a>, the actual database is at `db.obj`.
|
||||
If you are using a <a href="https://docs.peewee-orm.com/en/latest/peewee/database.html#dynamically-defining-a-database" class="external-link" target="_blank">Peewee Proxy</a>, the actual database is at `db.obj`.
|
||||
|
||||
So, you would reset it with:
|
||||
|
||||
```Python hl_lines="3 4"
|
||||
```Python hl_lines="3-4"
|
||||
async def reset_db_state():
|
||||
database.db.obj._state._state.set(db_state_default.copy())
|
||||
database.db.obj._state.reset()
|
||||
@@ -320,7 +320,7 @@ async def reset_db_state():
|
||||
|
||||
Now, finally, here's the standard **FastAPI** *path operations* code.
|
||||
|
||||
```Python hl_lines="32 33 34 35 36 37 40 41 42 43 46 47 48 49 50 51 52 53 56 57 58 59 60 61 62 65 66 67 68 71 72 73 74 75 76 77 78 79"
|
||||
```Python hl_lines="32-37 40-43 46-53 56-62 65-68 71-79"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ If you need to have two independent FastAPI applications, with their own indepen
|
||||
|
||||
First, create the main, top-level, **FastAPI** application, and its *path operations*:
|
||||
|
||||
```Python hl_lines="3 6 7 8"
|
||||
```Python hl_lines="3 6-8"
|
||||
{!../../../docs_src/sub_applications/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -20,7 +20,7 @@ Then, create your sub-application, and its *path operations*.
|
||||
|
||||
This sub-application is just another standard FastAPI application, but this is the one that will be "mounted":
|
||||
|
||||
```Python hl_lines="11 14 15 16"
|
||||
```Python hl_lines="11 14-16"
|
||||
{!../../../docs_src/sub_applications/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -30,7 +30,7 @@ In your top-level application, `app`, mount the sub-application, `subapi`.
|
||||
|
||||
In this case, it will be mounted at the path `/subapi`:
|
||||
|
||||
```Python hl_lines="11 19"
|
||||
```Python hl_lines="11 19"
|
||||
{!../../../docs_src/sub_applications/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -39,13 +39,16 @@ $ pip install aiofiles
|
||||
* Declare a `Request` parameter in the *path operation* that will return a template.
|
||||
* Use the `templates` you created to render and return a `TemplateResponse`, passing the `request` as one of the key-value pairs in the Jinja2 "context".
|
||||
|
||||
```Python hl_lines="3 10 14 15"
|
||||
```Python hl_lines="4 11 15-16"
|
||||
{!../../../docs_src/templates/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
Notice that you have to pass the `request` as part of the key-value pairs in the context for Jinja2. So, you also have to declare it in your *path operation*.
|
||||
|
||||
!!! tip
|
||||
By declaring `response_class=HTMLResponse` the docs UI will be able to know that the response will be HTML.
|
||||
|
||||
!!! note "Technical Details"
|
||||
You could also use `from starlette.templating import Jinja2Templates`.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ We create a new file at `sql_app/tests/test_sql_app.py`.
|
||||
|
||||
So the new file structure looks like:
|
||||
|
||||
``` hl_lines="9 10 11"
|
||||
``` hl_lines="9-11"
|
||||
.
|
||||
└── sql_app
|
||||
├── __init__.py
|
||||
@@ -48,7 +48,7 @@ For the tests we'll use a file `test.db` instead of `sql_app.db`.
|
||||
|
||||
But the rest of the session code is more or less the same, we just copy it.
|
||||
|
||||
```Python hl_lines="8 9 10 11 12 13"
|
||||
```Python hl_lines="8-13"
|
||||
{!../../../docs_src/sql_databases/sql_app/tests/test_sql_app.py!}
|
||||
```
|
||||
|
||||
@@ -77,7 +77,7 @@ So we add that line here, with the new file.
|
||||
|
||||
Now we create the dependency override and add it to the overrides for our app.
|
||||
|
||||
```Python hl_lines="19 20 21 22 23 24 27"
|
||||
```Python hl_lines="19-24 27"
|
||||
{!../../../docs_src/sql_databases/sql_app/tests/test_sql_app.py!}
|
||||
```
|
||||
|
||||
@@ -88,7 +88,7 @@ Now we create the dependency override and add it to the overrides for our app.
|
||||
|
||||
Then we can just test the app as normally.
|
||||
|
||||
```Python hl_lines="32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47"
|
||||
```Python hl_lines="32-47"
|
||||
{!../../../docs_src/sql_databases/sql_app/tests/test_sql_app.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -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="26-27 30"
|
||||
{!../../../docs_src/dependency_testing/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
When you need your event handlers (`startup` and `shutdown`) to run in your tests, you can use the `TestClient` with a `with` statement:
|
||||
|
||||
```Python hl_lines="9 10 11 12 20 21 22 23 24"
|
||||
```Python hl_lines="9-12 20-24"
|
||||
{!../../../docs_src/app_testing/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -4,6 +4,9 @@ You can use the same `TestClient` to test WebSockets.
|
||||
|
||||
For this, you use the `TestClient` in a `with` statement, connecting to the WebSocket:
|
||||
|
||||
```Python hl_lines="27 28 29 30 31"
|
||||
```Python hl_lines="27-31"
|
||||
{!../../../docs_src/app_testing/tutorial002.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
For more details, check Starlette's documentation for <a href="https://www.starlette.io/testclient/#testing-websocket-sessions" class="external-link" target="_blank">testing WebSockets</a>.
|
||||
|
||||
@@ -29,7 +29,7 @@ Let's imagine you want to get the client's IP address/host inside of your *path
|
||||
|
||||
For that you need to access the request directly.
|
||||
|
||||
```Python hl_lines="1 7 8"
|
||||
```Python hl_lines="1 7-8"
|
||||
{!../../../docs_src/using_request_directly/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ In production you would have one of the options above.
|
||||
|
||||
But it's the simplest way to focus on the server-side of WebSockets and have a working example:
|
||||
|
||||
```Python hl_lines="2 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 41 42 43"
|
||||
```Python hl_lines="2 6-38 41-43"
|
||||
{!../../../docs_src/websockets/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -32,7 +32,7 @@ But it's the simplest way to focus on the server-side of WebSockets and have a w
|
||||
|
||||
In your **FastAPI** application, create a `websocket`:
|
||||
|
||||
```Python hl_lines="1 46 47"
|
||||
```Python hl_lines="1 46-47"
|
||||
{!../../../docs_src/websockets/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -45,7 +45,7 @@ In your **FastAPI** application, create a `websocket`:
|
||||
|
||||
In your WebSocket route you can `await` for messages and send messages.
|
||||
|
||||
```Python hl_lines="48 49 50 51 52"
|
||||
```Python hl_lines="48-52"
|
||||
{!../../../docs_src/websockets/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -98,7 +98,7 @@ In WebSocket endpoints you can import from `fastapi` and use:
|
||||
|
||||
They work the same way as for other FastAPI endpoints/*path operations*:
|
||||
|
||||
```Python hl_lines="58 59 60 61 62 63 64 65 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83"
|
||||
```Python hl_lines="58-65 68-83"
|
||||
{!../../../docs_src/websockets/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -137,6 +137,33 @@ With that you can connect the WebSocket and then send and receive messages:
|
||||
|
||||
<img src="/img/tutorial/websockets/image05.png">
|
||||
|
||||
## Handling disconnections and multiple clients
|
||||
|
||||
When a WebSocket connection is closed, the `await websocket.receive_text()` will raise a `WebSocketDisconnect` exception, which you can then catch and handle like in this example.
|
||||
|
||||
```Python hl_lines="81-83"
|
||||
{!../../../docs_src/websockets/tutorial003.py!}
|
||||
```
|
||||
|
||||
To try it out:
|
||||
|
||||
* Open the app with several browser tabs.
|
||||
* Write messages from them.
|
||||
* Then close one of the tabs.
|
||||
|
||||
That will raise the `WebSocketDisconnect` exception, and all the other clients will receive a message like:
|
||||
|
||||
```
|
||||
Client #1596980209979 left the chat
|
||||
```
|
||||
|
||||
!!! tip
|
||||
The app above is a minimal and simple example to demonstrate how to handle and broadcast messages to several WebSocket connections.
|
||||
|
||||
But have in mind that, as everything is handled in memory, in a single list, it will only work while the process is running, and will only work with a single process.
|
||||
|
||||
If you need something easy to integrate with FastAPI but that is more robust, supported by Redis, PostgreSQL or others, check <a href="https://github.com/encode/broadcaster" class="external-link" target="_blank">encode/broadcaster</a>.
|
||||
|
||||
## More info
|
||||
|
||||
To learn more about the options, check Starlette's documentation for:
|
||||
|
||||
@@ -12,7 +12,7 @@ Then wrap the WSGI (e.g. Flask) app with the middleware.
|
||||
|
||||
And then mount that under a path.
|
||||
|
||||
```Python hl_lines="2 3 22"
|
||||
```Python hl_lines="2-3 22"
|
||||
{!../../../docs_src/wsgi/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ It was one of the first examples of **automatic API documentation**, and this wa
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
Have an automatic API documentation web user interface.
|
||||
|
||||
### <a href="http://flask.pocoo.org/" class="external-link" target="_blank">Flask</a>
|
||||
### <a href="https://flask.palletsprojects.com" class="external-link" target="_blank">Flask</a>
|
||||
|
||||
Flask is a "microframework", it doesn't include database integrations nor many of the things that come by default in Django.
|
||||
|
||||
@@ -57,7 +57,7 @@ Given the simplicity of Flask, it seemed like a good match for building APIs. Th
|
||||
Have a simple and easy to use routing system.
|
||||
|
||||
|
||||
### <a href="http://docs.python-requests.org" class="external-link" target="_blank">Requests</a>
|
||||
### <a href="https://requests.readthedocs.io" class="external-link" target="_blank">Requests</a>
|
||||
|
||||
**FastAPI** is not actually an alternative to **Requests**. Their scope is very different.
|
||||
|
||||
@@ -276,7 +276,7 @@ Routes are declared in a single place, using functions declared in other places
|
||||
|
||||
This actually inspired updating parts of Pydantic, to support the same validation declaration style (all this functionality is now already available in Pydantic).
|
||||
|
||||
### <a href="http://www.hug.rest/" class="external-link" target="_blank">Hug</a>
|
||||
### <a href="https://www.hug.rest/" class="external-link" target="_blank">Hug</a>
|
||||
|
||||
Hug was one of the first frameworks to implement the declaration of API parameter types using Python type hints. This was a great idea that inspired other tools to do the same.
|
||||
|
||||
@@ -410,7 +410,7 @@ It is the recommended server for Starlette and **FastAPI**.
|
||||
|
||||
You can combine it with Gunicorn, to have an asynchronous multi-process server.
|
||||
|
||||
Check more details in the [Deployment](deployment.md){.internal-link target=_blank} section.
|
||||
Check more details in the [Deployment](deployment/index.md){.internal-link target=_blank} section.
|
||||
|
||||
## Benchmarks and speed
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ Most of the existing popular Python frameworks (including Flask and Django) were
|
||||
|
||||
Even though the main specification for asynchronous web Python (ASGI) was developed at Django, to add support for WebSockets.
|
||||
|
||||
That kind of asynchronicity is what made NodeJS popular (even though NodeJS is not parallel) and that's the strength of Go as a programing language.
|
||||
That kind of asynchronicity is what made NodeJS popular (even though NodeJS is not parallel) and that's the strength of Go as a programming language.
|
||||
|
||||
And that's the same level of performance you get with **FastAPI**.
|
||||
|
||||
@@ -261,7 +261,7 @@ But you can also exploit the benefits of parallelism and multiprocessing (having
|
||||
|
||||
That, plus the simple fact that Python is the main language for **Data Science**, Machine Learning and especially Deep Learning, make FastAPI a very good match for Data Science / Machine Learning web APIs and applications (among many others).
|
||||
|
||||
To see how to achieve this parallelism in production see the section about [Deployment](deployment.md){.internal-link target=_blank}.
|
||||
To see how to achieve this parallelism in production see the section about [Deployment](deployment/index.md){.internal-link target=_blank}.
|
||||
|
||||
## `async` and `await`
|
||||
|
||||
@@ -305,7 +305,7 @@ burgers = get_burgers(2)
|
||||
|
||||
So, if you are using a library that tells you that you can call it with `await`, you need to create the *path operation functions* that uses it with `async def`, like in:
|
||||
|
||||
```Python hl_lines="2 3"
|
||||
```Python hl_lines="2-3"
|
||||
@app.get('/burgers')
|
||||
async def read_burgers():
|
||||
burgers = await get_burgers(2)
|
||||
@@ -334,7 +334,7 @@ This same syntax (or almost identical) was also included recently in modern vers
|
||||
|
||||
But before that, handling asynchronous code was quite more complex and difficult.
|
||||
|
||||
In previous versions of Python, you could have used threads or <a href="http://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. But the code is way more complex to understand, debug, and think about.
|
||||
In previous versions of Python, you could have used threads or <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. But the code is way more complex to understand, debug, and think about.
|
||||
|
||||
In previous versions of NodeJS / Browser JavaScript, you would have used "callbacks". Which leads to <a href="http://callbackhell.com/" class="external-link" target="_blank">callback hell</a>.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ When you check the benchmarks, it is common to see several tools of different ty
|
||||
|
||||
Specifically, to see Uvicorn, Starlette and FastAPI compared together (among many other tools).
|
||||
|
||||
The simplest the problem solved by the tool, the better performance it will get. And most of the benchmarks don't test the additional features provided by the tool.
|
||||
The simpler the problem solved by the tool, the better performance it will get. And most of the benchmarks don't test the additional features provided by the tool.
|
||||
|
||||
The hierarchy is like:
|
||||
|
||||
|
||||
@@ -499,13 +499,3 @@ $ bash scripts/test-cov-html.sh
|
||||
</div>
|
||||
|
||||
This command generates a directory `./htmlcov/`, if you open the file `./htmlcov/index.html` in your browser, you can explore interactively the regions of code that are covered by the tests, and notice if there is any region missing.
|
||||
|
||||
### Tests in your editor
|
||||
|
||||
If you want to use the integrated tests in your editor add `./docs_src` to your `PYTHONPATH` variable.
|
||||
|
||||
For example, in VS Code you can create a file `.env` with:
|
||||
|
||||
```env
|
||||
PYTHONPATH=./docs_src
|
||||
```
|
||||
|
||||
@@ -1,18 +1,57 @@
|
||||
a.external-link::after {
|
||||
/* \00A0 is a non-breaking space
|
||||
/* \00A0 is a non-breaking space
|
||||
to make the mark be on the same line as the link
|
||||
*/
|
||||
content: "\00A0[↪]";
|
||||
content: "\00A0[↪]";
|
||||
}
|
||||
|
||||
a.internal-link::after {
|
||||
/* \00A0 is a non-breaking space
|
||||
/* \00A0 is a non-breaking space
|
||||
to make the mark be on the same line as the link
|
||||
*/
|
||||
content: "\00A0↪";
|
||||
content: "\00A0↪";
|
||||
}
|
||||
|
||||
/* Give space to lower icons so Gitter chat doesn't get on top of them */
|
||||
.md-footer-meta {
|
||||
padding-bottom: 2em;
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
|
||||
.user-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.user-list-center {
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.user {
|
||||
margin: 1em;
|
||||
min-width: 7em;
|
||||
}
|
||||
|
||||
.user .avatar-wrapper {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: 10px auto;
|
||||
overflow: hidden;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.user .avatar-wrapper img {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.user .title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.user .count {
|
||||
font-size: 80%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -1,396 +0,0 @@
|
||||
# Deployment
|
||||
|
||||
Deploying a **FastAPI** application is relatively easy.
|
||||
|
||||
There are several ways to do it depending on your specific use case and the tools that you use.
|
||||
|
||||
You will see more about some of the ways to do it in the next sections.
|
||||
|
||||
## FastAPI versions
|
||||
|
||||
**FastAPI** is already being used in production in many applications and systems. And the test coverage is kept at 100%. But its development is still moving quickly.
|
||||
|
||||
New features are added frequently, bugs are fixed regularly, and the code is still continuously improving.
|
||||
|
||||
That's why the current versions are still `0.x.x`, this reflects that each version could potentially have breaking changes. This follows the <a href="https://semver.org/" class="external-link" target="_blank">Semantic Versioning</a> conventions.
|
||||
|
||||
You can create production applications with **FastAPI** right now (and you have probably been doing it for some time), you just have to make sure that you use a version that works correctly with the rest of your code.
|
||||
|
||||
### Pin your `fastapi` version
|
||||
|
||||
The first thing you should do is to "pin" the version of **FastAPI** you are using to the specific latest version that you know works correctly for your application.
|
||||
|
||||
For example, let's say you are using version `0.45.0` in your app.
|
||||
|
||||
If you use a `requirements.txt` file you could specify the version with:
|
||||
|
||||
```txt
|
||||
fastapi==0.45.0
|
||||
```
|
||||
|
||||
that would mean that you would use exactly the version `0.45.0`.
|
||||
|
||||
Or you could also pin it with:
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
that would mean that you would use the versions `0.45.0` or above, but less than `0.46.0`, for example, a version `0.45.2` would still be accepted.
|
||||
|
||||
If you use any other tool to manage your installations, like Poetry, Pipenv, or others, they all have a way that you can use to define specific versions for your packages.
|
||||
|
||||
### Available versions
|
||||
|
||||
You can see the available versions (e.g. to check what is the current latest) in the [Release Notes](release-notes.md){.internal-link target=_blank}.
|
||||
|
||||
### About versions
|
||||
|
||||
Following the Semantic Versioning conventions, any version below `1.0.0` could potentially add breaking changes.
|
||||
|
||||
FastAPI also follows the convention that any "PATCH" version change is for bug fixes and non-breaking changes.
|
||||
|
||||
!!! tip
|
||||
The "PATCH" is the last number, for example, in `0.2.3`, the PATCH version is `3`.
|
||||
|
||||
So, you should be able to pin to a version like:
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
Breaking changes and new features are added in "MINOR" versions.
|
||||
|
||||
!!! tip
|
||||
The "MINOR" is the number in the middle, for example, in `0.2.3`, the MINOR version is `2`.
|
||||
|
||||
### Upgrading the FastAPI versions
|
||||
|
||||
You should add tests for your app.
|
||||
|
||||
With **FastAPI** it's very easy (thanks to Starlette), check the docs: [Testing](tutorial/testing.md){.internal-link target=_blank}
|
||||
|
||||
After you have tests, then you can upgrade the **FastAPI** version to a more recent one, and make sure that all your code is working correctly by running your tests.
|
||||
|
||||
If everything is working, or after you make the necessary changes, and all your tests are passing, then you can pin your `fastapi` to that new recent version.
|
||||
|
||||
### About Starlette
|
||||
|
||||
You shouldn't pin the version of `starlette`.
|
||||
|
||||
Different versions of **FastAPI** will use a specific newer version of Starlette.
|
||||
|
||||
So, you can just let **FastAPI** use the correct Starlette version.
|
||||
|
||||
### About Pydantic
|
||||
|
||||
Pydantic includes the tests for **FastAPI** with its own tests, so new versions of Pydantic (above `1.0.0`) are always compatible with FastAPI.
|
||||
|
||||
You can pin Pydantic to any version above `1.0.0` that works for you and below `2.0.0`.
|
||||
|
||||
For example:
|
||||
|
||||
```txt
|
||||
pydantic>=1.2.0,<2.0.0
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
In this section you'll see instructions and links to guides to know how to:
|
||||
|
||||
* Make your **FastAPI** application a Docker image/container with maximum performance. In about **5 min**.
|
||||
* (Optionally) understand what you, as a developer, need to know about HTTPS.
|
||||
* Set up a Docker Swarm mode cluster with automatic HTTPS, even on a simple $5 USD/month server. In about **20 min**.
|
||||
* Generate and deploy a full **FastAPI** application, using your Docker Swarm cluster, with HTTPS, etc. In about **10 min**.
|
||||
|
||||
You can use <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a> for deployment. It has several advantages like security, replicability, development simplicity, etc.
|
||||
|
||||
If you are using Docker, you can use the official Docker image:
|
||||
|
||||
### <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>
|
||||
|
||||
This image has an "auto-tuning" mechanism included, so that you can just add your code and get very high performance automatically. And without making sacrifices.
|
||||
|
||||
But you can still change and update all the configurations with environment variables or configuration files.
|
||||
|
||||
!!! tip
|
||||
To see all the configurations and options, go to the Docker image page: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
|
||||
|
||||
### Create a `Dockerfile`
|
||||
|
||||
* Go to your project directory.
|
||||
* Create a `Dockerfile` with:
|
||||
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||
|
||||
COPY ./app /app
|
||||
```
|
||||
|
||||
#### Bigger Applications
|
||||
|
||||
If you followed the section about creating [Bigger Applications with Multiple Files](tutorial/bigger-applications.md){.internal-link target=_blank}, your `Dockerfile` might instead look like:
|
||||
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||
|
||||
COPY ./app /app/app
|
||||
```
|
||||
|
||||
#### Raspberry Pi and other architectures
|
||||
|
||||
If you are running Docker in a Raspberry Pi (that has an ARM processor) or any other architecture, you can create a `Dockerfile` from scratch, based on a Python base image (that is multi-architecture) and use Uvicorn alone.
|
||||
|
||||
In this case, your `Dockerfile` could look like:
|
||||
|
||||
```Dockerfile
|
||||
FROM python:3.7
|
||||
|
||||
RUN pip install fastapi uvicorn
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
COPY ./app /app
|
||||
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
### Create the **FastAPI** Code
|
||||
|
||||
* Create an `app` directory and enter in it.
|
||||
* Create a `main.py` file with:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
* You should now have a directory structure like:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ └── main.py
|
||||
└── Dockerfile
|
||||
```
|
||||
|
||||
### Build the Docker image
|
||||
|
||||
* Go to the project directory (in where your `Dockerfile` is, containing your `app` directory).
|
||||
* Build your FastAPI image:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ docker build -t myimage .
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Start the Docker container
|
||||
|
||||
* Run a container based on your image:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ docker run -d --name mycontainer -p 80:80 myimage
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Now you have an optimized FastAPI server in a Docker container. Auto-tuned for your current server (and number of CPU cores).
|
||||
|
||||
### Check it
|
||||
|
||||
You should be able to check it in your Docker container's URL, for example: <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> or <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (or equivalent, using your Docker host).
|
||||
|
||||
You will see something like:
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
### Interactive API docs
|
||||
|
||||
Now you can go to <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> or <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (or equivalent, using your Docker host).
|
||||
|
||||
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
|
||||
|
||||

|
||||
|
||||
### Alternative API docs
|
||||
|
||||
And you can also go to <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> or <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (or equivalent, using your Docker host).
|
||||
|
||||
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
|
||||
|
||||

|
||||
|
||||
## HTTPS
|
||||
|
||||
### About HTTPS
|
||||
|
||||
It is easy to assume that HTTPS is something that is just "enabled" or not.
|
||||
|
||||
But it is way more complex than that.
|
||||
|
||||
!!! tip
|
||||
If you are in a hurry or don't care, continue with the next section for step by step instructions to set everything up.
|
||||
|
||||
To learn the basics of HTTPS, from a consumer perspective, check <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a>.
|
||||
|
||||
Now, from a developer's perspective, here are several things to have in mind while thinking about HTTPS:
|
||||
|
||||
* For HTTPS, the server needs to have "certificates" generated by a third party.
|
||||
* Those certificates are actually acquired from the third-party, not "generated".
|
||||
* Certificates have a lifetime.
|
||||
* They expire.
|
||||
* And then they need to be renewed, acquired again from the third party.
|
||||
* The encryption of the connection happens at the TCP level.
|
||||
* That's one layer below HTTP.
|
||||
* So, the certificate and encryption handling is done before HTTP.
|
||||
* TCP doesn't know about "domains". Only about IP addresses.
|
||||
* The information about the specific domain requested goes in the HTTP data.
|
||||
* The HTTPS certificates "certify" a certain domain, but the protocol and encryption happen at the TCP level, before knowing which domain is being dealt with.
|
||||
* By default, that would mean that you can only have one HTTPS certificate per IP address.
|
||||
* No matter how big your server is or how small each application you have on it might be.
|
||||
* There is a solution to this, however.
|
||||
* There's an extension to the TLS protocol (the one handling the encryption at the TCP level, before HTTP) called <a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication">SNI</abbr></a>.
|
||||
* This SNI extension allows one single server (with a single IP address) to have several HTTPS certificates and serve multiple HTTPS domains/applications.
|
||||
* For this to work, a single component (program) running on the server, listening on the public IP address, must have all the HTTPS certificates in the server.
|
||||
* After obtaining a secure connection, the communication protocol is still HTTP.
|
||||
* The contents are encrypted, even though they are being sent with the HTTP protocol.
|
||||
|
||||
It is a common practice to have one program/HTTP server running on the server (the machine, host, etc.) and managing all the HTTPS parts : sending the decrypted HTTP requests to the actual HTTP application running in the same server (the **FastAPI** application, in this case), take the HTTP response from the application, encrypt it using the appropriate certificate and sending it back to the client using HTTPS. This server is often called a <a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">TLS Termination Proxy</a>.
|
||||
|
||||
### Let's Encrypt
|
||||
|
||||
Before Let's Encrypt, these HTTPS certificates were sold by trusted third-parties.
|
||||
|
||||
The process to acquire one of these certificates used to be cumbersome, require quite some paperwork and the certificates were quite expensive.
|
||||
|
||||
But then <a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a> was created.
|
||||
|
||||
It is a project from the Linux Foundation. It provides HTTPS certificates for free. In an automated way. These certificates use all the standard cryptographic security, and are short lived (about 3 months), so the security is actually better because of their reduced lifespan.
|
||||
|
||||
The domains are securely verified and the certificates are generated automatically. This also allows automating the renewal of these certificates.
|
||||
|
||||
The idea is to automate the acquisition and renewal of these certificates, so that you can have secure HTTPS, for free, forever.
|
||||
|
||||
### Traefik
|
||||
|
||||
<a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a> is a high performance reverse proxy / load balancer. It can do the "TLS Termination Proxy" job (apart from other features).
|
||||
|
||||
It has integration with Let's Encrypt. So, it can handle all the HTTPS parts, including certificate acquisition and renewal.
|
||||
|
||||
It also has integrations with Docker. So, you can declare your domains in each application configurations and have it read those configurations, generate the HTTPS certificates and serve HTTPS to your application automatically, without requiring any change in its configuration.
|
||||
|
||||
---
|
||||
|
||||
With this information and tools, continue with the next section to combine everything.
|
||||
|
||||
## Docker Swarm mode cluster with Traefik and HTTPS
|
||||
|
||||
You can have a Docker Swarm mode cluster set up in minutes (about 20 min) with a main Traefik handling HTTPS (including certificate acquisition and renewal).
|
||||
|
||||
By using Docker Swarm mode, you can start with a "cluster" of a single machine (it can even be a $5 USD / month server) and then you can grow as much as you need adding more servers.
|
||||
|
||||
To set up a Docker Swarm Mode cluster with Traefik and HTTPS handling, follow this guide:
|
||||
|
||||
### <a href="https://medium.com/@tiangolo/docker-swarm-mode-and-traefik-for-a-https-cluster-20328dba6232" class="external-link" target="_blank">Docker Swarm Mode and Traefik for an HTTPS cluster</a>
|
||||
|
||||
### Deploy a FastAPI application
|
||||
|
||||
The easiest way to set everything up, would be using the [**FastAPI** Project Generators](project-generation.md){.internal-link target=_blank}.
|
||||
|
||||
It is designed to be integrated with this Docker Swarm cluster with Traefik and HTTPS described above.
|
||||
|
||||
You can generate a project in about 2 min.
|
||||
|
||||
The generated project has instructions to deploy it, doing it takes another 2 min.
|
||||
|
||||
## Alternatively, deploy **FastAPI** without Docker
|
||||
|
||||
You can deploy **FastAPI** directly without Docker too.
|
||||
|
||||
You just need to install an ASGI compatible server like:
|
||||
|
||||
=== "Uvicorn"
|
||||
|
||||
* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>, a lightning-fast ASGI server, built on uvloop and httptools.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
=== "Hypercorn"
|
||||
|
||||
* <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>, an ASGI server also compatible with HTTP/2.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install hypercorn
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
...or any other ASGI server.
|
||||
|
||||
And run your application the same way you have done in the tutorials, but without the `--reload` option, e.g.:
|
||||
|
||||
=== "Uvicorn"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --host 0.0.0.0 --port 80
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
=== "Hypercorn"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ hypercorn main:app --bind 0.0.0.0:80
|
||||
|
||||
Running on 0.0.0.0:8080 over http (CTRL + C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
You might want to set up some tooling to make sure it is restarted automatically if it stops.
|
||||
|
||||
You might also want to install <a href="https://gunicorn.org/" class="external-link" target="_blank">Gunicorn</a> and <a href="https://www.uvicorn.org/#running-with-gunicorn" class="external-link" target="_blank">use it as a manager for Uvicorn</a>, or use Hypercorn with multiple workers.
|
||||
|
||||
Making sure to fine-tune the number of workers, etc.
|
||||
|
||||
But if you are doing all that, you might just use the Docker image that does it automatically.
|
||||
240
docs/en/docs/deployment/deta.md
Normal file
@@ -0,0 +1,240 @@
|
||||
# Deploy on Deta
|
||||
|
||||
In this section you will learn see how to easily deploy a **FastAPI** application on <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> using the free plan. 🎁
|
||||
|
||||
It will take you about **10 minutes**.
|
||||
|
||||
!!! info
|
||||
<a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> is a **FastAPI** sponsor. 🎉
|
||||
|
||||
## A basic **FastAPI** app
|
||||
|
||||
* Create a directory for your app, for example `./fastapideta/` and enter in it.
|
||||
|
||||
### FastAPI code
|
||||
|
||||
* Create a `main.py` file with:
|
||||
|
||||
```Python
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int):
|
||||
return {"item_id": item_id}
|
||||
```
|
||||
|
||||
### Requirements
|
||||
|
||||
Now, in the same directory create a file `requirements.txt` with:
|
||||
|
||||
```text
|
||||
fastapi
|
||||
```
|
||||
|
||||
!!! tip
|
||||
You don't need to install Uvicorn to deploy on Deta, although you would probably want to install it locally to test your app.
|
||||
|
||||
### Directory structure
|
||||
|
||||
You will now have one directory `./fastapideta/` with two files:
|
||||
|
||||
```
|
||||
.
|
||||
└── main.py
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
## Create a free Deta account
|
||||
|
||||
Now create a <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">free account on Deta</a>, you just need an email and password.
|
||||
|
||||
You don't even need a credit card.
|
||||
|
||||
## Install the CLI
|
||||
|
||||
Once you have your account, install the Deta <abbr title="Command Line Interface application">CLI</abbr>:
|
||||
|
||||
=== "Linux, macOS"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ curl -fsSL https://get.deta.dev/cli.sh | sh
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
=== "Windows PowerShell"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ iwr https://get.deta.dev/cli.ps1 -useb | iex
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
After installing it, open a new terminal so that the installed CLI is detected.
|
||||
|
||||
In a new terminal, confirm that it was correctly installed with:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ deta --help
|
||||
|
||||
Deta command line interface for managing deta micros.
|
||||
Complete documentation available at https://docs.deta.sh
|
||||
|
||||
Usage:
|
||||
deta [flags]
|
||||
deta [command]
|
||||
|
||||
Available Commands:
|
||||
auth Change auth settings for a deta micro
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
!!! tip
|
||||
If you have problems installing the CLI, check the <a href="https://docs.deta.sh/docs/micros/getting_started?ref=fastapi" class="external-link" target="_blank">official Deta docs</a>.
|
||||
|
||||
## Login with the CLI
|
||||
|
||||
Now login to Deta from the CLI with:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ deta login
|
||||
|
||||
Please, log in from the web page. Waiting..
|
||||
Logged in successfully.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
This will open a web browser and authenticate automatically.
|
||||
|
||||
## Deploy with Deta
|
||||
|
||||
Next, deploy your application with the Deta CLI:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ deta new
|
||||
|
||||
Successfully created a new micro
|
||||
|
||||
// Notice the "endpoint" 🔍
|
||||
|
||||
{
|
||||
"name": "fastapideta",
|
||||
"runtime": "python3.7",
|
||||
"endpoint": "https://qltnci.deta.dev",
|
||||
"visor": "enabled",
|
||||
"http_auth": "enabled"
|
||||
}
|
||||
|
||||
Adding dependencies...
|
||||
|
||||
|
||||
---> 100%
|
||||
|
||||
|
||||
Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
You will see a JSON message similar to:
|
||||
|
||||
```JSON hl_lines="4"
|
||||
{
|
||||
"name": "fastapideta",
|
||||
"runtime": "python3.7",
|
||||
"endpoint": "https://qltnci.deta.dev",
|
||||
"visor": "enabled",
|
||||
"http_auth": "enabled"
|
||||
}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Your deployment will have a different `"endpoint"` URL.
|
||||
|
||||
## Check it
|
||||
|
||||
Now open your browser in your `endpoint` URL. In the example above it was `https://qltnci.deta.dev`, but yours will be different.
|
||||
|
||||
You will see the JSON response from your FastAPI app:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"Hello": "World"
|
||||
}
|
||||
```
|
||||
|
||||
And now go to the `/docs` for your API, in the example above it would be `https://qltnci.deta.dev/docs`.
|
||||
|
||||
It will show your docs like:
|
||||
|
||||
<img src="/img/deployment/deta/image01.png">
|
||||
|
||||
## Enable public access
|
||||
|
||||
By default, Deta will handle authentication using cookies for your account.
|
||||
|
||||
But once you are ready, you can make it public with:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ deta auth disable
|
||||
|
||||
Successfully disabled http auth
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Now you can share that URL with anyone and they will be able to access your API. 🚀
|
||||
|
||||
## HTTPS
|
||||
|
||||
Congrats! You deployed your FastAPI app to Deta! 🎉 🍰
|
||||
|
||||
Also notice that Deta correctly handles HTTPS for you, so you don't have to take care of that and can be sure that your clients will have a secure encrypted connection. ✅ 🔒
|
||||
|
||||
## Check the Visor
|
||||
|
||||
From your docs UI (they will be in a URL like `https://qltnci.deta.dev/docs`) send a request to your *path operation* `/items/{item_id}`.
|
||||
|
||||
For example with ID `5`.
|
||||
|
||||
Now go to <a href="https://web.deta.sh/" class="external-link" target="_blank">https://web.deta.sh</a>.
|
||||
|
||||
You will see there's a section to the left called <abbr title="it comes from Micro(server)">"Micros"</abbr> with each of your apps.
|
||||
|
||||
You will see a tab with "Details", and also a tab "Visor", go to the tab "Visor".
|
||||
|
||||
In there you can inspect the recent requests sent to your app.
|
||||
|
||||
You can also edit them and re-play them.
|
||||
|
||||
<img src="/img/deployment/deta/image02.png">
|
||||
|
||||
## Learn more
|
||||
|
||||
At some point you will probably want to store some data for your app in a way that persists through time. For that you can use <a href="https://docs.deta.sh/docs/base/py_tutorial?ref=fastapi" class="external-link" target="_blank">Deta Base</a>, it also has a generous **free tier**.
|
||||
|
||||
You can also read more in the <a href="https://docs.deta.sh?ref=fastapi" class="external-link" target="_blank">Deta Docs</a>.
|
||||
179
docs/en/docs/deployment/docker.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# Deploy with Docker
|
||||
|
||||
In this section you'll see instructions and links to guides to know how to:
|
||||
|
||||
* Make your **FastAPI** application a Docker image/container with maximum performance. In about **5 min**.
|
||||
* (Optionally) understand what you, as a developer, need to know about HTTPS.
|
||||
* Set up a Docker Swarm mode cluster with automatic HTTPS, even on a simple $5 USD/month server. In about **20 min**.
|
||||
* Generate and deploy a full **FastAPI** application, using your Docker Swarm cluster, with HTTPS, etc. In about **10 min**.
|
||||
|
||||
You can use <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a> for deployment. It has several advantages like security, replicability, development simplicity, etc.
|
||||
|
||||
If you are using Docker, you can use the official Docker image:
|
||||
|
||||
## <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>
|
||||
|
||||
This image has an "auto-tuning" mechanism included, so that you can just add your code and get very high performance automatically. And without making sacrifices.
|
||||
|
||||
But you can still change and update all the configurations with environment variables or configuration files.
|
||||
|
||||
!!! tip
|
||||
To see all the configurations and options, go to the Docker image page: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
|
||||
|
||||
## Create a `Dockerfile`
|
||||
|
||||
* Go to your project directory.
|
||||
* Create a `Dockerfile` with:
|
||||
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||
|
||||
COPY ./app /app
|
||||
```
|
||||
|
||||
### Bigger Applications
|
||||
|
||||
If you followed the section about creating [Bigger Applications with Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}, your `Dockerfile` might instead look like:
|
||||
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||
|
||||
COPY ./app /app/app
|
||||
```
|
||||
|
||||
### Raspberry Pi and other architectures
|
||||
|
||||
If you are running Docker in a Raspberry Pi (that has an ARM processor) or any other architecture, you can create a `Dockerfile` from scratch, based on a Python base image (that is multi-architecture) and use Uvicorn alone.
|
||||
|
||||
In this case, your `Dockerfile` could look like:
|
||||
|
||||
```Dockerfile
|
||||
FROM python:3.7
|
||||
|
||||
RUN pip install fastapi uvicorn
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
COPY ./app /app
|
||||
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
## Create the **FastAPI** Code
|
||||
|
||||
* Create an `app` directory and enter in it.
|
||||
* Create a `main.py` file with:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
* You should now have a directory structure like:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ └── main.py
|
||||
└── Dockerfile
|
||||
```
|
||||
|
||||
## Build the Docker image
|
||||
|
||||
* Go to the project directory (in where your `Dockerfile` is, containing your `app` directory).
|
||||
* Build your FastAPI image:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ docker build -t myimage .
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Start the Docker container
|
||||
|
||||
* Run a container based on your image:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ docker run -d --name mycontainer -p 80:80 myimage
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Now you have an optimized FastAPI server in a Docker container. Auto-tuned for your current server (and number of CPU cores).
|
||||
|
||||
## Check it
|
||||
|
||||
You should be able to check it in your Docker container's URL, for example: <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> or <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (or equivalent, using your Docker host).
|
||||
|
||||
You will see something like:
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
## Interactive API docs
|
||||
|
||||
Now you can go to <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> or <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (or equivalent, using your Docker host).
|
||||
|
||||
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
|
||||
|
||||

|
||||
|
||||
## Alternative API docs
|
||||
|
||||
And you can also go to <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> or <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (or equivalent, using your Docker host).
|
||||
|
||||
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
|
||||
|
||||

|
||||
|
||||
## Traefik
|
||||
|
||||
<a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a> is a high performance reverse proxy / load balancer. It can do the "TLS Termination Proxy" job (apart from other features).
|
||||
|
||||
It has integration with Let's Encrypt. So, it can handle all the HTTPS parts, including certificate acquisition and renewal.
|
||||
|
||||
It also has integrations with Docker. So, you can declare your domains in each application configurations and have it read those configurations, generate the HTTPS certificates and serve HTTPS to your application automatically, without requiring any change in its configuration.
|
||||
|
||||
---
|
||||
|
||||
With this information and tools, continue with the next section to combine everything.
|
||||
|
||||
## Docker Swarm mode cluster with Traefik and HTTPS
|
||||
|
||||
You can have a Docker Swarm mode cluster set up in minutes (about 20 min) with a main Traefik handling HTTPS (including certificate acquisition and renewal).
|
||||
|
||||
By using Docker Swarm mode, you can start with a "cluster" of a single machine (it can even be a $5 USD / month server) and then you can grow as much as you need adding more servers.
|
||||
|
||||
To set up a Docker Swarm Mode cluster with Traefik and HTTPS handling, follow this guide:
|
||||
|
||||
### <a href="https://medium.com/@tiangolo/docker-swarm-mode-and-traefik-for-a-https-cluster-20328dba6232" class="external-link" target="_blank">Docker Swarm Mode and Traefik for an HTTPS cluster</a>
|
||||
|
||||
### Deploy a FastAPI application
|
||||
|
||||
The easiest way to set everything up, would be using the [**FastAPI** Project Generators](../project-generation.md){.internal-link target=_blank}.
|
||||
|
||||
It is designed to be integrated with this Docker Swarm cluster with Traefik and HTTPS described above.
|
||||
|
||||
You can generate a project in about 2 min.
|
||||
|
||||
The generated project has instructions to deploy it, doing it takes another 2 min.
|
||||
48
docs/en/docs/deployment/https.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# About HTTPS
|
||||
|
||||
It is easy to assume that HTTPS is something that is just "enabled" or not.
|
||||
|
||||
But it is way more complex than that.
|
||||
|
||||
!!! tip
|
||||
If you are in a hurry or don't care, continue with the next sections for step by step instructions to set everything up with different techniques.
|
||||
|
||||
To learn the basics of HTTPS, from a consumer perspective, check <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a>.
|
||||
|
||||
Now, from a developer's perspective, here are several things to have in mind while thinking about HTTPS:
|
||||
|
||||
* For HTTPS, the server needs to have "certificates" generated by a third party.
|
||||
* Those certificates are actually acquired from the third-party, not "generated".
|
||||
* Certificates have a lifetime.
|
||||
* They expire.
|
||||
* And then they need to be renewed, acquired again from the third party.
|
||||
* The encryption of the connection happens at the TCP level.
|
||||
* That's one layer below HTTP.
|
||||
* So, the certificate and encryption handling is done before HTTP.
|
||||
* TCP doesn't know about "domains". Only about IP addresses.
|
||||
* The information about the specific domain requested goes in the HTTP data.
|
||||
* The HTTPS certificates "certify" a certain domain, but the protocol and encryption happen at the TCP level, before knowing which domain is being dealt with.
|
||||
* By default, that would mean that you can only have one HTTPS certificate per IP address.
|
||||
* No matter how big your server is or how small each application you have on it might be.
|
||||
* There is a solution to this, however.
|
||||
* There's an extension to the TLS protocol (the one handling the encryption at the TCP level, before HTTP) called <a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication">SNI</abbr></a>.
|
||||
* This SNI extension allows one single server (with a single IP address) to have several HTTPS certificates and serve multiple HTTPS domains/applications.
|
||||
* For this to work, a single component (program) running on the server, listening on the public IP address, must have all the HTTPS certificates in the server.
|
||||
* After obtaining a secure connection, the communication protocol is still HTTP.
|
||||
* The contents are encrypted, even though they are being sent with the HTTP protocol.
|
||||
|
||||
It is a common practice to have one program/HTTP server running on the server (the machine, host, etc.) and managing all the HTTPS parts : sending the decrypted HTTP requests to the actual HTTP application running in the same server (the **FastAPI** application, in this case), take the HTTP response from the application, encrypt it using the appropriate certificate and sending it back to the client using HTTPS. This server is often called a <a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">TLS Termination Proxy</a>.
|
||||
|
||||
## Let's Encrypt
|
||||
|
||||
Before Let's Encrypt, these HTTPS certificates were sold by trusted third-parties.
|
||||
|
||||
The process to acquire one of these certificates used to be cumbersome, require quite some paperwork and the certificates were quite expensive.
|
||||
|
||||
But then <a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a> was created.
|
||||
|
||||
It is a project from the Linux Foundation. It provides HTTPS certificates for free. In an automated way. These certificates use all the standard cryptographic security, and are short lived (about 3 months), so the security is actually better because of their reduced lifespan.
|
||||
|
||||
The domains are securely verified and the certificates are generated automatically. This also allows automating the renewal of these certificates.
|
||||
|
||||
The idea is to automate the acquisition and renewal of these certificates, so that you can have secure HTTPS, for free, forever.
|
||||
7
docs/en/docs/deployment/index.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Deployment - Intro
|
||||
|
||||
Deploying a **FastAPI** application is relatively easy.
|
||||
|
||||
There are several ways to do it depending on your specific use case and the tools that you use.
|
||||
|
||||
You will see more details to have in mind and some of the techniques to do it in the next sections.
|
||||
69
docs/en/docs/deployment/manually.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Deploy manually
|
||||
|
||||
You can deploy **FastAPI** manually as well.
|
||||
|
||||
You just need to install an ASGI compatible server like:
|
||||
|
||||
=== "Uvicorn"
|
||||
|
||||
* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>, a lightning-fast ASGI server, built on uvloop and httptools.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
=== "Hypercorn"
|
||||
|
||||
* <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>, an ASGI server also compatible with HTTP/2.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install hypercorn
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
...or any other ASGI server.
|
||||
|
||||
And run your application the same way you have done in the tutorials, but without the `--reload` option, e.g.:
|
||||
|
||||
=== "Uvicorn"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --host 0.0.0.0 --port 80
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
=== "Hypercorn"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ hypercorn main:app --bind 0.0.0.0:80
|
||||
|
||||
Running on 0.0.0.0:8080 over http (CTRL + C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
You might want to set up some tooling to make sure it is restarted automatically if it stops.
|
||||
|
||||
You might also want to install <a href="https://gunicorn.org/" class="external-link" target="_blank">Gunicorn</a> and <a href="https://www.uvicorn.org/#running-with-gunicorn" class="external-link" target="_blank">use it as a manager for Uvicorn</a>, or use Hypercorn with multiple workers.
|
||||
|
||||
Making sure to fine-tune the number of workers, etc.
|
||||
|
||||
But if you are doing all that, you might just use the Docker image that does it automatically.
|
||||
87
docs/en/docs/deployment/versions.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# About FastAPI versions
|
||||
|
||||
**FastAPI** is already being used in production in many applications and systems. And the test coverage is kept at 100%. But its development is still moving quickly.
|
||||
|
||||
New features are added frequently, bugs are fixed regularly, and the code is still continuously improving.
|
||||
|
||||
That's why the current versions are still `0.x.x`, this reflects that each version could potentially have breaking changes. This follows the <a href="https://semver.org/" class="external-link" target="_blank">Semantic Versioning</a> conventions.
|
||||
|
||||
You can create production applications with **FastAPI** right now (and you have probably been doing it for some time), you just have to make sure that you use a version that works correctly with the rest of your code.
|
||||
|
||||
## Pin your `fastapi` version
|
||||
|
||||
The first thing you should do is to "pin" the version of **FastAPI** you are using to the specific latest version that you know works correctly for your application.
|
||||
|
||||
For example, let's say you are using version `0.45.0` in your app.
|
||||
|
||||
If you use a `requirements.txt` file you could specify the version with:
|
||||
|
||||
```txt
|
||||
fastapi==0.45.0
|
||||
```
|
||||
|
||||
that would mean that you would use exactly the version `0.45.0`.
|
||||
|
||||
Or you could also pin it with:
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
that would mean that you would use the versions `0.45.0` or above, but less than `0.46.0`, for example, a version `0.45.2` would still be accepted.
|
||||
|
||||
If you use any other tool to manage your installations, like Poetry, Pipenv, or others, they all have a way that you can use to define specific versions for your packages.
|
||||
|
||||
## Available versions
|
||||
|
||||
You can see the available versions (e.g. to check what is the current latest) in the [Release Notes](../release-notes.md){.internal-link target=_blank}.
|
||||
|
||||
## About versions
|
||||
|
||||
Following the Semantic Versioning conventions, any version below `1.0.0` could potentially add breaking changes.
|
||||
|
||||
FastAPI also follows the convention that any "PATCH" version change is for bug fixes and non-breaking changes.
|
||||
|
||||
!!! tip
|
||||
The "PATCH" is the last number, for example, in `0.2.3`, the PATCH version is `3`.
|
||||
|
||||
So, you should be able to pin to a version like:
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
Breaking changes and new features are added in "MINOR" versions.
|
||||
|
||||
!!! tip
|
||||
The "MINOR" is the number in the middle, for example, in `0.2.3`, the MINOR version is `2`.
|
||||
|
||||
## Upgrading the FastAPI versions
|
||||
|
||||
You should add tests for your app.
|
||||
|
||||
With **FastAPI** it's very easy (thanks to Starlette), check the docs: [Testing](../tutorial/testing.md){.internal-link target=_blank}
|
||||
|
||||
After you have tests, then you can upgrade the **FastAPI** version to a more recent one, and make sure that all your code is working correctly by running your tests.
|
||||
|
||||
If everything is working, or after you make the necessary changes, and all your tests are passing, then you can pin your `fastapi` to that new recent version.
|
||||
|
||||
## About Starlette
|
||||
|
||||
You shouldn't pin the version of `starlette`.
|
||||
|
||||
Different versions of **FastAPI** will use a specific newer version of Starlette.
|
||||
|
||||
So, you can just let **FastAPI** use the correct Starlette version.
|
||||
|
||||
## About Pydantic
|
||||
|
||||
Pydantic includes the tests for **FastAPI** with its own tests, so new versions of Pydantic (above `1.0.0`) are always compatible with FastAPI.
|
||||
|
||||
You can pin Pydantic to any version above `1.0.0` that works for you and below `2.0.0`.
|
||||
|
||||
For example:
|
||||
|
||||
```txt
|
||||
pydantic>=1.2.0,<2.0.0
|
||||
```
|
||||
@@ -7,127 +7,72 @@ There are many posts, articles, tools, and projects, related to **FastAPI**.
|
||||
Here's an incomplete list of some of them.
|
||||
|
||||
!!! tip
|
||||
If you have an article, project, tool, or anything related to **FastAPI** that is not yet listed here, create a <a href="https://github.com/tiangolo/fastapi/edit/master/docs/external-links.md" class="external-link" target="_blank">Pull Request adding it</a>.
|
||||
If you have an article, project, tool, or anything related to **FastAPI** that is not yet listed here, create a <a href="https://github.com/tiangolo/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">Pull Request adding it</a>.
|
||||
|
||||
## Articles
|
||||
|
||||
### English
|
||||
|
||||
* <a href="https://medium.com/@williamhayes/fastapi-starlette-debug-vs-prod-5f7561db3a59" class="external-link" target="_blank">FastAPI/Starlette debug vs prod</a> by <a href="https://medium.com/@williamhayes" class="external-link" target="_blank">William Hayes</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.english %}
|
||||
|
||||
* <a href="https://medium.com/data-rebels/fastapi-google-as-an-external-authentication-provider-3a527672cf33" class="external-link" target="_blank">FastAPI — Google as an external authentication provider</a> by <a href="https://medium.com/@nils_29588" class="external-link" target="_blank">Nils de Bruin</a>.
|
||||
|
||||
* <a href="https://medium.com/data-rebels/fastapi-how-to-add-basic-and-cookie-authentication-a45c85ef47d3" class="external-link" target="_blank">FastAPI — How to add basic and cookie authentication</a> by <a href="https://medium.com/@nils_29588" class="external-link" target="_blank">Nils de Bruin</a>.
|
||||
|
||||
* <a href="https://dev.to/errietta/introduction-to-the-fastapi-python-framework-2n10" class="external-link" target="_blank">Introduction to the fastapi python framework</a> by <a href="https://dev.to/errietta" class="external-link" target="_blank">Errieta Kostala</a>.
|
||||
|
||||
* <a href="http://nickc1.github.io/api,/scikit-learn/2019/01/10/scikit-fastapi.html" class="external-link" target="_blank">FastAPI and Scikit-Learn: Easily Deploy Models</a> by <a href="http://nickc1.github.io/" class="external-link" target="_blank">Nick Cortale</a>.
|
||||
|
||||
* <a href="https://medium.com/data-rebels/fastapi-authentication-revisited-enabling-api-key-authentication-122dc5975680" class="external-link" target="_blank">FastAPI authentication revisited: Enabling API key authentication</a> by <a href="https://medium.com/@nils_29588" class="external-link" target="_blank">Nils de Bruin</a>.
|
||||
|
||||
* <a href="https://medium.com/@nico.axtmann95/deploying-a-scikit-learn-model-with-onnx-und-fastapi-1af398268915" class="external-link" target="_blank">Deploying a scikit-learn model with ONNX and FastAPI</a> by <a href="https://www.linkedin.com/in/nico-axtmann" class="external-link" target="_blank">Nico Axtmann</a>.
|
||||
|
||||
* <a href="https://geekflare.com/python-asynchronous-web-frameworks/" class="external-link" target="_blank">Top 5 Asynchronous Web Frameworks for Python</a> by <a href="https://geekflare.com/author/ankush/" class="external-link" target="_blank">Ankush Thakur</a> on <a href="https://geekflare.com" class="external-link" target="_blank">GeekFlare</a>.
|
||||
|
||||
* <a href="https://medium.com/@gntrm/jwt-authentication-with-fastapi-and-aws-cognito-1333f7f2729e" class="external-link" target="_blank">JWT Authentication with FastAPI and AWS Cognito</a> by <a href="https://twitter.com/gntrm" class="external-link" target="_blank">Johannes Gontrum</a>.
|
||||
|
||||
* <a href="https://towardsdatascience.com/how-to-deploy-a-machine-learning-model-dc51200fe8cf" class="external-link" target="_blank">How to Deploy a Machine Learning Model</a> by <a href="https://www.linkedin.com/in/mgrootendorst/" class="external-link" target="_blank">Maarten Grootendorst</a> on <a href="https://towardsdatascience.com/" class="external-link" target="_blank">Towards Data Science</a>.
|
||||
|
||||
* [Uber: Ludwig v0.2 Adds New Features and Other Improvements to its Deep Learning Toolbox [including a FastAPI server]](https://eng.uber.com/ludwig-v0-2/){.external-link target=_blank} on <a href="https://eng.uber.com" class="external-link" target="_blank">Uber Engineering</a>.
|
||||
|
||||
* <a href="https://gitlab.com/euri10/fastapi_cheatsheet" class="external-link" target="_blank">A FastAPI and Swagger UI visual cheatsheet</a> by <a href="https://gitlab.com/euri10" class="external-link" target="_blank">@euri10</a>
|
||||
|
||||
* <a href="https://medium.com/@mike.p.moritz/using-docker-compose-to-deploy-a-lightweight-python-rest-api-with-a-job-queue-37e6072a209b" class="external-link" target="_blank">Using Docker Compose to deploy a lightweight Python REST API with a job queue</a> by <a href="https://medium.com/@mike.p.moritz" class="external-link" target="_blank">Mike Moritz</a>.
|
||||
|
||||
* <a href="https://robwagner.dev/tortoise-fastapi-setup/" class="external-link" target="_blank">Setting up Tortoise ORM with FastAPI</a> by <a href="https://robwagner.dev/" class="external-link" target="_blank">Rob Wagner</a>.
|
||||
|
||||
* <a href="https://dev.to/dbanty/why-i-m-leaving-flask-3ki6" class="external-link" target="_blank">Why I'm Leaving Flask</a> by <a href="https://dev.to/dbanty" class="external-link" target="_blank">Dylan Anthony</a>.
|
||||
|
||||
* <a href="https://medium.com/python-data/how-to-deploy-tensorflow-2-0-models-as-an-api-service-with-fastapi-docker-128b177e81f3" class="external-link" target="_blank">How To Deploy Tensorflow 2.0 Models As An API Service With FastAPI & Docker</a> by <a href="https://medium.com/@bbrenyah" class="external-link" target="_blank">Bernard Brenyah</a>.
|
||||
|
||||
* <a href="https://testdriven.io/blog/fastapi-crud/" class="external-link" target="_blank">TestDriven.io: Developing and Testing an Asynchronous API with FastAPI and Pytest</a> by <a href="https://testdriven.io/authors/herman/" class="external-link" target="_blank">Michael Herman</a>.
|
||||
|
||||
* <a href="https://towardsdatascience.com/deploying-iris-classifications-with-fastapi-and-docker-7c9b83fdec3a" class="external-link" target="_blank">Towards Data Science: Deploying Iris Classifications with FastAPI and Docker</a> by <a href="https://towardsdatascience.com/@mandygu" class="external-link" target="_blank">Mandy Gu</a>.
|
||||
|
||||
* <a href="https://medium.com/analytics-vidhya/deploy-machine-learning-models-with-keras-fastapi-redis-and-docker-4940df614ece" class="external-link" target="_blank">Deploy Machine Learning Models with Keras, FastAPI, Redis and Docker</a> by <a href="https://medium.com/@shane.soh" class="external-link" target="_blank">Shane Soh</a>.
|
||||
|
||||
* <a href="https://medium.com/@arthur393/another-boilerplate-to-fastapi-azure-pipeline-ci-pytest-3c8d9a4be0bb" class="external-link" target="_blank">Another Boilerplate to FastAPI: Azure Pipeline CI + Pytest</a> by <a href="https://twitter.com/arthurheinrique" class="external-link" target="_blank">Arthur Henrique</a>.
|
||||
|
||||
* <a href="https://iwpnd.pw/articles/2020-01/deploy-fastapi-to-aws-lambda" class="external-link" target="_blank">How to continuously deploy a FastAPI to AWS Lambda with AWS SAM</a> by <a href="https://iwpnd.pw" class="external-link" target="_blank">Benjamin Ramser</a>.
|
||||
|
||||
* <a href="https://www.tutlinks.com/create-and-deploy-fastapi-app-to-heroku/" class="external-link" target="_blank">Create and Deploy FastAPI app to Heroku without using Docker</a> by <a href="https://www.linkedin.com/in/navule/" class="external-link" target="_blank">Navule Pavan Kumar Rao</a>.
|
||||
|
||||
* <a href="https://iwpnd.pw/articles/2020-03/apache-kafka-fastapi-geostream" class="external-link" target="_blank">Apache Kafka producer and consumer with FastAPI and aiokafka</a> by <a href="https://iwpnd.pw" class="external-link" target="_blank">Benjamin Ramser</a>.
|
||||
|
||||
* <a href="https://wuilly.com/2019/10/real-time-notifications-with-python-and-postgres/" class="external-link" target="_blank">Real-time Notifications with Python and Postgres</a> by <a href="https://wuilly.com/" class="external-link" target="_blank">Guillermo Cruz</a>.
|
||||
|
||||
* <a href="https://dev.to/paurakhsharma/microservice-in-python-using-fastapi-24cc" class="external-link" target="_blank">Microservice in Python using FastAPI</a> by <a href="https://twitter.com/PaurakhSharma" class="external-link" target="_blank">Paurakh Sharma Humagain</a>.
|
||||
|
||||
* <a href="https://dev.to/cuongld2/build-simple-api-service-with-python-fastapi-part-1-581o" class="external-link" target="_blank">Build simple API service with Python FastAPI — Part 1</a> by <a href="https://dev.to/cuongld2" class="external-link" target="_blank">cuongld2</a>.
|
||||
|
||||
* <a href="https://paulsec.github.io/posts/fastapi_plus_zeit_serverless_fu/" class="external-link" target="_blank">FastAPI + Zeit.co = 🚀
|
||||
</a> by <a href="https://twitter.com/PaulWebSec" class="external-link" target="_blank">Paul Sec</a>.
|
||||
|
||||
* <a href="https://dev.to/tiangolo/build-a-web-api-from-scratch-with-fastapi-the-workshop-2ehe" class="external-link" target="_blank">Build a web API from scratch with FastAPI - the workshop</a> by <a href="https://twitter.com/tiangolo" class="external-link" target="_blank">Sebastián Ramírez (tiangolo)</a>.
|
||||
|
||||
* <a href="https://www.twilio.com/blog/build-secure-twilio-webhook-python-fastapi" class="external-link" target="_blank">Build a Secure Twilio Webhook with Python and FastAPI</a> by <a href="https://www.twilio.com" class="external-link" target="_blank">Twilio</a>.
|
||||
|
||||
* <a href="https://www.stavros.io/posts/fastapi-with-django/" class="external-link" target="_blank">Using FastAPI with Django</a> by <a href="https://twitter.com/Stavros" class="external-link" target="_blank">Stavros Korokithakis</a>.
|
||||
|
||||
* <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" class="external-link" target="_blank">Introducing Dispatch</a> by <a href="https://netflixtechblog.com/" class="external-link" target="_blank">Netflix</a>.
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Japanese
|
||||
|
||||
* <a href="https://qiita.com/mtitg/items/47770e9a562dd150631d" class="external-link" target="_blank">FastAPI|DB接続してCRUDするPython製APIサーバーを構築</a> by <a href="https://qiita.com/mtitg" class="external-link" target="_blank">@mtitg</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.japanese %}
|
||||
|
||||
* <a href="https://qiita.com/ryoryomaru/items/59958ed385b3571d50de" class="external-link" target="_blank">python製の最新APIフレームワーク FastAPI を触ってみた</a> by <a href="https://qiita.com/ryoryomaru" class="external-link" target="_blank">@ryoryomaru</a>.
|
||||
|
||||
* <a href="https://qiita.com/angel_katayoku/items/0e1f5dbbe62efc612a78" class="external-link" target="_blank">FastAPIでCORSを回避</a> by <a href="https://qiita.com/angel_katayoku" class="external-link" target="_blank">@angel_katayoku</a>.
|
||||
|
||||
* <a href="https://qiita.com/angel_katayoku/items/4fbc1a4e2b33fa2237d2" class="external-link" target="_blank">FastAPIをMySQLと接続してDockerで管理してみる</a> by <a href="https://qiita.com/angel_katayoku" class="external-link" target="_blank">@angel_katayoku</a>.
|
||||
|
||||
* <a href="https://qiita.com/angel_katayoku/items/8a458a8952f50b73f420" class="external-link" target="_blank">FastAPIでPOSTされたJSONのレスポンスbodyを受け取る</a> by <a href="https://qiita.com/angel_katayoku" class="external-link" target="_blank">@angel_katayoku</a>.
|
||||
|
||||
* <a href="https://qiita.com/hikarut/items/b178af2e2440c67c6ac4" class="external-link" target="_blank">フロントエンド開発者向けのDockerによるPython開発環境構築</a> by <a href="https://qiita.com/hikarut" class="external-link" target="_blank">Hikaru Takahashi</a>.
|
||||
|
||||
* <a href="https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-environment" class="external-link" target="_blank">【第1回】FastAPIチュートリアル: ToDoアプリを作ってみよう【環境構築編】</a> by <a href="https://rightcode.co.jp/author/jun" class="external-link" target="_blank">ライトコードメディア編集部</a>
|
||||
|
||||
* <a href="https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-model-building" class="external-link" target="_blank">【第2回】FastAPIチュートリアル: ToDoアプリを作ってみよう【モデル構築編】</a> by <a href="https://rightcode.co.jp/author/jun" class="external-link" target="_blank">ライトコードメディア編集部</a>
|
||||
|
||||
* <a href="https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-authentication-user-registration" class="external-link" target="_blank">【第3回】FastAPIチュートリアル: toDoアプリを作ってみよう【認証・ユーザ登録編】</a> by <a href="https://rightcode.co.jp/author/jun" class="external-link" target="_blank">ライトコードメディア編集部</a>
|
||||
|
||||
* <a href="https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-admin-page-improvement" class="external-link" target="_blank">【第4回】FastAPIチュートリアル: toDoアプリを作ってみよう【管理者ページ改良編】</a> by <a href="https://rightcode.co.jp/author/jun" class="external-link" target="_blank">ライトコードメディア編集部</a>
|
||||
|
||||
* <a href="https://qiita.com/bee2/items/0ad260ab9835a2087dae" class="external-link" target="_blank">PythonのWeb frameworkのパフォーマンス比較 (Django, Flask, responder, FastAPI, japronto)</a> by <a href="https://qiita.com/bee2" class="external-link" target="_blank">@bee2</a>.
|
||||
|
||||
* <a href="https://qiita.com/bee2/items/75d9c0d7ba20e7a4a0e9" class="external-link" target="_blank">[FastAPI] Python製のASGI Web フレームワーク FastAPIに入門する</a> by <a href="https://qiita.com/bee2" class="external-link" target="_blank">@bee2</a>.
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Vietnamese
|
||||
|
||||
* <a href="https://fullstackstation.com/fastapi-trien-khai-bang-docker/" class="external-link" target="_blank">FASTAPI: TRIỂN KHAI BẰNG DOCKER</a> by <a href="https://fullstackstation.com/author/figonking/" class="external-link" target="_blank">Nguyễn Nhân</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.vietnamese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Russian
|
||||
|
||||
* <a href="https://habr.com/ru/post/454440/" class="external-link" target="_blank">Мелкая питонячая радость #2: Starlette - Солидная примочка – FastAPI</a> by <a href="https://habr.com/ru/users/57uff3r/" class="external-link" target="_blank">Andrey Korchak</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.russian %}
|
||||
|
||||
* <a href="https://habr.com/ru/post/478620/" class="external-link" target="_blank">Почему Вы должны попробовать FastAPI?</a> by <a href="https://github.com/prostomarkeloff" class="external-link" target="_blank">prostomarkeloff</a>.
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### German
|
||||
|
||||
* <a href="https://blog.codecentric.de/2019/08/inbetriebnahme-eines-scikit-learn-modells-mit-onnx-und-fastapi/" class="external-link" target="_blank">Inbetriebnahme eines scikit-learn-Modells mit ONNX und FastAPI</a> by <a href="https://twitter.com/_nicoax" class="external-link" target="_blank">Nico Axtmann</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.german %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Podcasts
|
||||
|
||||
* <a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" class="external-link" target="_blank">FastAPI on PythonBytes</a> by <a href="https://pythonbytes.fm/" class="external-link" target="_blank">Python Bytes FM</a>.
|
||||
* <a href="https://www.pythonpodcast.com/fastapi-web-application-framework-episode-259/" class="external-link" target="_blank">Build The Next Generation Of Python Web Applications With FastAPI - Episode 259 - interview to Sebastían Ramírez (tiangolo)</a> by <a href="https://www.pythonpodcast.com/" class="external-link" target="_blank">Podcast.`__init__`</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.podcasts.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Talks
|
||||
|
||||
* <a href="https://www.youtube.com/watch?v=3DLwPcrE5mA" class="external-link" target="_blank">PyCon UK 2019: FastAPI from the ground up</a> by <a href="https://twitter.com/chriswithers13" class="external-link" target="_blank">Chris Withers</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.talks.english %}
|
||||
|
||||
* <a href="https://www.youtube.com/watch?v=z9K5pwb0rt8" class="external-link" target="_blank">PyConBY 2020: Serve ML models easily with FastAPI</a> by <a href="https://twitter.com/tiangolo" class="external-link" target="_blank">Sebastián Ramírez (tiangolo)</a>.
|
||||
|
||||
* <a href="https://www.youtube.com/watch?v=PnpTY1f4k2U" class="external-link" target="_blank">[VIRTUAL] Py.Amsterdam's flying Software Circus: Intro to FastAPI</a> by <a href="https://twitter.com/tiangolo" class="external-link" target="_blank">Sebastián Ramírez (tiangolo)</a>.
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Projects
|
||||
|
||||
|
||||
155
docs/en/docs/fastapi-people.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# FastAPI People
|
||||
|
||||
FastAPI has an amazing community that welcomes people from all backgrounds.
|
||||
|
||||
## Creator - Maintainer
|
||||
|
||||
Hey! 👋
|
||||
|
||||
This is me:
|
||||
|
||||
{% if people %}
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.maintainers %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Answers: {{ user.answers }}</div><div class="count">Pull Requests: {{ user.prs }}</div></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
I'm the creator and maintainer of **FastAPI**. You can read more about that in [Help FastAPI - Get Help - Connect with the author](help-fastapi.md#connect-with-the-author){.internal-link target=_blank}.
|
||||
|
||||
...But here I want to show you the community.
|
||||
|
||||
---
|
||||
|
||||
**FastAPI** receives a lot of support from the community. And I want to highlight their contributions.
|
||||
|
||||
These are the people that:
|
||||
|
||||
* [Help others with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank}.
|
||||
* [Create Pull Requests](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}.
|
||||
* Review Pull Requests, [especially important for translations](contributing.md#translations){.internal-link target=_blank}.
|
||||
|
||||
A round of applause to them. 👏 🙇
|
||||
|
||||
## Most active users last month
|
||||
|
||||
These are the users that have been [helping others the most with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} during the last month. ☕
|
||||
|
||||
{% if people %}
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.last_month_active %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Issues replied: {{ user.count }}</div></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
## Experts
|
||||
|
||||
Here are the **FastAPI Experts**. 🤓
|
||||
|
||||
These are the users that have [helped others the most with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} through *all time*.
|
||||
|
||||
They have proven to be experts by helping many others. ✨
|
||||
|
||||
{% if people %}
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.experts %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Issues replied: {{ user.count }}</div></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
## Top Contributors
|
||||
|
||||
Here are the **Top Contributors**. 👷
|
||||
|
||||
These users have [created the most Pull Requests](help-fastapi.md#create-a-pull-request){.internal-link target=_blank} that have been *merged*.
|
||||
|
||||
They have contributed source code, documentation, translations, etc. 📦
|
||||
|
||||
{% if people %}
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.top_contributors %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Pull Requests: {{ user.count }}</div></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
There are many other contributors (more than a hundred), you can see them all in the <a href="https://github.com/tiangolo/fastapi/graphs/contributors" class="external-link" target="_blank">FastAPI GitHub Contributors page</a>. 👷
|
||||
|
||||
## Top Reviewers
|
||||
|
||||
These users are the **Top Reviewers**. 🕵️
|
||||
|
||||
### Reviews for Translations
|
||||
|
||||
I only speak a few languages (and not very well 😅). So, the reviewers are the ones that have the [**power to approve translations**](contributing.md#translations){.internal-link target=_blank} of the documentation. Without them, there wouldn't be documentation in several other languages.
|
||||
|
||||
---
|
||||
|
||||
The **Top Reviewers** 🕵️ have reviewed the most Pull Requests from others, ensuring the quality of the code, documentation, and especially, the **translations**.
|
||||
|
||||
{% if people %}
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.top_reviewers %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Reviews: {{ user.count }}</div></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
## Sponsors
|
||||
|
||||
These are the **Sponsors**. 😎
|
||||
|
||||
They are supporting my work with **FastAPI** (and others), mainly through <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub Sponsors</a>.
|
||||
|
||||
### Gold Sponsors
|
||||
|
||||
{% if sponsors %}
|
||||
{% for sponsor in sponsors.gold -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Silver Sponsors
|
||||
|
||||
{% if sponsors %}
|
||||
{% for sponsor in sponsors.silver -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Individual Sponsors
|
||||
|
||||
{% if people %}
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.sponsors %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
## About the data - technical details
|
||||
|
||||
The main intention of this page is to highlight the effort of the community to help others.
|
||||
|
||||
Especially including efforts that are normally less visible, and in many cases more arduous, like helping others with issues and reviewing Pull Requests with translations.
|
||||
|
||||
The data is calculated each month, you can read the <a href="https://github.com/tiangolo/fastapi/blob/master/.github/actions/people/app/main.py" class="external-link" target="_blank">source code here</a>.
|
||||
|
||||
Here I'm also highlighting contributions from sponsors.
|
||||
|
||||
I also reserve the right to update the algorithm, sections, thresholds, etc (just in case 🤷).
|
||||
@@ -7,7 +7,7 @@
|
||||
### Based on open standards
|
||||
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> for API creation, including declarations of <abbr title="also known as: endpoints, routes">path</abbr> <abbr title="also known as HTTP methods, as POST, GET, PUT, DELETE">operations</abbr>, parameters, body requests, security, etc.
|
||||
* Automatic data model documentation with <a href="http://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (as OpenAPI itself is based on JSON Schema).
|
||||
* Automatic data model documentation with <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (as OpenAPI itself is based on JSON Schema).
|
||||
* Designed around these standards, after a meticulous study. Instead of an afterthought layer on top.
|
||||
* This also allows using automatic **client code generation** in many languages.
|
||||
|
||||
|
||||
BIN
docs/en/docs/img/deployment/deta/image01.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
docs/en/docs/img/deployment/deta/image02.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
99
docs/en/docs/img/sponsors/deta.svg
Normal file
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="240"
|
||||
height="100"
|
||||
viewBox="0 0 240 100"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg19">
|
||||
<metadata
|
||||
id="metadata23">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs17">
|
||||
<rect
|
||||
x="-491.25317"
|
||||
y="-261.21402"
|
||||
width="476.65652"
|
||||
height="212.95724"
|
||||
id="rect1716" />
|
||||
<clipPath
|
||||
id="clip0">
|
||||
<rect
|
||||
width="770"
|
||||
height="222.03999"
|
||||
fill="#ffffff"
|
||||
id="rect14"
|
||||
x="0"
|
||||
y="0" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
id="text1714"
|
||||
style="font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect1716);"
|
||||
transform="translate(44.332916,-25.667084)" />
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:none;stroke-width:1.60003;stop-color:#000000"
|
||||
id="rect1756"
|
||||
width="240"
|
||||
height="100"
|
||||
x="0"
|
||||
y="0" />
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:none;stroke-width:1.52703;stop-color:#000000"
|
||||
id="rect1758"
|
||||
width="230"
|
||||
height="90"
|
||||
x="5"
|
||||
y="5" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:16px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;stroke-width:0.489974"
|
||||
x="5.046875"
|
||||
y="81.521378"
|
||||
id="text1712"><tspan
|
||||
id="tspan1710"
|
||||
x="5.046875"
|
||||
y="81.521378"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.489974">Deploy your FastAPI app for free</tspan></text>
|
||||
<g
|
||||
clip-path="url(#clip0)"
|
||||
id="g12"
|
||||
transform="matrix(0.19133908,0,0,0.19133908,46.334454,11.992465)">
|
||||
<path
|
||||
d="m 111.14,0 c 61.38,0 111.139,49.7054 111.139,111.02 0,61.315 -49.759,111.02 -111.139,111.02 C 49.7589,222.04 0,172.335 0,111.02 0,49.7054 49.7589,0 111.14,0 Z"
|
||||
fill="#ef39a8"
|
||||
id="path2" />
|
||||
<path
|
||||
d="m 111.404,21.6757 c 49.689,0 89.97,40.2376 89.97,89.8733 0,49.636 -40.281,89.873 -89.97,89.873 -49.689,0 -89.9702,-40.237 -89.9702,-89.873 0,-49.6357 40.2812,-89.8733 89.9702,-89.8733 z"
|
||||
fill="#bd399c"
|
||||
id="path4" />
|
||||
<path
|
||||
d="m 111.404,45.4653 c 36.536,0 66.154,29.5861 66.154,66.0837 0,36.497 -29.618,66.083 -66.154,66.083 -36.536,0 -66.154,-29.586 -66.154,-66.083 0,-36.4976 29.618,-66.0837 66.154,-66.0837 z"
|
||||
fill="#93388e"
|
||||
id="path6" />
|
||||
<path
|
||||
d="m 110.874,65.5554 c 24.844,0 44.985,20.1184 44.985,44.9366 0,24.817 -20.141,44.936 -44.985,44.936 -24.8437,0 -44.9846,-20.119 -44.9846,-44.936 0,-24.8182 20.1409,-44.9366 44.9846,-44.9366 z"
|
||||
fill="#6030a2"
|
||||
id="path8" />
|
||||
<path
|
||||
d="m 339,170.836 h 49.915 c 23.004,0 40.365,-5.842 51.867,-17.745 11.719,-11.902 17.579,-25.752 17.579,-41.983 0,-16.2301 -5.86,-30.2964 -17.579,-42.1987 C 429.28,57.007 411.919,51.1641 388.915,51.1641 H 339 Z m 96.574,-59.728 c 0,11.686 -3.907,21.641 -11.719,29.864 -7.596,8.007 -19.315,12.119 -34.94,12.119 H 361.136 V 68.9093 h 27.779 c 15.625,0 27.344,4.1117 34.94,12.1186 7.812,8.2235 11.719,18.1781 11.719,30.0801 z m 40.582,10.388 c 0,30.08 19.098,51.504 52.302,51.504 22.136,0 39.931,-10.604 47.744,-30.513 h -24.523 c -5.426,8.44 -13.022,12.768 -23.221,12.768 -16.928,0 -27.778,-10.82 -29.732,-27.7 h 79.212 v -6.059 c 0,-29.6478 -19.966,-51.5047 -50.782,-51.5047 -31.034,0 -51,21.2077 -51,51.5047 z m 78.995,-8.224 h -56.208 c 2.388,-14.9316 11.936,-25.5355 28.213,-25.5355 15.843,0 25.608,10.3875 27.995,25.5355 z m 73.353,20.992 V 88.3857 h 24.957 V 72.1553 H 628.504 V 49 h -21.702 v 23.1553 h -16.06 v 16.2304 h 16.06 v 45.8783 c 0,14.499 3.038,24.237 9.332,29.431 6.293,5.193 15.191,7.79 26.693,7.79 3.69,0 6.944,-0.216 9.766,-0.865 l 4.123,-0.866 v -17.096 l -4.123,0.433 c -2.822,0.433 -6.076,0.649 -9.766,0.649 -11.719,0 -14.323,-6.059 -14.323,-19.476 z m 93.101,-63.6235 c -14.54,0 -25.825,3.0297 -33.638,9.3055 -8.029,6.2757 -11.936,13.8499 -11.936,22.723 h 22.136 c 0,-10.3879 11.719,-14.2833 23.438,-14.2833 14.757,0 23.872,5.1937 23.872,18.8273 v 6.059 h -26.693 c -26.259,0 -46.659,6.709 -46.659,28.782 0,20.342 15.625,30.946 38.847,30.946 14.973,0 25.607,-3.679 31.901,-11.037 l 3.039,-3.678 c 0,4.111 1.735,10.387 2.386,12.551 H 770 v -1.731 l -1.519,-4.761 c -0.868,-3.246 -1.302,-8.223 -1.302,-15.148 v -38.088 c 0,-28.998 -16.493,-40.4675 -45.574,-40.4675 z m 23.872,57.1305 c 0,19.693 -9.982,29.864 -28.863,29.864 -12.37,0 -22.354,-4.111 -22.354,-14.499 0,-11.902 10.852,-15.365 24.524,-15.581 z"
|
||||
fill="#000000"
|
||||
id="path10" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
235
docs/en/docs/img/sponsors/testdriven.svg
Normal file
@@ -0,0 +1,235 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="63.5mm"
|
||||
height="26.458334mm"
|
||||
viewBox="0 0 63.5 26.458334"
|
||||
version="1.1"
|
||||
id="svg975"
|
||||
inkscape:version="1.0.1 (1.0.1+r73)"
|
||||
sodipodi:docname="testdriven.svg">
|
||||
<defs
|
||||
id="defs969">
|
||||
<clipPath
|
||||
id="clip0">
|
||||
<rect
|
||||
width="770"
|
||||
height="222.03999"
|
||||
fill="#ffffff"
|
||||
id="rect14"
|
||||
x="0"
|
||||
y="0" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2"
|
||||
inkscape:cx="133.05705"
|
||||
inkscape:cy="115.91792"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1025"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata972">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-75.455132,-135.96141)">
|
||||
<rect
|
||||
style="fill:#212529;fill-opacity:1;stroke:none;stroke-width:0.364576;stop-color:#000000"
|
||||
id="rect901"
|
||||
width="63.5"
|
||||
height="26.458334"
|
||||
x="75.455132"
|
||||
y="135.96141" />
|
||||
<rect
|
||||
style="fill:#212529;fill-opacity:1;stroke:none;stroke-width:0.404023;stop-color:#000000"
|
||||
id="rect1758"
|
||||
width="60.854168"
|
||||
height="23.8125"
|
||||
x="76.778053"
|
||||
y="137.28433" />
|
||||
<g
|
||||
id="g1648"
|
||||
transform="matrix(0.40937885,0,0,0.40937885,80.597548,138.01872)">
|
||||
<path
|
||||
d="M 1.6,4.62 3.2,5.54 11.19,0.92 9.59,0 Z m 9.59,-3.7 1.6,-0.92 8,4.62 -1.6,0.92 z m 9.6,5.54 -1.6,-0.92 -8,4.61 1.6,0.93 z m -9.6,3.69 -1.6,0.93 L 1.6,6.46 3.2,5.54 Z"
|
||||
fill="#d2edf3"
|
||||
id="path1538" />
|
||||
<path
|
||||
d="m 11.19,23.08 1.6,-0.93 v -9.23 l -1.6,0.93 z m 1.6,-10.16 v -1.84 l 8,-4.62 v 1.85 z m 9.59,-5.54 -1.59,0.93 -0.01,9.23 1.6,-0.93 z m -1.6,10.16 v 1.84 L 12.79,24 v -1.85 z"
|
||||
fill="#76cede"
|
||||
id="path1540" />
|
||||
<path
|
||||
d="m 11.19,23.08 -1.6,-0.93 v -9.23 l 1.6,0.93 z M 9.59,12.92 V 11.08 L 1.6,6.46 V 8.31 Z M 0,7.38 1.6,8.31 v 9.23 L 0,16.61 Z m 1.6,10.16 v 1.84 L 9.59,24 v -1.85 z"
|
||||
fill="#339999"
|
||||
id="path1542" />
|
||||
<path
|
||||
d="m 11.19,10.15 -1.6,0.93 v 1.84 L 11.19,12 Z"
|
||||
fill="#76cede"
|
||||
id="path1544" />
|
||||
<path
|
||||
d="m 9.59,12.92 1.6,0.93 1.6,-0.93 -1.6,-0.92 z"
|
||||
fill="#d2edf3"
|
||||
id="path1546" />
|
||||
<path
|
||||
d="M 11.19,10.15 V 12 l 1.6,0.92 v -1.84 z"
|
||||
fill="#339999"
|
||||
id="path1548" />
|
||||
<path
|
||||
d="m 20.78,17.54 -1.6,-0.92 -6.39,3.69 v 1.85 z m -19.18,0 1.6,-0.92 6.39,3.69 v 1.85 z"
|
||||
fill="#d2edf3"
|
||||
id="path1550" />
|
||||
<path
|
||||
d="m 1.6,8.31 1.6,0.92 v 7.38 l -1.6,0.93 z"
|
||||
fill="#76cede"
|
||||
id="path1552" />
|
||||
<path
|
||||
d="m 20.79,8.31 -1.6,0.92 v 7.38 l 1.59,0.93 z"
|
||||
fill="#339999"
|
||||
id="path1554" />
|
||||
<path
|
||||
d="M 11.19,0.92 V 2.77 L 4.8,6.46 3.2,5.54 Z"
|
||||
fill="#76cede"
|
||||
id="path1556" />
|
||||
<path
|
||||
d="m 11.19,0.92 v 1.85 l 6.39,3.69 1.61,-0.92 z"
|
||||
fill="#339999"
|
||||
id="path1558" />
|
||||
<path
|
||||
d="m 4.8,13.85 -1.6,0.92 v 1.84 l 1.6,-0.92 z"
|
||||
fill="#d2edf3"
|
||||
id="path1560" />
|
||||
<path
|
||||
d="M 3.2,16.61 4.8,17.54 6.4,16.61 4.8,15.69 Z"
|
||||
fill="#76cede"
|
||||
id="path1562" />
|
||||
<path
|
||||
d="m 4.8,13.85 v 1.84 l 1.6,0.92 v -1.84 z"
|
||||
fill="#339999"
|
||||
id="path1564" />
|
||||
<path
|
||||
d="m 9.59,5.54 1.6,0.92 1.6,-0.92 -1.6,-0.93 z"
|
||||
fill="#d2edf3"
|
||||
id="path1566" />
|
||||
<path
|
||||
d="M 12.79,5.54 V 3.69 l -1.6,-0.92 v 1.84 z"
|
||||
fill="#76cede"
|
||||
id="path1568" />
|
||||
<path
|
||||
d="m 9.59,5.54 1.6,-0.93 V 2.77 l -1.6,0.92 z"
|
||||
fill="#339999"
|
||||
id="path1570" />
|
||||
<path
|
||||
d="m 15.99,16.61 1.6,0.93 1.6,-0.93 -1.6,-0.92 z"
|
||||
fill="#76cede"
|
||||
id="path1572" />
|
||||
<path
|
||||
d="m 19.19,16.61 v -1.84 l -1.6,-0.92 v 1.84 z"
|
||||
fill="#d2edf3"
|
||||
id="path1574" />
|
||||
<path
|
||||
d="m 15.99,16.61 1.6,-0.92 v -1.84 l -1.6,0.92 z"
|
||||
fill="#339999"
|
||||
id="path1576" />
|
||||
<path
|
||||
d="M 9.59,12.92 6.4,14.77 v 1.84 l 3.19,-1.84 z"
|
||||
fill="#76cede"
|
||||
id="path1578" />
|
||||
<path
|
||||
d="M 9.59,12.92 6.4,14.77 4.8,13.85 8,12 Z"
|
||||
fill="#d2edf3"
|
||||
id="path1580" />
|
||||
<path
|
||||
d="M 11.19,10.15 V 6.46 L 9.59,5.54 v 3.69 z"
|
||||
fill="#339999"
|
||||
id="path1582" />
|
||||
<path
|
||||
d="M 11.19,10.15 V 6.46 l 1.6,-0.92 v 3.69 z m 1.6,2.77 3.2,1.85 v 1.84 l -3.2,-1.84 z"
|
||||
fill="#76cede"
|
||||
id="path1584" />
|
||||
<path
|
||||
d="m 12.79,12.92 3.2,1.85 1.6,-0.92 -3.2,-1.85 z"
|
||||
fill="#d2edf3"
|
||||
id="path1586" />
|
||||
<path
|
||||
d="M 11.19,23.07 12.79,24 V 22.15 M 3.2,5.54 1.6,4.62 v 1.84"
|
||||
fill="#339999"
|
||||
id="path1588" />
|
||||
<path
|
||||
d="M 11.19,23.07 9.59,24 v -1.85"
|
||||
fill="#76cede"
|
||||
id="path1590" />
|
||||
<path
|
||||
d="m 20.79,6.46 1.6,0.92 -1.6,0.92 M 1.6,8.3 0,7.38 1.6,6.46"
|
||||
fill="#d2edf3"
|
||||
id="path1592" />
|
||||
<path
|
||||
d="m 19.19,5.54 1.6,-0.92 v 1.84"
|
||||
fill="#76cede"
|
||||
id="path1594" />
|
||||
<g
|
||||
fill="#ffffff"
|
||||
id="g1604">
|
||||
<path
|
||||
d="M 61.45,48.81 A 4.22,4.22 0 0 1 60.18,49 c -1.16,0 -1.5,-0.62 -1.5,-2.14 v -5.25 h 2.51 V 39.74 H 58.68 V 38.11 35 L 56,35.79 v 1.63 2.32 h -1.3 v 1.87 H 56 v 5.57 C 56,49.8 57.1,51 59.52,51 a 6.2,6.2 0 0 0 2.19,-0.34 z M 43.56,47.25 C 43.07,50.33 40.82,51 38.93,51 c -3.71,0 -5.17,-2.4 -5.17,-5.64 0,-3.62 2,-5.88 5.38,-5.88 3,0 4.55,1.87 4.55,5.08 0,0.36 0,0.82 -0.06,1.22 h -7.12 c 0,1.89 0.64,3.24 2.51,3.24 a 2.1,2.1 0 0 0 2.29,-2 z M 41.1,44 c 0.06,-1.72 -0.64,-2.7 -2.14,-2.7 -1.5,0 -2.36,1.27 -2.42,2.7 z M 71.58,35 V 51 H 70.26 V 49.16 A 3.77,3.77 0 0 1 66.88,51 c -2.64,0 -4.5,-1.54 -4.5,-5.55 0,-3.84 1.74,-5.92 4.65,-5.92 a 3.56,3.56 0 0 1 3.17,1.59 V 35 Z m -4.42,5.66 c -2.12,0 -3.32,1.57 -3.32,4.8 0,3.23 1.2,4.42 3.11,4.42 1.91,0 3.35,-1.16 3.35,-4.72 0,-3.56 -1.4,-4.5 -3.14,-4.5 z m 11.9,2.73 c 0.21,-2 -0.28,-2.42 -1.37,-2.42 -2,0 -2.72,1.87 -2.72,3.88 V 51 H 73.55 V 40 h 1.33 L 75,41.65 a 3.12,3.12 0 0 1 3,-1.87 c 1.69,0 2.77,1 2.38,3.54 z"
|
||||
transform="translate(0,-31)"
|
||||
id="path1596" />
|
||||
<path
|
||||
d="m 82.04,9.04 h 1.42 V 20 h -1.42 z m 0,-5.04 h 1.42 v 2.12 h -1.42 z"
|
||||
id="path1598" />
|
||||
<path
|
||||
d="m 88.78,51 -3.9,-11 h 1.46 L 89.45,49.18 92.51,40 H 94 l -4,11 z m 14.3,-3.69 A 3.81,3.81 0 0 1 99,51 c -3.6,0 -4.74,-2.47 -4.74,-5.64 0,-3.47 1.67,-5.83 4.93,-5.83 2.9,0 4.33,2.19 3.92,6 H 95.7 c 0,2.3 0.75,4.29 3.28,4.29 a 2.7,2.7 0 0 0 2.94,-2.66 z m -1.22,-2.87 c 0.06,-2.14 -0.69,-3.77 -2.9,-3.77 -2.21,0 -3.22,1.87 -3.26,3.77 z M 113.33,51 h -1.42 v -6.37 c 0,-2.6 -0.86,-3.67 -2.66,-3.67 -2.55,0 -3.24,1.93 -3.24,3.73 V 51 H 104.6 V 40 h 1.33 l 0.09,1.67 a 3.63,3.63 0 0 1 3.41,-1.93 c 2.53,0 3.9,1.48 3.9,4.65 z M 51,43.09 a 1.76,1.76 0 0 0 -1.93,-1.76 c -1.09,0 -1.78,0.36 -1.78,1.22 0,2.4 6.18,0.39 6.18,4.85 0,2.34 -2.14,3.6 -4.63,3.6 -2.7,0 -4.25,-1.39 -4.62,-3.73 l 2.37,-0.19 a 2.13,2.13 0 0 0 2.29,2.07 c 1.35,0 2,-0.6 2,-1.39 0,-2.53 -6.11,-0.51 -6.11,-4.85 0,-2.25 1.93,-3.43 4.35,-3.43 2.42,0 3.84,1.07 4.23,3.11 z M 33.14,48.81 A 4.22,4.22 0 0 1 31.87,49 c -1.16,0 -1.5,-0.62 -1.5,-2.14 v -5.25 h 2.51 V 39.74 H 30.37 V 38.11 35 l -2.66,0.79 v 1.63 2.32 h -1.33 v 1.87 h 1.33 v 5.57 c 0,2.62 1.07,3.82 3.5,3.82 a 6.2,6.2 0 0 0 2.19,-0.34 z m 87.47,-3.43 c 0,-3.67 2.08,-5.6 4.88,-5.6 2.8,0 4.5,1.89 4.5,5.39 C 130,49 128.26,51 125.26,51 c -3.18,0 -4.65,-2 -4.65,-5.62 z m 8,-0.08 c 0,-2.47 -0.88,-4.36 -3.22,-4.36 -2.34,0 -3.32,2 -3.32,4.42 0,2.42 0.84,4.51 3.28,4.51 2.44,0 3.23,-2.04 3.23,-4.57 z"
|
||||
transform="translate(0,-31)"
|
||||
id="path1600" />
|
||||
<path
|
||||
d="m 114.88,17.88 h 1.42 V 20 h -1.42 z m 2.86,-8.84 h 1.42 V 20 h -1.42 z m 0,-5.04 h 1.42 v 2.12 h -1.42 z"
|
||||
id="path1602" />
|
||||
</g>
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;stroke-width:0.133861"
|
||||
x="107.5555"
|
||||
y="154.45795"
|
||||
id="text1712"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1710"
|
||||
x="107.5555"
|
||||
y="154.45795"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333px;font-family:Roboto;-inkscape-font-specification:Roboto;text-align:center;text-anchor:middle;fill:#ffffff;stroke-width:0.133861">Learn Test-Driven Development </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="107.5555"
|
||||
y="159.79095"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333px;font-family:Roboto;-inkscape-font-specification:Roboto;text-align:center;text-anchor:middle;fill:#ffffff;stroke-width:0.133861"
|
||||
id="tspan2004">with FastAPI</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 61 KiB |
BIN
docs/en/docs/img/tutorial/behind-a-proxy/image03.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 76 KiB |
@@ -5,14 +5,14 @@
|
||||
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.com/tiangolo/fastapi" target="_blank">
|
||||
<img src="https://travis-ci.com/tiangolo/fastapi.svg?branch=master" alt="Build Status">
|
||||
<a href="https://github.com/tiangolo/fastapi/actions?query=workflow%3ATest" target="_blank">
|
||||
<img src="https://github.com/tiangolo/fastapi/workflows/Test/badge.svg" alt="Test">
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/tiangolo/fastapi" target="_blank">
|
||||
<img src="https://img.shields.io/codecov/c/github/tiangolo/fastapi" alt="Coverage">
|
||||
<img src="https://img.shields.io/codecov/c/github/tiangolo/fastapi?color=%2334D058" alt="Coverage">
|
||||
</a>
|
||||
<a href="https://pypi.org/project/fastapi" target="_blank">
|
||||
<img src="https://badge.fury.io/py/fastapi.svg" alt="Package version">
|
||||
<img src="https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package" alt="Package version">
|
||||
</a>
|
||||
<a href="https://gitter.im/tiangolo/fastapi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge" target="_blank">
|
||||
<img src="https://badges.gitter.im/tiangolo/fastapi.svg" alt="Join the chat at https://gitter.im/tiangolo/fastapi">
|
||||
@@ -39,10 +39,24 @@ The key features are:
|
||||
* **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: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
|
||||
<small>* estimation based on tests on an internal development team, building production applications.</small>
|
||||
|
||||
## Gold Sponsors
|
||||
|
||||
<!-- sponsors -->
|
||||
|
||||
{% if sponsors %}
|
||||
{% for sponsor in sponsors.gold -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">Other sponsors</a>
|
||||
|
||||
## Opinions
|
||||
|
||||
"_[...] 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._"
|
||||
@@ -71,7 +85,7 @@ The key features are:
|
||||
|
||||
"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="http://www.hug.rest/" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://www.hug.rest/" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
@@ -112,7 +126,7 @@ $ pip install fastapi
|
||||
|
||||
</div>
|
||||
|
||||
You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
|
||||
You will also need an ASGI server, for production such as <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -153,7 +167,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"
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
@@ -245,7 +259,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"
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
@@ -428,9 +442,9 @@ Used by Pydantic:
|
||||
|
||||
Used by Starlette:
|
||||
|
||||
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
||||
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
|
||||
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
||||
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
|
||||
@@ -439,7 +453,7 @@ Used by Starlette:
|
||||
|
||||
Used by FastAPI / Starlette:
|
||||
|
||||
* <a href="http://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - for the server that loads and serves your application.
|
||||
* <a href="https://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - for the server that loads and serves your application.
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Required if you want to use `ORJSONResponse`.
|
||||
|
||||
You can install all of these with `pip install fastapi[all]`.
|
||||
|
||||
@@ -20,7 +20,7 @@ GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" clas
|
||||
* **Easy**: Designed to be easy to use and learn. Less time reading docs.
|
||||
* **Short**: Minimize code duplication. Multiple features from each parameter declaration.
|
||||
* **Robust**: Get production-ready code. With automatic interactive documentation.
|
||||
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> and <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> and <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
* <a href="https://fastapi.tiangolo.com/features/" class="external-link" target="_blank">**Many other features**</a> including automatic validation, serialization, interactive documentation, authentication with OAuth2 JWT tokens, etc.
|
||||
* **Secure password** hashing by default.
|
||||
* **JWT token** authentication.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Python Types Intro
|
||||
|
||||
**Python 3.6+** has support for optional "type hints".
|
||||
Python has support for optional "type hints".
|
||||
|
||||
These **"type hints"** are a new syntax (since Python 3.6+) that allow declaring the <abbr title="for example: str, int, float, bool">type</abbr> of a variable.
|
||||
These **"type hints"** are a special syntax that allow declaring the <abbr title="for example: str, int, float, bool">type</abbr> of a variable.
|
||||
|
||||
By declaring types for your variables, editors and tools can give you better support.
|
||||
|
||||
@@ -193,7 +193,7 @@ And still, the editor knows it is a `str`, and provides support for that.
|
||||
|
||||
You would do the same to declare `tuple`s and `set`s:
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
```Python hl_lines="1 4"
|
||||
{!../../../docs_src/python_types/tutorial007.py!}
|
||||
```
|
||||
|
||||
@@ -210,7 +210,7 @@ The first type parameter is for the keys of the `dict`.
|
||||
|
||||
The second type parameter is for the values of the `dict`:
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
```Python hl_lines="1 4"
|
||||
{!../../../docs_src/python_types/tutorial008.py!}
|
||||
```
|
||||
|
||||
@@ -224,7 +224,7 @@ This means:
|
||||
|
||||
You can also use `Optional` to declare that a variable has a type, like `str`, but that it is "optional", which means that it could also be `None`:
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
```Python hl_lines="1 4"
|
||||
{!../../../docs_src/python_types/tutorial009.py!}
|
||||
```
|
||||
|
||||
@@ -249,7 +249,7 @@ You can also declare a class as the type of a variable.
|
||||
|
||||
Let's say you have a class `Person`, with a name:
|
||||
|
||||
```Python hl_lines="1 2 3"
|
||||
```Python hl_lines="1-3"
|
||||
{!../../../docs_src/python_types/tutorial010.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,6 +1,209 @@
|
||||
# Release Notes
|
||||
|
||||
## Latest changes
|
||||
## Latest Changes
|
||||
|
||||
* 📝 Fix image links for sponsors. PR [#2304](https://github.com/tiangolo/fastapi/pull/2304) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.61.2
|
||||
|
||||
### Fixes
|
||||
|
||||
* 📌 Relax Swagger UI version pin. PR [#2089](https://github.com/tiangolo/fastapi/pull/2089) by [@jmriebold](https://github.com/jmriebold).
|
||||
* 🐛 Fix bug overriding custom HTTPException and RequestValidationError from exception_handlers. PR [#1924](https://github.com/tiangolo/fastapi/pull/1924) by [@uriyyo](https://github.com/uriyyo).
|
||||
* ✏️ Fix typo on dependencies utils and cleanup unused variable. PR [#1912](https://github.com/tiangolo/fastapi/pull/1912) by [@Kludex](https://github.com/Kludex).
|
||||
|
||||
### Docs
|
||||
|
||||
* ✏️ Fix typo in Tutorial - Path Parameters. PR [#2231](https://github.com/tiangolo/fastapi/pull/2231) by [@mariacamilagl](https://github.com/mariacamilagl).
|
||||
* ✏ Fix a stylistic error in docs. PR [#2206](https://github.com/tiangolo/fastapi/pull/2206) by [@ddobrinskiy](https://github.com/ddobrinskiy).
|
||||
* ✏ Fix capitalizaiton typo in docs. PR [#2204](https://github.com/tiangolo/fastapi/pull/2204) by [@imba-tjd](https://github.com/imba-tjd).
|
||||
* ✏ Fix typo in docs. PR [#2179](https://github.com/tiangolo/fastapi/pull/2179) by [@ammarasmro](https://github.com/ammarasmro).
|
||||
* 📝 Update/fix links in docs to use HTTPS. PR [#2165](https://github.com/tiangolo/fastapi/pull/2165) by [@imba-tjd](https://github.com/imba-tjd).
|
||||
* ✏ Fix typos and add rewording in docs. PR [#2159](https://github.com/tiangolo/fastapi/pull/2159) by [@nukopy](https://github.com/nukopy).
|
||||
* 📝 Fix code consistency in examples for Tutorial - User Guide - Path Parameters. PR [#2158](https://github.com/tiangolo/fastapi/pull/2158) by [@nukopy](https://github.com/nukopy).
|
||||
* 📝 Fix renamed parameter `content_type` typo. PR [#2135](https://github.com/tiangolo/fastapi/pull/2135) by [@TeoZosa](https://github.com/TeoZosa).
|
||||
* ✏ Fix minor typos in docs. PR [#2122](https://github.com/tiangolo/fastapi/pull/2122) by [@TeoZosa](https://github.com/TeoZosa).
|
||||
* ✏ Fix typos in docs and source examples. PR [#2102](https://github.com/tiangolo/fastapi/pull/2102) by [@AdrianDeAnda](https://github.com/AdrianDeAnda).
|
||||
* ✏ Fix incorrect Celery URLs in docs. PR [#2100](https://github.com/tiangolo/fastapi/pull/2100) by [@CircleOnCircles](https://github.com/CircleOnCircles).
|
||||
* 📝 Simplify intro to Python Types, all currently supported Python versions include type hints 🎉. PR [#2085](https://github.com/tiangolo/fastapi/pull/2085) by [@ninjaaron](https://github.com/ninjaaron).
|
||||
* 📝 Fix example code with sets in Tutorial - Body - Nested Models 3. PR [#2054](https://github.com/tiangolo/fastapi/pull/2054) by [@hitrust](https://github.com/hitrust).
|
||||
* 📝 Fix example code with sets in Tutorial - Body - Nested Models 2. PR [#2053](https://github.com/tiangolo/fastapi/pull/2053) by [@hitrust](https://github.com/hitrust).
|
||||
* 📝 Fix example code with sets in Tutorial - Body - Nested Models. PR [#2052](https://github.com/tiangolo/fastapi/pull/2052) by [@hitrust](https://github.com/hitrust).
|
||||
* ✏ Fix typo in Benchmarks. PR [#1995](https://github.com/tiangolo/fastapi/pull/1995) by [@AlejoAsd](https://github.com/AlejoAsd).
|
||||
* 📝 Add note in CORS tutorial about allow_origins with ["*"] and allow_credentials. PR [#1895](https://github.com/tiangolo/fastapi/pull/1895) by [@dsmurrell](https://github.com/dsmurrell).
|
||||
* 📝 Add deployment to Deta, the first gold sponsor 🎉. PR [#2303](https://github.com/tiangolo/fastapi/pull/2303) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👥 Update FastAPI People. PR [#2282](https://github.com/tiangolo/fastapi/pull/2282) by [@github-actions[bot]](https://github.com/apps/github-actions).
|
||||
* ✏️ Fix uppercase in Tutorial - Query parameters. PR [#2245](https://github.com/tiangolo/fastapi/pull/2245) by [@mariacamilagl](https://github.com/mariacamilagl).
|
||||
* 📝 Add articles to External Links. PR [#2247](https://github.com/tiangolo/fastapi/pull/2247) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ✏ Fix typo in Spanish tutorial index. PR [#2020](https://github.com/tiangolo/fastapi/pull/2020) by [@aviloncho](https://github.com/aviloncho).
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Add Japanese translation for Advanced Tutorial - Response Directly. PR [#2191](https://github.com/tiangolo/fastapi/pull/2191) by [@Attsun1031](https://github.com/Attsun1031).
|
||||
* 📝 Add Japanese translation for Tutorial - Security - First Steps. PR [#2153](https://github.com/tiangolo/fastapi/pull/2153) by [@komtaki](https://github.com/komtaki).
|
||||
* 🌐 Add Japanese translation for Tutorial - Query Parameters and String Validations. PR [#1901](https://github.com/tiangolo/fastapi/pull/1901) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Portuguese translation for External Links. PR [#1443](https://github.com/tiangolo/fastapi/pull/1443) by [@Serrones](https://github.com/Serrones).
|
||||
* 🌐 Add Japanese translation for Tutorial - CORS. PR [#2125](https://github.com/tiangolo/fastapi/pull/2125) by [@tokusumi](https://github.com/tokusumi).
|
||||
* 🌐 Add Japanese translation for Contributing. PR [#2067](https://github.com/tiangolo/fastapi/pull/2067) by [@komtaki](https://github.com/komtaki).
|
||||
* 🌐 Add Japanese translation for Project Generation. PR [#2050](https://github.com/tiangolo/fastapi/pull/2050) by [@tokusumi](https://github.com/tokusumi).
|
||||
* 🌐 Add Japanese translation for Alternatives. PR [#2043](https://github.com/tiangolo/fastapi/pull/2043) by [@Attsun1031](https://github.com/Attsun1031).
|
||||
* 🌐 Add Japanese translation for History Design and Future. PR [#2002](https://github.com/tiangolo/fastapi/pull/2002) by [@komtaki](https://github.com/komtaki).
|
||||
* 🌐 Add Japanese translation for Benchmarks. PR [#1992](https://github.com/tiangolo/fastapi/pull/1992) by [@komtaki](https://github.com/komtaki).
|
||||
* 🌐 Add Japanese translation for Tutorial - Header Parameters. PR [#1935](https://github.com/tiangolo/fastapi/pull/1935) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Portuguese translation for Tutorial - First Steps. PR [#1861](https://github.com/tiangolo/fastapi/pull/1861) by [@jessicapaz](https://github.com/jessicapaz).
|
||||
* 🌐 Add Portuguese translation for Python Types. PR [#1796](https://github.com/tiangolo/fastapi/pull/1796) by [@izaguerreiro](https://github.com/izaguerreiro).
|
||||
* 🌐 Add Japanese translation for Help FastAPI. PR [#1692](https://github.com/tiangolo/fastapi/pull/1692) by [@tokusumi](https://github.com/tokusumi).
|
||||
* 🌐 Add Japanese translation for Tutorial - Body. PR [#1683](https://github.com/tiangolo/fastapi/pull/1683) by [@tokusumi](https://github.com/tokusumi).
|
||||
* 🌐 Add Japanese translation for Tutorial - Query Params. PR [#1674](https://github.com/tiangolo/fastapi/pull/1674) by [@tokusumi](https://github.com/tokusumi).
|
||||
* 🌐 Add Japanese translation for tutorial/path-params.md. PR [#1671](https://github.com/tiangolo/fastapi/pull/1671) by [@tokusumi](https://github.com/tokusumi).
|
||||
* 🌐 Add Japanese translation for tutorial/first-steps.md. PR [#1658](https://github.com/tiangolo/fastapi/pull/1658) by [@tokusumi](https://github.com/tokusumi).
|
||||
* 🌐 Add Japanese translation for tutorial/index.md. PR [#1656](https://github.com/tiangolo/fastapi/pull/1656) by [@tokusumi](https://github.com/tokusumi).
|
||||
* 🌐 Add translation to Portuguese for Project Generation. PR [#1602](https://github.com/tiangolo/fastapi/pull/1602) by [@Serrones](https://github.com/Serrones).
|
||||
* 🌐 Add Japanese translation for Features. PR [#1625](https://github.com/tiangolo/fastapi/pull/1625) by [@tokusumi](https://github.com/tokusumi).
|
||||
* 🌐 Initialize new language Korean for translations. PR [#2018](https://github.com/tiangolo/fastapi/pull/2018) by [@hard-coders](https://github.com/hard-coders).
|
||||
* 🌐 Add Portuguese translation of Deployment. PR [#1374](https://github.com/tiangolo/fastapi/pull/1374) by [@Serrones](https://github.com/Serrones).
|
||||
|
||||
### Internal
|
||||
|
||||
* 🔥 Cleanup after upgrade for Docs Previews GitHub Action. PR [#2248](https://github.com/tiangolo/fastapi/pull/2248) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🐛 Fix CI docs preview, unzip docs. PR [#2246](https://github.com/tiangolo/fastapi/pull/2246) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ✨ Add instant docs deploy previews for PRs from forks. PR [#2244](https://github.com/tiangolo/fastapi/pull/2244) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⚡️ Build docs for languages in parallel in subprocesses to speed up CI. PR [#2242](https://github.com/tiangolo/fastapi/pull/2242) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🐛 Fix docs order generation for partial translations. PR [#2238](https://github.com/tiangolo/fastapi/pull/2238) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👥 Update FastAPI People. PR [#2202](https://github.com/tiangolo/fastapi/pull/2202) by [@github-actions[bot]](https://github.com/apps/github-actions).
|
||||
* ♻️ Update FastAPI People GitHub Action to send the PR as github-actions. PR [#2201](https://github.com/tiangolo/fastapi/pull/2201) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update FastAPI People GitHub Action config, run monthly. PR [#2199](https://github.com/tiangolo/fastapi/pull/2199) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🐛 Fix FastAPI People GitHub Action Docker dependency, strike 1 ⚾. PR [#2198](https://github.com/tiangolo/fastapi/pull/2198) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🐛 Fix FastAPI People GitHub Action Docker dependencies. PR [#2197](https://github.com/tiangolo/fastapi/pull/2197) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🐛 Fix FastAPI People GitHub Action when there's nothing to change. PR [#2196](https://github.com/tiangolo/fastapi/pull/2196) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👥 Add new section FastAPI People. PR [#2195](https://github.com/tiangolo/fastapi/pull/2195) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆️ Upgrade GitHub Action Latest Changes. PR [#2190](https://github.com/tiangolo/fastapi/pull/2190) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆️ Upgrade GitHub Action Label Approved. PR [#2189](https://github.com/tiangolo/fastapi/pull/2189) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update GitHub Action Label Approved, run at 12:00. PR [#2185](https://github.com/tiangolo/fastapi/pull/2185) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Upgrade GitHub Action Latest Changes. PR [#2184](https://github.com/tiangolo/fastapi/pull/2184) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Set GitHub Action Label Approved to run daily, not every minute. PR [#2163](https://github.com/tiangolo/fastapi/pull/2163) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔥 Remove pr-approvals GitHub Action as it's not compatible with forks. Use the new one. PR [#2162](https://github.com/tiangolo/fastapi/pull/2162) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Add GitHub Action Latest Changes. PR [#2160](https://github.com/tiangolo/fastapi/pull/2160).
|
||||
* 👷 Add GitHub Action Label Approved. PR [#2161](https://github.com/tiangolo/fastapi/pull/2161).
|
||||
|
||||
## 0.61.1
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix issues using `jsonable_encoder` with SQLAlchemy models directly. PR [#1987](https://github.com/tiangolo/fastapi/pull/1987).
|
||||
|
||||
### Docs
|
||||
|
||||
* Fix typo in NoSQL docs. PR [#1980](https://github.com/tiangolo/fastapi/pull/1980) by [@facundojmaero](https://github.com/facundojmaero).
|
||||
|
||||
### Translations
|
||||
|
||||
* Add translation for [main page to Japanese](https://fastapi.tiangolo.com/ja/) PR [#1571](https://github.com/tiangolo/fastapi/pull/1571) by [@ryuckel](https://github.com/ryuckel).
|
||||
* Initialize French translations. PR [#1975](https://github.com/tiangolo/fastapi/pull/1975) by [@JulianMaurin-BM](https://github.com/JulianMaurin-BM).
|
||||
* Initialize Turkish translations. PR [#1905](https://github.com/tiangolo/fastapi/pull/1905) by [@ycd](https://github.com/ycd).
|
||||
|
||||
### Internal
|
||||
|
||||
* Improve docs maintainability by updating `hl_lines` syntax to use ranges. PR [#1863](https://github.com/tiangolo/fastapi/pull/1863) by [@la-mar](https://github.com/la-mar).
|
||||
|
||||
## 0.61.0
|
||||
|
||||
### Features
|
||||
|
||||
* Add support for injecting `HTTPConnection` (as `Request` and `WebSocket`). Useful for sharing app state in dependencies. PR [#1827](https://github.com/tiangolo/fastapi/pull/1827) by [@nsidnev](https://github.com/nsidnev).
|
||||
* Export `WebSocketDisconnect` and add example handling WebSocket disconnections to docs. PR [#1822](https://github.com/tiangolo/fastapi/pull/1822) by [@rkbeatss](https://github.com/rkbeatss).
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* Require Pydantic > `1.0.0`.
|
||||
* Remove support for deprecated Pydantic `0.32.2`. This improves maintainability and allows new features.
|
||||
* In `FastAPI` and `APIRouter`:
|
||||
* Remove *path operation decorators* related/deprecated parameter `response_model_skip_defaults` (use `response_model_exclude_unset` instead).
|
||||
* Change *path operation decorators* parameter default for `response_model_exclude` from `set()` to `None` (as is in Pydantic).
|
||||
* In `encoders.jsonable_encoder`:
|
||||
* Remove deprecated `skip_defaults`, use instead `exclude_unset`.
|
||||
* Set default of `exclude` from `set()` to `None` (as is in Pydantic).
|
||||
* PR [#1862](https://github.com/tiangolo/fastapi/pull/1862).
|
||||
* In `encoders.jsonable_encoder` remove parameter `sqlalchemy_safe`.
|
||||
* It was an early hack to allow returning SQLAlchemy models, but it was never documented, and the recommended way is using Pydantic's `orm_mode` as described in the tutorial: [SQL (Relational) Databases](https://fastapi.tiangolo.com/tutorial/sql-databases/).
|
||||
* PR [#1864](https://github.com/tiangolo/fastapi/pull/1864).
|
||||
|
||||
### Docs
|
||||
|
||||
* Add link to the course by TestDriven.io: [Test-Driven Development with FastAPI and Docker](https://testdriven.io/courses/tdd-fastapi/). PR [#1860](https://github.com/tiangolo/fastapi/pull/1860).
|
||||
* Fix empty log message in docs example about handling errors. PR [#1815](https://github.com/tiangolo/fastapi/pull/1815) by [@manlix](https://github.com/manlix).
|
||||
* Reword text to reduce ambiguity while not being gender-specific. PR [#1824](https://github.com/tiangolo/fastapi/pull/1824) by [@Mause](https://github.com/Mause).
|
||||
|
||||
### Internal
|
||||
|
||||
* Add Flake8 linting. Original PR [#1774](https://github.com/tiangolo/fastapi/pull/1774) by [@MashhadiNima](https://github.com/MashhadiNima).
|
||||
* Disable Gitter bot, as it's currently broken, and Gitter's response doesn't show the problem. PR [#1853](https://github.com/tiangolo/fastapi/pull/1853).
|
||||
|
||||
## 0.60.2
|
||||
|
||||
* Fix typo in docs for query parameters. PR [#1832](https://github.com/tiangolo/fastapi/pull/1832) by [@ycd](https://github.com/ycd).
|
||||
* Add docs about [Async Tests](https://fastapi.tiangolo.com/advanced/async-tests/). PR [#1619](https://github.com/tiangolo/fastapi/pull/1619) by [@empicano](https://github.com/empicano).
|
||||
* Raise an exception when using form data (`Form`, `File`) without having `python-multipart` installed.
|
||||
* Up to now the application would run, and raise an exception only when receiving a request with form data, the new behavior, raising early, will prevent from deploying applications with broken dependencies.
|
||||
* It also detects if the correct package `python-multipart` is installed instead of the incorrect `multipart` (both importable as `multipart`).
|
||||
* PR [#1851](https://github.com/tiangolo/fastapi/pull/1851) based on original PR [#1627](https://github.com/tiangolo/fastapi/pull/1627) by [@chrisngyn](https://github.com/chrisngyn), [@YKo20010](https://github.com/YKo20010), [@kx-chen](https://github.com/kx-chen).
|
||||
* Re-enable Gitter releases bot. PR [#1831](https://github.com/tiangolo/fastapi/pull/1831).
|
||||
* Add link to async SQL databases tutorial from main SQL tutorial. PR [#1813](https://github.com/tiangolo/fastapi/pull/1813) by [@short2strings](https://github.com/short2strings).
|
||||
* Fix typo in tutorial about behind a proxy. PR [#1807](https://github.com/tiangolo/fastapi/pull/1807) by [@toidi](https://github.com/toidi).
|
||||
* Fix typo in Portuguese docs. PR [#1795](https://github.com/tiangolo/fastapi/pull/1795) by [@izaguerreiro](https://github.com/izaguerreiro).
|
||||
* Add translations setup for Ukrainian. PR [#1830](https://github.com/tiangolo/fastapi/pull/1830).
|
||||
* Add external link [Build And Host Fast Data Science Applications Using FastAPI](https://towardsdatascience.com/build-and-host-fast-data-science-applications-using-fastapi-823be8a1d6a0). PR [#1786](https://github.com/tiangolo/fastapi/pull/1786) by [@Kludex](https://github.com/Kludex).
|
||||
* Fix encoding of Pydantic models that inherit from others models with custom `json_encoders`. PR [#1769](https://github.com/tiangolo/fastapi/pull/1769) by [@henrybetts](https://github.com/henrybetts).
|
||||
* Simplify and improve `jsonable_encoder`. PR [#1754](https://github.com/tiangolo/fastapi/pull/1754) by [@MashhadiNima](https://github.com/MashhadiNima).
|
||||
* Simplify internal code syntax in several points. PR [#1753](https://github.com/tiangolo/fastapi/pull/1753) by [@uriyyo](https://github.com/uriyyo).
|
||||
* Improve internal typing, declare `Optional` parameters. PR [#1731](https://github.com/tiangolo/fastapi/pull/1731) by [@MashhadiNima](https://github.com/MashhadiNima).
|
||||
* Add external link [Deploy FastAPI on Azure App Service](https://www.tutlinks.com/deploy-fastapi-on-azure/) to docs. PR [#1726](https://github.com/tiangolo/fastapi/pull/1726) by [@windson](https://github.com/windson).
|
||||
* Add link to Starlette docs about WebSocket testing. PR [#1717](https://github.com/tiangolo/fastapi/pull/1717) by [@hellocoldworld](https://github.com/hellocoldworld).
|
||||
* Refactor generating dependant, merge for loops. PR [#1714](https://github.com/tiangolo/fastapi/pull/1714) by [@Bloodielie](https://github.com/Bloodielie).
|
||||
* Update example for templates with Jinja to include HTML media type. PR [#1690](https://github.com/tiangolo/fastapi/pull/1690) by [@frafra](https://github.com/frafra).
|
||||
* Fix typos in docs for security. PR [#1678](https://github.com/tiangolo/fastapi/pull/1678) by [@nilslindemann](https://github.com/nilslindemann).
|
||||
* Fix typos in docs for dependencies. PR [#1675](https://github.com/tiangolo/fastapi/pull/1675) by [@nilslindemann](https://github.com/nilslindemann).
|
||||
* Fix type annotation for `**extra` parameters in `FastAPI`. PR [#1659](https://github.com/tiangolo/fastapi/pull/1659) by [@bharel](https://github.com/bharel).
|
||||
* Bump MkDocs Material to fix docs in browsers with dark mode. PR [#1789](https://github.com/tiangolo/fastapi/pull/1789) by [@adriencaccia](https://github.com/adriencaccia).
|
||||
* Remove docs preview comment from each commit. PR [#1826](https://github.com/tiangolo/fastapi/pull/1826).
|
||||
* Update GitHub context extraction for Gitter notification bot. PR [#1766](https://github.com/tiangolo/fastapi/pull/1766).
|
||||
|
||||
## 0.60.1
|
||||
|
||||
* Add debugging logs for GitHub actions to introspect GitHub hidden context. PR [#1764](https://github.com/tiangolo/fastapi/pull/1764).
|
||||
* Use OS preference theme for online docs. PR [#1760](https://github.com/tiangolo/fastapi/pull/1760) by [@adriencaccia](https://github.com/adriencaccia).
|
||||
* Upgrade Starlette to version `0.13.6` to handle a vulnerability when using static files in Windows. PR [#1759](https://github.com/tiangolo/fastapi/pull/1759) by [@jamesag26](https://github.com/jamesag26).
|
||||
* Pin Swagger UI temporarily, waiting for a fix for [swagger-api/swagger-ui#6249](https://github.com/swagger-api/swagger-ui/issues/6249). PR [#1763](https://github.com/tiangolo/fastapi/pull/1763).
|
||||
* Update GitHub Actions, use commit from PR for docs preview, not commit from pre-merge. PR [#1761](https://github.com/tiangolo/fastapi/pull/1761).
|
||||
* Update GitHub Actions, refactor Gitter bot. PR [#1746](https://github.com/tiangolo/fastapi/pull/1746).
|
||||
|
||||
## 0.60.0
|
||||
|
||||
* Add GitHub Action to watch for missing preview docs and trigger a preview deploy. PR [#1740](https://github.com/tiangolo/fastapi/pull/1740).
|
||||
* Add custom GitHub Action to get artifact with docs preview. PR [#1739](https://github.com/tiangolo/fastapi/pull/1739).
|
||||
* Add new GitHub Actions to preview docs from PRs. PR [#1738](https://github.com/tiangolo/fastapi/pull/1738).
|
||||
* Add XML test coverage to support GitHub Actions. PR [#1737](https://github.com/tiangolo/fastapi/pull/1737).
|
||||
* Update badges and remove Travis now that GitHub Actions is the main CI. PR [#1736](https://github.com/tiangolo/fastapi/pull/1736).
|
||||
* Add GitHub Actions for CI, move from Travis. PR [#1735](https://github.com/tiangolo/fastapi/pull/1735).
|
||||
* Add support for adding OpenAPI schema for GET requests with a body. PR [#1626](https://github.com/tiangolo/fastapi/pull/1626) by [@victorphoenix3](https://github.com/victorphoenix3).
|
||||
|
||||
## 0.59.0
|
||||
|
||||
* Fix typo in docstring for OAuth2 utils. PR [#1621](https://github.com/tiangolo/fastapi/pull/1621) by [@tomarv2](https://github.com/tomarv2).
|
||||
* Update JWT docs to use Python-jose instead of PyJWT. Initial PR [#1610](https://github.com/tiangolo/fastapi/pull/1610) by [@asheux](https://github.com/asheux).
|
||||
* Fix/re-enable search bar in docs. PR [#1703](https://github.com/tiangolo/fastapi/pull/1703).
|
||||
* Auto-generate a "server" in OpenAPI `servers` when there's a `root_path` instead of prefixing all the `paths`:
|
||||
* Add a new parameter for `FastAPI` classes: `root_path_in_servers` to disable the auto-generation of `servers`.
|
||||
* New docs about `root_path` and `servers` in [Additional Servers](https://fastapi.tiangolo.com/advanced/behind-a-proxy/#additional-servers).
|
||||
* Update OAuth2 examples to use a relative URL for `tokenUrl="token"` to make sure those examples keep working as-is even when behind a reverse proxy.
|
||||
* Initial PR [#1596](https://github.com/tiangolo/fastapi/pull/1596) by [@rkbeatss](https://github.com/rkbeatss).
|
||||
* Fix typo/link in External Links. PR [#1702](https://github.com/tiangolo/fastapi/pull/1702).
|
||||
* Update handling of [External Links](https://fastapi.tiangolo.com/external-links/) to use a data file and allow translating the headers without becoming obsolete quickly when new links are added. PR [#https://github.com/tiangolo/fastapi/pull/1701](https://github.com/tiangolo/fastapi/pull/1701).
|
||||
* Add external link [Machine learning model serving in Python using FastAPI and Streamlit](https://davidefiocco.github.io/2020/06/27/streamlit-fastapi-ml-serving.html) to docs. PR [#1669](https://github.com/tiangolo/fastapi/pull/1669) by [@davidefiocco](https://github.com/davidefiocco).
|
||||
* Add note in docs on order in Pydantic Unions. PR [#1591](https://github.com/tiangolo/fastapi/pull/1591) by [@kbanc](https://github.com/kbanc).
|
||||
* Improve support for tests in editor. PR [#1699](https://github.com/tiangolo/fastapi/pull/1699).
|
||||
* Pin dependencies. PR [#1697](https://github.com/tiangolo/fastapi/pull/1697).
|
||||
* Update isort to version 5.x.x. PR [#1670](https://github.com/tiangolo/fastapi/pull/1670) by [@asheux](https://github.com/asheux).
|
||||
|
||||
## 0.58.1
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
You can define background tasks to be run *after* returning a response.
|
||||
|
||||
This is useful for operations that need to happen after a request, but that the client doesn't really have to be waiting for the operation to complete before receiving his response.
|
||||
This is useful for operations that need to happen after a request, but that the client doesn't really have to be waiting for the operation to complete before receiving the response.
|
||||
|
||||
This includes, for example:
|
||||
|
||||
@@ -15,7 +15,7 @@ This includes, for example:
|
||||
|
||||
First, import `BackgroundTasks` and define a parameter in your *path operation function* with a type declaration of `BackgroundTasks`:
|
||||
|
||||
```Python hl_lines="1 13"
|
||||
```Python hl_lines="1 13"
|
||||
{!../../../docs_src/background_tasks/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -33,7 +33,7 @@ In this case, the task function will write to a file (simulating sending an emai
|
||||
|
||||
And as the write operation doesn't use `async` and `await`, we define the function with normal `def`:
|
||||
|
||||
```Python hl_lines="6 7 8 9"
|
||||
```Python hl_lines="6-9"
|
||||
{!../../../docs_src/background_tasks/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -57,7 +57,7 @@ Using `BackgroundTasks` also works with the dependency injection system, you can
|
||||
|
||||
**FastAPI** knows what to do in each case and how to re-use the same object, so that all the background tasks are merged together and are run in the background afterwards:
|
||||
|
||||
```Python hl_lines="13 15 22 25"
|
||||
```Python hl_lines="13 15 22 25"
|
||||
{!../../../docs_src/background_tasks/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -81,7 +81,7 @@ You can see more details in <a href="https://www.starlette.io/background/" class
|
||||
|
||||
## Caveat
|
||||
|
||||
If you need to perform heavy background computation and you don't necessarily need it to be run by the same process (for example, you don't need to share memory, variables, etc), you might benefit from using other bigger tools like <a href="http://www.celeryproject.org/" class="external-link" target="_blank">Celery</a>.
|
||||
If you need to perform heavy background computation and you don't necessarily need it to be run by the same process (for example, you don't need to share memory, variables, etc), you might benefit from using other bigger tools like <a href="https://docs.celeryproject.org" class="external-link" target="_blank">Celery</a>.
|
||||
|
||||
They tend to require more complex configurations, a message/job queue manager, like RabbitMQ or Redis, but they allow you to run background tasks in multiple processes, and especially, in multiple servers.
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ You can create the *path operations* for that module using `APIRouter`.
|
||||
|
||||
You import it and create an "instance" the same way you would with the class `FastAPI`:
|
||||
|
||||
```Python hl_lines="1 3"
|
||||
```Python hl_lines="1 3"
|
||||
{!../../../docs_src/bigger_applications/app/routers/users.py!}
|
||||
```
|
||||
|
||||
@@ -70,7 +70,7 @@ And then you use it to declare your *path operations*.
|
||||
|
||||
Use it the same way you would use the `FastAPI` class:
|
||||
|
||||
```Python hl_lines="6 11 16"
|
||||
```Python hl_lines="6 11 16"
|
||||
{!../../../docs_src/bigger_applications/app/routers/users.py!}
|
||||
```
|
||||
|
||||
@@ -83,7 +83,7 @@ All the same parameters, responses, dependencies, tags, etc.
|
||||
!!! tip
|
||||
In this example, the variable is called `router`, but you can name it however you want.
|
||||
|
||||
We are going to include this `APIrouter` in the main `FastAPI` app, but first, let's add another `APIRouter`.
|
||||
We are going to include this `APIRouter` in the main `FastAPI` app, but first, let's add another `APIRouter`.
|
||||
|
||||
## Another module with `APIRouter`
|
||||
|
||||
@@ -100,7 +100,7 @@ But let's say that this time we are more lazy.
|
||||
|
||||
And we don't want to have to explicitly type `/items/` and `tags=["items"]` in every *path operation* (we will be able to do it later):
|
||||
|
||||
```Python hl_lines="6 11"
|
||||
```Python hl_lines="6 11"
|
||||
{!../../../docs_src/bigger_applications/app/routers/items.py!}
|
||||
```
|
||||
|
||||
@@ -110,7 +110,7 @@ We are not adding the prefix `/items/` nor the `tags=["items"]` to add them late
|
||||
|
||||
But we can add custom `tags` and `responses` that will be applied to a specific *path operation*:
|
||||
|
||||
```Python hl_lines="18 19"
|
||||
```Python hl_lines="18-19"
|
||||
{!../../../docs_src/bigger_applications/app/routers/items.py!}
|
||||
```
|
||||
|
||||
@@ -126,7 +126,7 @@ This will be the main file in your application that ties everything together.
|
||||
|
||||
You import and create a `FastAPI` class as normally:
|
||||
|
||||
```Python hl_lines="1 5"
|
||||
```Python hl_lines="1 5"
|
||||
{!../../../docs_src/bigger_applications/app/main.py!}
|
||||
```
|
||||
|
||||
@@ -245,7 +245,7 @@ And we can add predefined `responses` that will be included in all the *path ope
|
||||
|
||||
And we can add a list of `dependencies` that will be added to all the *path operations* in the router and will be executed/solved for each request made to them. Note that, much like dependencies in *path operation decorators*, no value will be passed to your *path operation function*.
|
||||
|
||||
```Python hl_lines="8 9 10 14 15 16 17 18 19 20"
|
||||
```Python hl_lines="8-10 14-20"
|
||||
{!../../../docs_src/bigger_applications/app/main.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ First, you have to import it:
|
||||
|
||||
You can then use `Field` with model attributes:
|
||||
|
||||
```Python hl_lines="11 12 13 14"
|
||||
```Python hl_lines="11-14"
|
||||
{!../../../docs_src/body_fields/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ First, of course, you can mix `Path`, `Query` and request body parameter declara
|
||||
|
||||
And you can also declare body parameters as optional, by setting the default to `None`:
|
||||
|
||||
```Python hl_lines="19 20 21"
|
||||
```Python hl_lines="19-21"
|
||||
{!../../../docs_src/body_multiple_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ And Python has a special data type for sets of unique items, the `set`.
|
||||
|
||||
Then we can import `Set` and declare `tags` as a `set` of `str`:
|
||||
|
||||
```Python hl_lines="1 14"
|
||||
```Python hl_lines="1 14"
|
||||
{!../../../docs_src/body_nested_models/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -79,7 +79,7 @@ All that, arbitrarily nested.
|
||||
|
||||
For example, we can define an `Image` model:
|
||||
|
||||
```Python hl_lines="9 10 11"
|
||||
```Python hl_lines="9-11"
|
||||
{!../../../docs_src/body_nested_models/tutorial004.py!}
|
||||
```
|
||||
|
||||
@@ -122,7 +122,7 @@ To see all the options you have, checkout the docs for <a href="https://pydantic
|
||||
|
||||
For example, as in the `Image` model we have a `url` field, we can declare it to be instead of a `str`, a Pydantic's `HttpUrl`:
|
||||
|
||||
```Python hl_lines="4 10"
|
||||
```Python hl_lines="4 10"
|
||||
{!../../../docs_src/body_nested_models/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -169,7 +169,7 @@ This will expect (convert, validate, document, etc) a JSON body like:
|
||||
|
||||
You can define arbitrarily deeply nested models:
|
||||
|
||||
```Python hl_lines="9 14 20 23 27"
|
||||
```Python hl_lines="9 14 20 23 27"
|
||||
{!../../../docs_src/body_nested_models/tutorial007.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ To update an item you can use the <a href="https://developer.mozilla.org/en-US/d
|
||||
|
||||
You can use the `jsonable_encoder` to convert the input data to data that can be stored as JSON (e.g. with a NoSQL database). For example, converting `datetime` to `str`.
|
||||
|
||||
```Python hl_lines="30 31 32 33 34 35"
|
||||
```Python hl_lines="30-35"
|
||||
{!../../../docs_src/body_updates/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -82,7 +82,7 @@ In summary, to apply partial updates you would:
|
||||
* Save the data to your DB.
|
||||
* Return the updated model.
|
||||
|
||||
```Python hl_lines="30 31 32 33 34 35 36 37"
|
||||
```Python hl_lines="30-37"
|
||||
{!../../../docs_src/body_updates/tutorial002.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -9,9 +9,11 @@ Your API almost always has to send a **response** body. But clients don't necess
|
||||
To declare a **request** body, you use <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> models with all their power and benefits.
|
||||
|
||||
!!! info
|
||||
You cannot send a request body using a `GET` operation (HTTP method).
|
||||
To send data, you should use one of: `POST` (the more common), `PUT`, `DELETE` or `PATCH`.
|
||||
|
||||
To send data, you have to use one of: `POST` (the more common), `PUT`, `DELETE` or `PATCH`.
|
||||
Sending a body with a `GET` request has an undefined behavior in the specifications, nevertheless, it is supported by FastAPI, only for very complex/extreme use cases.
|
||||
|
||||
As it is discouraged, the interactive docs with Swagger UI won't show the documentation for the body when using `GET`, and proxies in the middle might not support it.
|
||||
|
||||
## Import Pydantic's `BaseModel`
|
||||
|
||||
@@ -27,7 +29,7 @@ Then you declare your data model as a class that inherits from `BaseModel`.
|
||||
|
||||
Use standard Python types for all the attributes:
|
||||
|
||||
```Python hl_lines="7 8 9 10 11"
|
||||
```Python hl_lines="7-11"
|
||||
{!../../../docs_src/body/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -73,7 +75,7 @@ With just that Python type declaration, **FastAPI** will:
|
||||
* If the data is invalid, it will return a nice and clear error, indicating exactly where and what was the incorrect data.
|
||||
* Give you the received data in the parameter `item`.
|
||||
* As you declared it in the function to be of type `Item`, you will also have all the editor support (completion, etc) for all of the attributes and their types.
|
||||
* Generate <a href="http://json-schema.org" class="external-link" target="_blank">JSON Schema</a> definitions for your model, you can also use them anywhere else you like if it makes sense for your project.
|
||||
* Generate <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> definitions for your model, you can also use them anywhere else you like if it makes sense for your project.
|
||||
* Those schemas will be part of the generated OpenAPI schema, and used by the automatic documentation <abbr title="User Interfaces">UIs</abbr>.
|
||||
|
||||
## Automatic docs
|
||||
@@ -129,11 +131,11 @@ Inside of the function, you can access all the attributes of the model object di
|
||||
|
||||
## Request body + path parameters
|
||||
|
||||
You can declare path parameters and body requests at the same time.
|
||||
You can declare path parameters and request body at the same time.
|
||||
|
||||
**FastAPI** will recognize that the function parameters that match path parameters should be **taken from the path**, and that function parameters that are declared to be Pydantic models should be **taken from the request body**.
|
||||
|
||||
```Python hl_lines="17 18"
|
||||
```Python hl_lines="17-18"
|
||||
{!../../../docs_src/body/tutorial003.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ You can also specify if your backend allows:
|
||||
* Specific HTTP methods (`POST`, `PUT`) or all of them with the wildcard `"*"`.
|
||||
* Specific HTTP headers or all of them with the wildcard `"*"`.
|
||||
|
||||
```Python hl_lines="2 6 7 8 9 10 11 13 14 15 16 17 18 19"
|
||||
```Python hl_lines="2 6-11 13-19"
|
||||
{!../../../docs_src/cors/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -55,10 +55,10 @@ The default parameters used by the `CORSMiddleware` implementation are restricti
|
||||
The following arguments are supported:
|
||||
|
||||
* `allow_origins` - A list of origins that should be permitted to make cross-origin requests. E.g. `['https://example.org', 'https://www.example.org']`. You can use `['*']` to allow any origin.
|
||||
* `allow_origin_regex` - A regex string to match against origins that should be permitted to make cross-origin requests. eg. `'https://.*\.example\.org'`.
|
||||
* `allow_origin_regex` - A regex string to match against origins that should be permitted to make cross-origin requests. e.g. `'https://.*\.example\.org'`.
|
||||
* `allow_methods` - A list of HTTP methods that should be allowed for cross-origin requests. Defaults to `['GET']`. You can use `['*']` to allow all standard methods.
|
||||
* `allow_headers` - A list of HTTP request headers that should be supported for cross-origin requests. Defaults to `[]`. You can use `['*']` to allow all headers. The `Accept`, `Accept-Language`, `Content-Language` and `Content-Type` headers are always allowed for CORS requests.
|
||||
* `allow_credentials` - Indicate that cookies should be supported for cross-origin requests. Defaults to `False`.
|
||||
* `allow_credentials` - Indicate that cookies should be supported for cross-origin requests. Defaults to `False`. Also, `allow_origins` cannot be set to `['*']` for credentials to be allowed, origins must be specified.
|
||||
* `expose_headers` - Indicate any response headers that should be made accessible to the browser. Defaults to `[]`.
|
||||
* `max_age` - Sets a maximum time in seconds for browsers to cache CORS responses. Defaults to `600`.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ You can connect the debugger in your editor, for example with Visual Studio Code
|
||||
|
||||
In your FastAPI application, import and run `uvicorn` directly:
|
||||
|
||||
```Python hl_lines="1 15"
|
||||
```Python hl_lines="1 15"
|
||||
{!../../../docs_src/debugging/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -69,9 +69,9 @@ If you pass a "callable" as a dependency in **FastAPI**, it will analyze the par
|
||||
|
||||
That also applies to callables with no parameters at all. The same as it would be for *path operation functions* with no parameters.
|
||||
|
||||
Then, we can change the dependency "dependable" `common_parameters` from above to the class `CommonQueryParameters`:
|
||||
Then, we can change the dependency "dependable" `common_parameters` from above to the class `CommonQueryParams`:
|
||||
|
||||
```Python hl_lines="11 12 13 14 15"
|
||||
```Python hl_lines="11-15"
|
||||
{!../../../docs_src/dependencies/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -101,15 +101,15 @@ In both cases the data will be converted, validated, documented on the OpenAPI s
|
||||
|
||||
Now you can declare your dependency using this class.
|
||||
|
||||
And as when **FastAPI** calls that class the value that will be passed as `commons` to your function will be an "instance" of the class, you can declare that parameter `commons` to be of type of the class, `CommonQueryParams`.
|
||||
|
||||
```Python hl_lines="19"
|
||||
{!../../../docs_src/dependencies/tutorial002.py!}
|
||||
```
|
||||
|
||||
**FastAPI** calls the `CommonQueryParams` class. This creates an "instance" of that class and the instance will be passed as the parameter `commons` to your function.
|
||||
|
||||
## Type annotation vs `Depends`
|
||||
|
||||
In the code above, you are declaring `commons` as:
|
||||
Notice how we write `CommonQueryParams` twice in the above code:
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
@@ -175,9 +175,9 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
commons: CommonQueryParams = Depends()
|
||||
```
|
||||
|
||||
So, you can declare the dependency as the type of the variable, and use `Depends()` as the "default" value (the value after the `=`) for that function's parameter, without any parameter, instead of having to write the full class *again* inside of `Depends(CommonQueryParams)`.
|
||||
You declare the dependency as the type of the parameter, and you use `Depends()` as its "default" value (that after the `=`) for that function's parameter, without any parameter in `Depends()`, instead of having to write the full class *again* inside of `Depends(CommonQueryParams)`.
|
||||
|
||||
So, the same example would look like:
|
||||
The same example would then look like:
|
||||
|
||||
```Python hl_lines="19"
|
||||
{!../../../docs_src/dependencies/tutorial004.py!}
|
||||
@@ -186,6 +186,6 @@ So, the same example would look like:
|
||||
...and **FastAPI** will know what to do.
|
||||
|
||||
!!! tip
|
||||
If all that seems more confusing than helpful, disregard it, you don't *need* it.
|
||||
|
||||
If that seems more confusing than helpful, disregard it, you don't *need* it.
|
||||
|
||||
It is just a shortcut. Because **FastAPI** cares about helping you minimize code repetition.
|
||||
|
||||
@@ -25,7 +25,7 @@ These dependencies will be executed/solved the same way normal dependencies. But
|
||||
|
||||
Using these `dependencies` in the *path operation decorator* you can make sure they are executed while avoiding editor/tooling errors.
|
||||
|
||||
It might also help avoiding confusion for new developers that see an un-used parameter in your code and could think it's unnecessary.
|
||||
It might also help avoid confusion for new developers that see an unused parameter in your code and could think it's unnecessary.
|
||||
|
||||
## Dependencies errors and return values
|
||||
|
||||
@@ -35,7 +35,7 @@ You can use the same dependency *functions* you use normally.
|
||||
|
||||
They can declare request requirements (like headers) or other sub-dependencies:
|
||||
|
||||
```Python hl_lines="6 11"
|
||||
```Python hl_lines="6 11"
|
||||
{!../../../docs_src/dependencies/tutorial006.py!}
|
||||
```
|
||||
|
||||
@@ -43,7 +43,7 @@ They can declare request requirements (like headers) or other sub-dependencies:
|
||||
|
||||
These dependencies can `raise` exceptions, the same as normal dependencies:
|
||||
|
||||
```Python hl_lines="8 13"
|
||||
```Python hl_lines="8 13"
|
||||
{!../../../docs_src/dependencies/tutorial006.py!}
|
||||
```
|
||||
|
||||
@@ -53,7 +53,7 @@ And they can return values or not, the values won't be used.
|
||||
|
||||
So, you can re-use a normal dependency (that returns a value) you already use somewhere else, and even though the value won't be used, the dependency will be executed:
|
||||
|
||||
```Python hl_lines="9 14"
|
||||
```Python hl_lines="9 14"
|
||||
{!../../../docs_src/dependencies/tutorial006.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ For example, you could use this to create a database session and close it after
|
||||
|
||||
Only the code prior to and including the `yield` statement is executed before sending a response:
|
||||
|
||||
```Python hl_lines="2 3 4"
|
||||
```Python hl_lines="2-4"
|
||||
{!../../../docs_src/dependencies/tutorial007.py!}
|
||||
```
|
||||
|
||||
@@ -44,7 +44,7 @@ The yielded value is what is injected into *path operations* and other dependenc
|
||||
|
||||
The code following the `yield` statement is executed after the response has been delivered:
|
||||
|
||||
```Python hl_lines="5 6"
|
||||
```Python hl_lines="5-6"
|
||||
{!../../../docs_src/dependencies/tutorial007.py!}
|
||||
```
|
||||
|
||||
@@ -63,7 +63,7 @@ So, you can look for that specific exception inside the dependency with `except
|
||||
|
||||
In the same way, you can use `finally` to make sure the exit steps are executed, no matter if there was an exception or not.
|
||||
|
||||
```Python hl_lines="3 5"
|
||||
```Python hl_lines="3 5"
|
||||
{!../../../docs_src/dependencies/tutorial007.py!}
|
||||
```
|
||||
|
||||
@@ -75,7 +75,7 @@ You can have sub-dependencies and "trees" of sub-dependencies of any size and sh
|
||||
|
||||
For example, `dependency_c` can have a dependency on `dependency_b`, and `dependency_b` on `dependency_a`:
|
||||
|
||||
```Python hl_lines="4 12 20"
|
||||
```Python hl_lines="4 12 20"
|
||||
{!../../../docs_src/dependencies/tutorial008.py!}
|
||||
```
|
||||
|
||||
@@ -85,7 +85,7 @@ In this case `dependency_c`, to execute its exit code, needs the value from `dep
|
||||
|
||||
And, in turn, `dependency_b` needs the value from `dependency_a` (here named `dep_a`) to be available for its exit code.
|
||||
|
||||
```Python hl_lines="16 17 24 25"
|
||||
```Python hl_lines="16-17 24-25"
|
||||
{!../../../docs_src/dependencies/tutorial008.py!}
|
||||
```
|
||||
|
||||
@@ -207,7 +207,7 @@ In Python, you can create Context Managers by <a href="https://docs.python.org/3
|
||||
You can also use them inside of **FastAPI** dependencies with `yield` by using
|
||||
`with` or `async with` statements inside of the dependency function:
|
||||
|
||||
```Python hl_lines="1 2 3 4 5 6 7 8 9 13"
|
||||
```Python hl_lines="1-9 13"
|
||||
{!../../../docs_src/dependencies/tutorial010.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ Let's first focus on the dependency.
|
||||
|
||||
It is just a function that can take all the same parameters that a *path operation function* can take:
|
||||
|
||||
```Python hl_lines="8 9"
|
||||
```Python hl_lines="8-9"
|
||||
{!../../../docs_src/dependencies/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -39,7 +39,7 @@ That's it.
|
||||
|
||||
**2 lines**.
|
||||
|
||||
And it has the same shape and structure that all your *path operation functions*.
|
||||
And it has the same shape and structure that all your *path operation functions* have.
|
||||
|
||||
You can think of it as a *path operation function* without the "decorator" (without the `@app.get("/some-path")`).
|
||||
|
||||
@@ -123,10 +123,9 @@ So, the interactive docs will have all the information from these dependencies t
|
||||
|
||||
<img src="/img/tutorial/dependencies/image01.png">
|
||||
|
||||
|
||||
## Simple usage
|
||||
|
||||
If you look at it, *path operation functions* are declared to be used whenever a *path* and *operation* matches, and then **FastAPI** takes care of calling the function with the correct parameters and use the response.
|
||||
If you look at it, *path operation functions* are declared to be used whenever a *path* and *operation* matches, and then **FastAPI** takes care of calling the function with the correct parameters, extracting the data from the request.
|
||||
|
||||
Actually, all (or most) of the web frameworks work in this same way.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ They can be as **deep** as you need them to be.
|
||||
|
||||
You could create a first dependency ("dependable") like:
|
||||
|
||||
```Python hl_lines="8 9"
|
||||
```Python hl_lines="8-9"
|
||||
{!../../../docs_src/dependencies/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -31,7 +31,7 @@ Let's focus on the parameters declared:
|
||||
* Even though this function is a dependency ("dependable") itself, it also declares another dependency (it "depends" on something else).
|
||||
* It depends on the `query_extractor`, and assigns the value returned by it to the parameter `q`.
|
||||
* It also declares an optional `last_query` cookie, as a `str`.
|
||||
* Let's imagine that if the user didn't provide any query `q`, we just use the last query used, that we had saved to a cookie before.
|
||||
* If the user didn't provide any query `q`, we use the last query used, which we saved to a cookie before.
|
||||
|
||||
### Use the dependency
|
||||
|
||||
|
||||