Compare commits

...

45 Commits

Author SHA1 Message Date
Sebastián Ramírez
0f54657377 🔖 Release version 0.60.0 2020-07-20 18:26:56 +02:00
Sebastián Ramírez
79e5b36551 📝 Update release notes (#1745)
* 📝 Update release notes

* 📝 Update release notes
2020-07-20 18:22:29 +02:00
Sebastián Ramírez
074868d77e Run watch docs previews every hour 2020-07-20 17:55:02 +02:00
Sebastián Ramírez
3dd16a9458 Fetch artifacts only once in preview docs GitHub action 2020-07-20 17:48:43 +02:00
Sebastián Ramírez
62c23ab5fa 🔒 Use personal access token to trigger docs previews 2020-07-20 17:45:28 +02:00
Sebastián Ramírez
11c05beece 🔊 Add more logging to Watch Preview when artifact is not found 2020-07-20 17:13:27 +02:00
Sebastián Ramírez
7b3ef43127 🐛 Fix Watch Preview Docs GitHub Action, strike 2 2020-07-20 16:59:09 +02:00
Sebastián Ramírez
e0080e5f75 🐛 Fix Watch Previews action 2020-07-20 16:47:48 +02:00
Sebastián Ramírez
e1ba54bd12 🔧 Update Watch Docs Previews GitHub action 2020-07-20 16:35:26 +02:00
Sebastián Ramírez
7032dfb4f1 Add GitHub Action to watch for missing preview docs (#1740)
* 📝 Update release notes

* 🔊 Make curl verbose when triggering docs preview

* 🔧 Update GitHub Actions circus to use commit hash

*  Add PR docs preview watcher
2020-07-20 16:33:17 +02:00
Sebastián Ramírez
14e7f7c1f4 ⬆ Upgrade Deploy to Netlify action 2020-07-19 22:27:32 +02:00
Sebastián Ramírez
9ed6f1e419 🐛 Fix custom GitHub action 2020-07-19 22:22:25 +02:00
Sebastián Ramírez
b268c39758 Add internal GitHub action to deploy docs previews (#1739)
* 📝 Update release notes

*  Add internal GitHub action to pull docs artifact

* 🙈 Add archive.zip to gitignore
2020-07-19 22:11:28 +02:00
Sebastián Ramírez
4dd386b807 🚀 Preview docs for external PRs (#1738)
* 🍱 Save docs zip when building docs

* 🙈 Add docs.zip artifact to .gitignore

* 🚀 Update deploy artifact name

* ♻️ Upload artifact directory

*  Add WIP trigger docs preview

* ♻️ Update trigger docs preview

* 👷 Update env vars for docs preview

* 👷 Update PR extraction

* 👷 Try to show GitHub event

* 💚 Try to see if GitHub context templates is causing the problem

* 💚 Try to debug context GitHub event

* 🔊 Debug GitHub event context

* 👷 Update debugging action

* 👷 Update debug

* 👷 Update Action

* ♻️ Update script to trigger docs preview

* ️ Try to use Zip again to improve speed

* 🔧 Update zip scripts

*  Add preview docs on event

* 🚀 Trigger deploy preview on PRs

* 🐛 Fix trigger script env vars
2020-07-19 20:49:52 +02:00
Sebastián Ramírez
b7251f1654 📝 Update release notes 2020-07-19 14:25:28 +02:00
Sebastián Ramírez
780d3e65ad Add XML coverage report for GitHub Actions (#1737) 2020-07-19 14:24:24 +02:00
Sebastián Ramírez
cc8cac200f 📝 Update release notes 2020-07-19 14:10:51 +02:00
Sebastián Ramírez
e7be5c8ac5 💄 Update badges, remove Travis (#1736)
* 💄 Update badges

* 🔥 Remove Travis
2020-07-19 14:09:55 +02:00
Sebastián Ramírez
8f52864899 📝 Update release notes 2020-07-19 14:04:45 +02:00
Sebastián Ramírez
47a630721a 👷 Add GitHub Actions, move from Travis (#1735) 2020-07-19 14:03:38 +02:00
Sebastián Ramírez
10ae6de111 📝 Update release notes 2020-07-19 12:19:39 +02:00
JAYATI SHRIVASTAVA
2b47f3e56b Add support for adding OpenAPI schema for GET requests with a body (#1626)
* add test for get request body's openapi schema

* 📝 Update docs note for GET requests with body

*  Update test for GET request with body, test it receives the body

* 🔇 Temporary type ignore while it's handled in Pydantic

Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2020-07-19 12:17:50 +02:00
Sebastián Ramírez
d60dd1b60e 🔖 Release version 0.59.0 2020-07-10 20:41:35 +02:00
Sebastián Ramírez
2822f7ca64 📝 Update release notes 2020-07-10 20:32:16 +02:00
tomarv2
ff6afeaf78 ✏ Fix docstring typo for oauth2 utils (#1621) 2020-07-10 20:31:15 +02:00
Sebastián Ramírez
74852d406c 📝 Update release notes 2020-07-10 20:26:29 +02:00
Brian Mboya
921642dc7b 📝 Update JWT docs to use python-jose (#1610)
* 📝 Update JWT docs with python-jose

* 📝 Update format and use python-jose in docs

*  Add Python-jose to dependencies

Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2020-07-10 20:24:38 +02:00
Sebastián Ramírez
5c01d44ee9 📝 Update release notes 2020-07-10 19:46:36 +02:00
Sebastián Ramírez
135704dcc8 🐛 Re-enable search bar after adding markdown-data plugin (#1703) 2020-07-10 19:45:47 +02:00
Sebastián Ramírez
88793bb6c2 📝 Update release notes 2020-07-10 19:34:22 +02:00
Rupsi Kaushik
70a51b3aff Auto-generate OpenAPI servers from root_path (#1596)
* root_path included in servers object instead of path prefix

* ♻️ Refactor implementation of auto-including root_path in OpenAPI servers

* 📝 Update docs and examples for Behind a Proxy, including servers

* 📝 Update Extending OpenAPI as openapi_prefix is no longer needed

*  Add extra tests for root_path in servers and root_path_in_servers=False

* 🍱 Update security docs images with relative token URL

* 📝 Update security docs with relative token URL

* 📝 Update example sources with relative token URLs

*  Update tests with relative tokens

Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2020-07-10 19:28:18 +02:00
Sebastián Ramírez
340a582be7 📝 Update release notes 2020-07-10 14:48:42 +02:00
Sebastián Ramírez
5f66b5466f ✏️ Fix external links typo/link (#1702) 2020-07-10 14:47:56 +02:00
Sebastián Ramírez
d2169ee567 📝 Update release notes 2020-07-10 14:35:28 +02:00
Sebastián Ramírez
a5c03ba1b7 External links in docs with data file (#1701)
*  Add mkdocs-markdownextradata-plugin for docs

* 🔧 Update MkDocs config file(s) to include external data

*  Add external links data file

* 📝 Use external data file in External Links

* ♻️ Update data files for langs

The cost is some duplication 😔, these files are updated by the script, but to be able to serve locally they have to be duplicated

*  Update docs script to copy data files

* 🔥 Remove needed duplication of data files for live docs in translations
2020-07-10 14:31:44 +02:00
Sebastián Ramírez
e4ea6426dc 📝 Update release notes 2020-07-10 12:24:03 +02:00
Davide Fiocco
8bf7cd1dc6 📝 Fix link to edit External Links, add additional link (#1669)
Added a link to the correct link to editing the en docs, plus an additional example (of mine!) which got some buzz on social media:
https://twitter.com/monodavide/status/1276913357388382212
https://madewithml.com/projects/1649/model-serving-using-fastapi-and-streamlit/
2020-07-10 12:21:46 +02:00
Sebastián Ramírez
92feb3ade7 📝 Update release notes 2020-07-10 11:18:28 +02:00
Katherine Bancroft
d0e739d8f2 📝 Add note in docs on order in Pydantic Unions (#1591)
* Add note on order in Unions

* Add an example of Union order

Co-authored-by: kbanc <katherine.bancoft@gmail.com>
2020-07-10 11:16:46 +02:00
Sebastián Ramírez
4efa6bd75e 📝 Update release notes 2020-07-10 11:09:43 +02:00
Sebastián Ramírez
600f15faa0 ✔ Improve support for tests in editor (#1699)
* ♻️ Remove required extra steps to test in editor

* 🎨 Format lint script

* 📝 Remove obsolete extra steps required to test in editor from docs

* 🐛 Fix coverage
2020-07-10 11:08:19 +02:00
Sebastián Ramírez
250fa519f9 📝 Update release notes 2020-07-10 00:16:35 +02:00
Sebastián Ramírez
3c6dafcc8e 📌 Pin dependencies (#1697)
* 📌 Pin dependencies

* 🐛 Fix config in pyproject.toml
2020-07-10 00:15:39 +02:00
Sebastián Ramírez
8447000eee 📝 Update release notes 2020-07-09 20:09:38 +02:00
Brian Mboya
fe453f80ed ⬆ Upgrade isort to version 5.x.x (#1670)
* Update isort script to match changes in the new release, isort v5.0.2

* Downgrade isort to version v4.3.21

* Add an alternative flag to --recursive in isort v5.0.2

* Add isort config file

* 🚚 Import from docs_src for tests

* 🎨 Format dependencies.utils

* 🎨 Remove isort combine_as_imports, keep black profile

* 🔧 Update isort config, use pyproject.toml, Black profile

* 🔧 Update format scripts to use explicit directories to format

otherwise it would try to format venv env directories, I have several with different Python versions

* 🎨 Format NoSQL tutorial after re-sorting imports

* 🎨 Fix format for __init__.py

Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2020-07-09 20:06:12 +02:00
184 changed files with 1316 additions and 446 deletions

1
.env
View File

@@ -1 +0,0 @@
PYTHONPATH=./docs_src

View File

@@ -0,0 +1,7 @@
FROM python:3.7
RUN pip install httpx "pydantic==1.5.1"
COPY ./app /app
CMD ["python", "/app/main.py"]

16
.github/actions/get-artifact/action.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: "Get Artifact"
description: "Get artifact, possibly uploaded by a PR, useful to deploy docs previews"
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
name:
description: 'Artifact name'
required: true
path:
description: 'Where to store the artifact'
required: true
runs:
using: 'docker'
image: 'Dockerfile'

View File

@@ -0,0 +1,63 @@
import logging
from datetime import datetime
from pathlib import Path
from typing import List, Optional
import httpx
from pydantic import BaseModel, BaseSettings, SecretStr
github_api = "https://api.github.com"
netlify_api = "https://api.netlify.com"
class Settings(BaseSettings):
input_name: str
input_token: SecretStr
input_path: str
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]
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
settings = Settings()
logging.info(f"Using config: {settings.json()}")
github_headers = {
"Authorization": f"token {settings.input_token.get_secret_value()}"
}
response = httpx.get(
f"{github_api}/repos/{settings.github_repository}/actions/artifacts",
headers=github_headers,
)
data = response.json()
artifacts_response = ArtifactResponse.parse_obj(data)
use_artifact: Optional[Artifact] = None
for artifact in artifacts_response.artifacts:
if artifact.name == settings.input_name:
use_artifact = artifact
break
assert use_artifact
file_response = httpx.get(
use_artifact.archive_download_url, headers=github_headers, timeout=30
)
zip_file = Path(settings.input_path)
zip_file.write_bytes(file_response.content)
logging.info("Finished")

View 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"]

View 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'

View 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")

View File

@@ -1,4 +1,4 @@
name: Build and Deploy to Netlify
name: Build Docs
on:
push:
pull_request:
@@ -18,8 +18,20 @@ 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-${{ github.sha }}
path: ./docs.zip
- name: Trigger Docs Preview
env:
PR: "${{ github.event.number }}"
NAME: "docs-zip-${{ github.sha }}"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
run: bash ./scripts/trigger-docs-preview.sh
- 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

43
.github/workflows/preview-docs.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: Preview Docs
on:
workflow_dispatch:
inputs:
pr:
description: Pull Request number
required: true
name:
description: Artifact name for zip file with docs
required: true
commit:
description: Commit SHA hash
required: true
jobs:
deploy:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/get-artifact
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: ${{ github.event.inputs.name }}
path: ./archive.zip
- name: Unzip docs
run: bash ./scripts/unzip-docs.sh
- 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 }}
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
- name: Comment Deploy
env:
PR: "${{ github.event.inputs.pr }}"
DEPLOY_URL: "${{ steps.netlify.outputs.deploy-url }}"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
COMMIT: "${{ github.event.inputs.commit }}"
run: bash ./scripts/docs-comment-deploy.sh

29
.github/workflows/publish.yml vendored Normal file
View File

@@ -0,0 +1,29 @@
name: Publish
on:
release:
types:
- created
jobs:
publish:
runs-on: ubuntu-latest
steps:
- 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: Notify
env:
GITTER_TOKEN: ${{ secrets.GITTER_TOKEN }}
run: bash scripts/notify.sh

29
.github/workflows/test.yml vendored Normal file
View 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

View File

@@ -0,0 +1,13 @@
name: Watch Docs Previews
on:
schedule:
- cron: "0 * * * *"
jobs:
deploy:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- uses: ./.github/actions/watch-previews
with:
token: ${{ secrets.ACTIONS_TOKEN }}

2
.gitignore vendored
View File

@@ -17,6 +17,8 @@ env3.*
env
docs_build
venv
docs.zip
archive.zip
# vim temporary files
*~

View File

@@ -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"

View File

@@ -5,14 +5,17 @@
<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://github.com/tiangolo/fastapi/actions?query=workflow%3APublish" target="_blank">
<img src="https://github.com/tiangolo/fastapi/workflows/Publish/badge.svg" alt="Publish">
</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">

View File

@@ -0,0 +1,222 @@
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: FastAPIGoogle 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: FastAPIHow 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: http://nickc1.github.io/api,/scikit-learn/2019/01/10/scikit-fastapi.html
title: "FastAPI and Scikit-Learn: Easily Deploy Models"
author_link: http://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
japanese:
- link: https://qiita.com/mtitg/items/47770e9a562dd150631d
title: FastAPIDB接続して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)"

View File

@@ -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 5 6 7 8"
{
"openapi": "3.0.2",
// More stuff here
"paths": {
"/api/v1/app": {
// More stuff here
"servers": [
{
"url": "/api/v1"
}
],
"paths": {
// More stuff here
}
}
```
@@ -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 5 6 7"
{!../../../docs_src/behind_a_proxy/tutorial003.py!}
```
Will generate an OpenAPI schema like:
```JSON hl_lines="5 6 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.

View File

@@ -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
@@ -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 16 17 18 19 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 22 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!}
```

View File

@@ -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 4 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 13 14 15 16 17 18 19 20 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 25 26 27 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 32 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 37 38 39 40 41 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!}
```
@@ -145,7 +145,7 @@ As our code is calling Couchbase and we are not using the <a href="https://docs.
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:
```Python hl_lines="50 51 52 53 54"
```Python hl_lines="49 50 51 52 53"
{!../../../docs_src/nosql_databases/tutorial001.py!}
```

View File

@@ -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 108 109 110 111 112 113 114 115 121 122 123 124 128 129 130 131 132 133 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 63 64 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 108 109 110 111 112 113 114 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 117 118 119 120 121 122 123 124 125 126 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 129 130 131 132 133 134"
{!../../../docs_src/security/tutorial005.py!}
```

View File

@@ -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
```

View File

@@ -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">FastAPIGoogle 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">FastAPIHow 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">FastAPIDB接続して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

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 88 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 80 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 87 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

@@ -5,14 +5,17 @@
<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://github.com/tiangolo/fastapi/actions?query=workflow%3APublish" target="_blank">
<img src="https://github.com/tiangolo/fastapi/workflows/Publish/badge.svg" alt="Publish">
</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">

View File

@@ -2,6 +2,34 @@
## Latest changes
## 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
* Add link in docs to Pydantic data types. PR [#1612](https://github.com/tiangolo/fastapi/pull/1612) by [@tayoogunbiyi](https://github.com/tayoogunbiyi).

View File

@@ -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`

View File

@@ -162,6 +162,9 @@ It will be defined in OpenAPI with `anyOf`.
To do that, use the standard Python type hint <a href="https://docs.python.org/3/library/typing.html#typing.Union" class="external-link" target="_blank">`typing.Union`</a>:
!!! note
When defining a <a href="https://pydantic-docs.helpmanual.io/usage/types/#unions" class="external-link" target="_blank">`Union`</a>, include the most specific type first, followed by the less specific type. In the example below, the more specific `PlaneItem` comes before `CarItem` in `Union[PlaneItem, CarItem]`.
```Python hl_lines="1 14 15 18 19 20 33"
{!../../../docs_src/extra_models/tutorial003.py!}
```

View File

@@ -86,8 +86,8 @@ But in this case, the same **FastAPI** application will handle the API and the a
So, let's review it from that simplified point of view:
* The user types his `username` and `password` in the frontend, and hits `Enter`.
* The frontend (running in the user's browser) sends that `username` and `password` to a specific URL in our API.
* The API checks that `username` and `password`, and responds with a "token".
* The frontend (running in the user's browser) sends that `username` and `password` to a specific URL in our API (declared with `tokenUrl="token"`).
* The API checks that `username` and `password`, and responds with a "token" (we haven't implemented any of this yet).
* A "token" is just a string with some content that we can use later to verify this user.
* Normally, a token is set to expire after some time.
* So, the user will have to login again at some point later.
@@ -114,13 +114,20 @@ In this example we are going to use **OAuth2**, with the **Password** flow, usin
In that case, **FastAPI** also provides you with the tools to build it.
`OAuth2PasswordBearer` is a class that we create passing a parameter of the URL in where the client (the frontend running in the user's browser) can use to send the `username` and `password` and get a token.
`OAuth2PasswordBearer` is a class that we create passing a parameter with the URL the client (the frontend running in the user's browser) can use to send the `username` and `password` and get a token.
```Python hl_lines="6"
{!../../../docs_src/security/tutorial001.py!}
```
It doesn't create that endpoint / *path operation*, but declares that that URL is the one that the client should use to get the token. That information is used in OpenAPI, and then in the interactive API documentation systems.
!!! tip
here `tokenUrl="token"` refers to a relative URL `token` that we haven't created yet. As it's a relative URL, it's equivalent to `./token`.
Because we are using a relative URL, if your API was located at `https://example.com/`, then it would refer to `https://example.com/token`. But if your API was located at `https://example.com/api/v1/`, then it would refer to `https://example.com/api/v1/token`.
Using a relative URL is important to make sure your application keeps working even in an advanced use case like [Behind a Proxy](../../advanced/behind-a-proxy.md){.internal-link target=_blank}.
It doesn't create that endpoint / *path operation* for `./token`, but declares that that URL `./token` is the one that the client should use to get the token. That information is used in OpenAPI, and then in the interactive API documentation systems.
!!! info
If you are a very strict "Pythonista" you might dislike the style of the parameter name `tokenUrl` instead of `token_url`.

View File

@@ -26,20 +26,29 @@ And after a week, the token will be expired and the user will not be authorized
If you want to play with JWT tokens and see how they work, check <a href="https://jwt.io/" class="external-link" target="_blank">https://jwt.io</a>.
## Install `PyJWT`
## Install `python-jose`
We need to install `PyJWT` to generate and verify the JWT tokens in Python:
We need to install `python-jose` to generate and verify the JWT tokens in Python:
<div class="termy">
```console
$ pip install pyjwt
$ pip install python-jose[cryptography]
---> 100%
```
</div>
<a href="https://github.com/mpdavis/python-jose" class="external-link" target="_blank">Python-jose</a> requires a cryptographic backend as an extra.
Here we are using the recommended one: <a href="http://cryptography.io/" class="external-link" target="_blank">pyca/cryptography</a>.
!!! tip
This tutorial previously used <a href="https://pyjwt.readthedocs.io/" class="external-link" target="_blank">PyJWT</a>.
But it was updated to use Python-jose instead as it provides all the features from PyJWT plus some extras that you might need later when building integrations with other tools.
## Password hashing
"Hashing" means converting some content (a password in this case) into a sequence of bytes (just a string) that looks like gibberish.
@@ -100,7 +109,7 @@ And another utility to verify if a received password matches the hash stored.
And another one to authenticate and return a user.
```Python hl_lines="8 49 56 57 60 61 70 71 72 73 74 75 76"
```Python hl_lines="7 48 55 56 59 60 69 70 71 72 73 74 75"
{!../../../docs_src/security/tutorial004.py!}
```
@@ -135,7 +144,7 @@ Define a Pydantic Model that will be used in the token endpoint for the response
Create a utility function to generate a new access token.
```Python hl_lines="4 7 13 14 15 29 30 31 79 80 81 82 83 84 85 86 87"
```Python hl_lines="6 12 13 14 28 29 30 78 79 80 81 82 83 84 85 86"
{!../../../docs_src/security/tutorial004.py!}
```
@@ -147,7 +156,7 @@ Decode the received token, verify it, and return the current user.
If the token is invalid, return an HTTP error right away.
```Python hl_lines="90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107"
```Python hl_lines="89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106"
{!../../../docs_src/security/tutorial004.py!}
```
@@ -157,7 +166,7 @@ Create a `timedelta` with the expiration time of the token.
Create a real JWT access token and return it.
```Python hl_lines="116 117 118 119 120 121 122 123 124 125 126 127 128 129"
```Python hl_lines="115 116 117 118 119 120 121 122 123 124 125 126 127 128"
{!../../../docs_src/security/tutorial004.py!}
```
@@ -167,13 +176,13 @@ The JWT specification says that there's a key `sub`, with the subject of the tok
It's optional to use it, but that's where you would put the user's identification, so we are using it here.
JWT might be used for other things apart from identifying a user and allowing him to perform operations directly on your API.
JWT might be used for other things apart from identifying a user and allowing them to perform operations directly on your API.
For example, you could identify a "car" or a "blog post".
Then you could add permissions about that entity, like "drive" (for the car) or "edit" (for the blog).
And then, you could give that JWT token to a user (or bot), and he could use it to perform those actions (drive the car, or edit the blog post) without even needing to have an account, just with the JWT token your API generated for that.
And then, you could give that JWT token to a user (or bot), and they could use it to perform those actions (drive the car, or edit the blog post) without even needing to have an account, just with the JWT token your API generated for that.
Using these ideas, JWT can be used for way more sophisticated scenarios.
@@ -247,7 +256,7 @@ Many packages that simplify it a lot have to make many compromises with the data
It gives you all the flexibility to choose the ones that fit your project the best.
And you can use directly many well maintained and widely used packages like `passlib` and `pyjwt`, because **FastAPI** doesn't require any complex mechanisms to integrate external packages.
And you can use directly many well maintained and widely used packages like `passlib` and `python-jose`, because **FastAPI** doesn't require any complex mechanisms to integrate external packages.
But it provides you the tools to simplify the process as much as possible without compromising flexibility, robustness, or security.

View File

@@ -47,7 +47,7 @@ Now let's use the utilities provided by **FastAPI** to handle this.
### `OAuth2PasswordRequestForm`
First, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depends` for the path `/token`:
First, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depends` in the *path operation* for `/token`:
```Python hl_lines="4 76"
{!../../../docs_src/security/tutorial003.py!}

View File

@@ -17,6 +17,10 @@ edit_uri: ''
google_analytics:
- UA-133183413-1
- auto
plugins:
- search
- markdownextradata:
data: data
nav:
- FastAPI: index.md
- Languages:

View File

@@ -5,14 +5,17 @@
<em>FastAPI framework, alto desempeño, fácil de aprender, rápido de programar, listo para producción</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://github.com/tiangolo/fastapi/actions?query=workflow%3APublish" target="_blank">
<img src="https://github.com/tiangolo/fastapi/workflows/Publish/badge.svg" alt="Publish">
</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">

View File

@@ -17,6 +17,10 @@ edit_uri: ''
google_analytics:
- UA-133183413-1
- auto
plugins:
- search
- markdownextradata:
data: data
nav:
- FastAPI: index.md
- Languages:

View File

@@ -17,6 +17,10 @@ edit_uri: ''
google_analytics:
- UA-133183413-1
- auto
plugins:
- search
- markdownextradata:
data: data
nav:
- FastAPI: index.md
- Languages:

View File

@@ -5,14 +5,17 @@
<em>Framework FastAPI, alta performance, fácil de aprender, fácil de codar, pronto para produção</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://github.com/tiangolo/fastapi/actions?query=workflow%3APublish" target="_blank">
<img src="https://github.com/tiangolo/fastapi/workflows/Publish/badge.svg" alt="Publish">
</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">

View File

@@ -17,6 +17,10 @@ edit_uri: ''
google_analytics:
- UA-133183413-1
- auto
plugins:
- search
- markdownextradata:
data: data
nav:
- FastAPI: index.md
- Languages:

View File

@@ -17,6 +17,10 @@ edit_uri: ''
google_analytics:
- UA-133183413-1
- auto
plugins:
- search
- markdownextradata:
data: data
nav:
- FastAPI: index.md
- Languages:

View File

@@ -498,13 +498,3 @@ $ bash scripts/test-cov-html.sh
</div>
该命令生成了一个 `./htmlcov/` 目录,如果你在浏览器中打开 `./htmlcov/index.html` 文件,你可以交互式地浏览被测试所覆盖的代码区块,并注意是否缺少了任何区块。
### 在编辑器中测试
如果你想要在编辑器中运行集成测试,请将 `./docs_src` 加入到你的 `PYTHONPATH` 变量中。
例如,在 VS Code 中你可以创建一个包含以下内容的 `.env` 文件:
```env
PYTHONPATH=./docs_src
```

View File

@@ -5,14 +5,17 @@
<em>FastAPI 框架,高性能,易于学习,高效编码,生产可用</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://github.com/tiangolo/fastapi/actions?query=workflow%3APublish" target="_blank">
<img src="https://github.com/tiangolo/fastapi/workflows/Publish/badge.svg" alt="Publish">
</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">

View File

@@ -17,6 +17,10 @@ edit_uri: ''
google_analytics:
- UA-133183413-1
- auto
plugins:
- search
- markdownextradata:
data: data
nav:
- FastAPI: index.md
- Languages:

View File

@@ -0,0 +1,14 @@
from fastapi import FastAPI, Request
app = FastAPI(
servers=[
{"url": "https://stag.example.com", "description": "Staging environment"},
{"url": "https://prod.example.com", "description": "Production environment"},
],
root_path="/api/v1",
)
@app.get("/app")
def read_main(request: Request):
return {"message": "Hello World", "root_path": request.scope.get("root_path")}

View File

@@ -0,0 +1,15 @@
from fastapi import FastAPI, Request
app = FastAPI(
servers=[
{"url": "https://stag.example.com", "description": "Staging environment"},
{"url": "https://prod.example.com", "description": "Production environment"},
],
root_path="/api/v1",
root_path_in_servers=False,
)
@app.get("/app")
def read_main(request: Request):
return {"message": "Hello World", "root_path": request.scope.get("root_path")}

View File

@@ -9,7 +9,7 @@ async def read_items():
return [{"name": "Foo"}]
def custom_openapi(openapi_prefix: str):
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
@@ -17,7 +17,6 @@ def custom_openapi(openapi_prefix: str):
version="2.5.0",
description="This is a very custom OpenAPI schema",
routes=app.routes,
openapi_prefix=openapi_prefix,
)
openapi_schema["info"]["x-logo"] = {
"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"

View File

@@ -1,11 +1,10 @@
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
from couchbase import LOCKMODE_WAIT
from couchbase.bucket import Bucket
from couchbase.cluster import Cluster, PasswordAuthenticator
from fastapi import FastAPI
from pydantic import BaseModel
USERPROFILE_DOC_TYPE = "userprofile"

View File

@@ -3,7 +3,7 @@ from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")

View File

@@ -6,7 +6,7 @@ from pydantic import BaseModel
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
class User(BaseModel):

View File

@@ -28,7 +28,7 @@ def fake_hash_password(password: str):
return "fakehashed" + password
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
class User(BaseModel):

View File

@@ -1,10 +1,9 @@
from datetime import datetime, timedelta
from typing import Optional
import jwt
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jwt import PyJWTError
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel
@@ -48,7 +47,7 @@ class UserInDB(User):
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
app = FastAPI()
@@ -99,7 +98,7 @@ async def get_current_user(token: str = Depends(oauth2_scheme)):
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
except PyJWTError:
except JWTError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:

View File

@@ -1,14 +1,13 @@
from datetime import datetime, timedelta
from typing import List, Optional
import jwt
from fastapi import Depends, FastAPI, HTTPException, Security, status
from fastapi.security import (
OAuth2PasswordBearer,
OAuth2PasswordRequestForm,
SecurityScopes,
)
from jwt import PyJWTError
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel, ValidationError
@@ -61,7 +60,7 @@ class UserInDB(User):
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="/token",
tokenUrl="token",
scopes={"me": "Read information about the current user.", "items": "Read items."},
)
@@ -121,7 +120,7 @@ async def get_current_user(
raise credentials_exception
token_scopes = payload.get("scopes", [])
token_data = TokenData(scopes=token_scopes, username=username)
except (PyJWTError, ValidationError):
except (JWTError, ValidationError):
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:

View File

@@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
__version__ = "0.58.1"
__version__ = "0.60.0"
from starlette import status

View File

@@ -50,6 +50,7 @@ class FastAPI(Starlette):
on_shutdown: Sequence[Callable] = None,
openapi_prefix: str = "",
root_path: str = "",
root_path_in_servers: bool = True,
**extra: Dict[str, Any],
) -> None:
self.default_response_class = default_response_class
@@ -71,7 +72,7 @@ class FastAPI(Starlette):
self.title = title
self.description = description
self.version = version
self.servers = servers
self.servers = servers or []
self.openapi_url = openapi_url
self.openapi_tags = openapi_tags
# TODO: remove when discarding the openapi_prefix parameter
@@ -83,6 +84,7 @@ class FastAPI(Starlette):
"https://fastapi.tiangolo.com/advanced/sub-applications/"
)
self.root_path = root_path or openapi_prefix
self.root_path_in_servers = root_path_in_servers
self.docs_url = docs_url
self.redoc_url = redoc_url
self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url
@@ -98,7 +100,7 @@ class FastAPI(Starlette):
self.openapi_schema: Optional[Dict[str, Any]] = None
self.setup()
def openapi(self, openapi_prefix: str = "") -> Dict:
def openapi(self) -> Dict:
if not self.openapi_schema:
self.openapi_schema = get_openapi(
title=self.title,
@@ -106,7 +108,6 @@ class FastAPI(Starlette):
openapi_version=self.openapi_version,
description=self.description,
routes=self.routes,
openapi_prefix=openapi_prefix,
tags=self.openapi_tags,
servers=self.servers,
)
@@ -114,10 +115,19 @@ class FastAPI(Starlette):
def setup(self) -> None:
if self.openapi_url:
server_urls = set()
for server_data in self.servers:
url = server_data.get("url")
if url:
server_urls.add(url)
async def openapi(req: Request) -> JSONResponse:
root_path = req.scope.get("root_path", "").rstrip("/")
return JSONResponse(self.openapi(root_path))
if root_path not in server_urls:
if root_path and self.root_path_in_servers:
self.servers.insert(0, {"url": root_path})
server_urls.add(root_path)
return JSONResponse(self.openapi())
self.add_route(self.openapi_url, openapi, include_in_schema=False)
if self.openapi_url and self.docs_url:

View File

@@ -60,9 +60,9 @@ try:
from pydantic.typing import ForwardRef, evaluate_forwardref
except ImportError: # pragma: nocover
# TODO: remove when removing support for Pydantic < 1.0.0
from pydantic import Schema as FieldInfo # type: ignore
from pydantic.fields import Field as ModelField # type: ignore
from pydantic.fields import Required, Shape # type: ignore
from pydantic import Schema as FieldInfo # type: ignore
from pydantic.schema import get_annotation_from_schema # type: ignore
from pydantic.utils import ForwardRef, evaluate_forwardref # type: ignore
@@ -246,7 +246,9 @@ def get_typed_signature(call: Callable) -> inspect.Signature:
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any:
annotation = param.annotation
if isinstance(annotation, str):
annotation = ForwardRef(annotation)
# Temporary ignore type
# Ref: https://github.com/samuelcolvin/pydantic/issues/1738
annotation = ForwardRef(annotation) # type: ignore
annotation = evaluate_forwardref(annotation, globalns, globalns)
return annotation

View File

@@ -1,3 +1,3 @@
METHODS_WITH_BODY = set(("POST", "PUT", "DELETE", "PATCH"))
METHODS_WITH_BODY = set(("GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"))
STATUS_CODES_WITH_NO_BODY = set((100, 101, 102, 103, 204, 304))
REF_PREFIX = "#/components/schemas/"

View File

@@ -331,7 +331,6 @@ def get_openapi(
openapi_version: str = "3.0.2",
description: str = None,
routes: Sequence[BaseRoute],
openapi_prefix: str = "",
tags: Optional[List[Dict[str, Any]]] = None,
servers: Optional[List[Dict[str, Union[str, Any]]]] = None,
) -> Dict:
@@ -356,9 +355,7 @@ def get_openapi(
if result:
path, security_schemes, path_definitions = result
if path:
paths.setdefault(openapi_prefix + route.path_format, {}).update(
path
)
paths.setdefault(route.path_format, {}).update(path)
if security_schemes:
components.setdefault("securitySchemes", {}).update(
security_schemes

View File

@@ -3,10 +3,8 @@ from base64 import b64decode
from typing import Optional
from fastapi.exceptions import HTTPException
from fastapi.openapi.models import (
HTTPBase as HTTPBaseModel,
HTTPBearer as HTTPBearerModel,
)
from fastapi.openapi.models import HTTPBase as HTTPBaseModel
from fastapi.openapi.models import HTTPBearer as HTTPBearerModel
from fastapi.security.base import SecurityBase
from fastapi.security.utils import get_authorization_scheme_param
from pydantic import BaseModel

View File

@@ -1,7 +1,8 @@
from typing import List, Optional
from fastapi.exceptions import HTTPException
from fastapi.openapi.models import OAuth2 as OAuth2Model, OAuthFlows as OAuthFlowsModel
from fastapi.openapi.models import OAuth2 as OAuth2Model
from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel
from fastapi.param_functions import Form
from fastapi.security.base import SecurityBase
from fastapi.security.utils import get_authorization_scheme_param
@@ -14,7 +15,7 @@ class OAuth2PasswordRequestForm:
This is a dependency class, use it like:
@app.post("/login")
def login(form_data: Oauth2PasswordRequestForm = Depends()):
def login(form_data: OAuth2PasswordRequestForm = Depends()):
data = form_data.parse()
print(data.username)
print(data.password)
@@ -64,7 +65,7 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
This is a dependency class, use it like:
@app.post("/login")
def login(form_data: Oauth2PasswordRequestFormStrict = Depends()):
def login(form_data: OAuth2PasswordRequestFormStrict = Depends()):
data = form_data.parse()
print(data.username)
print(data.password)

View File

@@ -18,8 +18,8 @@ try:
PYDANTIC_1 = True
except ImportError: # pragma: nocover
# TODO: remove when removing support for Pydantic < 1.0.0
from pydantic.fields import Field as ModelField # type: ignore
from pydantic import Schema as FieldInfo # type: ignore
from pydantic.fields import Field as ModelField # type: ignore
class UndefinedType: # type: ignore
def __repr__(self) -> str:

View File

@@ -31,7 +31,7 @@ def get_security(sec=Security(HTTPBasic())):
reusable_oauth2 = OAuth2(
flows={
"password": {
"tokenUrl": "/token",
"tokenUrl": "token",
"scopes": {"read:user": "Read a User", "write:user": "Create a user"},
}
}

View File

@@ -43,51 +43,56 @@ Documentation = "https://fastapi.tiangolo.com/"
[tool.flit.metadata.requires-extra]
test = [
"pytest==5.4.3",
"pytest-cov==2.10.0",
"mypy",
"black",
"isort",
"requests",
"email_validator",
"sqlalchemy",
"peewee",
"databases[sqlite]",
"orjson",
"async_exit_stack",
"async_generator",
"python-multipart",
"aiofiles",
"flask"
"pytest ==5.4.3",
"pytest-cov ==2.10.0",
"mypy ==0.782",
"black ==19.10b0",
"isort >=5.0.6,<6.0.0",
"requests >=2.24.0,<3.0.0",
"email_validator >=1.1.1,<2.0.0",
"sqlalchemy >=1.3.18,<2.0.0",
"peewee >=3.13.3,<4.0.0",
"databases[sqlite] >=0.3.2,<0.4.0",
"orjson >=3.2.1,<4.0.0",
"async_exit_stack >=1.0.1,<2.0.0",
"async_generator >=1.10,<2.0.0",
"python-multipart >=0.0.5,<0.0.6",
"aiofiles >=0.5.0,<0.6.0",
"flask >=1.1.2,<2.0.0"
]
doc = [
"mkdocs",
"mkdocs-material",
"markdown-include",
"typer",
"typer-cli",
"pyyaml"
"mkdocs >=1.1.2,<2.0.0",
"mkdocs-material >=5.4.0,<6.0.0",
"markdown-include >=0.5.1,<0.6.0",
"mkdocs-markdownextradata-plugin >=0.1.7,<0.2.0",
"typer >=0.3.0,<0.4.0",
"typer-cli >=0.0.9,<0.0.10",
"pyyaml >=5.3.1,<6.0.0"
]
dev = [
"pyjwt",
"passlib[bcrypt]",
"autoflake",
"flake8",
"uvicorn",
"graphene"
"python-jose[cryptography] >=3.1.0,<4.0.0",
"passlib[bcrypt] >=1.7.2,<2.0.0",
"autoflake >=1.3.1,<2.0.0",
"flake8 >=3.8.3,<4.0.0",
"uvicorn >=0.11.5,<0.12.0",
"graphene >=2.1.8,<3.0.0"
]
all = [
"requests",
"aiofiles",
"jinja2",
"python-multipart",
"itsdangerous",
"pyyaml",
"graphene",
"ujson",
"orjson",
"email_validator",
"uvicorn",
"async_exit_stack",
"async_generator"
"requests >=2.24.0,<3.0.0",
"aiofiles >=0.5.0,<0.6.0",
"jinja2 >=2.11.2,<3.0.0",
"python-multipart >=0.0.5,<0.0.6",
"itsdangerous >=1.1.0,<2.0.0",
"pyyaml >=5.3.1,<6.0.0",
"graphene >=2.1.8,<3.0.0",
"ujson >=3.0.0,<4.0.0",
"orjson >=3.2.1,<4.0.0",
"email_validator >=1.1.1,<2.0.0",
"uvicorn >=0.11.5,<0.12.0",
"async_exit_stack >=1.0.1,<2.0.0",
"async_generator >=1.10,<2.0.0"
]
[tool.isort]
profile = "black"
known_third_party = ["fastapi", "pydantic", "starlette"]

View File

@@ -0,0 +1,14 @@
#! /usr/bin/env bash
set -x
set -e
PR=${PR:?Variable not set}
DEPLOY_URL=${DEPLOY_URL:?Variable not set}
GITHUB_TOKEN=${GITHUB_TOKEN:?Variable not set}
COMMIT=${COMMIT:?Variable not set}
curl \
-H "Authorization: token ${GITHUB_TOKEN}" \
https://api.github.com/repos/tiangolo/fastapi/issues/${PR}/comments \
-d '{"body": "📝 Docs preview for commit '"${COMMIT} at: ${DEPLOY_URL}"'"}'

View File

@@ -132,6 +132,7 @@ def build_lang(
dist_path: Path = site_path / lang
shutil.rmtree(build_lang_path, ignore_errors=True)
shutil.copytree(lang_path, build_lang_path)
shutil.copytree(en_docs_path / "data", build_lang_path / "data")
en_config_path: Path = en_lang_path / mkdocs_name
en_config: dict = mkdocs.utils.yaml_load(en_config_path.read_text(encoding="utf-8"))
nav = en_config["nav"]
@@ -211,6 +212,12 @@ def build_all():
shutil.copyfile(en_index, "README.md")
def update_single_lang(lang: str):
lang_path = docs_path / lang
typer.echo(f"Updating {lang_path.name}")
update_config(lang_path.name)
@app.command()
def update_languages(
lang: str = typer.Argument(
@@ -226,11 +233,9 @@ def update_languages(
if lang is None:
for lang_path in get_lang_paths():
if lang_path.is_dir():
typer.echo(f"Updating {lang_path.name}")
update_config(lang_path.name)
update_single_lang(lang_path.name)
else:
typer.echo(f"Updating {lang}")
update_config(lang)
update_single_lang(lang)
@app.command()

View File

@@ -2,5 +2,5 @@
set -x
# Sort imports one per line, so autoflake can remove unused imports
isort --recursive --force-single-line-imports --thirdparty fastapi --apply fastapi tests docs_src scripts
isort fastapi tests docs_src scripts --force-single-line-imports
sh ./scripts/format.sh

View File

@@ -3,4 +3,4 @@ set -x
autoflake --remove-all-unused-imports --recursive --remove-unused-variables --in-place docs_src fastapi tests scripts --exclude=__init__.py
black fastapi tests docs_src scripts
isort --multi-line=3 --trailing-comma --force-grid-wrap=0 --combine-as --line-width 88 --recursive --thirdparty fastapi --thirdparty pydantic --thirdparty starlette --apply fastapi tests docs_src scripts
isort fastapi tests docs_src scripts

View File

@@ -5,4 +5,4 @@ set -x
mypy fastapi
black fastapi tests --check
isort --multi-line=3 --trailing-comma --force-grid-wrap=0 --combine-as --line-width 88 --recursive --check-only --thirdparty fastapi --thirdparty fastapi --thirdparty pydantic --thirdparty starlette fastapi tests
isort fastapi tests docs_src scripts --check-only

View File

@@ -2,8 +2,4 @@
set -e
bash scripts/publish.sh
bash scripts/trigger-docker.sh
python scripts/gitter_releases_bot.py

View File

@@ -7,4 +7,4 @@ bash ./scripts/lint.sh
# Check README.md is up to date
diff --brief docs/en/docs/index.md README.md
export PYTHONPATH=./docs_src
pytest --cov=fastapi --cov=tests --cov=docs/src --cov-report=term-missing tests ${@}
pytest --cov=fastapi --cov=tests --cov=docs/src --cov-report=term-missing --cov-report=xml tests ${@}

View File

@@ -1,17 +0,0 @@
#!/usr/bin/env bash
set -e
set -x
body='{
"request": {
"branch":"master"
}}'
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Travis-API-Version: 3" \
-H "Authorization: token $TRAVIS_TOKEN" \
-d "$body" \
https://api.travis-ci.org/repo/tiangolo%2Fuvicorn-gunicorn-fastapi-docker/requests

View File

@@ -0,0 +1,21 @@
#! /usr/bin/env bash
set -x
set -e
PR=${PR}
if [ -z "$PR" ]; then
echo "Not a PR build, skip trigger docs preview"
exit 0
fi
NAME=${NAME:?Variable not set}
GITHUB_TOKEN=${GITHUB_TOKEN:?Variable not set}
curl -v \
-X POST \
-H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/tiangolo/fastapi/actions/workflows/preview-docs.yml/dispatches \
-d '{"ref":"master", "inputs": {"pr": "'"${PR}"'", "name": "'"${NAME}"'"}}'

13
scripts/unzip-docs.sh Normal file
View File

@@ -0,0 +1,13 @@
#! /usr/bin/env bash
set -x
set -e
if [ -d ./site/ ]; then
rm -rf ./site/
fi
unzip archive.zip
# Double zipped by GitHub when downlading the archive
unzip docs.zip
rm -rf archive.zip
rm -rf docs.zip

9
scripts/zip-docs.sh Normal file
View File

@@ -0,0 +1,9 @@
#! /usr/bin/env bash
set -x
set -e
if [ -f docs.zip ]; then
rm -rf docs.zip
fi
zip -r docs.zip ./site

View File

@@ -15,7 +15,7 @@ openapi_schema = {
"openapi": "3.0.2",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/api/v1/app": {
"/app": {
"get": {
"summary": "Read Main",
"operationId": "read_main_app_get",
@@ -28,6 +28,7 @@ openapi_schema = {
}
}
},
"servers": [{"url": "/api/v1"}],
}

View File

@@ -0,0 +1,108 @@
from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel
app = FastAPI()
class Product(BaseModel):
name: str
description: str = None
price: float
@app.get("/product")
async def create_item(product: Product):
return product
client = TestClient(app)
openapi_schema = {
"openapi": "3.0.2",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/product": {
"get": {
"summary": "Create Item",
"operationId": "create_item_product_get",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Product"}
}
},
"required": True,
},
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
"Product": {
"title": "Product",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {"title": "Description", "type": "string"},
"price": {"title": "Price", "type": "number"},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {"type": "string"},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
}
},
}
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == openapi_schema
def test_get_with_body():
body = {"name": "Foo", "description": "Some description", "price": 5.5}
response = client.get("/product", json=body)
assert response.json() == body

View File

@@ -9,7 +9,7 @@ app = FastAPI()
reusable_oauth2 = OAuth2(
flows={
"password": {
"tokenUrl": "/token",
"tokenUrl": "token",
"scopes": {"read:users": "Read the users", "write:users": "Create users"},
}
}
@@ -144,7 +144,7 @@ openapi_schema = {
"read:users": "Read the users",
"write:users": "Create users",
},
"tokenUrl": "/token",
"tokenUrl": "token",
}
},
}

View File

@@ -7,7 +7,7 @@ from fastapi.testclient import TestClient
app = FastAPI()
oauth2_scheme = OAuth2AuthorizationCodeBearer(
authorizationUrl="/authorize", tokenUrl="/token", auto_error=True
authorizationUrl="authorize", tokenUrl="token", auto_error=True
)
@@ -42,8 +42,8 @@ openapi_schema = {
"type": "oauth2",
"flows": {
"authorizationCode": {
"authorizationUrl": "/authorize",
"tokenUrl": "/token",
"authorizationUrl": "authorize",
"tokenUrl": "token",
"scopes": {},
}
},

View File

@@ -11,7 +11,7 @@ app = FastAPI()
reusable_oauth2 = OAuth2(
flows={
"password": {
"tokenUrl": "/token",
"tokenUrl": "token",
"scopes": {"read:users": "Read the users", "write:users": "Create users"},
}
},
@@ -148,7 +148,7 @@ openapi_schema = {
"read:users": "Read the users",
"write:users": "Create users",
},
"tokenUrl": "/token",
"tokenUrl": "token",
}
},
}

View File

@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
from additional_responses.tutorial001 import app
from docs_src.additional_responses.tutorial001 import app
client = TestClient(app)

View File

@@ -3,7 +3,7 @@ import shutil
from fastapi.testclient import TestClient
from additional_responses.tutorial002 import app
from docs_src.additional_responses.tutorial002 import app
client = TestClient(app)

View File

@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
from additional_responses.tutorial003 import app
from docs_src.additional_responses.tutorial003 import app
client = TestClient(app)

View File

@@ -3,7 +3,7 @@ import shutil
from fastapi.testclient import TestClient
from additional_responses.tutorial004 import app
from docs_src.additional_responses.tutorial004 import app
client = TestClient(app)

View File

@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
from additional_status_codes.tutorial001 import app
from docs_src.additional_status_codes.tutorial001 import app
client = TestClient(app)

View File

@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
from advanced_middleware.tutorial001 import app
from docs_src.advanced_middleware.tutorial001 import app
def test_middleware():

View File

@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
from advanced_middleware.tutorial002 import app
from docs_src.advanced_middleware.tutorial002 import app
def test_middleware():

View File

@@ -1,7 +1,7 @@
from fastapi.responses import PlainTextResponse
from fastapi.testclient import TestClient
from advanced_middleware.tutorial003 import app
from docs_src.advanced_middleware.tutorial003 import app
@app.get("/large")

View File

@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
from async_sql_databases.tutorial001 import app
from docs_src.async_sql_databases.tutorial001 import app
openapi_schema = {
"openapi": "3.0.2",

View File

@@ -3,7 +3,7 @@ from pathlib import Path
from fastapi.testclient import TestClient
from background_tasks.tutorial001 import app
from docs_src.background_tasks.tutorial001 import app
client = TestClient(app)

View File

@@ -3,7 +3,7 @@ from pathlib import Path
from fastapi.testclient import TestClient
from background_tasks.tutorial002 import app
from docs_src.background_tasks.tutorial002 import app
client = TestClient(app)

View File

@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
from behind_a_proxy.tutorial001 import app
from docs_src.behind_a_proxy.tutorial001 import app
client = TestClient(app, root_path="/api/v1")
@@ -8,7 +8,7 @@ openapi_schema = {
"openapi": "3.0.2",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/api/v1/app": {
"/app": {
"get": {
"summary": "Read Main",
"operationId": "read_main_app_get",
@@ -21,6 +21,7 @@ openapi_schema = {
}
}
},
"servers": [{"url": "/api/v1"}],
}

View File

@@ -1,6 +1,6 @@
from fastapi.testclient import TestClient
from behind_a_proxy.tutorial002 import app
from docs_src.behind_a_proxy.tutorial002 import app
client = TestClient(app)
@@ -8,7 +8,7 @@ openapi_schema = {
"openapi": "3.0.2",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/api/v1/app": {
"/app": {
"get": {
"summary": "Read Main",
"operationId": "read_main_app_get",
@@ -21,6 +21,7 @@ openapi_schema = {
}
}
},
"servers": [{"url": "/api/v1"}],
}

View File

@@ -0,0 +1,41 @@
from fastapi.testclient import TestClient
from docs_src.behind_a_proxy.tutorial003 import app
client = TestClient(app)
openapi_schema = {
"openapi": "3.0.2",
"info": {"title": "FastAPI", "version": "0.1.0"},
"servers": [
{"url": "/api/v1"},
{"url": "https://stag.example.com", "description": "Staging environment"},
{"url": "https://prod.example.com", "description": "Production environment"},
],
"paths": {
"/app": {
"get": {
"summary": "Read Main",
"operationId": "read_main_app_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
}
}
},
}
def test_openapi():
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == openapi_schema
def test_main():
response = client.get("/app")
assert response.status_code == 200
assert response.json() == {"message": "Hello World", "root_path": "/api/v1"}

View File

@@ -0,0 +1,40 @@
from fastapi.testclient import TestClient
from docs_src.behind_a_proxy.tutorial004 import app
client = TestClient(app)
openapi_schema = {
"openapi": "3.0.2",
"info": {"title": "FastAPI", "version": "0.1.0"},
"servers": [
{"url": "https://stag.example.com", "description": "Staging environment"},
{"url": "https://prod.example.com", "description": "Production environment"},
],
"paths": {
"/app": {
"get": {
"summary": "Read Main",
"operationId": "read_main_app_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
}
}
},
}
def test_openapi():
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == openapi_schema
def test_main():
response = client.get("/app")
assert response.status_code == 200
assert response.json() == {"message": "Hello World", "root_path": "/api/v1"}

View File

@@ -1,7 +1,7 @@
import pytest
from fastapi.testclient import TestClient
from bigger_applications.app.main import app
from docs_src.bigger_applications.app.main import app
client = TestClient(app)

View File

@@ -3,7 +3,7 @@ from unittest.mock import patch
import pytest
from fastapi.testclient import TestClient
from body.tutorial001 import app
from docs_src.body.tutorial001 import app
client = TestClient(app)

View File

@@ -1,7 +1,7 @@
import pytest
from fastapi.testclient import TestClient
from body_fields.tutorial001 import app
from docs_src.body_fields.tutorial001 import app
# TODO: remove when removing support for Pydantic < 1.0.0
try:

Some files were not shown because too many files have changed in this diff Show More