Compare commits

...

181 Commits

Author SHA1 Message Date
Sebastián Ramírez
148bcf5ce4 🔖 Release version 0.90.0 2023-02-08 11:30:01 +01:00
Sebastián Ramírez
e4c8df062b 📝 Update release notes 2023-02-08 11:28:55 +01:00
github-actions
b313f86338 📝 Update release notes 2023-02-08 10:23:46 +00:00
Marcelo Trylesinski
9293795e99 ⬆️ Bump Starlette from 0.22.0 to 0.23.0 (#5739)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-02-08 11:23:07 +01:00
github-actions
58757f63af 📝 Update release notes 2023-02-07 16:51:06 +00:00
Leon
88dc4ce3d7 📝 Add article "Tortoise ORM / FastAPI 整合快速筆記" to External Links (#5496)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-02-07 16:50:02 +00:00
github-actions
c9d3656a6e 📝 Update release notes 2023-02-07 16:46:40 +00:00
Sebastián Ramírez
3e4840f21b ⬆️ Upgrade Ubuntu version for docs workflow (#5971) 2023-02-07 16:46:03 +00:00
github-actions
9cb2586499 📝 Update release notes 2023-02-07 13:33:51 +00:00
Alexander Sviridov
8b62319d6c 🌐 Add Russian translation for docs/ru/docs/tutorial/body-fields.md (#5898) 2023-02-07 14:33:16 +01:00
github-actions
6e3c707c60 📝 Update release notes 2023-02-07 13:28:45 +00:00
Sebastián Ramírez
94fa151881 🌐 Add Russian translation for docs/ru/docs/help-fastapi.md (#5970)
Co-authored-by: Xewus <xewuss@yandex.ru>
Co-authored-by: Vladislav Kramorenko <85196001+Xewus@users.noreply.github.com>
2023-02-07 13:28:10 +00:00
github-actions
a4f3bc5a69 📝 Update release notes 2023-02-07 13:10:13 +00:00
github-actions
05342cc264 📝 Update release notes 2023-02-07 13:09:45 +00:00
Bruno Artur Torres Lopes Pereira
8115282ed3 🌐 Add Portuguese translation for docs/pt/docs/tutorial/static-files.md (#5858)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-02-07 14:09:32 +01:00
felipebpl
9ad2cb29f9 🌐 Add Portuguese translation for docs/pt/docs/tutorial/encoder.md (#5525)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-02-07 13:09:00 +00:00
github-actions
23d0efa894 📝 Update release notes 2023-02-07 13:05:18 +00:00
Vladislav Kramorenko
e1129af819 🌐 Add Russian translation for docs/ru/docs/contributing.md (#5870)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-02-07 14:04:38 +01:00
github-actions
c59539913d 📝 Update release notes 2023-02-03 17:56:25 +00:00
github-actions[bot]
7a64587d7f 👥 Update FastAPI People (#5954)
Co-authored-by: github-actions <github-actions@github.com>
2023-02-03 18:55:25 +01:00
github-actions
62fc0b4923 📝 Update release notes 2023-02-03 17:55:03 +00:00
Sebastián Ramírez
fc7da62005 📝 Micro-tweak help docs (#5960) 2023-02-03 17:54:22 +00:00
github-actions
40df42f5c7 📝 Update release notes 2023-01-31 14:03:27 +00:00
Sebastián Ramírez
0b0af37b0e 🔧 Update new issue chooser to direct to GitHub Discussions (#5948) 2023-01-31 14:02:52 +00:00
github-actions
73920366e5 📝 Update release notes 2023-01-30 16:50:10 +00:00
Sebastián Ramírez
682067cab2 📝 Recommend GitHub Discussions for questions (#5944) 2023-01-30 16:49:32 +00:00
github-actions
ca30b92dd7 📝 Update release notes 2023-01-30 16:24:22 +00:00
Sebastián Ramírez
72b542d90a 🔧 Update sponsors badges (#5943) 2023-01-30 16:23:43 +00:00
github-actions
9012ab8bcd 📝 Update release notes 2023-01-30 15:16:30 +00:00
Sebastián Ramírez
9530defba8 Compute FastAPI Experts including GitHub Discussions (#5941) 2023-01-30 15:15:56 +00:00
github-actions
7c23bbd96f 📝 Update release notes 2023-01-30 15:10:29 +00:00
Sebastián Ramírez
11b6c0146d ⬆️ Upgrade isort and update pre-commit (#5940) 2023-01-30 16:09:51 +01:00
github-actions
4e29835609 📝 Update release notes 2023-01-24 14:30:38 +00:00
Sebastián Ramírez
9858577cd6 🔧 Add template for questions in Discussions (#5920) 2023-01-24 18:30:03 +04:00
github-actions
cd1ee83435 📝 Update release notes 2023-01-23 14:24:31 +00:00
Sebastián Ramírez
fe74890b4b 🔧 Update Sponsor Budget Insight to Powens (#5916) 2023-01-23 14:23:53 +00:00
github-actions
97a2ebc219 📝 Update release notes 2023-01-23 14:13:39 +00:00
Sebastián Ramírez
805226c2b0 🔧 Update GitHub Sponsors badge data (#5915) 2023-01-23 14:13:03 +00:00
Sebastián Ramírez
5905c3f740 🔖 Release version 0.89.1 2023-01-10 20:31:23 +04:00
Sebastián Ramírez
00f3c831f3 📝 Update release notes 2023-01-10 20:30:10 +04:00
github-actions
e84cb6663e 📝 Update release notes 2023-01-10 16:23:24 +00:00
Sebastián Ramírez
fb8e9083f4 📝 Update docs and examples for Response Model with Return Type Annotations, and update runtime error (#5873) 2023-01-10 16:22:47 +00:00
github-actions
6b83525ff4 📝 Update release notes 2023-01-10 12:46:04 +00:00
Marcelo Trylesinski
fba7493042 🐛 Ignore Response classes on return annotation (#5855)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-01-10 12:45:18 +00:00
github-actions
53973f7f94 📝 Update release notes 2023-01-10 12:38:39 +00:00
Kader M
1562592bde 🌐 Add Turkish translation for docs/tr/docs/tutorial/first_steps.md (#5691)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-10 12:38:01 +00:00
github-actions
52a84175c1 📝 Update release notes 2023-01-10 12:34:24 +00:00
Raf Rasenberg
929289b630 📝 Add External Link: FastAPI lambda container: serverless simplified (#5784)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-10 16:33:36 +04:00
Sebastián Ramírez
69bd7d8501 🔖 Release version 0.89.0 2023-01-07 21:17:10 +04:00
Sebastián Ramírez
a6af7c27f8 📝 Update release notes 2023-01-07 21:15:11 +04:00
github-actions
aa6a8e5d49 📝 Update release notes 2023-01-07 17:05:20 +00:00
dependabot[bot]
c482dd3d42 ⬆ Update coverage[toml] requirement from <7.0,>=6.5.0 to >=6.5.0,<8.0 (#5801)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 17:04:43 +00:00
github-actions
681e5c0199 📝 Update release notes 2023-01-07 17:02:15 +00:00
github-actions
eb39b0f8f8 📝 Update release notes 2023-01-07 17:01:58 +00:00
Xhy-5000
27ce2e2108 📝 Add External Link: Authorization on FastAPI with Casbin (#5712)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 21:01:38 +04:00
dependabot[bot]
f56b0d571d ⬆ Update uvicorn[standard] requirement from <0.19.0,>=0.12.0 to >=0.12.0,<0.21.0 for development (#5795)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 17:01:21 +00:00
github-actions
5c6d7b2ff3 📝 Update release notes 2023-01-07 16:57:45 +00:00
Nonso Mgbechi
78813a543d ✏ Fix typo in docs/en/docs/async.md (#5785)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 20:56:58 +04:00
github-actions
903e3be3b8 📝 Update release notes 2023-01-07 16:56:07 +00:00
dependabot[bot]
a17da3d0f4 ⬆ Bump dawidd6/action-download-artifact from 2.24.2 to 2.24.3 (#5842)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 20:55:29 +04:00
github-actions
d202598c71 📝 Update release notes 2023-01-07 15:35:51 +00:00
github-actions[bot]
2dfdcea69a 👥 Update FastAPI People (#5825)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 15:35:14 +00:00
github-actions
789d649fba 📝 Update release notes 2023-01-07 15:31:38 +00:00
Kelby Faessler
bea1fdd2eb ✏ Fix typo in docs/en/docs/deployment/concepts.md (#5824) 2023-01-07 19:31:03 +04:00
github-actions
929c700117 📝 Update release notes 2023-01-07 15:13:27 +00:00
dependabot[bot]
f4e895bc8a ⬆ Bump types-ujson from 5.5.0 to 5.6.0.0 (#5735)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 15:12:49 +00:00
github-actions
adef9f4c02 📝 Update release notes 2023-01-07 15:08:57 +00:00
dependabot[bot]
6e1152d31f ⬆ Bump pypa/gh-action-pypi-publish from 1.5.2 to 1.6.4 (#5750)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 15:08:12 +00:00
github-actions
9812116dc7 📝 Update release notes 2023-01-07 14:55:35 +00:00
Sviatoslav Sydorenko
2583a83f9d 👷 Add GitHub Action gate/check (#5492) 2023-01-07 18:54:59 +04:00
github-actions
59d654672f 📝 Update release notes 2023-01-07 14:46:09 +00:00
Vladislav Kramorenko
d0027de64f 🌐 Add Russian translation for docs/ru/docs/fastapi-people.md (#5577)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 18:45:32 +04:00
github-actions
3c20b6e42b 📝 Update release notes 2023-01-07 14:34:13 +00:00
Ben Ho
3178c17776 🌐 Fix typo in Chinese translation for docs/zh/docs/benchmarks.md (#4269)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 14:33:29 +00:00
github-actions
1be95ba02d 📝 Update release notes 2023-01-07 14:21:59 +00:00
Nina Hwang
2a3a786dd7 🌐 Add Korean translation for docs/tutorial/cors.md (#3764)
Co-authored-by: weekwith.me <63915557+0417taehyun@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-01-07 18:21:23 +04:00
github-actions
a3edc76051 📝 Update release notes 2023-01-07 14:14:07 +00:00
Sebastián Ramírez
d70eef825e 🔧 Update sponsors, add Svix (#5848) 2023-01-07 14:13:34 +00:00
github-actions
679aee85ce 📝 Update release notes 2023-01-07 13:59:26 +00:00
Sebastián Ramírez
cb35e275e3 🔧 Remove Doist sponsor (#5847) 2023-01-07 13:58:46 +00:00
github-actions
18d087f9c6 📝 Update release notes 2023-01-07 13:46:24 +00:00
Yurii Karabas
d0573f5713 Add support for function return type annotations to declare the response_model (#1436)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 17:45:48 +04:00
github-actions
efc12c5cdb 📝 Update release notes 2022-12-16 20:25:51 +00:00
dependabot[bot]
4d5cbc71ac ⬆ Update sqlalchemy requirement from <=1.4.41,>=1.3.18 to >=1.3.18,<1.4.43 (#5540)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2022-12-16 23:41:48 +04:00
github-actions
10500dbc03 📝 Update release notes 2022-12-16 19:11:14 +00:00
dependabot[bot]
63ad0ed4a6 ⬆ Bump nwtgck/actions-netlify from 1.2.4 to 2.0.0 (#5757)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-16 23:10:29 +04:00
github-actions
dc9fb1305a 📝 Update release notes 2022-12-16 18:11:45 +00:00
Sebastián Ramírez
9efab1bd96 👷 Refactor CI artifact upload/download for docs previews (#5793) 2022-12-16 22:11:03 +04:00
github-actions
97f04ab58c 📝 Update release notes 2022-12-03 22:26:17 +00:00
dependabot[bot]
1ba515a18d ⬆ Bump pypa/gh-action-pypi-publish from 1.5.1 to 1.5.2 (#5714)
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.5.1 to 1.5.2.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/v1.5.1...v1.5.2)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-03 23:25:39 +01:00
github-actions
5f1cc3a5ff 📝 Update release notes 2022-12-02 17:23:12 +00:00
github-actions[bot]
41db4cba4c 👥 Update FastAPI People (#5722)
Co-authored-by: github-actions <github-actions@github.com>
2022-12-02 18:22:33 +01:00
github-actions
83bcdc40d8 📝 Update release notes 2022-11-29 18:06:22 +00:00
Sebastián Ramírez
8bdab084f9 🔧 Update sponsors, disable course bundle (#5713) 2022-11-29 19:05:40 +01:00
github-actions
5c4054ab8a 📝 Update release notes 2022-11-28 07:13:14 +00:00
dependabot[bot]
7e4e0d22ae ⬆ Update typer[all] requirement from <0.7.0,>=0.6.1 to >=0.6.1,<0.8.0 (#5639)
Updates the requirements on [typer[all]](https://github.com/tiangolo/typer) to permit the latest version.
- [Release notes](https://github.com/tiangolo/typer/releases)
- [Changelog](https://github.com/tiangolo/typer/blob/master/docs/release-notes.md)
- [Commits](https://github.com/tiangolo/typer/compare/0.6.1...0.7.0)

---
updated-dependencies:
- dependency-name: typer[all]
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2022-11-28 08:12:37 +01:00
Sebastián Ramírez
612b8ff168 🔖 Release version 0.88.0 2022-11-27 15:50:32 +01:00
Sebastián Ramírez
46bb5d2c4b 📝 Update release notes 2022-11-27 15:49:33 +01:00
github-actions
c458ca6f07 📝 Update release notes 2022-11-27 14:46:48 +00:00
Eugenio Panadero
46974c510e ⬆ Bump Starlette to version 0.22.0 to fix bad encoding for query parameters in TestClient (#5659)
closes https://github.com/tiangolo/fastapi/issues/5646
2022-11-27 15:46:06 +01:00
github-actions
89ec1f2d36 📝 Update release notes 2022-11-27 14:23:13 +00:00
github-actions
128c925c35 📝 Update release notes 2022-11-27 14:22:41 +00:00
Sebastián Ramírez
884203676d 👷 Tweak build-docs to improve CI performance (#5699) 2022-11-27 14:22:30 +00:00
pre-commit-ci[bot]
9b4e85f088 ⬆ [pre-commit.ci] pre-commit autoupdate (#5566)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2022-11-27 15:22:03 +01:00
github-actions
991db7b05a 📝 Update release notes 2022-11-27 14:14:28 +00:00
Ayrton Freeman
ebd917a530 🌐 Add Portuguese translation for docs/pt/docs/deployment/docker.md (#5663)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2022-11-27 14:13:50 +00:00
github-actions
99d8470a8e 📝 Update release notes 2022-11-27 14:00:09 +00:00
Sebastián Ramírez
7c5626bef7 ⬆️ Upgrade Ruff (#5698) 2022-11-27 14:59:32 +01:00
github-actions
91e5a5d1cf 📝 Update release notes 2022-11-27 13:53:52 +00:00
Sebastián Ramírez
fcc4dd61f1 👷 Remove pip cache for Smokeshow as it depends on a requirements.txt (#5700) 2022-11-27 14:53:13 +01:00
github-actions
0b53ee505b 📝 Update release notes 2022-11-27 13:40:03 +00:00
Sebastián Ramírez
c942a9b8d0 💚 Fix pip cache for Smokeshow (#5697) 2022-11-27 14:39:17 +01:00
github-actions
c77384fc8f 📝 Update release notes 2022-11-27 13:12:12 +00:00
Sebastián Ramírez
0c07e542a7 👷 Fix and tweak CI cache handling (#5696) 2022-11-27 13:11:22 +00:00
github-actions
ec30c3001d 📝 Update release notes 2022-11-25 11:39:33 +00:00
Michael Adkins
22837ee202 👷 Update setup-python action in tests to use new caching feature (#5680) 2022-11-25 12:38:55 +01:00
github-actions
0eb05cabbf 📝 Update release notes 2022-11-22 13:30:37 +00:00
Muhammad Abdur Rakib
6883f362a5 ✏️ Fix typo in docs for docs/en/docs/advanced/middleware.md (#5376)
Fix typo in documentation

A full-stop was missing in `TrustedHostMiddleware` section

Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2022-11-22 13:29:57 +00:00
github-actions
4638b2c64e 📝 Update release notes 2022-11-13 22:07:03 +00:00
dependabot[bot]
3c01b2469f ⬆ Bump black from 22.8.0 to 22.10.0 (#5569)
Bumps [black](https://github.com/psf/black) from 22.8.0 to 22.10.0.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/compare/22.8.0...22.10.0)

---
updated-dependencies:
- dependency-name: black
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2022-11-13 23:06:28 +01:00
Sebastián Ramírez
63a5ffcf57 🔖 Release version 0.87.0 2022-11-13 22:36:53 +01:00
Sebastián Ramírez
da1c67338f 🔖 Release version 0.87.0 2022-11-13 22:27:53 +01:00
Sebastián Ramírez
46a509649d 📝 Update release notes 2022-11-13 22:26:43 +01:00
github-actions
1d416c4c53 📝 Update release notes 2022-11-13 20:51:19 +00:00
Sebastián Ramírez
89095eba4f ⬆️ Upgrade and relax dependencies for extras "all" (#5634) 2022-11-13 21:50:43 +01:00
github-actions
5a63f660de 📝 Update release notes 2022-11-13 20:30:05 +00:00
Sebastián Ramírez
9c483505e3 ✏️ Tweak Help FastAPI from PR review after merging (#5633) 2022-11-13 20:29:23 +00:00
github-actions
ad0e923fed 📝 Update release notes 2022-11-13 20:29:15 +00:00
Pax
fc717f84ff ✏️ Clarify docs on CORS (#5627) 2022-11-13 21:28:37 +01:00
Sebastián Ramírez
b1204a9b62 📝 Update release notes 2022-11-13 21:23:22 +01:00
github-actions
16630bf54d 📝 Update release notes 2022-11-13 19:34:43 +00:00
Sebastián Ramírez
50ea75ae98 📝 Update Help FastAPI: Help Maintain FastAPI (#5632) 2022-11-13 20:34:09 +01:00
github-actions
a0852e2f53 📝 Update release notes 2022-11-13 18:19:43 +00:00
Sebastián Ramírez
fa74093440 Use Ruff for linting (#5630) 2022-11-13 19:19:04 +01:00
github-actions
bcd9ab95e1 📝 Update release notes 2022-11-13 16:11:29 +00:00
Sebastián Ramírez
d537ee93d7 Re-export Starlette's WebSocketException and add it to docs (#5629) 2022-11-13 17:10:54 +01:00
github-actions
1c93d5523a 📝 Update release notes 2022-11-13 15:20:44 +00:00
Sebastián Ramírez
f92f87d379 📝 Update references to Requests for tests to HTTPX, and add HTTPX to extras (#5628) 2022-11-13 16:20:05 +01:00
github-actions
57141ccac4 📝 Update release notes 2022-11-13 14:35:13 +00:00
github-actions
46b903f70b 📝 Update release notes 2022-11-13 14:26:43 +00:00
Paweł Rubin
fdbd48be5f ⬆ Upgrade Starlette to 0.21.0, including the new [TestClient based on HTTPX](https://github.com/encode/starlette/releases/tag/0.21.0) (#5471)
Co-authored-by: Paweł Rubin <pawel.rubin@ocado.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2022-11-13 15:26:09 +01:00
github-actions
5f67ac6fd6 📝 Update release notes 2022-11-13 14:04:27 +00:00
axel584
ba5310f731 🌐 Add French translation for docs/fr/docs/advanced/additional-status-code.md (#5477)
Co-authored-by: Julian Maurin <julian.maurin.perso@pm.me>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2022-11-13 14:03:48 +00:00
github-actions
f57ccd8ef3 📝 Update release notes 2022-11-13 13:59:55 +00:00
Bruno Artur Torres Lopes Pereira
c040e3602a 🌐 Add Portuguese translation for docs/pt/docs/tutorial/request-forms-and-files.md (#5579)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2022-11-13 14:59:16 +01:00
github-actions
86d4073632 📝 Update release notes 2022-11-13 13:59:09 +00:00
Ryusei Ishikawa
59208e4ddc 🌐 Add Japanese translation for docs/ja/docs/advanced/websockets.md (#4983)
Co-authored-by: tokusumi <41147016+tokusumi@users.noreply.github.com>
Co-authored-by: komtaki <39375566+komtaki@users.noreply.github.com>
2022-11-13 14:58:31 +01:00
nikkie
0781a91d19 🌐 Fix highlight lines for Japanese translation for docs/tutorial/query-params.md (#2969)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
Fix https://github.com/tiangolo/fastapi/issues/2966
2022-11-13 14:57:52 +01:00
github-actions
41735d2de9 📝 Update release notes 2022-11-10 12:22:58 +00:00
Sebastián Ramírez
a0c717d784 🛠 Add Arabic issue number to Notify Translations GitHub Action (#5610) 2022-11-10 12:22:25 +00:00
github-actions
0ed9ca78bc 📝 Update release notes 2022-11-10 11:16:30 +00:00
dependabot[bot]
678d35994a ⬆ Bump dawidd6/action-download-artifact from 2.24.1 to 2.24.2 (#5609)
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 2.24.1 to 2.24.2.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](https://github.com/dawidd6/action-download-artifact/compare/v2.24.1...v2.24.2)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-10 12:15:55 +01:00
github-actions
a7edd0b80d 📝 Update release notes 2022-11-09 11:46:50 +00:00
dependabot[bot]
f36d2e2b2b ⬆ Bump dawidd6/action-download-artifact from 2.24.0 to 2.24.1 (#5603)
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 2.24.0 to 2.24.1.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](https://github.com/dawidd6/action-download-artifact/compare/v2.24.0...v2.24.1)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-09 12:46:14 +01:00
github-actions
5f0e095689 📝 Update release notes 2022-11-04 19:20:29 +00:00
Sebastián Ramírez
ccd242348f 🔖 Release version 0.86.0 2022-11-03 22:17:44 +01:00
Sebastián Ramírez
066cfae56e 📝 Update release notes 2022-11-03 22:16:37 +01:00
github-actions
51e768e85a 📝 Update release notes 2022-11-03 21:13:25 +00:00
Sebastián Ramírez
10fbfd6dc7 ⬆ Add Python 3.11 to the officially supported versions (#5587) 2022-11-03 21:12:43 +00:00
Sebastián Ramírez
85e602d7cc 📝 Update release notes 2022-11-03 22:05:26 +01:00
github-actions
fbc13d1f5b 📝 Update release notes 2022-11-03 21:01:09 +00:00
Vivek Ashokkumar
d4e2bdb33a ✏ Fix typo in docs/en/docs/tutorial/security/oauth2-jwt.md (#5584)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2022-11-03 21:00:28 +00:00
github-actions
8a5befd099 📝 Update release notes 2022-11-03 20:56:13 +00:00
Sebastián Ramírez
9a442c9730 👷 Update FastAPI People to exclude bots: pre-commit-ci, dependabot (#5586) 2022-11-03 20:55:32 +00:00
Sebastián Ramírez
4fa4965beb 📝 Update coverage badge to use Samuel Colvin's Smokeshow (#5585) 2022-11-03 21:55:00 +01:00
github-actions
5f4680201c 📝 Update release notes 2022-11-03 20:06:36 +00:00
Irfanuddin Shafi Ahmed
5cd99a9517 🎨 Format OpenAPI JSON in test_starlette_exception.py (#5379) 2022-11-03 21:06:00 +01:00
github-actions
b6ea8414a9 📝 Update release notes 2022-11-03 20:01:17 +00:00
Sebastián Ramírez
be3e29fb3c 👷 Switch from Codecov to Smokeshow plus pytest-cov to pure coverage for internal tests (#5583) 2022-11-03 21:00:29 +01:00
github-actions
cf730518bc 📝 Update release notes 2022-11-03 12:27:24 +00:00
Sebastián Ramírez
d62f5c1b28 Enable tests for Python 3.11 (#4881) 2022-11-03 13:26:48 +01:00
github-actions
4cf9075809 📝 Update release notes 2022-11-03 12:08:23 +00:00
ZHCai
a0c677ef0d 🌐 Update wording in Chinese translation for docs/zh/docs/python-types.md (#5416) 2022-11-03 13:07:49 +01:00
github-actions
54aa27ca07 📝 Update release notes 2022-11-03 12:07:29 +00:00
Adrian Garcia Badaracco
ac9f56ea5e 🐛 Close FormData (uploaded files) after the request is done (#5465)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2022-11-03 13:06:52 +01:00
github-actions
ed9425ef50 📝 Update release notes 2022-11-03 11:52:17 +00:00
Vladislav Kramorenko
9a85535e7f 🌐 Add Russian translation for docs/ru/docs/deployment/index.md (#5336)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2022-11-03 11:51:44 +00:00
github-actions
c9308cf070 📝 Update release notes 2022-11-03 11:51:26 +00:00
jaystone776
058cb6e88e 🌐 Update Chinese translation for docs/tutorial/security/oauth2-jwt.md (#3846)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2022-11-03 11:50:48 +00:00
github-actions
876ea7978f 📝 Update release notes 2022-11-03 11:45:26 +00:00
github-actions[bot]
da0bfd22aa 👥 Update FastAPI People (#5571)
Co-authored-by: github-actions <github-actions@github.com>
2022-11-03 12:44:51 +01:00
172 changed files with 6619 additions and 963 deletions

View File

@@ -1,5 +0,0 @@
[flake8]
max-line-length = 88
select = C,E,F,W,B,B9
ignore = E203, E501, W503
exclude = __init__.py

View File

@@ -1,5 +1,3 @@
name: Question or Problem
description: Ask a question or ask about a problem
labels: [question]
body:
- type: markdown
@@ -9,9 +7,9 @@ body:
Please follow these instructions, fill every question, and do every step. 🙏
I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time.
I'm asking this because answering questions and solving problems in GitHub is what consumes most of the time.
I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues.
I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling questions.
All that, on top of all the incredible help provided by a bunch of community members, the [FastAPI Experts](https://fastapi.tiangolo.com/fastapi-people/#experts), that give a lot of their time to come here and help others.
@@ -21,16 +19,16 @@ body:
And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎
As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓
As there are too many questions, I'll have to discard and close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓
- type: checkboxes
id: checks
attributes:
label: First Check
description: Please confirm and check all the following options.
options:
- label: I added a very descriptive title to this issue.
- label: I added a very descriptive title here.
required: true
- label: I used the GitHub search to find a similar issue and didn't find it.
- label: I used the GitHub search to find a similar question and didn't find it.
required: true
- label: I searched the FastAPI documentation, with the integrated search.
required: true
@@ -51,9 +49,9 @@ body:
description: |
After submitting this, I commit to one of:
* Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
* Read open questions until I find 2 where I can help someone and add a comment to help there.
* I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.
* Implement a Pull Request for a confirmed bug.
* Review one Pull Request by downloading the code and following [all the review process](https://fastapi.tiangolo.com/help-fastapi/#review-pull-requests).
options:
- label: I commit to help with one of those options 👆

View File

@@ -2,3 +2,15 @@ blank_issues_enabled: false
contact_links:
- name: Security Contact
about: Please report security vulnerabilities to security@tiangolo.com
- name: Question or Problem
about: Ask a question or ask about a problem in GitHub Discussions.
url: https://github.com/tiangolo/fastapi/discussions/categories/questions
- name: Feature Request
about: To suggest an idea or ask about a feature, please start with a question saying what you would like to achieve. There might be a way to do it already.
url: https://github.com/tiangolo/fastapi/discussions/categories/questions
- name: Show and tell
about: Show what you built with FastAPI or to be used with FastAPI.
url: https://github.com/tiangolo/fastapi/discussions/categories/show-and-tell
- name: Translations
about: Coordinate translations in GitHub Discussions.
url: https://github.com/tiangolo/fastapi/discussions/categories/translations

View File

@@ -1,181 +0,0 @@
name: Feature Request
description: Suggest an idea or ask for a feature that you would like to have in FastAPI
labels: [enhancement]
body:
- type: markdown
attributes:
value: |
Thanks for your interest in FastAPI! 🚀
Please follow these instructions, fill every question, and do every step. 🙏
I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time.
I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues.
All that, on top of all the incredible help provided by a bunch of community members, the [FastAPI Experts](https://fastapi.tiangolo.com/fastapi-people/#experts), that give a lot of their time to come here and help others.
That's a lot of work they are doing, but if more FastAPI users came to help others like them just a little bit more, it would be much less effort for them (and you and me 😅).
By asking questions in a structured way (following this) it will be much easier to help you.
And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎
As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓
- type: checkboxes
id: checks
attributes:
label: First Check
description: Please confirm and check all the following options.
options:
- label: I added a very descriptive title to this issue.
required: true
- label: I used the GitHub search to find a similar issue and didn't find it.
required: true
- label: I searched the FastAPI documentation, with the integrated search.
required: true
- label: I already searched in Google "How to X in FastAPI" and didn't find any information.
required: true
- label: I already read and followed all the tutorial in the docs and didn't find an answer.
required: true
- label: I already checked if it is not related to FastAPI but to [Pydantic](https://github.com/samuelcolvin/pydantic).
required: true
- label: I already checked if it is not related to FastAPI but to [Swagger UI](https://github.com/swagger-api/swagger-ui).
required: true
- label: I already checked if it is not related to FastAPI but to [ReDoc](https://github.com/Redocly/redoc).
required: true
- type: checkboxes
id: help
attributes:
label: Commit to Help
description: |
After submitting this, I commit to one of:
* Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
* I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.
* Implement a Pull Request for a confirmed bug.
options:
- label: I commit to help with one of those options 👆
required: true
- type: textarea
id: example
attributes:
label: Example Code
description: |
Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case.
If I (or someone) can copy it, run it, and see it right away, there's a much higher chance I (or someone) will be able to help you.
placeholder: |
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
render: python
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: |
What is your feature request?
Write a short description telling me what you are trying to solve and what you are currently doing.
placeholder: |
* Open the browser and call the endpoint `/`.
* It returns a JSON with `{"Hello": "World"}`.
* I would like it to have an extra parameter to teleport me to the moon and back.
validations:
required: true
- type: textarea
id: wanted-solution
attributes:
label: Wanted Solution
description: |
Tell me what's the solution you would like.
placeholder: |
I would like it to have a `teleport_to_moon` parameter that defaults to `False`, and can be set to `True` to teleport me.
validations:
required: true
- type: textarea
id: wanted-code
attributes:
label: Wanted Code
description: Show me an example of how you would want the code to look like.
placeholder: |
from fastapi import FastAPI
app = FastAPI()
@app.get("/", teleport_to_moon=True)
def read_root():
return {"Hello": "World"}
render: python
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives
description: |
Tell me about alternatives you've considered.
placeholder: |
To wait for Space X moon travel plans to drop down long after they release them. But I would rather teleport.
- type: dropdown
id: os
attributes:
label: Operating System
description: What operating system are you on?
multiple: true
options:
- Linux
- Windows
- macOS
- Other
validations:
required: true
- type: textarea
id: os-details
attributes:
label: Operating System Details
description: You can add more details about your operating system here, in particular if you chose "Other".
- type: input
id: fastapi-version
attributes:
label: FastAPI Version
description: |
What FastAPI version are you using?
You can find the FastAPI version with:
```bash
python -c "import fastapi; print(fastapi.__version__)"
```
validations:
required: true
- type: input
id: python-version
attributes:
label: Python Version
description: |
What Python version are you using?
You can find the Python version with:
```bash
python --version
```
validations:
required: true
- type: textarea
id: context
attributes:
label: Additional Context
description: Add any additional context information or screenshots you think are useful.

22
.github/ISSUE_TEMPLATE/privileged.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Privileged
description: You are @tiangolo or he asked you directly to create an issue here. If not, check the other options. 👇
body:
- type: markdown
attributes:
value: |
Thanks for your interest in FastAPI! 🚀
If you are not @tiangolo or he didn't ask you directly to create an issue here, please start the conversation in a [Question in GitHub Discussions](https://github.com/tiangolo/fastapi/discussions/categories/questions) instead.
- type: checkboxes
id: privileged
attributes:
label: Privileged issue
description: Confirm that you are allowed to create an issue here.
options:
- label: I'm @tiangolo or he asked me directly to create an issue here.
required: true
- type: textarea
id: content
attributes:
label: Issue Content
description: Add the content of the issue here.

View File

@@ -18,3 +18,4 @@ uz: 4883
sv: 5146
he: 5157
ta: 5434
ar: 3349

View File

@@ -4,7 +4,7 @@ import sys
from collections import Counter, defaultdict
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Container, DefaultDict, Dict, List, Set, Union
from typing import Any, Container, DefaultDict, Dict, List, Set, Union
import httpx
import yaml
@@ -12,6 +12,50 @@ from github import Github
from pydantic import BaseModel, BaseSettings, SecretStr
github_graphql_url = "https://api.github.com/graphql"
questions_category_id = "MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMyMDAxNDM0"
discussions_query = """
query Q($after: String, $category_id: ID) {
repository(name: "fastapi", owner: "tiangolo") {
discussions(first: 100, after: $after, categoryId: $category_id) {
edges {
cursor
node {
number
author {
login
avatarUrl
url
}
title
createdAt
comments(first: 100) {
nodes {
createdAt
author {
login
avatarUrl
url
}
isAnswer
replies(first: 10) {
nodes {
createdAt
author {
login
avatarUrl
url
}
}
}
}
}
}
}
}
}
}
"""
issues_query = """
query Q($after: String) {
@@ -131,15 +175,30 @@ class Author(BaseModel):
url: str
# Issues and Discussions
class CommentsNode(BaseModel):
createdAt: datetime
author: Union[Author, None] = None
class Replies(BaseModel):
nodes: List[CommentsNode]
class DiscussionsCommentsNode(CommentsNode):
replies: Replies
class Comments(BaseModel):
nodes: List[CommentsNode]
class DiscussionsComments(BaseModel):
nodes: List[DiscussionsCommentsNode]
class IssuesNode(BaseModel):
number: int
author: Union[Author, None] = None
@@ -149,27 +208,59 @@ class IssuesNode(BaseModel):
comments: Comments
class DiscussionsNode(BaseModel):
number: int
author: Union[Author, None] = None
title: str
createdAt: datetime
comments: DiscussionsComments
class IssuesEdge(BaseModel):
cursor: str
node: IssuesNode
class DiscussionsEdge(BaseModel):
cursor: str
node: DiscussionsNode
class Issues(BaseModel):
edges: List[IssuesEdge]
class Discussions(BaseModel):
edges: List[DiscussionsEdge]
class IssuesRepository(BaseModel):
issues: Issues
class DiscussionsRepository(BaseModel):
discussions: Discussions
class IssuesResponseData(BaseModel):
repository: IssuesRepository
class DiscussionsResponseData(BaseModel):
repository: DiscussionsRepository
class IssuesResponse(BaseModel):
data: IssuesResponseData
class DiscussionsResponse(BaseModel):
data: DiscussionsResponseData
# PRs
class LabelNode(BaseModel):
name: str
@@ -219,6 +310,9 @@ class PRsResponse(BaseModel):
data: PRsResponseData
# Sponsors
class SponsorEntity(BaseModel):
login: str
avatarUrl: str
@@ -264,10 +358,16 @@ class Settings(BaseSettings):
def get_graphql_response(
*, settings: Settings, query: str, after: Union[str, None] = None
):
*,
settings: Settings,
query: str,
after: Union[str, None] = None,
category_id: Union[str, None] = None,
) -> Dict[str, Any]:
headers = {"Authorization": f"token {settings.input_token.get_secret_value()}"}
variables = {"after": after}
# category_id is only used by one query, but GraphQL allows unused variables, so
# keep it here for simplicity
variables = {"after": after, "category_id": category_id}
response = httpx.post(
github_graphql_url,
headers=headers,
@@ -275,7 +375,9 @@ def get_graphql_response(
json={"query": query, "variables": variables, "operationName": "Q"},
)
if response.status_code != 200:
logging.error(f"Response was not 200, after: {after}")
logging.error(
f"Response was not 200, after: {after}, category_id: {category_id}"
)
logging.error(response.text)
raise RuntimeError(response.text)
data = response.json()
@@ -288,6 +390,21 @@ def get_graphql_issue_edges(*, settings: Settings, after: Union[str, None] = Non
return graphql_response.data.repository.issues.edges
def get_graphql_question_discussion_edges(
*,
settings: Settings,
after: Union[str, None] = None,
):
data = get_graphql_response(
settings=settings,
query=discussions_query,
after=after,
category_id=questions_category_id,
)
graphql_response = DiscussionsResponse.parse_obj(data)
return graphql_response.data.repository.discussions.edges
def get_graphql_pr_edges(*, settings: Settings, after: Union[str, None] = None):
data = get_graphql_response(settings=settings, query=prs_query, after=after)
graphql_response = PRsResponse.parse_obj(data)
@@ -300,7 +417,7 @@ def get_graphql_sponsor_edges(*, settings: Settings, after: Union[str, None] = N
return graphql_response.data.user.sponsorshipsAsMaintainer.edges
def get_experts(settings: Settings):
def get_issues_experts(settings: Settings):
issue_nodes: List[IssuesNode] = []
issue_edges = get_graphql_issue_edges(settings=settings)
@@ -326,13 +443,74 @@ def get_experts(settings: Settings):
for comment in issue.comments.nodes:
if comment.author:
authors[comment.author.login] = comment.author
if comment.author.login == issue_author_name:
continue
issue_commentors.add(comment.author.login)
if comment.author.login != issue_author_name:
issue_commentors.add(comment.author.login)
for author_name in issue_commentors:
commentors[author_name] += 1
if issue.createdAt > one_month_ago:
last_month_commentors[author_name] += 1
return commentors, last_month_commentors, authors
def get_discussions_experts(settings: Settings):
discussion_nodes: List[DiscussionsNode] = []
discussion_edges = get_graphql_question_discussion_edges(settings=settings)
while discussion_edges:
for discussion_edge in discussion_edges:
discussion_nodes.append(discussion_edge.node)
last_edge = discussion_edges[-1]
discussion_edges = get_graphql_question_discussion_edges(
settings=settings, after=last_edge.cursor
)
commentors = Counter()
last_month_commentors = Counter()
authors: Dict[str, Author] = {}
now = datetime.now(tz=timezone.utc)
one_month_ago = now - timedelta(days=30)
for discussion in discussion_nodes:
discussion_author_name = None
if discussion.author:
authors[discussion.author.login] = discussion.author
discussion_author_name = discussion.author.login
discussion_commentors = set()
for comment in discussion.comments.nodes:
if comment.author:
authors[comment.author.login] = comment.author
if comment.author.login != discussion_author_name:
discussion_commentors.add(comment.author.login)
for reply in comment.replies.nodes:
if reply.author:
authors[reply.author.login] = reply.author
if reply.author.login != discussion_author_name:
discussion_commentors.add(reply.author.login)
for author_name in discussion_commentors:
commentors[author_name] += 1
if discussion.createdAt > one_month_ago:
last_month_commentors[author_name] += 1
return commentors, last_month_commentors, authors
def get_experts(settings: Settings):
(
issues_commentors,
issues_last_month_commentors,
issues_authors,
) = get_issues_experts(settings=settings)
(
discussions_commentors,
discussions_last_month_commentors,
discussions_authors,
) = get_discussions_experts(settings=settings)
commentors = issues_commentors + discussions_commentors
last_month_commentors = (
issues_last_month_commentors + discussions_last_month_commentors
)
authors = {**issues_authors, **discussions_authors}
return commentors, last_month_commentors, authors
@@ -425,22 +603,22 @@ if __name__ == "__main__":
logging.info(f"Using config: {settings.json()}")
g = Github(settings.input_standard_token.get_secret_value())
repo = g.get_repo(settings.github_repository)
issue_commentors, issue_last_month_commentors, issue_authors = get_experts(
question_commentors, question_last_month_commentors, question_authors = get_experts(
settings=settings
)
contributors, pr_commentors, reviewers, pr_authors = get_contributors(
settings=settings
)
authors = {**issue_authors, **pr_authors}
authors = {**question_authors, **pr_authors}
maintainers_logins = {"tiangolo"}
bot_names = {"codecov", "github-actions"}
bot_names = {"codecov", "github-actions", "pre-commit-ci", "dependabot"}
maintainers = []
for login in maintainers_logins:
user = authors[login]
maintainers.append(
{
"login": login,
"answers": issue_commentors[login],
"answers": question_commentors[login],
"prs": contributors[login],
"avatarUrl": user.avatarUrl,
"url": user.url,
@@ -453,13 +631,13 @@ if __name__ == "__main__":
min_count_reviewer = 4
skip_users = maintainers_logins | bot_names
experts = get_top_users(
counter=issue_commentors,
counter=question_commentors,
min_count=min_count_expert,
authors=authors,
skip_users=skip_users,
)
last_month_active = get_top_users(
counter=issue_last_month_commentors,
counter=question_last_month_commentors,
min_count=min_count_last_month,
authors=authors,
skip_users=skip_users,

View File

@@ -7,7 +7,7 @@ on:
types: [opened, synchronize]
jobs:
build-docs:
runs-on: ubuntu-18.04
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
@@ -17,7 +17,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.7"
python-version: "3.11"
- uses: actions/cache@v3
id: cache
with:
@@ -36,9 +36,9 @@ jobs:
- uses: actions/upload-artifact@v3
with:
name: docs-zip
path: ./docs.zip
path: ./site/docs.zip
- name: Deploy to Netlify
uses: nwtgck/actions-netlify@v1.2.4
uses: nwtgck/actions-netlify@v2.0.0
with:
publish-dir: './site'
production-branch: master

View File

@@ -11,21 +11,26 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Clean site
run: |
rm -rf ./site
mkdir ./site
- name: Download Artifact Docs
uses: dawidd6/action-download-artifact@v2.24.0
uses: dawidd6/action-download-artifact@v2.24.3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
workflow: build-docs.yml
run_id: ${{ github.event.workflow_run.id }}
name: docs-zip
path: ./site/
- name: Unzip docs
run: |
rm -rf ./site
cd ./site
unzip docs.zip
rm -f docs.zip
- name: Deploy to Netlify
id: netlify
uses: nwtgck/actions-netlify@v1.2.4
uses: nwtgck/actions-netlify@v2.0.0
with:
publish-dir: './site'
production-deploy: false

View File

@@ -18,6 +18,8 @@ jobs:
uses: actions/setup-python@v4
with:
python-version: "3.7"
cache: "pip"
cache-dependency-path: pyproject.toml
- uses: actions/cache@v3
id: cache
with:
@@ -29,7 +31,7 @@ jobs:
- name: Build distribution
run: python -m build
- name: Publish
uses: pypa/gh-action-pypi-publish@v1.5.1
uses: pypa/gh-action-pypi-publish@v1.6.4
with:
password: ${{ secrets.PYPI_API_TOKEN }}
- name: Dump GitHub context

35
.github/workflows/smokeshow.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Smokeshow
on:
workflow_run:
workflows: [Test]
types: [completed]
permissions:
statuses: write
jobs:
smokeshow:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v4
with:
python-version: '3.9'
- run: pip install smokeshow
- uses: dawidd6/action-download-artifact@v2.24.3
with:
workflow: test.yml
commit: ${{ github.event.workflow_run.head_sha }}
- run: smokeshow upload coverage-html
env:
SMOKESHOW_GITHUB_STATUS_DESCRIPTION: Coverage {coverage-percentage}
SMOKESHOW_GITHUB_COVERAGE_THRESHOLD: 100
SMOKESHOW_GITHUB_CONTEXT: coverage
SMOKESHOW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SMOKESHOW_GITHUB_PR_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
SMOKESHOW_AUTH_KEY: ${{ secrets.SMOKESHOW_AUTH_KEY }}

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
fail-fast: false
steps:
@@ -21,17 +21,73 @@ jobs:
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
cache-dependency-path: pyproject.toml
- uses: actions/cache@v3
id: cache
with:
path: ${{ env.pythonLocation }}
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test-v02
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test-v03
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -e .[all,dev,doc,test]
- name: Lint
run: bash scripts/lint.sh
- run: mkdir coverage
- name: Test
run: bash scripts/test.sh
- name: Upload coverage
uses: codecov/codecov-action@v3
env:
COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}
- name: Store coverage files
uses: actions/upload-artifact@v3
with:
name: coverage
path: coverage
coverage-combine:
needs: [test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.8'
cache: "pip"
cache-dependency-path: pyproject.toml
- name: Get coverage files
uses: actions/download-artifact@v3
with:
name: coverage
path: coverage
- run: pip install coverage[toml]
- run: ls -la coverage
- run: coverage combine coverage
- run: coverage report
- run: coverage html --show-contexts --title "Coverage for ${{ github.sha }}"
- name: Store coverage HTML
uses: actions/upload-artifact@v3
with:
name: coverage-html
path: htmlcov
# https://github.com/marketplace/actions/alls-green#why
check: # This job does nothing and is only used for the branch protection
if: always()
needs:
- coverage-combine
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1
with:
jobs: ${{ toJSON(needs) }}

View File

@@ -1,5 +1,7 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
default_language_version:
python: python3.10
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
@@ -12,27 +14,20 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/asottile/pyupgrade
rev: v3.1.0
rev: v3.2.2
hooks:
- id: pyupgrade
args:
- --py3-plus
- --keep-runtime-typing
- repo: https://github.com/PyCQA/autoflake
rev: v1.7.7
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.138
hooks:
- id: autoflake
- id: ruff
args:
- --recursive
- --in-place
- --remove-all-unused-imports
- --remove-unused-variables
- --expand-star-imports
- --exclude
- __init__.py
- --remove-duplicate-keys
- --fix
- repo: https://github.com/pycqa/isort
rev: 5.10.1
rev: 5.12.0
hooks:
- id: isort
name: isort (python)

View File

@@ -8,8 +8,8 @@
<a href="https://github.com/tiangolo/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank">
<img src="https://github.com/tiangolo/fastapi/workflows/Test/badge.svg?event=push&branch=master" alt="Test">
</a>
<a href="https://codecov.io/gh/tiangolo/fastapi" target="_blank">
<img src="https://img.shields.io/codecov/c/github/tiangolo/fastapi?color=%2334D058" alt="Coverage">
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/tiangolo/fastapi" target="_blank">
<img src="https://coverage-badge.samuelcolvin.workers.dev/tiangolo/fastapi.svg" alt="Coverage">
</a>
<a href="https://pypi.org/project/fastapi" target="_blank">
<img src="https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package" alt="Package version">
@@ -49,14 +49,14 @@ The key features are:
<a href="https://bit.ly/3dmXC5S" target="_blank" title="The data structure for unstructured multimodal data"><img src="https://fastapi.tiangolo.com/img/sponsors/docarray.svg"></a>
<a href="https://bit.ly/3JJ7y5C" target="_blank" title="Build cross-modal and multimodal applications on the cloud"><img src="https://fastapi.tiangolo.com/img/sponsors/jina2.svg"></a>
<a href="https://cryptapi.io/" target="_blank" title="CryptAPI: Your easy to use, secure and privacy oriented payment gateway."><img src="https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg"></a>
<a href="https://doist.com/careers/9B437B1615-wa-senior-backend-engineer-python" target="_blank" title="Help us migrate doist to FastAPI"><img src="https://fastapi.tiangolo.com/img/sponsors/doist.svg"></a>
<a href="https://www.deta.sh/?ref=fastapi" target="_blank" title="The launchpad for all your (team's) ideas"><img src="https://fastapi.tiangolo.com/img/sponsors/deta.svg"></a>
<a href="https://www.investsuite.com/jobs" target="_blank" title="Wealthtech jobs with FastAPI"><img src="https://fastapi.tiangolo.com/img/sponsors/investsuite.svg"></a>
<a href="https://training.talkpython.fm/fastapi-courses" target="_blank" title="FastAPI video courses on demand from people you trust"><img src="https://fastapi.tiangolo.com/img/sponsors/talkpython.png"></a>
<a href="https://testdriven.io/courses/tdd-fastapi/" target="_blank" title="Learn to build high-quality web apps with best practices"><img src="https://fastapi.tiangolo.com/img/sponsors/testdriven.svg"></a>
<a href="https://github.com/deepset-ai/haystack/" target="_blank" title="Build powerful search from composable, open source building blocks"><img src="https://fastapi.tiangolo.com/img/sponsors/haystack-fastapi.svg"></a>
<a href="https://www.udemy.com/course/fastapi-rest/" target="_blank" title="Learn FastAPI by building a complete project. Extend your knowledge on advanced web development-AWS, Payments, Emails."><img src="https://fastapi.tiangolo.com/img/sponsors/ines-course.jpg"></a>
<a href="https://careers.budget-insight.com/" target="_blank" title="Budget Insight is hiring!"><img src="https://fastapi.tiangolo.com/img/sponsors/budget-insight.svg"></a>
<a href="https://careers.powens.com/" target="_blank" title="Powens is hiring!"><img src="https://fastapi.tiangolo.com/img/sponsors/powens.png"></a>
<a href="https://www.svix.com/" target="_blank" title="Svix - Webhooks as a service"><img src="https://fastapi.tiangolo.com/img/sponsors/svix.svg"></a>
<!-- /sponsors -->
@@ -427,7 +427,7 @@ For a more complete example including more features, see the <a href="https://fa
* **GraphQL** integration with <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> and other libraries.
* Many extra features (thanks to Starlette) as:
* **WebSockets**
* extremely easy tests based on `requests` and `pytest`
* extremely easy tests based on HTTPX and `pytest`
* **CORS**
* **Cookie Sessions**
* ...and more.
@@ -447,7 +447,7 @@ Used by Pydantic:
Used by Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.

View File

@@ -446,7 +446,7 @@ Used by Pydantic:
Used by Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.

View File

@@ -169,7 +169,7 @@ Mit **FastAPI** bekommen Sie viele von **Starlette**'s Funktionen (da FastAPI nu
* **WebSocket**-Unterstützung.
* Hintergrundaufgaben im selben Prozess.
* Ereignisse für das Starten und Herunterfahren.
* Testclient basierend auf `requests`.
* Testclient basierend auf HTTPX.
* **CORS**, GZip, statische Dateien, Antwortfluss.
* **Sitzungs und Cookie** Unterstützung.
* 100% Testabdeckung.

View File

@@ -445,7 +445,7 @@ Used by Pydantic:
Used by Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.

View File

@@ -1,5 +1,13 @@
articles:
english:
- author: Raf Rasenberg
author_link: https://rafrasenberg.com/about/
link: https://rafrasenberg.com/fastapi-lambda/
title: 'FastAPI lambda container: serverless simplified'
- author: Teresa N. Fontanella De Santis
author_link: https://dev.to/
link: https://dev.to/teresafds/authorization-on-fastapi-with-casbin-41og
title: Authorization on FastAPI with Casbin
- author: WayScript
author_link: https://www.wayscript.com
link: https://blog.wayscript.com/fast-api-quickstart/
@@ -300,6 +308,11 @@ articles:
author_link: https://fullstackstation.com/author/figonking/
link: https://fullstackstation.com/fastapi-trien-khai-bang-docker/
title: 'FASTAPI: TRIỂN KHAI BẰNG DOCKER'
taiwanese:
- author: Leon
author_link: http://editor.leonh.space/
link: https://editor.leonh.space/2022/tortoise/
title: 'Tortoise ORM / FastAPI 整合快速筆記'
podcasts:
english:
- author: Podcast.`__init__`

View File

@@ -2,18 +2,15 @@ sponsors:
- - login: jina-ai
avatarUrl: https://avatars.githubusercontent.com/u/60539444?v=4
url: https://github.com/jina-ai
- - login: Doist
avatarUrl: https://avatars.githubusercontent.com/u/2565372?v=4
url: https://github.com/Doist
- login: cryptapi
- - login: cryptapi
avatarUrl: https://avatars.githubusercontent.com/u/44925437?u=61369138589bc7fee6c417f3fbd50fbd38286cc4&v=4
url: https://github.com/cryptapi
- - login: ObliviousAI
- - login: nihpo
avatarUrl: https://avatars.githubusercontent.com/u/1841030?u=0264956d7580f7e46687a762a7baa629f84cf97c&v=4
url: https://github.com/nihpo
- login: ObliviousAI
avatarUrl: https://avatars.githubusercontent.com/u/65656077?v=4
url: https://github.com/ObliviousAI
- login: Lovage-Labs
avatarUrl: https://avatars.githubusercontent.com/u/71685552?v=4
url: https://github.com/Lovage-Labs
- login: chaserowbotham
avatarUrl: https://avatars.githubusercontent.com/u/97751084?v=4
url: https://github.com/chaserowbotham
@@ -29,18 +26,21 @@ sponsors:
- login: investsuite
avatarUrl: https://avatars.githubusercontent.com/u/73833632?v=4
url: https://github.com/investsuite
- login: svix
avatarUrl: https://avatars.githubusercontent.com/u/80175132?v=4
url: https://github.com/svix
- login: VincentParedes
avatarUrl: https://avatars.githubusercontent.com/u/103889729?v=4
url: https://github.com/VincentParedes
- - login: InesIvanova
avatarUrl: https://avatars.githubusercontent.com/u/22920417?u=409882ec1df6dbd77455788bb383a8de223dbf6f&v=4
url: https://github.com/InesIvanova
- - login: zopyx
avatarUrl: https://avatars.githubusercontent.com/u/594239?u=8e5ce882664f47fd61002bed51718c78c3799d24&v=4
url: https://github.com/zopyx
- login: SendCloud
avatarUrl: https://avatars.githubusercontent.com/u/7831959?v=4
url: https://github.com/SendCloud
- - login: getsentry
avatarUrl: https://avatars.githubusercontent.com/u/1396951?v=4
url: https://github.com/getsentry
- - login: vyos
avatarUrl: https://avatars.githubusercontent.com/u/5647000?v=4
url: https://github.com/vyos
- login: takashi-yoneya
avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4
url: https://github.com/takashi-yoneya
- login: mercedes-benz
avatarUrl: https://avatars.githubusercontent.com/u/34240465?v=4
url: https://github.com/mercedes-benz
@@ -62,42 +62,42 @@ sponsors:
- login: Trivie
avatarUrl: https://avatars.githubusercontent.com/u/8161763?v=4
url: https://github.com/Trivie
- login: wdwinslow
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4
url: https://github.com/wdwinslow
- login: Lovage-Labs
avatarUrl: https://avatars.githubusercontent.com/u/71685552?v=4
url: https://github.com/Lovage-Labs
- - login: moellenbeck
avatarUrl: https://avatars.githubusercontent.com/u/169372?v=4
url: https://github.com/moellenbeck
- login: birkjernstrom
avatarUrl: https://avatars.githubusercontent.com/u/281715?u=4be14b43f76b4bd497b1941309bb390250b405e6&v=4
url: https://github.com/birkjernstrom
- login: AccentDesign
avatarUrl: https://avatars.githubusercontent.com/u/2429332?v=4
url: https://github.com/AccentDesign
- login: RodneyU215
avatarUrl: https://avatars.githubusercontent.com/u/3329665?u=ec6a9adf8e7e8e306eed7d49687c398608d1604f&v=4
url: https://github.com/RodneyU215
- login: tizz98
avatarUrl: https://avatars.githubusercontent.com/u/5739698?u=f095a3659e3a8e7c69ccd822696990b521ea25f9&v=4
url: https://github.com/tizz98
- login: Vikka
- login: dorianturba
avatarUrl: https://avatars.githubusercontent.com/u/9381120?u=4bfc7032a824d1ed1994aa8256dfa597c8f187ad&v=4
url: https://github.com/Vikka
url: https://github.com/dorianturba
- login: jmaralc
avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4
url: https://github.com/jmaralc
- login: takashi-yoneya
avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4
url: https://github.com/takashi-yoneya
- login: mainframeindustries
avatarUrl: https://avatars.githubusercontent.com/u/55092103?v=4
url: https://github.com/mainframeindustries
- login: DelfinaCare
avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4
url: https://github.com/DelfinaCare
- - login: povilasb
avatarUrl: https://avatars.githubusercontent.com/u/1213442?u=b11f58ed6ceea6e8297c9b310030478ebdac894d&v=4
url: https://github.com/povilasb
- login: primer-io
avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4
url: https://github.com/primer-io
- - login: A-Edge
avatarUrl: https://avatars.githubusercontent.com/u/59514131?v=4
url: https://github.com/A-Edge
- - login: indeedeng
avatarUrl: https://avatars.githubusercontent.com/u/2905043?v=4
url: https://github.com/indeedeng
- - login: Kludex
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
@@ -137,42 +137,45 @@ sponsors:
- login: jqueguiner
avatarUrl: https://avatars.githubusercontent.com/u/690878?u=bd65cc1f228ce6455e56dfaca3ef47c33bc7c3b0&v=4
url: https://github.com/jqueguiner
- login: alexsantos
avatarUrl: https://avatars.githubusercontent.com/u/932219?v=4
url: https://github.com/alexsantos
- login: tcsmith
avatarUrl: https://avatars.githubusercontent.com/u/989034?u=7d8d741552b3279e8f4d3878679823a705a46f8f&v=4
url: https://github.com/tcsmith
- login: ltieman
avatarUrl: https://avatars.githubusercontent.com/u/1084689?u=e69b17de17cb3ca141a17daa7ccbe173ceb1eb17&v=4
url: https://github.com/ltieman
- login: mrkmcknz
avatarUrl: https://avatars.githubusercontent.com/u/1089376?u=2b9b8a8c25c33a4f6c220095638bd821cdfd13a3&v=4
url: https://github.com/mrkmcknz
- login: theonlynexus
avatarUrl: https://avatars.githubusercontent.com/u/1515004?v=4
url: https://github.com/theonlynexus
- login: coffeewasmyidea
avatarUrl: https://avatars.githubusercontent.com/u/1636488?u=8e32a4f200eff54dd79cd79d55d254bfce5e946d&v=4
url: https://github.com/coffeewasmyidea
- login: jonakoudijs
avatarUrl: https://avatars.githubusercontent.com/u/1906344?u=5ca0c9a1a89b6a2ba31abe35c66bdc07af60a632&v=4
url: https://github.com/jonakoudijs
- login: corleyma
avatarUrl: https://avatars.githubusercontent.com/u/2080732?u=aed2ff652294a87d666b1c3f6dbe98104db76d26&v=4
url: https://github.com/corleyma
- login: madisonmay
avatarUrl: https://avatars.githubusercontent.com/u/2645393?u=f22b93c6ea345a4d26a90a3834dfc7f0789fcb63&v=4
url: https://github.com/madisonmay
- login: saivarunk
avatarUrl: https://avatars.githubusercontent.com/u/2976867?u=71f4385e781e9a9e871a52f2d4686f9a8d69ba2f&v=4
url: https://github.com/saivarunk
- login: andre1sk
avatarUrl: https://avatars.githubusercontent.com/u/3148093?v=4
url: https://github.com/andre1sk
- login: Shark009
avatarUrl: https://avatars.githubusercontent.com/u/3163309?u=0c6f4091b0eda05c44c390466199826e6dc6e431&v=4
url: https://github.com/Shark009
- login: grillazz
avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=0b32b7073ae1ab8b7f6d2db0188c2e1e357ff451&v=4
url: https://github.com/grillazz
- login: ColliotL
avatarUrl: https://avatars.githubusercontent.com/u/3412402?u=ca64b07ecbef2f9da1cc2cac3f37522aa4814902&v=4
url: https://github.com/ColliotL
- login: dblackrun
avatarUrl: https://avatars.githubusercontent.com/u/3528486?v=4
url: https://github.com/dblackrun
- login: zsinx6
avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4
url: https://github.com/zsinx6
- login: MarekBleschke
avatarUrl: https://avatars.githubusercontent.com/u/3616870?v=4
url: https://github.com/MarekBleschke
- login: aacayaco
avatarUrl: https://avatars.githubusercontent.com/u/3634801?u=eaadda178c964178fcb64886f6c732172c8f8219&v=4
url: https://github.com/aacayaco
@@ -183,7 +186,7 @@ sponsors:
avatarUrl: https://avatars.githubusercontent.com/u/3860655?u=f55f47eb2d6a9b495e806ac5a044e3ae01ccc1fa&v=4
url: https://github.com/peterHoburg
- login: jgreys
avatarUrl: https://avatars.githubusercontent.com/u/4136890?u=b579fd97033269a5e703ab509c7d5478b146cc2d&v=4
avatarUrl: https://avatars.githubusercontent.com/u/4136890?u=c66ae617d614f6c886f1f1c1799d22100b3c848d&v=4
url: https://github.com/jgreys
- login: gorhack
avatarUrl: https://avatars.githubusercontent.com/u/4141690?u=ec119ebc4bdf00a7bc84657a71aa17834f4f27f3&v=4
@@ -194,15 +197,12 @@ sponsors:
- login: oliverxchen
avatarUrl: https://avatars.githubusercontent.com/u/4471774?u=534191f25e32eeaadda22dfab4b0a428733d5489&v=4
url: https://github.com/oliverxchen
- login: CINOAdam
avatarUrl: https://avatars.githubusercontent.com/u/4728508?u=76ef23f06ae7c604e009873bc27cf0ea9ba738c9&v=4
url: https://github.com/CINOAdam
- login: ScrimForever
avatarUrl: https://avatars.githubusercontent.com/u/5040124?u=091ec38bfe16d6e762099e91309b59f248616a65&v=4
url: https://github.com/ScrimForever
- login: ennui93
avatarUrl: https://avatars.githubusercontent.com/u/5300907?u=5b5452725ddb391b2caaebf34e05aba873591c3a&v=4
url: https://github.com/ennui93
- login: ternaus
avatarUrl: https://avatars.githubusercontent.com/u/5481618?u=fabc8d75c921b3380126adb5a931c5da6e7db04f&v=4
url: https://github.com/ternaus
- login: Yaleesa
avatarUrl: https://avatars.githubusercontent.com/u/6135475?v=4
url: https://github.com/Yaleesa
@@ -216,43 +216,40 @@ sponsors:
avatarUrl: https://avatars.githubusercontent.com/u/6347418?u=98f5918b32e214a168a2f5d59b0b8ebdf57dca0d&v=4
url: https://github.com/pkucmus
- login: s3ich4n
avatarUrl: https://avatars.githubusercontent.com/u/6926298?u=ba3025d698e1c986655e776ae383a3d60d9d578e&v=4
avatarUrl: https://avatars.githubusercontent.com/u/6926298?u=6690c5403bc1d9a1837886defdc5256e9a43b1db&v=4
url: https://github.com/s3ich4n
- login: Rehket
avatarUrl: https://avatars.githubusercontent.com/u/7015688?u=3afb0ba200feebbc7f958950e92db34df2a3c172&v=4
url: https://github.com/Rehket
- login: ValentinCalomme
avatarUrl: https://avatars.githubusercontent.com/u/7288672?u=e09758c7a36c49f0fb3574abe919cbd344fdc2d6&v=4
url: https://github.com/ValentinCalomme
- login: hiancdtrsnm
avatarUrl: https://avatars.githubusercontent.com/u/7343177?v=4
url: https://github.com/hiancdtrsnm
- login: Shackelford-Arden
avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4
url: https://github.com/Shackelford-Arden
- login: Ge0f3
avatarUrl: https://avatars.githubusercontent.com/u/11887760?u=ccd80f1ac36dcb8517ef5c4e702e8cc5a80cad2f&v=4
url: https://github.com/Ge0f3
- login: wdwinslow
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4
url: https://github.com/wdwinslow
- login: svats2k
avatarUrl: https://avatars.githubusercontent.com/u/12378398?u=ecf28c19f61052e664bdfeb2391f8107d137915c&v=4
url: https://github.com/svats2k
- login: gokulyc
avatarUrl: https://avatars.githubusercontent.com/u/13468848?u=269f269d3e70407b5fb80138c52daba7af783997&v=4
url: https://github.com/gokulyc
- login: dannywade
avatarUrl: https://avatars.githubusercontent.com/u/13680237?u=418ee985bd41577b20fde81417fb2d901e875e8a&v=4
url: https://github.com/dannywade
- login: khadrawy
avatarUrl: https://avatars.githubusercontent.com/u/13686061?u=59f25ef42ecf04c22657aac4238ce0e2d3d30304&v=4
url: https://github.com/khadrawy
- login: pablonnaoji
avatarUrl: https://avatars.githubusercontent.com/u/15187159?u=afc15bd5a4ba9c5c7206bbb1bcaeef606a0932e0&v=4
url: https://github.com/pablonnaoji
- login: robintully
avatarUrl: https://avatars.githubusercontent.com/u/17059673?u=862b9bb01513f5acd30df97433cb97a24dbfb772&v=4
url: https://github.com/robintully
- login: wedwardbeck
avatarUrl: https://avatars.githubusercontent.com/u/19333237?u=1de4ae2bf8d59eb4c013f21d863cbe0f2010575f&v=4
url: https://github.com/wedwardbeck
- login: RedCarpetUp
avatarUrl: https://avatars.githubusercontent.com/u/20360440?v=4
url: https://github.com/RedCarpetUp
- login: Filimoa
avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=75e02d102d2ee3e3d793e555fa5c63045913ccb0&v=4
avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=0be845711495bbd7b756e13fcaeb8efc1ebd78ba&v=4
url: https://github.com/Filimoa
- login: shuheng-liu
avatarUrl: https://avatars.githubusercontent.com/u/22414322?u=813c45f30786c6b511b21a661def025d8f7b609e&v=4
@@ -287,6 +284,9 @@ sponsors:
- login: ProteinQure
avatarUrl: https://avatars.githubusercontent.com/u/33707203?v=4
url: https://github.com/ProteinQure
- login: AbdulwahabDev
avatarUrl: https://avatars.githubusercontent.com/u/34792253?u=9d27cbb6e196c95d747abf002df7fe0539764265&v=4
url: https://github.com/AbdulwahabDev
- login: ybressler
avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=41e2c00f1eebe3c402635f0325e41b4e6511462c&v=4
url: https://github.com/ybressler
@@ -296,26 +296,23 @@ sponsors:
- login: VictorCalderon
avatarUrl: https://avatars.githubusercontent.com/u/44529243?u=cea69884f826a29aff1415493405209e0706d07a&v=4
url: https://github.com/VictorCalderon
- login: arthuRHD
avatarUrl: https://avatars.githubusercontent.com/u/48015496?u=05a0d5b8b9320eeb7990d35c9337b823f269d2ff&v=4
url: https://github.com/arthuRHD
- login: rafsaf
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
url: https://github.com/rafsaf
- login: yezz123
avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4
url: https://github.com/yezz123
- login: dudikbender
avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=494f85229115076121b3639a3806bbac1c6ae7f6&v=4
url: https://github.com/dudikbender
- login: llamington
avatarUrl: https://avatars.githubusercontent.com/u/54869395?u=42ea59b76f49449f41a4d106bb65a130797e8d7c&v=4
url: https://github.com/llamington
- login: thisistheplace
avatarUrl: https://avatars.githubusercontent.com/u/57633545?u=a3f3a7f8ace8511c6c067753f6eb6aee0db11ac6&v=4
url: https://github.com/thisistheplace
- login: A-Edge
avatarUrl: https://avatars.githubusercontent.com/u/59514131?v=4
url: https://github.com/A-Edge
- login: yakkonaut
avatarUrl: https://avatars.githubusercontent.com/u/60633704?u=90a71fd631aa998ba4a96480788f017c9904e07b&v=4
url: https://github.com/yakkonaut
- login: patsatsia
avatarUrl: https://avatars.githubusercontent.com/u/61111267?u=419516384f798a35e9d9e2dd81282cc46c151b58&v=4
avatarUrl: https://avatars.githubusercontent.com/u/61111267?u=3271b85f7a37b479c8d0ae0a235182e83c166edf&v=4
url: https://github.com/patsatsia
- login: predictionmachine
avatarUrl: https://avatars.githubusercontent.com/u/63719559?v=4
@@ -329,14 +326,20 @@ sponsors:
- login: anthonycepeda
avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=4252c6b6dc5024af502a823a3ac5e7a03a69963f&v=4
url: https://github.com/anthonycepeda
- login: dotlas
avatarUrl: https://avatars.githubusercontent.com/u/88832003?v=4
url: https://github.com/dotlas
- login: DelfinaCare
avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4
url: https://github.com/DelfinaCare
- login: programvx
avatarUrl: https://avatars.githubusercontent.com/u/96057906?v=4
url: https://github.com/programvx
- login: pyt3h
avatarUrl: https://avatars.githubusercontent.com/u/99658549?v=4
url: https://github.com/pyt3h
- login: Dagmaara
avatarUrl: https://avatars.githubusercontent.com/u/115501964?v=4
url: https://github.com/Dagmaara
- - login: linux-china
avatarUrl: https://avatars.githubusercontent.com/u/46711?v=4
avatarUrl: https://avatars.githubusercontent.com/u/46711?u=cd77c65338b158750eb84dc7ff1acf3209ccfc4f&v=4
url: https://github.com/linux-china
- login: ddanier
avatarUrl: https://avatars.githubusercontent.com/u/113563?u=ed1dc79de72f93bd78581f88ebc6952b62f472da&v=4
@@ -353,15 +356,9 @@ sponsors:
- login: hhatto
avatarUrl: https://avatars.githubusercontent.com/u/150309?u=3e8f63c27bf996bfc68464b0ce3f7a3e40e6ea7f&v=4
url: https://github.com/hhatto
- login: yourkin
avatarUrl: https://avatars.githubusercontent.com/u/178984?u=b43a7e5f8818f7d9083d3b110118d9c27d48a794&v=4
url: https://github.com/yourkin
- login: slafs
avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4
url: https://github.com/slafs
- login: assem-ch
avatarUrl: https://avatars.githubusercontent.com/u/315228?u=e0c5ab30726d3243a40974bb9bae327866e42d9b&v=4
url: https://github.com/assem-ch
- login: adamghill
avatarUrl: https://avatars.githubusercontent.com/u/317045?u=f1349d5ffe84a19f324e204777859fbf69ddf633&v=4
url: https://github.com/adamghill
@@ -371,9 +368,6 @@ sponsors:
- login: dmig
avatarUrl: https://avatars.githubusercontent.com/u/388564?v=4
url: https://github.com/dmig
- login: rinckd
avatarUrl: https://avatars.githubusercontent.com/u/546002?u=8ec88ab721a5636346f19dcd677a6f323058be8b&v=4
url: https://github.com/rinckd
- login: securancy
avatarUrl: https://avatars.githubusercontent.com/u/606673?v=4
url: https://github.com/securancy
@@ -398,6 +392,9 @@ sponsors:
- login: WillHogan
avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=7036c064cf29781470573865264ec8e60b6b809f&v=4
url: https://github.com/WillHogan
- login: my3
avatarUrl: https://avatars.githubusercontent.com/u/1825270?v=4
url: https://github.com/my3
- login: cbonoz
avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4
url: https://github.com/cbonoz
@@ -407,9 +404,9 @@ sponsors:
- login: paul121
avatarUrl: https://avatars.githubusercontent.com/u/3116995?u=6e2d8691cc345e63ee02e4eb4d7cef82b1fcbedc&v=4
url: https://github.com/paul121
- login: igorcorrea
avatarUrl: https://avatars.githubusercontent.com/u/3438238?u=c57605077c31a8f7b2341fc4912507f91b4a5621&v=4
url: https://github.com/igorcorrea
- login: larsvik
avatarUrl: https://avatars.githubusercontent.com/u/3442226?v=4
url: https://github.com/larsvik
- login: anthonycorletti
avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4
url: https://github.com/anthonycorletti
@@ -419,6 +416,9 @@ sponsors:
- login: pawamoy
avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4
url: https://github.com/pawamoy
- login: nikeee
avatarUrl: https://avatars.githubusercontent.com/u/4068864?u=63f8eee593f25138e0f1032ef442e9ad24907d4c&v=4
url: https://github.com/nikeee
- login: Alisa-lisa
avatarUrl: https://avatars.githubusercontent.com/u/4137964?u=e7e393504f554f4ff15863a1e01a5746863ef9ce&v=4
url: https://github.com/Alisa-lisa
@@ -426,7 +426,7 @@ sponsors:
avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4
url: https://github.com/danielunderwood
- login: unredundant
avatarUrl: https://avatars.githubusercontent.com/u/5607577?u=57dd0023365bec03f4fc566df6b81bc0a264a47d&v=4
avatarUrl: https://avatars.githubusercontent.com/u/5607577?u=1ffbf39f5bb8736b75c0d235707d6e8f803725c5&v=4
url: https://github.com/unredundant
- login: Baghdady92
avatarUrl: https://avatars.githubusercontent.com/u/5708590?v=4
@@ -434,6 +434,9 @@ sponsors:
- login: holec
avatarUrl: https://avatars.githubusercontent.com/u/6438041?u=f5af71ec85b3a9d7b8139cb5af0512b02fa9ab1e&v=4
url: https://github.com/holec
- login: mattwelke
avatarUrl: https://avatars.githubusercontent.com/u/7719209?u=5d963ead289969257190b133250653bd99df06ba&v=4
url: https://github.com/mattwelke
- login: hcristea
avatarUrl: https://avatars.githubusercontent.com/u/7814406?u=61d7a4fcf846983a4606788eac25e1c6c1209ba8&v=4
url: https://github.com/hcristea
@@ -470,12 +473,9 @@ sponsors:
- login: logan-connolly
avatarUrl: https://avatars.githubusercontent.com/u/16244943?u=8ae66dfbba936463cc8aa0dd7a6d2b4c0cc757eb&v=4
url: https://github.com/logan-connolly
- login: sanghunka
avatarUrl: https://avatars.githubusercontent.com/u/16280020?u=7d8fafd8bfe6d7900bb1e52d5a5d5da0c02bc164&v=4
url: https://github.com/sanghunka
- login: stevenayers
avatarUrl: https://avatars.githubusercontent.com/u/16361214?u=098b797d8d48afb8cd964b717847943b61d24a6d&v=4
url: https://github.com/stevenayers
- login: harripj
avatarUrl: https://avatars.githubusercontent.com/u/16853829?u=14db1ad132af9ec340f3f1da564620a73b6e4981&v=4
url: https://github.com/harripj
- login: cdsre
avatarUrl: https://avatars.githubusercontent.com/u/16945936?v=4
url: https://github.com/cdsre
@@ -486,7 +486,7 @@ sponsors:
avatarUrl: https://avatars.githubusercontent.com/u/18649504?u=d8a6ac40321f2bded0eba78b637751c7f86c6823&v=4
url: https://github.com/paulowiz
- login: yannicschroeer
avatarUrl: https://avatars.githubusercontent.com/u/22749683?u=4df05a7296c207b91c5d7c7a11c29df5ab313e2b&v=4
avatarUrl: https://avatars.githubusercontent.com/u/22749683?u=91515328b5418a4e7289a83f0dcec3573f1a6500&v=4
url: https://github.com/yannicschroeer
- login: ghandic
avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
@@ -494,6 +494,18 @@ sponsors:
- login: fstau
avatarUrl: https://avatars.githubusercontent.com/u/24669867?u=60e7c8c09f8dafabee8fc3edcd6f9e19abbff918&v=4
url: https://github.com/fstau
- login: pers0n4
avatarUrl: https://avatars.githubusercontent.com/u/24864600?u=f211a13a7b572cbbd7779b9c8d8cb428cc7ba07e&v=4
url: https://github.com/pers0n4
- login: SebTota
avatarUrl: https://avatars.githubusercontent.com/u/25122511?v=4
url: https://github.com/SebTota
- login: hoenie-ams
avatarUrl: https://avatars.githubusercontent.com/u/25708487?u=cda07434f0509ac728d9edf5e681117c0f6b818b&v=4
url: https://github.com/hoenie-ams
- login: joerambo
avatarUrl: https://avatars.githubusercontent.com/u/26282974?v=4
url: https://github.com/joerambo
- login: mertguvencli
avatarUrl: https://avatars.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4
url: https://github.com/mertguvencli
@@ -506,6 +518,9 @@ sponsors:
- login: engineerjoe440
avatarUrl: https://avatars.githubusercontent.com/u/33275230?u=eb223cad27017bb1e936ee9b429b450d092d0236&v=4
url: https://github.com/engineerjoe440
- login: bnkc
avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=76cdc0a8b4e88c7d3e58dccb4b2670839e1247b4&v=4
url: https://github.com/bnkc
- login: declon
avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4
url: https://github.com/declon
@@ -519,10 +534,10 @@ sponsors:
avatarUrl: https://avatars.githubusercontent.com/u/38921751?u=ae14bc1e40f2dd5a9c5741fc0b0dffbd416a5fa9&v=4
url: https://github.com/ww-daniel-mora
- login: rwxd
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=9ddf8023ca3326381ba8fb77285ae36598a15de3&v=4
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=34cba2eaca6a52072498e06bccebe141694fe1d7&v=4
url: https://github.com/rwxd
- login: ilias-ant
avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4
avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a84d169eb6f6bbcb85434c2bed0b4a6d4d13c10e&v=4
url: https://github.com/ilias-ant
- login: arrrrrmin
avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=2a812c1a2ec58227ed01778837f255143de9df97&v=4
@@ -557,27 +572,27 @@ sponsors:
- login: realabja
avatarUrl: https://avatars.githubusercontent.com/u/66185192?u=001e2dd9297784f4218997981b4e6fa8357bb70b&v=4
url: https://github.com/realabja
- login: alessio-proietti
avatarUrl: https://avatars.githubusercontent.com/u/67370599?u=8ac73db1e18e946a7681f173abdb640516f88515&v=4
url: https://github.com/alessio-proietti
- login: pondDevThai
avatarUrl: https://avatars.githubusercontent.com/u/71592181?u=08af9a59bccfd8f6b101de1005aa9822007d0a44&v=4
url: https://github.com/pondDevThai
- - login: mattwelke
avatarUrl: https://avatars.githubusercontent.com/u/7719209?u=5d963ead289969257190b133250653bd99df06ba&v=4
url: https://github.com/mattwelke
- login: cesarfreire
avatarUrl: https://avatars.githubusercontent.com/u/21126103?u=5d428f77f9b63c741f0e9ca5e15a689017b66fe8&v=4
url: https://github.com/cesarfreire
- login: lukzmu
avatarUrl: https://avatars.githubusercontent.com/u/80778518?u=f636ad03cab8e8de15183fa81e768bfad3f515d0&v=4
url: https://github.com/lukzmu
- - login: chrislemke
avatarUrl: https://avatars.githubusercontent.com/u/11752694?u=70ceb6ee7c51d9a52302ab9220ffbf09eaa9c2a4&v=4
url: https://github.com/chrislemke
- login: gabrielmbmb
avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=6d1e00b5d558e96718312ff910a2318f47cc3145&v=4
url: https://github.com/gabrielmbmb
- login: danburonline
avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4
url: https://github.com/danburonline
- login: Moises6669
avatarUrl: https://avatars.githubusercontent.com/u/66188523?u=96af25b8d5be9f983cb96e9dd7c605c716caf1f5&v=4
url: https://github.com/Moises6669
- login: zahariev-webbersof
avatarUrl: https://avatars.githubusercontent.com/u/68993494?u=b341c94a8aa0624e05e201bcf8ae5b2697e3be2f&v=4
url: https://github.com/zahariev-webbersof
- login: buabaj
avatarUrl: https://avatars.githubusercontent.com/u/49881677?u=a85952891036eb448f86eb847902f25badd5f9f7&v=4
url: https://github.com/buabaj
- login: SoulPancake
avatarUrl: https://avatars.githubusercontent.com/u/70265851?u=9cdd82f2835da7d6a56a2e29e1369d5bf251e8f2&v=4
url: https://github.com/SoulPancake
- login: junah201
avatarUrl: https://avatars.githubusercontent.com/u/75025529?u=2451c256e888fa2a06bcfc0646d09b87ddb6a945&v=4
url: https://github.com/junah201

View File

@@ -1,12 +1,12 @@
maintainers:
- login: tiangolo
answers: 1271
prs: 338
answers: 1956
prs: 372
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4
url: https://github.com/tiangolo
experts:
- login: Kludex
count: 364
count: 400
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: dmontagu
@@ -14,103 +14,111 @@ experts:
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
url: https://github.com/dmontagu
- login: ycd
count: 221
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=fa40e037060d62bf82e16b505d870a2866725f38&v=4
count: 224
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
url: https://github.com/ycd
- login: Mause
count: 207
count: 223
avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4
url: https://github.com/Mause
- login: JarroVGIT
count: 196
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
url: https://github.com/JarroVGIT
- login: euri10
count: 166
avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
url: https://github.com/euri10
- login: JarroVGIT
count: 163
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
url: https://github.com/JarroVGIT
- login: phy25
count: 130
avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4
url: https://github.com/phy25
- login: iudeen
count: 118
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: jgould22
count: 95
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
url: https://github.com/jgould22
- login: raphaelauv
count: 77
count: 79
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
url: https://github.com/raphaelauv
- login: ArcLightSlavik
count: 71
count: 74
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4
url: https://github.com/ArcLightSlavik
- login: iudeen
count: 65
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: ghandic
count: 72
avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
url: https://github.com/ghandic
- login: falkben
count: 58
count: 59
avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4
url: https://github.com/falkben
- login: sm-Fifteen
count: 49
count: 52
avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4
url: https://github.com/sm-Fifteen
- login: insomnes
count: 46
avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4
url: https://github.com/insomnes
- login: jgould22
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
url: https://github.com/jgould22
- login: Dustyposa
count: 43
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4
url: https://github.com/Dustyposa
- login: acidjunk
count: 44
avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
url: https://github.com/acidjunk
- login: adriangb
count: 40
avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=75087f0cf0e9f725f3cd18a899218b6c63ae60d3&v=4
count: 44
avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=1e2c2c9b39f5c9b780fb933d8995cf08ec235a47&v=4
url: https://github.com/adriangb
- login: frankie567
count: 41
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
url: https://github.com/frankie567
- login: includeamin
count: 39
count: 40
avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4
url: https://github.com/includeamin
- login: odiseo0
count: 40
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
url: https://github.com/odiseo0
- login: STeveShary
count: 37
avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4
url: https://github.com/STeveShary
- login: chbndrhnns
count: 35
count: 36
avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4
url: https://github.com/chbndrhnns
- login: krishnardt
count: 35
avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4
url: https://github.com/krishnardt
- login: prostomarkeloff
count: 33
avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4
url: https://github.com/prostomarkeloff
- login: frankie567
count: 31
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
url: https://github.com/frankie567
- login: krishnardt
count: 31
avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4
url: https://github.com/krishnardt
- login: yinziyan1206
count: 33
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
url: https://github.com/yinziyan1206
- login: panla
count: 32
avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4
url: https://github.com/panla
- login: wshayes
count: 29
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
url: https://github.com/wshayes
- login: panla
count: 29
avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4
url: https://github.com/panla
- login: acidjunk
count: 27
avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
url: https://github.com/acidjunk
- login: ghandic
count: 25
avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
url: https://github.com/ghandic
- login: dbanty
count: 25
count: 26
avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4
url: https://github.com/dbanty
- login: SirTelemak
@@ -129,22 +137,22 @@ experts:
count: 21
avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4
url: https://github.com/chris-allnutt
- login: odiseo0
- login: rafsaf
count: 21
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=ab724eae71c3fe1cf81e8dc76e73415da926ef7d&v=4
url: https://github.com/odiseo0
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
url: https://github.com/rafsaf
- login: Hultner
count: 19
avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4
url: https://github.com/Hultner
- login: retnikt
count: 19
avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4
url: https://github.com/retnikt
- login: Hultner
- login: zoliknemet
count: 18
avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4
url: https://github.com/Hultner
- login: rafsaf
count: 18
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
url: https://github.com/rafsaf
avatarUrl: https://avatars.githubusercontent.com/u/22326718?u=31ba446ac290e23e56eea8e4f0c558aaf0b40779&v=4
url: https://github.com/zoliknemet
- login: jorgerpo
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4
@@ -166,62 +174,66 @@ experts:
avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4
url: https://github.com/dstlny
- login: jonatasoli
count: 15
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4
url: https://github.com/jonatasoli
- login: hellocoldworld
count: 14
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/47581948?u=3d2186796434c507a6cb6de35189ab0ad27c356f&v=4
url: https://github.com/hellocoldworld
- login: mbroton
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/50829834?u=a48610bf1bffaa9c75d03228926e2eb08a2e24ee&v=4
url: https://github.com/mbroton
- login: simondale00
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/33907262?v=4
url: https://github.com/simondale00
- login: haizaar
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/58201?u=dd40d99a3e1935d0b768f122bfe2258d6ea53b2b&v=4
url: https://github.com/haizaar
- login: yinziyan1206
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4
url: https://github.com/yinziyan1206
- login: valentin994
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/42819267?u=fdeeaa9242a59b243f8603496b00994f6951d5a2&v=4
url: https://github.com/valentin994
- login: David-Lor
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/17401854?u=474680c02b94cba810cb9032fb7eb787d9cc9d22&v=4
url: https://github.com/David-Lor
- login: n8sty
count: 12
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4
url: https://github.com/n8sty
- login: zoliknemet
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/22326718?u=31ba446ac290e23e56eea8e4f0c558aaf0b40779&v=4
url: https://github.com/zoliknemet
last_month_active:
- login: JarroVGIT
count: 27
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
url: https://github.com/JarroVGIT
- login: iudeen
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: mbroton
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/50829834?u=a48610bf1bffaa9c75d03228926e2eb08a2e24ee&v=4
url: https://github.com/mbroton
- login: csrgxtu
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/5053620?u=9655a3e9661492fcdaaf99193eb16d5cbcc3849e&v=4
url: https://github.com/csrgxtu
- login: Kludex
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: jgould22
count: 3
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
url: https://github.com/jgould22
- login: yinziyan1206
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
url: https://github.com/yinziyan1206
- login: Kludex
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: moadennagi
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/16942283?v=4
url: https://github.com/moadennagi
- login: iudeen
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: anthonycorletti
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4
url: https://github.com/anthonycorletti
- login: ThirVondukr
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/50728601?u=56010d6430583b2096a96f0946501156cdb79c75&v=4
url: https://github.com/ThirVondukr
- login: ebottos94
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/100039558?u=e2c672da5a7977fd24d87ce6ab35f8bf5b1ed9fa&v=4
url: https://github.com/ebottos94
- login: odiseo0
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
url: https://github.com/odiseo0
top_contributors:
- login: waynerv
count: 25
@@ -231,16 +243,16 @@ top_contributors:
count: 22
avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
url: https://github.com/tokusumi
- login: jaystone776
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4
url: https://github.com/jaystone776
- login: dmontagu
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
url: https://github.com/dmontagu
- login: jaystone776
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4
url: https://github.com/jaystone776
- login: Kludex
count: 15
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: euri10
@@ -255,22 +267,22 @@ top_contributors:
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4
url: https://github.com/Smlep
- login: dependabot
count: 9
avatarUrl: https://avatars.githubusercontent.com/in/29110?v=4
url: https://github.com/apps/dependabot
- login: Serrones
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4
url: https://github.com/Serrones
- login: RunningIkkyu
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=efb5b45b55584450507834f279ce48d4d64dea2f&v=4
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=494ecc298e3f26197495bb357ad0f57cfd5f7a32&v=4
url: https://github.com/RunningIkkyu
- login: hard-coders
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4
url: https://github.com/hard-coders
- login: rjNemo
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
url: https://github.com/rjNemo
- login: wshayes
count: 5
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
@@ -285,19 +297,31 @@ top_contributors:
url: https://github.com/Attsun1031
- login: ComicShrimp
count: 5
avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4
avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=f440bc9062afb3c43b9b9c6cdfdcfe31d58699ef&v=4
url: https://github.com/ComicShrimp
- login: NinaHwang
count: 5
avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4
url: https://github.com/NinaHwang
- login: batlopes
count: 5
avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4
url: https://github.com/batlopes
- login: jekirl
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4
url: https://github.com/jekirl
- login: samuelcolvin
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4
url: https://github.com/samuelcolvin
- login: jfunez
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/805749?v=4
url: https://github.com/jfunez
- login: ycd
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=fa40e037060d62bf82e16b505d870a2866725f38&v=4
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
url: https://github.com/ycd
- login: komtaki
count: 4
@@ -307,33 +331,29 @@ top_contributors:
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/3360631?u=5fa1f475ad784d64eb9666bdd43cc4d285dcc773&v=4
url: https://github.com/hitrust
- login: rjNemo
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
url: https://github.com/rjNemo
- login: lsglucas
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
url: https://github.com/lsglucas
- login: NinaHwang
- login: Xewus
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4
url: https://github.com/NinaHwang
- login: pre-commit-ci
count: 4
avatarUrl: https://avatars.githubusercontent.com/in/68672?v=4
url: https://github.com/apps/pre-commit-ci
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=4bdd4a0300530a504987db27488ba79c37f2fb18&v=4
url: https://github.com/Xewus
top_reviewers:
- login: Kludex
count: 101
count: 110
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: BilalAlpaslan
count: 64
count: 72
avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4
url: https://github.com/BilalAlpaslan
- login: yezz123
count: 70
avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4
url: https://github.com/yezz123
- login: tokusumi
count: 50
count: 51
avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
url: https://github.com/tokusumi
- login: waynerv
@@ -344,18 +364,22 @@ top_reviewers:
count: 47
avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4
url: https://github.com/Laineyzhang55
- login: yezz123
count: 46
avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4
url: https://github.com/yezz123
- login: ycd
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=fa40e037060d62bf82e16b505d870a2866725f38&v=4
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
url: https://github.com/ycd
- login: iudeen
count: 44
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: cikay
count: 41
avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4
url: https://github.com/cikay
- login: JarroVGIT
count: 34
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
url: https://github.com/JarroVGIT
- login: AdrianDeAnda
count: 33
avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=b2ea249c6b41ddf98679c8d110d0f67d4a3ebf93&v=4
@@ -364,34 +388,46 @@ top_reviewers:
count: 31
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4
url: https://github.com/ArcLightSlavik
- login: JarroVGIT
count: 31
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
url: https://github.com/JarroVGIT
- login: cassiobotaro
count: 25
count: 28
avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4
url: https://github.com/cassiobotaro
- login: komtaki
count: 27
avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4
url: https://github.com/komtaki
- login: lsglucas
count: 24
count: 26
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
url: https://github.com/lsglucas
- login: dmontagu
count: 23
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
url: https://github.com/dmontagu
- login: komtaki
count: 21
avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4
url: https://github.com/komtaki
- login: hard-coders
count: 20
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4
url: https://github.com/hard-coders
- login: LorhanSohaky
count: 19
avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4
url: https://github.com/LorhanSohaky
- login: 0417taehyun
count: 19
avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4
url: https://github.com/0417taehyun
- login: rjNemo
count: 18
avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
url: https://github.com/rjNemo
- login: odiseo0
count: 18
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
url: https://github.com/odiseo0
- login: Smlep
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4
url: https://github.com/Smlep
- login: zy7y
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/67154681?u=5d634834cc514028ea3f9115f7030b99a1f4d5a4&v=4
@@ -404,14 +440,6 @@ top_reviewers:
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4
url: https://github.com/SwftAlpc
- login: rjNemo
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
url: https://github.com/rjNemo
- login: Smlep
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4
url: https://github.com/Smlep
- login: DevDae
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/87962045?u=08e10fa516e844934f4b3fc7c38b33c61697e4a1&v=4
@@ -424,30 +452,26 @@ top_reviewers:
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4
url: https://github.com/delhi09
- login: iudeen
count: 14
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: sh0nk
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4
url: https://github.com/sh0nk
- login: RunningIkkyu
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=efb5b45b55584450507834f279ce48d4d64dea2f&v=4
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=494ecc298e3f26197495bb357ad0f57cfd5f7a32&v=4
url: https://github.com/RunningIkkyu
- login: odiseo0
- login: Ryandaydev
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=ab724eae71c3fe1cf81e8dc76e73415da926ef7d&v=4
url: https://github.com/odiseo0
- login: LorhanSohaky
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4
url: https://github.com/LorhanSohaky
avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=809f3d1074d04bbc28012a7f17f06ea56f5bd71a&v=4
url: https://github.com/Ryandaydev
- login: solomein-sv
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4
url: https://github.com/solomein-sv
- login: Xewus
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=4bdd4a0300530a504987db27488ba79c37f2fb18&v=4
url: https://github.com/Xewus
- login: mariacamilagl
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
@@ -462,8 +486,16 @@ top_reviewers:
url: https://github.com/maoyibo
- login: ComicShrimp
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=b3e4d9a14d9a65d429ce62c566aef73178b7111d&v=4
avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=f440bc9062afb3c43b9b9c6cdfdcfe31d58699ef&v=4
url: https://github.com/ComicShrimp
- login: peidrao
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=5401640e0b961cc199dee39ec79e162c7833cd6b&v=4
url: https://github.com/peidrao
- login: izaguerreiro
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4
url: https://github.com/izaguerreiro
- login: graingert
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/413772?u=64b77b6aa405c68a9c6bcf45f84257c66eea5f32&v=4
@@ -480,14 +512,18 @@ top_reviewers:
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4
url: https://github.com/bezaca
- login: izaguerreiro
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4
url: https://github.com/izaguerreiro
- login: dimaqq
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/662249?v=4
url: https://github.com/dimaqq
- login: raphaelauv
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
url: https://github.com/raphaelauv
- login: axel584
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/1334088?v=4
url: https://github.com/axel584
- login: blt232018
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/43393471?u=172b0e0391db1aa6c1706498d6dfcb003c8a4857&v=4
@@ -500,23 +536,3 @@ top_reviewers:
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4
url: https://github.com/NinaHwang
- login: dimaqq
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/662249?v=4
url: https://github.com/dimaqq
- login: Serrones
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4
url: https://github.com/Serrones
- login: jovicon
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4
url: https://github.com/jovicon
- login: ryuckel
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/36391432?u=094eec0cfddd5013f76f31e55e56147d78b19553&v=4
url: https://github.com/ryuckel
- login: NastasiaSaby
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/8245071?u=b3afd005f9e4bf080c219ef61a592b3a8004b764&v=4
url: https://github.com/NastasiaSaby

View File

@@ -8,9 +8,6 @@ gold:
- url: https://cryptapi.io/
title: "CryptAPI: Your easy to use, secure and privacy oriented payment gateway."
img: https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg
- url: https://doist.com/careers/9B437B1615-wa-senior-backend-engineer-python
title: Help us migrate doist to FastAPI
img: https://fastapi.tiangolo.com/img/sponsors/doist.svg
silver:
- url: https://www.deta.sh/?ref=fastapi
title: The launchpad for all your (team's) ideas
@@ -30,9 +27,12 @@ silver:
- url: https://www.udemy.com/course/fastapi-rest/
title: Learn FastAPI by building a complete project. Extend your knowledge on advanced web development-AWS, Payments, Emails.
img: https://fastapi.tiangolo.com/img/sponsors/ines-course.jpg
- url: https://careers.budget-insight.com/
title: Budget Insight is hiring!
img: https://fastapi.tiangolo.com/img/sponsors/budget-insight.svg
- url: https://careers.powens.com/
title: Powens is hiring!
img: https://fastapi.tiangolo.com/img/sponsors/powens.png
- url: https://www.svix.com/
title: Svix - Webhooks as a service
img: https://fastapi.tiangolo.com/img/sponsors/svix.svg
bronze:
- url: https://www.exoflare.com/open-source/?utm_source=FastAPI&utm_campaign=open_source
title: Biosecurity risk assessments made easy.

View File

@@ -13,3 +13,5 @@ logins:
- BLUE-DEVIL1134
- ObliviousAI
- Doist
- nihpo
- svix

View File

@@ -1,6 +1,6 @@
# Async Tests
You have already seen how to test your **FastAPI** applications using the provided `TestClient`, but with it, you can't test or run any other `async` function in your (synchronous) pytest functions.
You have already seen how to test your **FastAPI** applications using the provided `TestClient`. Up to now, you have only seen how to write synchronous tests, without using `async` functions.
Being able to use asynchronous functions in your tests could be useful, for example, when you're querying your database asynchronously. Imagine you want to test sending requests to your FastAPI application and then verify that your backend successfully wrote the correct data in the database, while using an async database library.
@@ -8,7 +8,7 @@ Let's look at how we can make that work.
## pytest.mark.anyio
If we want to call asynchronous functions in our tests, our test functions have to be asynchronous. Anyio provides a neat plugin for this, that allows us to specify that some test functions are to be called asynchronously.
If we want to call asynchronous functions in our tests, our test functions have to be asynchronous. AnyIO provides a neat plugin for this, that allows us to specify that some test functions are to be called asynchronously.
## HTTPX
@@ -16,13 +16,7 @@ Even if your **FastAPI** application uses normal `def` functions instead of `asy
The `TestClient` does some magic inside to call the asynchronous FastAPI application in your normal `def` test functions, using standard pytest. But that magic doesn't work anymore when we're using it inside asynchronous functions. By running our tests asynchronously, we can no longer use the `TestClient` inside our test functions.
Luckily there's a nice alternative, called <a href="https://www.python-httpx.org/" class="external-link" target="_blank">HTTPX</a>.
HTTPX is an HTTP client for Python 3 that allows us to query our FastAPI application similarly to how we did it with the `TestClient`.
If you're familiar with the <a href="https://requests.readthedocs.io/en/master/" class="external-link" target="_blank">Requests</a> library, you'll find that the API of HTTPX is almost identical.
The important difference for us is that with HTTPX we are not limited to synchronous, but can also make asynchronous requests.
The `TestClient` is based on <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>, and luckily, we can use it directly to test the API.
## Example
@@ -85,7 +79,7 @@ This is the equivalent to:
response = client.get('/')
```
that we used to make our requests with the `TestClient`.
...that we used to make our requests with the `TestClient`.
!!! tip
Note that we're using async/await with the new `AsyncClient` - the request is asynchronous.

View File

@@ -68,7 +68,7 @@ Enforces that all incoming requests have a correctly set `Host` header, in order
The following arguments are supported:
* `allowed_hosts` - A list of domain names that should be allowed as hostnames. Wildcard domains such as `*.example.com` are supported for matching subdomains to allow any hostname either use `allowed_hosts=["*"]` or omit the middleware.
* `allowed_hosts` - A list of domain names that should be allowed as hostnames. Wildcard domains such as `*.example.com` are supported for matching subdomains. To allow any hostname either use `allowed_hosts=["*"]` or omit the middleware.
If an incoming request does not validate correctly then a `400` response will be sent.

View File

@@ -50,7 +50,7 @@ It could be just one or two lines of code, like:
```Python
callback_url = "https://example.com/api/v1/invoices/events/"
requests.post(callback_url, json={"description": "Invoice paid", "paid": True})
httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
```
But possibly the most important part of the callback is making sure that your API user (the external developer) implements the *external API* correctly, according to the data that *your API* is going to send in the request body of the callback, etc.
@@ -64,7 +64,7 @@ This example doesn't implement the callback itself (that could be just a line of
!!! tip
The actual callback is just an HTTP request.
When implementing the callback yourself, you could use something like <a href="https://www.encode.io/httpx/" class="external-link" target="_blank">HTTPX</a> or <a href="https://requests.readthedocs.io/" class="external-link" target="_blank">Requests</a>.
When implementing the callback yourself, you could use something like <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> or <a href="https://requests.readthedocs.io/" class="external-link" target="_blank">Requests</a>.
## Write the callback documentation code

View File

@@ -112,17 +112,15 @@ In WebSocket endpoints you can import from `fastapi` and use:
They work the same way as for other FastAPI endpoints/*path operations*:
```Python hl_lines="58-65 68-83"
```Python hl_lines="66-77 76-91"
{!../../../docs_src/websockets/tutorial002.py!}
```
!!! info
In a WebSocket it doesn't really make sense to raise an `HTTPException`. So it's better to close the WebSocket connection directly.
As this is a WebSocket it doesn't really make sense to raise an `HTTPException`, instead we raise a `WebSocketException`.
You can use a closing code from the <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">valid codes defined in the specification</a>.
In the future, there will be a `WebSocketException` that you will be able to `raise` from anywhere, and add exception handlers for it. It depends on the <a href="https://github.com/encode/starlette/pull/527" class="external-link" target="_blank">PR #527</a> in Starlette.
### Try the WebSockets with dependencies
If your file is named `main.py`, run your application with:

View File

@@ -367,7 +367,7 @@ It has:
* WebSocket support.
* In-process background tasks.
* Startup and shutdown events.
* Test client built on requests.
* Test client built on HTTPX.
* CORS, GZip, Static Files, Streaming responses.
* Session and Cookie support.
* 100% test coverage.

View File

@@ -283,7 +283,7 @@ For example:
### Concurrency + Parallelism: Web + Machine Learning
With **FastAPI** you can take the advantage of concurrency that is very common for web development (the same main attractive of NodeJS).
With **FastAPI** you can take the advantage of concurrency that is very common for web development (the same main attraction of NodeJS).
But you can also exploit the benefits of parallelism and multiprocessing (having multiple processes running in parallel) for **CPU bound** workloads like those in Machine Learning systems.

View File

@@ -235,7 +235,7 @@ Here are some possible combinations and strategies:
* One Uvicorn **process manager** would listen on the **IP** and **port**, and it would start **multiple Uvicorn worker processes**
* **Kubernetes** and other distributed **container systems**
* Something in the **Kubernetes** layer would listen on the **IP** and **port**. The replication would be by having **multiple containers**, each with **one Uvicorn process** running
* **Cloud services** that handle this for your
* **Cloud services** that handle this for you
* The cloud service will probably **handle replication for you**. It would possibly let you define **a process to run**, or a **container image** to use, in any case, it would most probably be **a single Uvicorn process**, and the cloud service would be in charge of replicating it.
!!! tip

View File

@@ -56,6 +56,15 @@ Here's an incomplete list of some of them.
{% endfor %}
{% endif %}
### Taiwanese
{% if external_links %}
{% for article in external_links.articles.taiwanese %}
* <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
{% if external_links %}

View File

@@ -28,7 +28,7 @@ I'm the creator and maintainer of **FastAPI**. You can read more about that in [
These are the people that:
* [Help others with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank}.
* [Help others with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github){.internal-link target=_blank}.
* [Create Pull Requests](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}.
* Review Pull Requests, [especially important for translations](contributing.md#translations){.internal-link target=_blank}.
@@ -36,13 +36,13 @@ A round of applause to them. 👏 🙇
## Most active users last month
These are the users that have been [helping others the most with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} during the last month. ☕
These are the users that have been [helping others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github){.internal-link target=_blank} during the last month. ☕
{% if people %}
<div class="user-list user-list-center">
{% for user in people.last_month_active %}
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Issues replied: {{ user.count }}</div></div>
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Questions replied: {{ user.count }}</div></div>
{% endfor %}
</div>
@@ -52,7 +52,7 @@ These are the users that have been [helping others the most with issues (questio
Here are the **FastAPI Experts**. 🤓
These are the users that have [helped others the most with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} through *all time*.
These are the users that have [helped others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github){.internal-link target=_blank} through *all time*.
They have proven to be experts by helping many others. ✨
@@ -60,7 +60,7 @@ They have proven to be experts by helping many others. ✨
<div class="user-list user-list-center">
{% for user in people.experts %}
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Issues replied: {{ user.count }}</div></div>
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Questions replied: {{ user.count }}</div></div>
{% endfor %}
</div>
@@ -169,7 +169,7 @@ They are supporting my work with **FastAPI** (and others), mainly through <a hre
The main intention of this page is to highlight the effort of the community to help others.
Especially including efforts that are normally less visible, and in many cases more arduous, like helping others with issues and reviewing Pull Requests with translations.
Especially including efforts that are normally less visible, and in many cases more arduous, like helping others with questions and reviewing Pull Requests with translations.
The data is calculated each month, you can read the <a href="https://github.com/tiangolo/fastapi/blob/master/.github/actions/people/app/main.py" class="external-link" target="_blank">source code here</a>.

View File

@@ -166,7 +166,7 @@ With **FastAPI** you get all of **Starlette**'s features (as FastAPI is just Sta
* **WebSocket** support.
* In-process background tasks.
* Startup and shutdown events.
* Test client built on `requests`.
* Test client built on HTTPX.
* **CORS**, GZip, Static Files, Streaming responses.
* **Session and Cookie** support.
* 100% test coverage.

View File

@@ -47,7 +47,7 @@ You can:
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">Follow me on **GitHub**</a>.
* See other Open Source projects I have created that could help you.
* Follow me to see when I create a new Open Source project.
* <a href="https://twitter.com/tiangolo" class="external-link" target="_blank">Follow me on **Twitter**</a>.
* <a href="https://twitter.com/tiangolo" class="external-link" target="_blank">Follow me on **Twitter**</a> or <a href="https://fosstodon.org/@tiangolo" class="external-link" target="_blank">Mastodon</a>.
* Tell me how you use FastAPI (I love to hear that).
* Hear when I make announcements or release new tools.
* You can also <a href="https://twitter.com/fastapi" class="external-link" target="_blank">follow @fastapi on Twitter</a> (a separate account).
@@ -67,29 +67,129 @@ I love to hear about how **FastAPI** is being used, what you have liked in it, i
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Vote for **FastAPI** in Slant</a>.
* <a href="https://alternativeto.net/software/fastapi/" class="external-link" target="_blank">Vote for **FastAPI** in AlternativeTo</a>.
* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">Say you use **FastAPI** on StackShare</a>.
## Help others with issues in GitHub
## Help others with questions in GitHub
You can see <a href="https://github.com/tiangolo/fastapi/issues" class="external-link" target="_blank">existing issues</a> and try and help others, most of the times they are questions that you might already know the answer for. 🤓
You can try and help others with their questions in:
If you are helping a lot of people with issues, you might become an official [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}. 🎉
* <a href="https://github.com/tiangolo/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered" class="external-link" target="_blank">GitHub Discussions</a>
* <a href="https://github.com/tiangolo/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+" class="external-link" target="_blank">GitHub Issues</a>
In many cases you might already know the answer for those questions. 🤓
If you are helping a lot of people with their questions, you will become an official [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}. 🎉
Just remember, the most important point is: try to be kind. People come with their frustrations and in many cases don't ask in the best way, but try as best as you can to be kind. 🤗
The idea is for the **FastAPI** community to be kind and welcoming. At the same time, don't accept bullying or disrespectful behavior towards others. We have to take care of each other.
---
Here's how to help others with questions (in discussions or issues):
### Understand the question
* Check if you can understand what is the **purpose** and use case of the person asking.
* Then check if the question (the vast majority are questions) is **clear**.
* In many cases the question asked is about an imaginary solution from the user, but there might be a **better** one. If you can understand the problem and use case better, you might be able to suggest a better **alternative solution**.
* If you can't understand the question, ask for more **details**.
### Reproduce the problem
For most of the cases and most of the questions there's something related to the person's **original code**.
In many cases they will only copy a fragment of the code, but that's not enough to **reproduce the problem**.
* You can ask them to provide a <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">minimal, reproducible, example</a>, that you can **copy-paste** and run locally to see the same error or behavior they are seeing, or to understand their use case better.
* If you are feeling too generous, you can try to **create an example** like that yourself, just based on the description of the problem. Just have in mind that this might take a lot of time and it might be better to ask them to clarify the problem first.
### Suggest solutions
* After being able to understand the question, you can give them a possible **answer**.
* In many cases, it's better to understand their **underlying problem or use case**, because there might be a better way to solve it than what they are trying to do.
### Ask to close
If they reply, there's a high chance you would have solved their problem, congrats, **you're a hero**! 🦸
* Now, if that solved their problem, you can ask them to:
* In GitHub Discussions: mark the comment as the **answer**.
* In GitHub Issues: **close** the issue**.
## Watch the GitHub repository
You can "watch" FastAPI in GitHub (clicking the "watch" button at the top right): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. 👀
If you select "Watching" instead of "Releases only" you will receive notifications when someone creates a new issue.
If you select "Watching" instead of "Releases only" you will receive notifications when someone creates a new issue or question. You can also specify that you only want to be notified about new issues, or discussions, or PRs, etc.
Then you can try and help them solve those issues.
Then you can try and help them solve those questions.
## Create issues
## Ask Questions
You can <a href="https://github.com/tiangolo/fastapi/issues/new/choose" class="external-link" target="_blank">create a new issue</a> in the GitHub repository, for example to:
You can <a href="https://github.com/tiangolo/fastapi/discussions/new?category=questions" class="external-link" target="_blank">create a new question</a> in the GitHub repository, for example to:
* Ask a **question** or ask about a **problem**.
* Suggest a new **feature**.
**Note**: if you create an issue, then I'm going to ask you to also help others. 😉
**Note**: if you do it, then I'm going to ask you to also help others. 😉
## Review Pull Requests
You can help me review pull requests from others.
Again, please try your best to be kind. 🤗
---
Here's what to have in mind and how to review a pull request:
### Understand the problem
* First, make sure you **understand the problem** that the pull request is trying to solve. It might have a longer discussion in a GitHub Discussion or issue.
* There's also a good chance that the pull request is not actually needed because the problem can be solved in a **different way**. Then you can suggest or ask about that.
### Don't worry about style
* Don't worry too much about things like commit message styles, I will squash and merge customizing the commit manually.
* Also don't worry about style rules, there are already automatized tools checking that.
And if there's any other style or consistency need, I'll ask directly for that, or I'll add commits on top with the needed changes.
### Check the code
* Check and read the code, see if it makes sense, **run it locally** and see if it actually solves the problem.
* Then **comment** saying that you did that, that's how I will know you really checked it.
!!! info
Unfortunately, I can't simply trust PRs that just have several approvals.
Several times it has happened that there are PRs with 3, 5 or more approvals, probably because the description is appealing, but when I check the PRs, they are actually broken, have a bug, or don't solve the problem they claim to solve. 😅
So, it's really important that you actually read and run the code, and let me know in the comments that you did. 🤓
* If the PR can be simplified in a way, you can ask for that, but there's no need to be too picky, there might be a lot of subjective points of view (and I will have my own as well 🙈), so it's better if you can focus on the fundamental things.
### Tests
* Help me check that the PR has **tests**.
* Check that the tests **fail** before the PR. 🚨
* Then check that the tests **pass** after the PR. ✅
* Many PRs don't have tests, you can **remind** them to add tests, or you can even **suggest** some tests yourself. That's one of the things that consume most time and you can help a lot with that.
* Then also comment what you tried, that way I'll know that you checked it. 🤓
## Create a Pull Request
@@ -102,14 +202,32 @@ You can [contribute](contributing.md){.internal-link target=_blank} to the sourc
* You can also help to review the translations created by others.
* To propose new documentation sections.
* To fix an existing issue/bug.
* Make sure to add tests.
* To add a new feature.
* Make sure to add tests.
* Make sure to add documentation if it's relevant.
## Help Maintain FastAPI
Help me maintain **FastAPI**! 🤓
There's a lot of work to do, and for most of it, **YOU** can do it.
The main tasks that you can do right now are:
* [Help others with questions in GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (see the section above).
* [Review Pull Requests](#review-pull-requests){.internal-link target=_blank} (see the section above).
Those two tasks are what **consume time the most**. That's the main work of maintaining FastAPI.
If you can help me with that, **you are helping me maintain FastAPI** and making sure it keeps **advancing faster and better**. 🚀
## Join the chat
Join the 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank">Discord chat server</a> 👥 and hang out with others in the FastAPI community.
!!! tip
For questions, ask them in <a href="https://github.com/tiangolo/fastapi/issues/new/choose" class="external-link" target="_blank">GitHub issues</a>, there's a much better chance you will receive help by the [FastAPI Experts](fastapi-people.md#experts){.internal-link target=_blank}.
For questions, ask them in <a href="https://github.com/tiangolo/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussions</a>, there's a much better chance you will receive help by the [FastAPI Experts](fastapi-people.md#experts){.internal-link target=_blank}.
Use the chat only for other general conversations.
@@ -119,9 +237,9 @@ There is also the previous <a href="https://gitter.im/tiangolo/fastapi" class="e
Have in mind that as chats allow more "free conversation", it's easy to ask questions that are too general and more difficult to answer, so, you might not receive answers.
In GitHub issues the template will guide you to write the right question so that you can more easily get a good answer, or even solve the problem yourself even before asking. And in GitHub I can make sure I always answer everything, even if it takes some time. I can't personally do that with the chat systems. 😅
In GitHub, the template will guide you to write the right question so that you can more easily get a good answer, or even solve the problem yourself even before asking. And in GitHub I can make sure I always answer everything, even if it takes some time. I can't personally do that with the chat systems. 😅
Conversations in the chat systems are also not as easily searchable as in GitHub, so questions and answers might get lost in the conversation. And only the ones in GitHub issues count to become a [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}, so you will most probably receive more attention in GitHub issues.
Conversations in the chat systems are also not as easily searchable as in GitHub, so questions and answers might get lost in the conversation. And only the ones in GitHub count to become a [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}, so you will most probably receive more attention in GitHub.
On the other side, there are thousands of users in the chat systems, so there's a high chance you'll find someone to talk to there, almost all the time. 😄

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,178 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
width="240"
height="100"
viewBox="0 0 240 100"
sodipodi:docname="svix-vector.svg"
inkscape:version="1.0.2 (1.0.2+r75+1)"
inkscape:export-filename="../../../../../tmp/banner.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<metadata
id="metadata15">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6" />
<sodipodi:namedview
id="namedview4"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="2.364373"
inkscape:cx="9.516265"
inkscape:cy="64.499129"
inkscape:window-width="1920"
inkscape:window-height="1025"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="text1936"
inkscape:document-rotation="0" />
<g
inkscape:groupmode="layer"
inkscape:label="Image"
id="g8">
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.986808;stroke-opacity:1;paint-order:fill markers stroke"
id="rect3346"
width="240"
height="100"
x="-240"
y="0"
rx="0"
transform="scale(-1,1)" />
<g
id="g6454"
transform="matrix(0.87971356,0,0,0.87971356,13.956407,4.3914173)">
<g
id="g8-7"
transform="matrix(0.10637635,0,0,0.10637635,14.16696,-68.565829)">
<path
fill-rule="evenodd"
clip-rule="evenodd"
fill="#ffffff"
d="m 356.996,807.521 c -24.779,24.776 -40.104,59.008 -40.104,96.812 0,37.809 15.325,72.034 40.104,96.808 55.364,55.372 104.225,24.98 135.285,56.04 9.84,9.842 15.933,23.447 15.933,38.474 0,15.023 -6.093,28.632 -15.933,38.473 -9.843,9.845 -23.45,15.936 -38.475,15.936 -10.021,0 -19.375,-2.686 -27.377,-7.354 -25.975,-15.161 -30.519,-48.084 -70.353,-71.339 -20.285,-11.842 -43.846,-18.637 -68.954,-18.637 -35.289,0 -67.459,13.355 -91.735,35.282 9.772,28.697 24.19,55.246 42.359,78.749 2.707,-5.83 6.413,-11.102 10.901,-15.589 9.841,-9.842 23.45,-15.936 38.475,-15.936 10.021,0 19.375,2.686 27.376,7.354 8.556,4.994 15.55,11.989 20.191,20.202 12.059,21.337 29.423,39.029 50.162,51.137 20.285,11.842 43.846,18.637 68.955,18.637 37.804,0 72.036,-15.326 96.812,-40.105 24.775,-24.775 40.104,-59.001 40.104,-96.81 0,-37.802 -15.328,-72.034 -40.104,-96.81 -55.367,-55.367 -104.229,-24.983 -135.285,-56.038 -9.843,-9.845 -15.935,-23.448 -15.935,-38.473 0,-15.025 6.092,-28.632 15.935,-38.475 9.839,-9.839 23.448,-15.933 38.473,-15.933 10.021,0 19.376,2.682 27.378,7.354 25.973,15.162 30.517,48.083 70.351,71.339 20.284,11.842 43.846,18.635 68.956,18.635 35.284,0 67.459,-13.352 91.733,-35.28 -9.772,-28.7 -24.19,-55.247 -42.359,-78.751 -2.705,5.831 -6.413,11.102 -10.901,15.589 -9.843,9.843 -23.448,15.935 -38.473,15.935 -10.021,0 -19.375,-2.684 -27.378,-7.354 -8.556,-4.995 -15.548,-11.99 -20.19,-20.202 -12.059,-21.336 -29.422,-39.029 -50.16,-51.138 -20.285,-11.841 -43.847,-18.634 -68.956,-18.634 -37.81,-10e-4 -72.037,15.327 -96.811,40.102 z"
id="path2-0" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
fill="#018ffa"
d="m 453.806,727.069 c -150.731,0 -272.922,122.192 -272.922,272.924 0,30.797 5.1,60.402 14.503,88.021 24.276,-21.927 56.446,-35.282 91.735,-35.282 25.108,0 48.669,6.795 68.954,18.637 39.833,23.255 44.377,56.178 70.353,71.339 8.002,4.669 17.356,7.354 27.377,7.354 15.025,0 28.632,-6.091 38.475,-15.936 9.84,-9.841 15.933,-23.449 15.933,-38.473 0,-15.026 -6.093,-28.632 -15.933,-38.474 -31.06,-31.06 -79.921,-0.668 -135.285,-56.04 -24.779,-24.773 -40.104,-58.999 -40.104,-96.808 0,-37.804 15.325,-72.036 40.104,-96.812 24.774,-24.776 59.001,-40.104 96.81,-40.104 25.109,0 48.671,6.793 68.956,18.634 20.738,12.108 38.101,29.802 50.16,51.138 4.643,8.212 11.634,15.208 20.19,20.202 8.004,4.67 17.358,7.354 27.378,7.354 15.025,0 28.63,-6.092 38.473,-15.935 4.488,-4.488 8.196,-9.759 10.901,-15.589 C 619.951,768.65 541.735,727.069 453.806,727.069 Z"
id="path4-9" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
fill="#018ffa"
d="m 550.617,998.844 c 24.775,24.776 40.104,59.008 40.104,96.81 0,37.809 -15.328,72.034 -40.104,96.81 -24.776,24.779 -59.008,40.105 -96.812,40.105 -25.108,0 -48.67,-6.795 -68.955,-18.637 -20.738,-12.107 -38.103,-29.8 -50.162,-51.137 -4.641,-8.213 -11.635,-15.208 -20.191,-20.202 -8.002,-4.669 -17.356,-7.354 -27.376,-7.354 -15.025,0 -28.634,6.094 -38.475,15.936 -4.488,4.487 -8.194,9.759 -10.901,15.589 49.916,64.571 128.132,106.15 216.06,106.15 150.732,0 272.923,-122.19 272.923,-272.921 0,-30.797 -5.102,-60.403 -14.505,-88.02 -24.274,21.928 -56.449,35.28 -91.733,35.28 -25.109,0 -48.671,-6.793 -68.956,-18.635 -39.834,-23.257 -44.378,-56.178 -70.351,-71.339 -8.002,-4.672 -17.358,-7.354 -27.378,-7.354 -15.025,0 -28.634,6.094 -38.473,15.933 -9.843,9.843 -15.935,23.45 -15.935,38.475 0,15.025 6.092,28.628 15.935,38.473 31.056,31.055 79.918,0.672 135.285,56.038 z"
id="path6-3" />
</g>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fill="#1a283f"
d="m 130.33984,26.880256 c -3.16236,-2.773976 -6.38003,-3.606158 -10.65199,-3.606158 -4.9932,0 -11.53972,2.219223 -11.53972,8.543723 0,6.213868 6.15824,8.100027 11.31771,8.488514 3.88359,0.221902 5.43699,0.998661 5.43699,2.884821 0,1.997109 -2.3857,3.328942 -4.93756,3.273306 -3.0514,-0.05542 -7.48974,-1.664365 -9.43143,-3.828059 l -3.32873,4.826615 c 3.99444,4.16091 8.32193,4.882248 12.64922,4.882248 7.8227,0 11.7616,-4.160911 11.7616,-8.987525 0,-7.267846 -6.5465,-8.432879 -11.70619,-8.765837 -3.49509,-0.221902 -5.10415,-1.220563 -5.10415,-2.995878 0,-1.719787 1.77542,-2.71834 4.9932,-2.71834 2.60739,0 4.82683,0.61028 6.7683,2.441125 z m 26.57462,-2.884929 -3.77274,9.154112 -4.16091,11.428864 -4.21655,-11.539709 -3.77243,-9.043159 h -7.37879 l 11.70597,27.517648 h 7.32359 l 11.65045,-27.517648 h -7.37859 z m 17.4203,-0.05552 v 27.462122 h -6.76852 V 23.939802 Z m -7.37847,-7.600591 c 0,5.270417 7.98896,5.270417 7.98896,0 -10e-5,-5.270523 -7.98896,-5.270523 -7.98896,0 z m 26.68514,16.976603 -5.38137,-9.26485 h -8.09992 v 0.22169 l 8.98753,13.259494 -9.54228,13.703403 v 0.166266 h 8.09993 l 5.93611,-9.154112 5.93655,9.154111 h 8.09992 v -0.166266 l -9.54218,-13.703403 8.98743,-13.259494 v -0.22169 h -8.09992 z"
id="path10-6"
style="stroke-width:0.106376" />
</g>
<g
aria-label="Webhooks as a Service"
id="text1936"
style="font-style:normal;font-weight:normal;font-size:16px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none">
<path
d="M 43.474213,86.844101 H 40.739838 L 39.24765,80.476913 q -0.273437,-1.125 -0.460937,-2.351562 -0.1875,1.023437 -0.304688,1.5625 -0.117187,0.53125 -1.664062,7.15625 H 34.083588 L 31.24765,75.836288 h 2.335938 l 1.59375,7.109375 0.359375,1.71875 q 0.21875,-1.085937 0.421875,-2.070312 0.210937,-0.992188 1.5625,-6.757813 h 2.578125 l 1.390625,5.859375 q 0.164062,0.65625 0.554687,2.96875 l 0.195313,-0.90625 0.414062,-1.796875 1.328125,-6.125 h 2.335938 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path840" />
<path
d="m 50.62265,87.000351 q -1.90625,0 -2.929687,-1.125 -1.023438,-1.132813 -1.023438,-3.296875 0,-2.09375 1.039063,-3.21875 1.039062,-1.125 2.945312,-1.125 1.820313,0 2.78125,1.210937 0.960938,1.203125 0.960938,3.53125 v 0.0625 h -5.421875 q 0,1.234375 0.453125,1.867188 0.460937,0.625 1.304687,0.625 1.164063,0 1.46875,-1.007813 l 2.070313,0.179688 q -0.898438,2.296875 -3.648438,2.296875 z m 0,-7.382813 q -0.773437,0 -1.195312,0.539063 -0.414063,0.539062 -0.4375,1.507812 h 3.28125 q -0.0625,-1.023437 -0.492188,-1.53125 -0.429687,-0.515625 -1.15625,-0.515625 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path842" />
<path
d="m 64.067963,82.586288 q 0,2.09375 -0.84375,3.257813 -0.835938,1.15625 -2.398438,1.15625 -0.898437,0 -1.554687,-0.390625 -0.65625,-0.390625 -1.007813,-1.125 h -0.01563 q 0,0.273437 -0.03906,0.75 -0.03125,0.476562 -0.07031,0.609375 h -2.132812 q 0.0625,-0.726563 0.0625,-1.929688 v -9.664062 h 2.195312 v 3.234375 l -0.03125,1.375 h 0.03125 q 0.742188,-1.625 2.703125,-1.625 1.5,0 2.296875,1.140625 0.804688,1.132812 0.804688,3.210937 z m -2.289063,0 q 0,-1.4375 -0.421875,-2.132812 -0.421875,-0.695313 -1.304687,-0.695313 -0.890625,0 -1.359375,0.75 -0.460938,0.742188 -0.460938,2.148438 0,1.34375 0.453125,2.09375 0.460938,0.75 1.351563,0.75 1.742187,0 1.742187,-2.914063 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path844" />
<path
d="m 68.013275,80.078476 q 0.445313,-0.96875 1.117188,-1.40625 0.671875,-0.4375 1.601562,-0.4375 1.34375,0 2.0625,0.828125 0.71875,0.828125 0.71875,2.421875 v 5.359375 h -2.1875 v -4.734375 q 0,-2.226563 -1.507812,-2.226563 -0.796875,0 -1.289063,0.6875 -0.484375,0.679688 -0.484375,1.75 v 4.523438 h -2.195312 v -11.59375 h 2.195312 v 3.164062 q 0,0.851563 -0.0625,1.664063 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path846" />
<path
d="m 83.661713,82.609726 q 0,2.054687 -1.140625,3.226562 -1.140625,1.164063 -3.15625,1.164063 -1.976563,0 -3.101563,-1.171875 -1.125,-1.171875 -1.125,-3.21875 0,-2.039063 1.125,-3.203125 1.125,-1.171875 3.148438,-1.171875 2.070312,0 3.15625,1.132812 1.09375,1.125 1.09375,3.242188 z m -2.296875,0 q 0,-1.507813 -0.492188,-2.1875 -0.492187,-0.679688 -1.429687,-0.679688 -2,0 -2,2.867188 0,1.414062 0.484375,2.15625 0.492187,0.734375 1.414062,0.734375 2.023438,0 2.023438,-2.890625 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path848" />
<path
d="m 93.442963,82.609726 q 0,2.054687 -1.140625,3.226562 -1.140625,1.164063 -3.15625,1.164063 -1.976563,0 -3.101563,-1.171875 -1.125,-1.171875 -1.125,-3.21875 0,-2.039063 1.125,-3.203125 1.125,-1.171875 3.148438,-1.171875 2.070312,0 3.15625,1.132812 1.09375,1.125 1.09375,3.242188 z m -2.296875,0 q 0,-1.507813 -0.492188,-2.1875 -0.492187,-0.679688 -1.429687,-0.679688 -2,0 -2,2.867188 0,1.414062 0.484375,2.15625 0.492187,0.734375 1.414062,0.734375 2.023438,0 2.023438,-2.890625 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path850" />
<path
d="m 100.5914,86.844101 -2.257812,-3.828125 -0.945313,0.65625 v 3.171875 h -2.195312 v -11.59375 h 2.195312 v 6.640625 l 3.015625,-3.5 h 2.35938 l -2.968755,3.296875 3.195315,5.15625 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path852" />
<path
d="m 111.22421,84.375351 q 0,1.226562 -1.00781,1.929687 -1,0.695313 -2.77344,0.695313 -1.74218,0 -2.67187,-0.546875 -0.92188,-0.554688 -1.22656,-1.71875 l 1.92968,-0.289063 q 0.16407,0.601563 0.5625,0.851563 0.40625,0.25 1.40625,0.25 0.92188,0 1.34375,-0.234375 0.42188,-0.234375 0.42188,-0.734375 0,-0.40625 -0.34375,-0.640625 -0.33594,-0.242188 -1.14844,-0.40625 -1.85937,-0.367188 -2.50781,-0.679688 -0.64844,-0.320312 -0.99219,-0.820312 -0.33594,-0.507813 -0.33594,-1.242188 0,-1.210937 0.92969,-1.882812 0.9375,-0.679688 2.64844,-0.679688 1.50781,0 2.42187,0.585938 0.92188,0.585937 1.14844,1.695312 l -1.94531,0.203125 q -0.0937,-0.515625 -0.46094,-0.765625 -0.36719,-0.257812 -1.16406,-0.257812 -0.78125,0 -1.17188,0.203125 -0.39062,0.195312 -0.39062,0.664062 0,0.367188 0.29687,0.585938 0.30469,0.210937 1.01563,0.351562 0.99219,0.203125 1.75781,0.421875 0.77344,0.210938 1.23438,0.507813 0.46875,0.296875 0.74218,0.765625 0.28125,0.460937 0.28125,1.1875 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path854" />
<path
d="m 119.39609,87.000351 q -1.22656,0 -1.91406,-0.664063 -0.6875,-0.671875 -0.6875,-1.882812 0,-1.3125 0.85156,-2 0.85937,-0.6875 2.48437,-0.703125 l 1.82032,-0.03125 v -0.429688 q 0,-0.828125 -0.28907,-1.226562 -0.28906,-0.40625 -0.94531,-0.40625 -0.60937,0 -0.89844,0.28125 -0.28125,0.273437 -0.35156,0.914062 l -2.28906,-0.109375 q 0.21094,-1.234375 1.125,-1.867187 0.92187,-0.640625 2.50781,-0.640625 1.60156,0 2.46875,0.789062 0.86719,0.789063 0.86719,2.242188 v 3.078125 q 0,0.710937 0.15625,0.984375 0.16406,0.265625 0.53906,0.265625 0.25,0 0.48438,-0.04687 v 1.1875 q -0.19532,0.04687 -0.35157,0.08594 -0.15625,0.03906 -0.3125,0.0625 -0.15625,0.02344 -0.33593,0.03906 -0.17188,0.01563 -0.40625,0.01563 -0.82813,0 -1.22657,-0.40625 -0.39062,-0.40625 -0.46875,-1.195313 h -0.0469 q -0.92188,1.664063 -2.78125,1.664063 z m 2.55469,-4.070313 -1.125,0.01563 q -0.76563,0.03125 -1.08594,0.171875 -0.32031,0.132813 -0.49219,0.414063 -0.16406,0.28125 -0.16406,0.75 0,0.601562 0.27344,0.898437 0.28125,0.289063 0.74218,0.289063 0.51563,0 0.9375,-0.28125 0.42969,-0.28125 0.67188,-0.773438 0.24219,-0.5 0.24219,-1.054687 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path856" />
<path
d="m 133.47421,84.375351 q 0,1.226562 -1.00781,1.929687 -1,0.695313 -2.77344,0.695313 -1.74218,0 -2.67187,-0.546875 -0.92188,-0.554688 -1.22656,-1.71875 l 1.92968,-0.289063 q 0.16407,0.601563 0.5625,0.851563 0.40625,0.25 1.40625,0.25 0.92188,0 1.34375,-0.234375 0.42188,-0.234375 0.42188,-0.734375 0,-0.40625 -0.34375,-0.640625 -0.33594,-0.242188 -1.14844,-0.40625 -1.85937,-0.367188 -2.50781,-0.679688 -0.64844,-0.320312 -0.99219,-0.820312 -0.33594,-0.507813 -0.33594,-1.242188 0,-1.210937 0.92969,-1.882812 0.9375,-0.679688 2.64844,-0.679688 1.50781,0 2.42187,0.585938 0.92188,0.585937 1.14844,1.695312 l -1.94531,0.203125 q -0.0937,-0.515625 -0.46094,-0.765625 -0.36719,-0.257812 -1.16406,-0.257812 -0.78125,0 -1.17188,0.203125 -0.39062,0.195312 -0.39062,0.664062 0,0.367188 0.29687,0.585938 0.30469,0.210937 1.01563,0.351562 0.99219,0.203125 1.75781,0.421875 0.77344,0.210938 1.23438,0.507813 0.46875,0.296875 0.74218,0.765625 0.28125,0.460937 0.28125,1.1875 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path858" />
<path
d="m 141.64609,87.000351 q -1.22656,0 -1.91406,-0.664063 -0.6875,-0.671875 -0.6875,-1.882812 0,-1.3125 0.85156,-2 0.85937,-0.6875 2.48437,-0.703125 l 1.82032,-0.03125 v -0.429688 q 0,-0.828125 -0.28907,-1.226562 -0.28906,-0.40625 -0.94531,-0.40625 -0.60937,0 -0.89844,0.28125 -0.28125,0.273437 -0.35156,0.914062 l -2.28906,-0.109375 q 0.21094,-1.234375 1.125,-1.867187 0.92187,-0.640625 2.50781,-0.640625 1.60156,0 2.46875,0.789062 0.86719,0.789063 0.86719,2.242188 v 3.078125 q 0,0.710937 0.15625,0.984375 0.16406,0.265625 0.53906,0.265625 0.25,0 0.48438,-0.04687 v 1.1875 q -0.19532,0.04687 -0.35157,0.08594 -0.15625,0.03906 -0.3125,0.0625 -0.15625,0.02344 -0.33593,0.03906 -0.17188,0.01563 -0.40625,0.01563 -0.82813,0 -1.22657,-0.40625 -0.39062,-0.40625 -0.46875,-1.195313 h -0.0469 q -0.92188,1.664063 -2.78125,1.664063 z m 2.55469,-4.070313 -1.125,0.01563 q -0.76563,0.03125 -1.08594,0.171875 -0.32031,0.132813 -0.49219,0.414063 -0.16406,0.28125 -0.16406,0.75 0,0.601562 0.27344,0.898437 0.28125,0.289063 0.74218,0.289063 0.51563,0 0.9375,-0.28125 0.42969,-0.28125 0.67188,-0.773438 0.24219,-0.5 0.24219,-1.054687 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path860" />
<path
d="m 161.9664,83.672226 q 0,1.617187 -1.20312,2.476562 -1.19532,0.851563 -3.51563,0.851563 -2.11719,0 -3.32031,-0.75 -1.20313,-0.75 -1.54688,-2.273438 l 2.22657,-0.367187 q 0.22656,0.875 0.88281,1.273437 0.65625,0.390625 1.82031,0.390625 2.41406,0 2.41406,-1.46875 0,-0.46875 -0.28125,-0.773437 -0.27343,-0.304688 -0.78125,-0.507813 -0.5,-0.203125 -1.92968,-0.492187 -1.23438,-0.289063 -1.71875,-0.460938 -0.48438,-0.179687 -0.875,-0.414062 -0.39063,-0.242188 -0.66407,-0.578125 -0.27343,-0.335938 -0.42968,-0.789063 -0.14844,-0.453125 -0.14844,-1.039062 0,-1.492188 1.11719,-2.28125 1.125,-0.796875 3.26562,-0.796875 2.04688,0 3.07031,0.640625 1.03125,0.640625 1.32813,2.117187 l -2.23438,0.304688 q -0.17187,-0.710938 -0.70312,-1.070313 -0.52344,-0.359375 -1.50781,-0.359375 -2.09375,0 -2.09375,1.3125 0,0.429688 0.21875,0.703125 0.22656,0.273438 0.66406,0.46875 0.4375,0.1875 1.77344,0.476563 1.58593,0.335937 2.26562,0.625 0.6875,0.28125 1.08594,0.664062 0.39844,0.375 0.60937,0.90625 0.21094,0.523438 0.21094,1.210938 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path862" />
<path
d="m 167.18515,87.000351 q -1.90625,0 -2.92969,-1.125 -1.02343,-1.132813 -1.02343,-3.296875 0,-2.09375 1.03906,-3.21875 1.03906,-1.125 2.94531,-1.125 1.82031,0 2.78125,1.210937 0.96094,1.203125 0.96094,3.53125 v 0.0625 h -5.42188 q 0,1.234375 0.45313,1.867188 0.46094,0.625 1.30469,0.625 1.16406,0 1.46875,-1.007813 l 2.07031,0.179688 q -0.89844,2.296875 -3.64844,2.296875 z m 0,-7.382813 q -0.77344,0 -1.19531,0.539063 -0.41406,0.539062 -0.4375,1.507812 h 3.28125 q -0.0625,-1.023437 -0.49219,-1.53125 -0.42969,-0.515625 -1.15625,-0.515625 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path864" />
<path
d="m 172.63046,86.844101 v -6.46875 q 0,-0.695313 -0.0234,-1.15625 -0.0156,-0.46875 -0.0391,-0.828125 h 2.09375 q 0.0234,0.140625 0.0625,0.859375 0.0391,0.710937 0.0391,0.945312 h 0.0312 q 0.32031,-0.890625 0.57031,-1.25 0.25,-0.367187 0.59375,-0.539062 0.34375,-0.179688 0.85937,-0.179688 0.42188,0 0.67969,0.117188 v 1.835937 q -0.53125,-0.117187 -0.9375,-0.117187 -0.82031,0 -1.28125,0.664062 -0.45312,0.664063 -0.45312,1.96875 v 4.148438 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path866" />
<path
d="m 183.44296,86.844101 h -2.625 l -3.02343,-8.453125 h 2.32031 l 1.47656,4.726562 q 0.11719,0.390625 0.55469,1.953125 0.0781,-0.320312 0.32031,-1.125 0.24219,-0.804687 1.79688,-5.554687 h 2.29687 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path868" />
<path
d="m 187.75546,76.867538 v -1.617187 h 2.19532 v 1.617187 z m 0,9.976563 v -8.453125 h 2.19532 v 8.453125 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path870" />
<path
d="m 195.7164,87.000351 q -1.92187,0 -2.96875,-1.140625 -1.04687,-1.148438 -1.04687,-3.195313 0,-2.09375 1.05468,-3.257812 1.05469,-1.171875 2.99219,-1.171875 1.49219,0 2.46875,0.75 0.97656,0.75 1.22656,2.070312 l -2.21093,0.109375 q -0.0937,-0.648437 -0.46875,-1.03125 -0.375,-0.390625 -1.0625,-0.390625 -1.69532,0 -1.69532,2.835938 0,2.921875 1.72657,2.921875 0.625,0 1.04687,-0.390625 0.42188,-0.398438 0.52344,-1.179688 l 2.20312,0.101563 q -0.11718,0.867187 -0.625,1.546875 -0.5,0.679687 -1.32031,1.054687 -0.82031,0.367188 -1.84375,0.367188 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path872" />
<path
d="m 204.56015,87.000351 q -1.90625,0 -2.92969,-1.125 -1.02343,-1.132813 -1.02343,-3.296875 0,-2.09375 1.03906,-3.21875 1.03906,-1.125 2.94531,-1.125 1.82031,0 2.78125,1.210937 0.96094,1.203125 0.96094,3.53125 v 0.0625 h -5.42188 q 0,1.234375 0.45313,1.867188 0.46094,0.625 1.30469,0.625 1.16406,0 1.46875,-1.007813 l 2.07031,0.179688 q -0.89844,2.296875 -3.64844,2.296875 z m 0,-7.382813 q -0.77344,0 -1.19531,0.539063 -0.41406,0.539062 -0.4375,1.507812 h 3.28125 q -0.0625,-1.023437 -0.49219,-1.53125 -0.42969,-0.515625 -1.15625,-0.515625 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:16px;font-family:'Nimbus Sans';-inkscape-font-specification:'Nimbus Sans Bold'"
id="path874" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -8,8 +8,8 @@
<a href="https://github.com/tiangolo/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank">
<img src="https://github.com/tiangolo/fastapi/workflows/Test/badge.svg?event=push&branch=master" alt="Test">
</a>
<a href="https://codecov.io/gh/tiangolo/fastapi" target="_blank">
<img src="https://img.shields.io/codecov/c/github/tiangolo/fastapi?color=%2334D058" alt="Coverage">
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/tiangolo/fastapi" target="_blank">
<img src="https://coverage-badge.samuelcolvin.workers.dev/tiangolo/fastapi.svg" alt="Coverage">
</a>
<a href="https://pypi.org/project/fastapi" target="_blank">
<img src="https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package" alt="Package version">
@@ -424,7 +424,7 @@ For a more complete example including more features, see the <a href="https://fa
* **GraphQL** integration with <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> and other libraries.
* Many extra features (thanks to Starlette) as:
* **WebSockets**
* extremely easy tests based on `requests` and `pytest`
* extremely easy tests based on HTTPX and `pytest`
* **CORS**
* **Cookie Sessions**
* ...and more.
@@ -444,7 +444,7 @@ Used by Pydantic:
Used by Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.

View File

@@ -3,6 +3,215 @@
## Latest Changes
## 0.90.0
### Upgrades
* ⬆️ Bump Starlette from 0.22.0 to 0.23.0. Initial PR [#5739](https://github.com/tiangolo/fastapi/pull/5739) by [@Kludex](https://github.com/Kludex).
### Docs
* 📝 Add article "Tortoise ORM / FastAPI 整合快速筆記" to External Links. PR [#5496](https://github.com/tiangolo/fastapi/pull/5496) by [@Leon0824](https://github.com/Leon0824).
* 👥 Update FastAPI People. PR [#5954](https://github.com/tiangolo/fastapi/pull/5954) by [@github-actions[bot]](https://github.com/apps/github-actions).
* 📝 Micro-tweak help docs. PR [#5960](https://github.com/tiangolo/fastapi/pull/5960) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update new issue chooser to direct to GitHub Discussions. PR [#5948](https://github.com/tiangolo/fastapi/pull/5948) by [@tiangolo](https://github.com/tiangolo).
* 📝 Recommend GitHub Discussions for questions. PR [#5944](https://github.com/tiangolo/fastapi/pull/5944) by [@tiangolo](https://github.com/tiangolo).
### Translations
* 🌐 Add Russian translation for `docs/ru/docs/tutorial/body-fields.md`. PR [#5898](https://github.com/tiangolo/fastapi/pull/5898) by [@simatheone](https://github.com/simatheone).
* 🌐 Add Russian translation for `docs/ru/docs/help-fastapi.md`. PR [#5970](https://github.com/tiangolo/fastapi/pull/5970) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/static-files.md`. PR [#5858](https://github.com/tiangolo/fastapi/pull/5858) by [@batlopes](https://github.com/batlopes).
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/encoder.md`. PR [#5525](https://github.com/tiangolo/fastapi/pull/5525) by [@felipebpl](https://github.com/felipebpl).
* 🌐 Add Russian translation for `docs/ru/docs/contributing.md`. PR [#5870](https://github.com/tiangolo/fastapi/pull/5870) by [@Xewus](https://github.com/Xewus).
### Internal
* ⬆️ Upgrade Ubuntu version for docs workflow. PR [#5971](https://github.com/tiangolo/fastapi/pull/5971) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update sponsors badges. PR [#5943](https://github.com/tiangolo/fastapi/pull/5943) by [@tiangolo](https://github.com/tiangolo).
* ✨ Compute FastAPI Experts including GitHub Discussions. PR [#5941](https://github.com/tiangolo/fastapi/pull/5941) by [@tiangolo](https://github.com/tiangolo).
* ⬆️ Upgrade isort and update pre-commit. PR [#5940](https://github.com/tiangolo/fastapi/pull/5940) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Add template for questions in Discussions. PR [#5920](https://github.com/tiangolo/fastapi/pull/5920) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update Sponsor Budget Insight to Powens. PR [#5916](https://github.com/tiangolo/fastapi/pull/5916) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update GitHub Sponsors badge data. PR [#5915](https://github.com/tiangolo/fastapi/pull/5915) by [@tiangolo](https://github.com/tiangolo).
## 0.89.1
### Fixes
* 🐛 Ignore Response classes on return annotation. PR [#5855](https://github.com/tiangolo/fastapi/pull/5855) by [@Kludex](https://github.com/Kludex). See the new docs in the PR below.
### Docs
* 📝 Update docs and examples for Response Model with Return Type Annotations, and update runtime error. PR [#5873](https://github.com/tiangolo/fastapi/pull/5873) by [@tiangolo](https://github.com/tiangolo). New docs at [Response Model - Return Type: Other Return Type Annotations](https://fastapi.tiangolo.com/tutorial/response-model/#other-return-type-annotations).
* 📝 Add External Link: FastAPI lambda container: serverless simplified. PR [#5784](https://github.com/tiangolo/fastapi/pull/5784) by [@rafrasenberg](https://github.com/rafrasenberg).
### Translations
* 🌐 Add Turkish translation for `docs/tr/docs/tutorial/first_steps.md`. PR [#5691](https://github.com/tiangolo/fastapi/pull/5691) by [@Kadermiyanyedi](https://github.com/Kadermiyanyedi).
## 0.89.0
### Features
* ✨ Add support for function return type annotations to declare the `response_model`. Initial PR [#1436](https://github.com/tiangolo/fastapi/pull/1436) by [@uriyyo](https://github.com/uriyyo).
Now you can declare the return type / `response_model` in the function return type annotation:
```python
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
@app.get("/items/")
async def read_items() -> list[Item]:
return [
Item(name="Portal Gun", price=42.0),
Item(name="Plumbus", price=32.0),
]
```
FastAPI will use the return type annotation to perform:
* Data validation
* Automatic documentation
* It could power automatic client generators
* **Data filtering**
Before this version it was only supported via the `response_model` parameter.
Read more about it in the new docs: [Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/).
### Docs
* 📝 Add External Link: Authorization on FastAPI with Casbin. PR [#5712](https://github.com/tiangolo/fastapi/pull/5712) by [@Xhy-5000](https://github.com/Xhy-5000).
* ✏ Fix typo in `docs/en/docs/async.md`. PR [#5785](https://github.com/tiangolo/fastapi/pull/5785) by [@Kingdageek](https://github.com/Kingdageek).
* ✏ Fix typo in `docs/en/docs/deployment/concepts.md`. PR [#5824](https://github.com/tiangolo/fastapi/pull/5824) by [@kelbyfaessler](https://github.com/kelbyfaessler).
### Translations
* 🌐 Add Russian translation for `docs/ru/docs/fastapi-people.md`. PR [#5577](https://github.com/tiangolo/fastapi/pull/5577) by [@Xewus](https://github.com/Xewus).
* 🌐 Fix typo in Chinese translation for `docs/zh/docs/benchmarks.md`. PR [#4269](https://github.com/tiangolo/fastapi/pull/4269) by [@15027668g](https://github.com/15027668g).
* 🌐 Add Korean translation for `docs/tutorial/cors.md`. PR [#3764](https://github.com/tiangolo/fastapi/pull/3764) by [@NinaHwang](https://github.com/NinaHwang).
### Internal
* ⬆ Update coverage[toml] requirement from <7.0,>=6.5.0 to >=6.5.0,<8.0. PR [#5801](https://github.com/tiangolo/fastapi/pull/5801) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Update uvicorn[standard] requirement from <0.19.0,>=0.12.0 to >=0.12.0,<0.21.0 for development. PR [#5795](https://github.com/tiangolo/fastapi/pull/5795) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump dawidd6/action-download-artifact from 2.24.2 to 2.24.3. PR [#5842](https://github.com/tiangolo/fastapi/pull/5842) by [@dependabot[bot]](https://github.com/apps/dependabot).
* 👥 Update FastAPI People. PR [#5825](https://github.com/tiangolo/fastapi/pull/5825) by [@github-actions[bot]](https://github.com/apps/github-actions).
* ⬆ Bump types-ujson from 5.5.0 to 5.6.0.0. PR [#5735](https://github.com/tiangolo/fastapi/pull/5735) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump pypa/gh-action-pypi-publish from 1.5.2 to 1.6.4. PR [#5750](https://github.com/tiangolo/fastapi/pull/5750) by [@dependabot[bot]](https://github.com/apps/dependabot).
* 👷 Add GitHub Action gate/check. PR [#5492](https://github.com/tiangolo/fastapi/pull/5492) by [@webknjaz](https://github.com/webknjaz).
* 🔧 Update sponsors, add Svix. PR [#5848](https://github.com/tiangolo/fastapi/pull/5848) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Remove Doist sponsor. PR [#5847](https://github.com/tiangolo/fastapi/pull/5847) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Update sqlalchemy requirement from <=1.4.41,>=1.3.18 to >=1.3.18,<1.4.43. PR [#5540](https://github.com/tiangolo/fastapi/pull/5540) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump nwtgck/actions-netlify from 1.2.4 to 2.0.0. PR [#5757](https://github.com/tiangolo/fastapi/pull/5757) by [@dependabot[bot]](https://github.com/apps/dependabot).
* 👷 Refactor CI artifact upload/download for docs previews. PR [#5793](https://github.com/tiangolo/fastapi/pull/5793) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Bump pypa/gh-action-pypi-publish from 1.5.1 to 1.5.2. PR [#5714](https://github.com/tiangolo/fastapi/pull/5714) by [@dependabot[bot]](https://github.com/apps/dependabot).
* 👥 Update FastAPI People. PR [#5722](https://github.com/tiangolo/fastapi/pull/5722) by [@github-actions[bot]](https://github.com/apps/github-actions).
* 🔧 Update sponsors, disable course bundle. PR [#5713](https://github.com/tiangolo/fastapi/pull/5713) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Update typer[all] requirement from <0.7.0,>=0.6.1 to >=0.6.1,<0.8.0. PR [#5639](https://github.com/tiangolo/fastapi/pull/5639) by [@dependabot[bot]](https://github.com/apps/dependabot).
## 0.88.0
### Upgrades
* ⬆ Bump Starlette to version `0.22.0` to fix bad encoding for query parameters in new `TestClient`. PR [#5659](https://github.com/tiangolo/fastapi/pull/5659) by [@azogue](https://github.com/azogue).
### Docs
* ✏️ Fix typo in docs for `docs/en/docs/advanced/middleware.md`. PR [#5376](https://github.com/tiangolo/fastapi/pull/5376) by [@rifatrakib](https://github.com/rifatrakib).
### Translations
* 🌐 Add Portuguese translation for `docs/pt/docs/deployment/docker.md`. PR [#5663](https://github.com/tiangolo/fastapi/pull/5663) by [@ayr-ton](https://github.com/ayr-ton).
### Internal
* 👷 Tweak build-docs to improve CI performance. PR [#5699](https://github.com/tiangolo/fastapi/pull/5699) by [@tiangolo](https://github.com/tiangolo).
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5566](https://github.com/tiangolo/fastapi/pull/5566) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
* ⬆️ Upgrade Ruff. PR [#5698](https://github.com/tiangolo/fastapi/pull/5698) by [@tiangolo](https://github.com/tiangolo).
* 👷 Remove pip cache for Smokeshow as it depends on a requirements.txt. PR [#5700](https://github.com/tiangolo/fastapi/pull/5700) by [@tiangolo](https://github.com/tiangolo).
* 💚 Fix pip cache for Smokeshow. PR [#5697](https://github.com/tiangolo/fastapi/pull/5697) by [@tiangolo](https://github.com/tiangolo).
* 👷 Fix and tweak CI cache handling. PR [#5696](https://github.com/tiangolo/fastapi/pull/5696) by [@tiangolo](https://github.com/tiangolo).
* 👷 Update `setup-python` action in tests to use new caching feature. PR [#5680](https://github.com/tiangolo/fastapi/pull/5680) by [@madkinsz](https://github.com/madkinsz).
* ⬆ Bump black from 22.8.0 to 22.10.0. PR [#5569](https://github.com/tiangolo/fastapi/pull/5569) by [@dependabot[bot]](https://github.com/apps/dependabot).
## 0.87.0
Highlights of this release:
* [Upgraded Starlette](https://github.com/encode/starlette/releases/tag/0.21.0)
* Now the `TestClient` is based on HTTPX instead of Requests. 🚀
* There are some possible **breaking changes** in the `TestClient` usage, but [@Kludex](https://github.com/Kludex) built [bump-testclient](https://github.com/Kludex/bump-testclient) to help you automatize migrating your tests. Make sure you are using Git and that you can undo any unnecessary changes (false positive changes, etc) before using `bump-testclient`.
* New [WebSocketException (and docs)](https://fastapi.tiangolo.com/advanced/websockets/#using-depends-and-others), re-exported from Starlette.
* Upgraded and relaxed dependencies for package extras `all` (including new Uvicorn version), when you install `"fastapi[all]"`.
* New docs about how to [**Help Maintain FastAPI**](https://fastapi.tiangolo.com/help-fastapi/#help-maintain-fastapi).
### Features
* ⬆️ Upgrade and relax dependencies for extras "all". PR [#5634](https://github.com/tiangolo/fastapi/pull/5634) by [@tiangolo](https://github.com/tiangolo).
* ✨ Re-export Starlette's `WebSocketException` and add it to docs. PR [#5629](https://github.com/tiangolo/fastapi/pull/5629) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update references to Requests for tests to HTTPX, and add HTTPX to extras. PR [#5628](https://github.com/tiangolo/fastapi/pull/5628) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Upgrade Starlette to `0.21.0`, including the new [`TestClient` based on HTTPX](https://github.com/encode/starlette/releases/tag/0.21.0). PR [#5471](https://github.com/tiangolo/fastapi/pull/5471) by [@pawelrubin](https://github.com/pawelrubin).
### Docs
* ✏️ Tweak Help FastAPI from PR review after merging. PR [#5633](https://github.com/tiangolo/fastapi/pull/5633) by [@tiangolo](https://github.com/tiangolo).
* ✏️ Clarify docs on CORS. PR [#5627](https://github.com/tiangolo/fastapi/pull/5627) by [@paxcodes](https://github.com/paxcodes).
* 📝 Update Help FastAPI: Help Maintain FastAPI. PR [#5632](https://github.com/tiangolo/fastapi/pull/5632) by [@tiangolo](https://github.com/tiangolo).
### Translations
* 🌐 Fix highlight lines for Japanese translation for `docs/tutorial/query-params.md`. PR [#2969](https://github.com/tiangolo/fastapi/pull/2969) by [@ftnext](https://github.com/ftnext).
* 🌐 Add French translation for `docs/fr/docs/advanced/additional-status-code.md`. PR [#5477](https://github.com/tiangolo/fastapi/pull/5477) by [@axel584](https://github.com/axel584).
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/request-forms-and-files.md`. PR [#5579](https://github.com/tiangolo/fastapi/pull/5579) by [@batlopes](https://github.com/batlopes).
* 🌐 Add Japanese translation for `docs/ja/docs/advanced/websockets.md`. PR [#4983](https://github.com/tiangolo/fastapi/pull/4983) by [@xryuseix](https://github.com/xryuseix).
### Internal
* ✨ Use Ruff for linting. PR [#5630](https://github.com/tiangolo/fastapi/pull/5630) by [@tiangolo](https://github.com/tiangolo).
* 🛠 Add Arabic issue number to Notify Translations GitHub Action. PR [#5610](https://github.com/tiangolo/fastapi/pull/5610) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Bump dawidd6/action-download-artifact from 2.24.1 to 2.24.2. PR [#5609](https://github.com/tiangolo/fastapi/pull/5609) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump dawidd6/action-download-artifact from 2.24.0 to 2.24.1. PR [#5603](https://github.com/tiangolo/fastapi/pull/5603) by [@dependabot[bot]](https://github.com/apps/dependabot).
* 📝 Update coverage badge to use Samuel Colvin's Smokeshow. PR [#5585](https://github.com/tiangolo/fastapi/pull/5585) by [@tiangolo](https://github.com/tiangolo).
## 0.86.0
### Features
* ⬆ Add Python 3.11 to the officially supported versions. PR [#5587](https://github.com/tiangolo/fastapi/pull/5587) by [@tiangolo](https://github.com/tiangolo).
* ✅ Enable tests for Python 3.11. PR [#4881](https://github.com/tiangolo/fastapi/pull/4881) by [@tiangolo](https://github.com/tiangolo).
### Fixes
* 🐛 Close FormData (uploaded files) after the request is done. PR [#5465](https://github.com/tiangolo/fastapi/pull/5465) by [@adriangb](https://github.com/adriangb).
### Docs
* ✏ Fix typo in `docs/en/docs/tutorial/security/oauth2-jwt.md`. PR [#5584](https://github.com/tiangolo/fastapi/pull/5584) by [@vivekashok1221](https://github.com/vivekashok1221).
### Translations
* 🌐 Update wording in Chinese translation for `docs/zh/docs/python-types.md`. PR [#5416](https://github.com/tiangolo/fastapi/pull/5416) by [@supercaizehua](https://github.com/supercaizehua).
* 🌐 Add Russian translation for `docs/ru/docs/deployment/index.md`. PR [#5336](https://github.com/tiangolo/fastapi/pull/5336) by [@Xewus](https://github.com/Xewus).
* 🌐 Update Chinese translation for `docs/tutorial/security/oauth2-jwt.md`. PR [#3846](https://github.com/tiangolo/fastapi/pull/3846) by [@jaystone776](https://github.com/jaystone776).
### Internal
* 👷 Update FastAPI People to exclude bots: pre-commit-ci, dependabot. PR [#5586](https://github.com/tiangolo/fastapi/pull/5586) by [@tiangolo](https://github.com/tiangolo).
* 🎨 Format OpenAPI JSON in `test_starlette_exception.py`. PR [#5379](https://github.com/tiangolo/fastapi/pull/5379) by [@iudeen](https://github.com/iudeen).
* 👷 Switch from Codecov to Smokeshow plus pytest-cov to pure coverage for internal tests. PR [#5583](https://github.com/tiangolo/fastapi/pull/5583) by [@tiangolo](https://github.com/tiangolo).
* 👥 Update FastAPI People. PR [#5571](https://github.com/tiangolo/fastapi/pull/5571) by [@github-actions[bot]](https://github.com/apps/github-actions).
## 0.85.2
### Docs

View File

@@ -57,7 +57,7 @@ The following arguments are supported:
* `allow_origins` - A list of origins that should be permitted to make cross-origin requests. E.g. `['https://example.org', 'https://www.example.org']`. You can use `['*']` to allow any origin.
* `allow_origin_regex` - A regex string to match against origins that should be permitted to make cross-origin requests. e.g. `'https://.*\.example\.org'`.
* `allow_methods` - A list of HTTP methods that should be allowed for cross-origin requests. Defaults to `['GET']`. You can use `['*']` to allow all standard methods.
* `allow_headers` - A list of HTTP request headers that should be supported for cross-origin requests. Defaults to `[]`. You can use `['*']` to allow all headers. The `Accept`, `Accept-Language`, `Content-Language` and `Content-Type` headers are always allowed for CORS requests.
* `allow_headers` - A list of HTTP request headers that should be supported for cross-origin requests. Defaults to `[]`. You can use `['*']` to allow all headers. The `Accept`, `Accept-Language`, `Content-Language` and `Content-Type` headers are always allowed for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests" class="external-link" rel="noopener" target="_blank">simple CORS requests</a>.
* `allow_credentials` - Indicate that cookies should be supported for cross-origin requests. Defaults to `False`. Also, `allow_origins` cannot be set to `['*']` for credentials to be allowed, origins must be specified.
* `expose_headers` - Indicate any response headers that should be made accessible to the browser. Defaults to `[]`.
* `max_age` - Sets a maximum time in seconds for browsers to cache CORS responses. Defaults to `600`.

View File

@@ -1,6 +1,51 @@
# Response Model
# Response Model - Return Type
You can declare the model used for the response with the parameter `response_model` in any of the *path operations*:
You can declare the type used for the response by annotating the *path operation function* **return type**.
You can use **type annotations** the same way you would for input data in function **parameters**, you can use Pydantic models, lists, dictionaries, scalar values like integers, booleans, etc.
=== "Python 3.6 and above"
```Python hl_lines="18 23"
{!> ../../../docs_src/response_model/tutorial001_01.py!}
```
=== "Python 3.9 and above"
```Python hl_lines="18 23"
{!> ../../../docs_src/response_model/tutorial001_01_py39.py!}
```
=== "Python 3.10 and above"
```Python hl_lines="16 21"
{!> ../../../docs_src/response_model/tutorial001_01_py310.py!}
```
FastAPI will use this return type to:
* **Validate** the returned data.
* If the data is invalid (e.g. you are missing a field), it means that *your* app code is broken, not returning what it should, and it will return a server error instead of returning incorrect data. This way you and your clients can be certain that they will receive the data and the data shape expected.
* Add a **JSON Schema** for the response, in the OpenAPI *path operation*.
* This will be used by the **automatic docs**.
* It will also be used by automatic client code generation tools.
But most importantly:
* It will **limit and filter** the output data to what is defined in the return type.
* This is particularly important for **security**, we'll see more of that below.
## `response_model` Parameter
There are some cases where you need or want to return some data that is not exactly what the type declares.
For example, you could want to **return a dictionary** or a database object, but **declare it as a Pydantic model**. This way the Pydantic model would do all the data documentation, validation, etc. for the object that you returned (e.g. a dictionary or database object).
If you added the return type annotation, tools and editors would complain with a (correct) error telling you that your function is returning a type (e.g. a dict) that is different from what you declared (e.g. a Pydantic model).
In those cases, you can use the *path operation decorator* parameter `response_model` instead of the return type.
You can use the `response_model` parameter in any of the *path operations*:
* `@app.get()`
* `@app.post()`
@@ -10,40 +55,41 @@ You can declare the model used for the response with the parameter `response_mod
=== "Python 3.6 and above"
```Python hl_lines="17"
```Python hl_lines="17 22 24-27"
{!> ../../../docs_src/response_model/tutorial001.py!}
```
=== "Python 3.9 and above"
```Python hl_lines="17"
```Python hl_lines="17 22 24-27"
{!> ../../../docs_src/response_model/tutorial001_py39.py!}
```
=== "Python 3.10 and above"
```Python hl_lines="15"
```Python hl_lines="17 22 24-27"
{!> ../../../docs_src/response_model/tutorial001_py310.py!}
```
!!! note
Notice that `response_model` is a parameter of the "decorator" method (`get`, `post`, etc). Not of your *path operation function*, like all the parameters and body.
It receives the same type you would declare for a Pydantic model attribute, so, it can be a Pydantic model, but it can also be, e.g. a `list` of Pydantic models, like `List[Item]`.
`response_model` receives the same type you would declare for a Pydantic model field, so, it can be a Pydantic model, but it can also be, e.g. a `list` of Pydantic models, like `List[Item]`.
FastAPI will use this `response_model` to:
FastAPI will use this `response_model` to do all the data documentation, validation, etc. and also to **convert and filter the output data** to its type declaration.
* Convert the output data to its type declaration.
* Validate the data.
* Add a JSON Schema for the response, in the OpenAPI *path operation*.
* Will be used by the automatic documentation systems.
!!! tip
If you have strict type checks in your editor, mypy, etc, you can declare the function return type as `Any`.
But most importantly:
That way you tell the editor that you are intentionally returning anything. But FastAPI will still do the data documentation, validation, filtering, etc. with the `response_model`.
* Will limit the output data to that of the model. We'll see how that's important below.
### `response_model` Priority
!!! note "Technical Details"
The response model is declared in this parameter instead of as a function return type annotation, because the path function may not actually return that response model but rather return a `dict`, database object or some other model, and then use the `response_model` to perform the field limiting and serialization.
If you declare both a return type and a `response_model`, the `response_model` will take priority and be used by FastAPI.
This way you can add correct type annotations to your functions even when you are returning a type different than the response model, to be used by the editor and tools like mypy. And still you can have FastAPI do the data validation, documentation, etc. using the `response_model`.
You can also use `response_model=None` to disable creating a response model for that *path operation*, you might need to do it if you are adding type annotations for things that are not valid Pydantic fields, you will see an example of that in one of the sections below.
## Return the same input data
@@ -71,24 +117,24 @@ And we are using this model to declare our input and the same model to declare o
=== "Python 3.6 and above"
```Python hl_lines="17-18"
```Python hl_lines="18"
{!> ../../../docs_src/response_model/tutorial002.py!}
```
=== "Python 3.10 and above"
```Python hl_lines="15-16"
```Python hl_lines="16"
{!> ../../../docs_src/response_model/tutorial002_py310.py!}
```
Now, whenever a browser is creating a user with a password, the API will return the same password in the response.
In this case, it might not be a problem, because the user themself is sending the password.
In this case, it might not be a problem, because it's the same user sending the password.
But if we use the same model for another *path operation*, we could be sending our user's passwords to every client.
!!! danger
Never store the plain password of a user or send it in a response.
Never store the plain password of a user or send it in a response like this, unless you know all the caveats and you know what you are doing.
## Add an output model
@@ -102,7 +148,7 @@ We can instead create an input model with the plaintext password and an output m
=== "Python 3.10 and above"
```Python hl_lines="7 9 14"
```Python hl_lines="9 11 16"
{!> ../../../docs_src/response_model/tutorial003_py310.py!}
```
@@ -116,7 +162,7 @@ Here, even though our *path operation function* is returning the same input user
=== "Python 3.10 and above"
```Python hl_lines="22"
```Python hl_lines="24"
{!> ../../../docs_src/response_model/tutorial003_py310.py!}
```
@@ -130,12 +176,66 @@ Here, even though our *path operation function* is returning the same input user
=== "Python 3.10 and above"
```Python hl_lines="20"
```Python hl_lines="22"
{!> ../../../docs_src/response_model/tutorial003_py310.py!}
```
So, **FastAPI** will take care of filtering out all the data that is not declared in the output model (using Pydantic).
### `response_model` or Return Type
In this case, because the two models are different, if we annotated the function return type as `UserOut`, the editor and tools would complain that we are returning an invalid type, as those are different classes.
That's why in this example we have to declare it in the `response_model` parameter.
...but continue reading below to see how to overcome that.
## Return Type and Data Filtering
Let's continue from the previous example. We wanted to **annotate the function with one type** but return something that includes **more data**.
We want FastAPI to keep **filtering** the data using the response model.
In the previous example, because the classes were different, we had to use the `response_model` parameter. But that also means that we don't get the support from the editor and tools checking the function return type.
But in most of the cases where we need to do something like this, we want the model just to **filter/remove** some of the data as in this example.
And in those cases, we can use classes and inheritance to take advantage of function **type annotations** to get better support in the editor and tools, and still get the FastAPI **data filtering**.
=== "Python 3.6 and above"
```Python hl_lines="9-13 15-16 20"
{!> ../../../docs_src/response_model/tutorial003_01.py!}
```
=== "Python 3.10 and above"
```Python hl_lines="7-10 13-14 18"
{!> ../../../docs_src/response_model/tutorial003_01_py310.py!}
```
With this, we get tooling support, from editors and mypy as this code is correct in terms of types, but we also get the data filtering from FastAPI.
How does this work? Let's check that out. 🤓
### Type Annotations and Tooling
First let's see how editors, mypy and other tools would see this.
`BaseUser` has the base fields. Then `UserIn` inherits from `BaseUser` and adds the `password` field, so, it will include all the fields from both models.
We annotate the function return type as `BaseUser`, but we are actually returning a `UserIn` instance.
The editor, mypy, and other tools won't complain about this because, in typing terms, `UserIn` is a subclass of `BaseUser`, which means it's a *valid* type when what is expected is anything that is a `BaseUser`.
### FastAPI Data Filtering
Now, for FastAPI, it will see the return type and make sure that what you return includes **only** the fields that are declared in the type.
FastAPI does several things internally with Pydantic to make sure that those same rules of class inheritance are not used for the returned data filtering, otherwise you could end up returning much more data than what you expected.
This way, you can get the best of both worlds: type annotations with **tooling support** and **data filtering**.
## See it in the docs
When you see the automatic docs, you can check that the input model and output model will both have their own JSON Schema:
@@ -146,6 +246,74 @@ And both models will be used for the interactive API documentation:
<img src="/img/tutorial/response-model/image02.png">
## Other Return Type Annotations
There might be cases where you return something that is not a valid Pydantic field and you annotate it in the function, only to get the support provided by tooling (the editor, mypy, etc).
### Return a Response Directly
The most common case would be [returning a Response directly as explained later in the advanced docs](../advanced/response-directly.md){.internal-link target=_blank}.
```Python hl_lines="8 10-11"
{!> ../../../docs_src/response_model/tutorial003_02.py!}
```
This simple case is handled automatically by FastAPI because the return type annotation is the class (or a subclass) of `Response`.
And tools will also be happy because both `RedirectResponse` and `JSONResponse` are subclasses of `Response`, so the type annotation is correct.
### Annotate a Response Subclass
You can also use a subclass of `Response` in the type annotation:
```Python hl_lines="8-9"
{!> ../../../docs_src/response_model/tutorial003_03.py!}
```
This will also work because `RedirectResponse` is a subclass of `Response`, and FastAPI will automatically handle this simple case.
### Invalid Return Type Annotations
But when you return some other arbitrary object that is not a valid Pydantic type (e.g. a database object) and you annotate it like that in the function, FastAPI will try to create a Pydantic response model from that type annotation, and will fail.
The same would happen if you had something like a <abbr title='A union between multiple types means "any of these types".'>union</abbr> between different types where one or more of them are not valid Pydantic types, for example this would fail 💥:
=== "Python 3.6 and above"
```Python hl_lines="10"
{!> ../../../docs_src/response_model/tutorial003_04.py!}
```
=== "Python 3.10 and above"
```Python hl_lines="8"
{!> ../../../docs_src/response_model/tutorial003_04_py310.py!}
```
...this fails because the type annotation is not a Pydantic type and is not just a single `Response` class or subclass, it's a union (any of the two) between a `Response` and a `dict`.
### Disable Response Model
Continuing from the example above, you might not want to have the default data validation, documentation, filtering, etc. that is performed by FastAPI.
But you might want to still keep the return type annotation in the function to get the support from tools like editors and type checkers (e.g. mypy).
In this case, you can disable the response model generation by setting `response_model=None`:
=== "Python 3.6 and above"
```Python hl_lines="9"
{!> ../../../docs_src/response_model/tutorial003_05.py!}
```
=== "Python 3.10 and above"
```Python hl_lines="7"
{!> ../../../docs_src/response_model/tutorial003_05_py310.py!}
```
This will make FastAPI skip the response model generation and that way you can have any return type annotations you need without it affecting your FastAPI application. 🤓
## Response Model encoding parameters
Your response model could have default values, like:

View File

@@ -257,7 +257,7 @@ Call the endpoint `/users/me/`, you will get the response as:
<img src="/img/tutorial/security/image09.png">
If you open the developer tools, you could see how the data sent and only includes the token, the password is only sent in the first request to authenticate the user and get that access token, but not afterwards:
If you open the developer tools, you could see how the data sent only includes the token, the password is only sent in the first request to authenticate the user and get that access token, but not afterwards:
<img src="/img/tutorial/security/image10.png">

View File

@@ -2,16 +2,16 @@
Thanks to <a href="https://www.starlette.io/testclient/" class="external-link" target="_blank">Starlette</a>, testing **FastAPI** applications is easy and enjoyable.
It is based on <a href="https://requests.readthedocs.io" class="external-link" target="_blank">Requests</a>, so it's very familiar and intuitive.
It is based on <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>, which in turn is designed based on Requests, so it's very familiar and intuitive.
With it, you can use <a href="https://docs.pytest.org/" class="external-link" target="_blank">pytest</a> directly with **FastAPI**.
## Using `TestClient`
!!! info
To use `TestClient`, first install <a href="https://github.com/psf/requests" class="external-link" target="_blank">`requests`</a>.
To use `TestClient`, first install <a href="https://www.python-httpx.org" class="external-link" target="_blank">`httpx`</a>.
E.g. `pip install requests`.
E.g. `pip install httpx`.
Import `TestClient`.
@@ -19,7 +19,7 @@ Create a `TestClient` by passing your **FastAPI** application to it.
Create functions with a name that starts with `test_` (this is standard `pytest` conventions).
Use the `TestClient` object the same way as you do with `requests`.
Use the `TestClient` object the same way as you do with `httpx`.
Write simple `assert` statements with the standard Python expressions that you need to check (again, standard `pytest`).
@@ -130,7 +130,7 @@ You could then update `test_main.py` with the extended tests:
{!> ../../../docs_src/app_testing/app_b/test_main.py!}
```
Whenever you need the client to pass information in the request and you don't know how to, you can search (Google) how to do it in `requests`.
Whenever you need the client to pass information in the request and you don't know how to, you can search (Google) how to do it in `httpx`, or even how to do it with `requests`, as HTTPX's design is based on Requests' design.
Then you just do the same in your tests.
@@ -142,7 +142,7 @@ E.g.:
* To pass *headers*, use a `dict` in the `headers` parameter.
* For *cookies*, a `dict` in the `cookies` parameter.
For more information about how to pass data to the backend (using `requests` or the `TestClient`) check the <a href="https://requests.readthedocs.io" class="external-link" target="_blank">Requests documentation</a>.
For more information about how to pass data to the backend (using `httpx` or the `TestClient`) check the <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX documentation</a>.
!!! info
Note that the `TestClient` receives data that can be converted to JSON, not Pydantic models.

View File

@@ -22,12 +22,6 @@
</div>
</div>
<div id="announce-right" style="position: relative;">
<div class="item">
<a title="Get three courses at 10% off their current prices! Plus, we'll be donating 10% of all profits from sales of this bundle to the FastAPI team." style="display: block; position: relative;" href="https://testdriven.io/talkpython/" target="_blank">
<span class="sponsor-badge">sponsor</span>
<img class="sponsor-image" src="/img/sponsors/fastapi-course-bundle-banner.png" />
</a>
</div>
<div class="item">
<a title="The data structure for unstructured multimodal data" style="display: block; position: relative;" href="https://bit.ly/3AcNTYL" target="_blank">
<span class="sponsor-badge">sponsor</span>
@@ -40,18 +34,6 @@
<img class="sponsor-image" src="/img/sponsors/cryptapi-banner.svg" />
</a>
</div>
<!-- <div class="item">
<a title="The ultimate solution to unlimited and forever cloud storage." style="display: block; position: relative;" href="https://app.imgwhale.xyz/" target="_blank">
<span class="sponsor-badge">sponsor</span>
<img class="sponsor-image" src="/img/sponsors/imgwhale-banner.svg" />
</a>
</div> -->
<div class="item">
<a title="Help us migrate doist to FastAPI" style="display: block; position: relative;" href="https://doist.com/careers/9B437B1615-wa-senior-backend-engineer-python" target="_blank">
<span class="sponsor-badge">sponsor</span>
<img class="sponsor-image" src="/img/sponsors/doist-banner.svg" />
</a>
</div>
<div class="item">
<a title="Build cross-modal and multimodal applications on the cloud" style="display: block; position: relative;" href="https://bit.ly/3dphxRq" target="_blank">
<span class="sponsor-badge">sponsor</span>

View File

@@ -167,7 +167,7 @@ Con **FastAPI** obtienes todas las características de **Starlette** (porque Fas
* Soporte para **GraphQL**.
* <abbr title="En español: tareas que se ejecutan en el fondo, sin frenar requests, en el mismo proceso. En ingles: In-process background tasks">Tareas en background</abbr>.
* Eventos de startup y shutdown.
* Cliente de pruebas construido con `requests`.
* Cliente de pruebas construido con HTTPX.
* **CORS**, GZip, Static Files, Streaming responses.
* Soporte para **Session and Cookie**.
* Cobertura de pruebas al 100%.

View File

@@ -418,7 +418,7 @@ Para un ejemplo más completo que incluye más características ve el <a href="h
* Muchas características extra (gracias a Starlette) como:
* **WebSockets**
* **GraphQL**
* pruebas extremadamente fáciles con `requests` y `pytest`
* pruebas extremadamente fáciles con HTTPX y `pytest`
* **CORS**
* **Cookie Sessions**
* ...y mucho más.
@@ -438,7 +438,7 @@ Usadas por Pydantic:
Usados por Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Requerido si quieres usar el `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Requerido si quieres usar el `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Requerido si quieres usar la configuración por defecto de templates.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Requerido si quieres dar soporte a <abbr title="convertir el string que viene de un HTTP request a datos de Python">"parsing"</abbr> de formularios, con `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Requerido para dar soporte a `SessionMiddleware`.

View File

@@ -421,7 +421,7 @@ item: Item
* قابلیت‌های اضافی دیگر (بر اساس Starlette) شامل:
* **<abbr title="WebSocket">وب‌سوکت</abbr>**
* **GraphQL**
* تست‌های خودکار آسان مبتنی بر `requests` و `pytest`
* تست‌های خودکار آسان مبتنی بر HTTPX و `pytest`
* **CORS**
* **Cookie Sessions**
* و موارد بیشمار دیگر.
@@ -441,7 +441,7 @@ item: Item
استفاده شده توسط Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - در صورتی که می‌خواهید از `TestClient` استفاده کنید.
* <a href="https://www.python-httpx.org" target="_blank"><code>HTTPX</code></a> - در صورتی که می‌خواهید از `TestClient` استفاده کنید.
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - در صورتی که می‌خواهید از `FileResponse` و `StaticFiles` استفاده کنید.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - در صورتی که بخواهید از پیکربندی پیش‌فرض برای قالب‌ها استفاده کنید.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - در صورتی که بخواهید با استفاده از `request.form()` از قابلیت <abbr title="تبدیل رشته متنی موجود در درخواست HTTP به انواع داده پایتون">"تجزیه (parse)"</abbr> فرم استفاده کنید.

View File

@@ -0,0 +1,240 @@
# Réponses supplémentaires dans OpenAPI
!!! Attention
Ceci concerne un sujet plutôt avancé.
Si vous débutez avec **FastAPI**, vous n'en aurez peut-être pas besoin.
Vous pouvez déclarer des réponses supplémentaires, avec des codes HTTP, des types de médias, des descriptions, etc.
Ces réponses supplémentaires seront incluses dans le schéma OpenAPI, elles apparaîtront donc également dans la documentation de l'API.
Mais pour ces réponses supplémentaires, vous devez vous assurer de renvoyer directement une `Response` comme `JSONResponse`, avec votre code HTTP et votre contenu.
## Réponse supplémentaire avec `model`
Vous pouvez ajouter à votre décorateur de *paramètre de chemin* un paramètre `responses`.
Il prend comme valeur un `dict` dont les clés sont des codes HTTP pour chaque réponse, comme `200`, et la valeur de ces clés sont d'autres `dict` avec des informations pour chacun d'eux.
Chacun de ces `dict` de réponse peut avoir une clé `model`, contenant un modèle Pydantic, tout comme `response_model`.
**FastAPI** prendra ce modèle, générera son schéma JSON et l'inclura au bon endroit dans OpenAPI.
Par exemple, pour déclarer une autre réponse avec un code HTTP `404` et un modèle Pydantic `Message`, vous pouvez écrire :
```Python hl_lines="18 22"
{!../../../docs_src/additional_responses/tutorial001.py!}
```
!!! Remarque
Gardez à l'esprit que vous devez renvoyer directement `JSONResponse`.
!!! Info
La clé `model` ne fait pas partie d'OpenAPI.
**FastAPI** prendra le modèle Pydantic à partir de là, générera le `JSON Schema` et le placera au bon endroit.
Le bon endroit est :
* Dans la clé `content`, qui a pour valeur un autre objet JSON (`dict`) qui contient :
* Une clé avec le type de support, par ex. `application/json`, qui contient comme valeur un autre objet JSON, qui contient :
* Une clé `schema`, qui a pour valeur le schéma JSON du modèle, voici le bon endroit.
* **FastAPI** ajoute ici une référence aux schémas JSON globaux à un autre endroit de votre OpenAPI au lieu de l'inclure directement. De cette façon, d'autres applications et clients peuvent utiliser ces schémas JSON directement, fournir de meilleurs outils de génération de code, etc.
Les réponses générées au format OpenAPI pour cette *opération de chemin* seront :
```JSON hl_lines="3-12"
{
"responses": {
"404": {
"description": "Additional Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Message"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Item"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
```
Les schémas sont référencés à un autre endroit du modèle OpenAPI :
```JSON hl_lines="4-16"
{
"components": {
"schemas": {
"Message": {
"title": "Message",
"required": [
"message"
],
"type": "object",
"properties": {
"message": {
"title": "Message",
"type": "string"
}
}
},
"Item": {
"title": "Item",
"required": [
"id",
"value"
],
"type": "object",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"value": {
"title": "Value",
"type": "string"
}
}
},
"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"
}
}
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
}
}
}
}
```
## Types de médias supplémentaires pour la réponse principale
Vous pouvez utiliser ce même paramètre `responses` pour ajouter différents types de médias pour la même réponse principale.
Par exemple, vous pouvez ajouter un type de média supplémentaire `image/png`, en déclarant que votre *opération de chemin* peut renvoyer un objet JSON (avec le type de média `application/json`) ou une image PNG :
```Python hl_lines="19-24 28"
{!../../../docs_src/additional_responses/tutorial002.py!}
```
!!! Remarque
Notez que vous devez retourner l'image en utilisant directement un `FileResponse`.
!!! Info
À moins que vous ne spécifiiez explicitement un type de média différent dans votre paramètre `responses`, FastAPI supposera que la réponse a le même type de média que la classe de réponse principale (par défaut `application/json`).
Mais si vous avez spécifié une classe de réponse personnalisée avec `None` comme type de média, FastAPI utilisera `application/json` pour toute réponse supplémentaire associée à un modèle.
## Combinaison d'informations
Vous pouvez également combiner des informations de réponse provenant de plusieurs endroits, y compris les paramètres `response_model`, `status_code` et `responses`.
Vous pouvez déclarer un `response_model`, en utilisant le code HTTP par défaut `200` (ou un code personnalisé si vous en avez besoin), puis déclarer des informations supplémentaires pour cette même réponse dans `responses`, directement dans le schéma OpenAPI.
**FastAPI** conservera les informations supplémentaires des `responses` et les combinera avec le schéma JSON de votre modèle.
Par exemple, vous pouvez déclarer une réponse avec un code HTTP `404` qui utilise un modèle Pydantic et a une `description` personnalisée.
Et une réponse avec un code HTTP `200` qui utilise votre `response_model`, mais inclut un `example` personnalisé :
```Python hl_lines="20-31"
{!../../../docs_src/additional_responses/tutorial003.py!}
```
Tout sera combiné et inclus dans votre OpenAPI, et affiché dans la documentation de l'API :
<img src="/img/tutorial/additional-responses/image01.png">
## Combinez les réponses prédéfinies et les réponses personnalisées
Vous voulez peut-être avoir des réponses prédéfinies qui s'appliquent à de nombreux *paramètre de chemin*, mais vous souhaitez les combiner avec des réponses personnalisées nécessaires à chaque *opération de chemin*.
Dans ces cas, vous pouvez utiliser la technique Python "d'affection par décomposition" (appelé _unpacking_ en anglais) d'un `dict` avec `**dict_to_unpack` :
``` Python
old_dict = {
"old key": "old value",
"second old key": "second old value",
}
new_dict = {**old_dict, "new key": "new value"}
```
Ici, `new_dict` contiendra toutes les paires clé-valeur de `old_dict` plus la nouvelle paire clé-valeur :
``` Python
{
"old key": "old value",
"second old key": "second old value",
"new key": "new value",
}
```
Vous pouvez utiliser cette technique pour réutiliser certaines réponses prédéfinies dans vos *paramètres de chemin* et les combiner avec des réponses personnalisées supplémentaires.
Par exemple:
```Python hl_lines="13-17 26"
{!../../../docs_src/additional_responses/tutorial004.py!}
```
## Plus d'informations sur les réponses OpenAPI
Pour voir exactement ce que vous pouvez inclure dans les réponses, vous pouvez consulter ces sections dans la spécification OpenAPI :
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject" class="external-link" target="_blank">Objet Responses de OpenAPI </a>, il inclut le `Response Object`.
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject" class="external-link" target="_blank">Objet Response de OpenAPI </a>, vous pouvez inclure n'importe quoi directement dans chaque réponse à l'intérieur de votre paramètre `responses`. Y compris `description`, `headers`, `content` (à l'intérieur de cela, vous déclarez différents types de médias et schémas JSON) et `links`.

View File

@@ -0,0 +1,37 @@
# Codes HTTP supplémentaires
Par défaut, **FastAPI** renverra les réponses à l'aide d'une structure de données `JSONResponse`, en plaçant la réponse de votre *chemin d'accès* à l'intérieur de cette `JSONResponse`.
Il utilisera le code HTTP par défaut ou celui que vous avez défini dans votre *chemin d'accès*.
## Codes HTTP supplémentaires
Si vous souhaitez renvoyer des codes HTTP supplémentaires en plus du code principal, vous pouvez le faire en renvoyant directement une `Response`, comme une `JSONResponse`, et en définissant directement le code HTTP supplémentaire.
Par exemple, disons que vous voulez avoir un *chemin d'accès* qui permet de mettre à jour les éléments et renvoie les codes HTTP 200 "OK" en cas de succès.
Mais vous voulez aussi qu'il accepte de nouveaux éléments. Et lorsque les éléments n'existaient pas auparavant, il les crée et renvoie un code HTTP de 201 "Créé".
Pour y parvenir, importez `JSONResponse` et renvoyez-y directement votre contenu, en définissant le `status_code` que vous souhaitez :
```Python hl_lines="4 25"
{!../../../docs_src/additional_status_codes/tutorial001.py!}
```
!!! Attention
Lorsque vous renvoyez une `Response` directement, comme dans l'exemple ci-dessus, elle sera renvoyée directement.
Elle ne sera pas sérialisée avec un modèle.
Assurez-vous qu'il contient les données souhaitées et que les valeurs soient dans un format JSON valides (si vous utilisez une `JSONResponse`).
!!! note "Détails techniques"
Vous pouvez également utiliser `from starlette.responses import JSONResponse`.
Pour plus de commodités, **FastAPI** fournit les objets `starlette.responses` sous forme d'un alias accessible par `fastapi.responses`. Mais la plupart des réponses disponibles proviennent directement de Starlette. Il en est de même avec l'objet `statut`.
## Documents OpenAPI et API
Si vous renvoyez directement des codes HTTP et des réponses supplémentaires, ils ne seront pas inclus dans le schéma OpenAPI (la documentation de l'API), car FastAPI n'a aucun moyen de savoir à l'avance ce que vous allez renvoyer.
Mais vous pouvez documenter cela dans votre code, en utilisant : [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.

View File

@@ -426,7 +426,7 @@ For a more complete example including more features, see the <a href="https://fa
* Many extra features (thanks to Starlette) as:
* **WebSockets**
* **GraphQL**
* extremely easy tests based on `requests` and `pytest`
* extremely easy tests based on HTTPX and `pytest`
* **CORS**
* **Cookie Sessions**
* ...and more.
@@ -446,7 +446,7 @@ Used by Pydantic:
Used by Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>HTTPX</code></a> - Required if you want to use the `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.

View File

@@ -67,6 +67,9 @@ nav:
- tutorial/query-params.md
- tutorial/body.md
- tutorial/background-tasks.md
- Guide utilisateur avancé:
- advanced/additional-status-codes.md
- advanced/additional-responses.md
- async.md
- Déploiement:
- deployment/index.md

View File

@@ -445,7 +445,7 @@ item: Item
בשימוש Starlette:
- <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - דרוש אם ברצונכם להשתמש ב - `TestClient`.
- <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - דרוש אם ברצונכם להשתמש ב - `TestClient`.
- <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - דרוש אם ברצונכם להשתמש בברירת המחדל של תצורת הטמפלייטים.
- <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - דרוש אם ברצונכם לתמוך ב <abbr title="המרת המחרוזת שמגיעה מבקשת HTTP למידע פייתון">"פרסור"</abbr> טפסים, באצמעות <code dir="ltr">request.form()</code>.
- <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - דרוש אם ברצונכם להשתמש ב - `SessionMiddleware`.

View File

@@ -426,7 +426,7 @@ For a more complete example including more features, see the <a href="https://fa
* Many extra features (thanks to Starlette) as:
* **WebSockets**
* **GraphQL**
* extremely easy tests based on `requests` and `pytest`
* extremely easy tests based on HTTPX and `pytest`
* **CORS**
* **Cookie Sessions**
* ...and more.
@@ -446,7 +446,7 @@ Used by Pydantic:
Used by Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.

View File

@@ -423,7 +423,7 @@ For a more complete example including more features, see the <a href="https://fa
* Many extra features (thanks to Starlette) as:
* **WebSockets**
* **GraphQL**
* extremely easy tests based on `requests` and `pytest`
* extremely easy tests based on HTTPX and `pytest`
* **CORS**
* **Cookie Sessions**
* ...and more.
@@ -443,7 +443,7 @@ Used by Pydantic:
Used by Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.

View File

@@ -0,0 +1,186 @@
# WebSocket
**FastAPI**で<a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" class="external-link" target="_blank">WebSocket</a>が使用できます。
## `WebSockets`のインストール
まず `WebSockets`のインストールが必要です。
<div class="termy">
```console
$ pip install websockets
---> 100%
```
</div>
## WebSocket クライアント
### 本番環境
本番環境では、React、Vue.js、Angularなどの最新のフレームワークで作成されたフロントエンドを使用しているでしょう。
そして、バックエンドとWebSocketを使用して通信するために、おそらくフロントエンドのユーティリティを使用することになるでしょう。
または、ネイティブコードでWebSocketバックエンドと直接通信するネイティブモバイルアプリケーションがあるかもしれません。
他にも、WebSocketのエンドポイントと通信する方法があるかもしれません。
---
ただし、この例では非常にシンプルなHTML文書といくつかのJavaScriptを、すべてソースコードの中に入れて使用することにします。
もちろん、これは最適な方法ではありませんし、本番環境で使うことはないでしょう。
本番環境では、上記の方法のいずれかの選択肢を採用することになるでしょう。
しかし、これはWebSocketのサーバーサイドに焦点を当て、実用的な例を示す最も簡単な方法です。
```Python hl_lines="2 6-38 41-43"
{!../../../docs_src/websockets/tutorial001.py!}
```
## `websocket` を作成する
**FastAPI** アプリケーションで、`websocket` を作成します。
```Python hl_lines="1 46-47"
{!../../../docs_src/websockets/tutorial001.py!}
```
!!! note "技術詳細"
`from starlette.websockets import WebSocket` を使用しても構いません.
**FastAPI** は開発者の利便性のために、同じ `WebSocket` を提供します。しかし、こちらはStarletteから直接提供されるものです。
## メッセージの送受信
WebSocketルートでは、 `await` を使ってメッセージの送受信ができます。
```Python hl_lines="48-52"
{!../../../docs_src/websockets/tutorial001.py!}
```
バイナリやテキストデータ、JSONデータを送受信できます。
## 試してみる
ファイル名が `main.py` である場合、以下の方法でアプリケーションを実行します。
<div class="termy">
```console
$ uvicorn main:app --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
ブラウザで <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a> を開きます。
次のようなシンプルなページが表示されます。
<img src="/img/tutorial/websockets/image01.png">
入力ボックスにメッセージを入力して送信できます。
<img src="/img/tutorial/websockets/image02.png">
そして、 WebSocketを使用した**FastAPI**アプリケーションが応答します。
<img src="/img/tutorial/websockets/image03.png">
複数のメッセージを送信(および受信)できます。
<img src="/img/tutorial/websockets/image04.png">
そして、これらの通信はすべて同じWebSocket接続を使用します。
## 依存関係
WebSocketエンドポイントでは、`fastapi` から以下をインポートして使用できます。
* `Depends`
* `Security`
* `Cookie`
* `Header`
* `Path`
* `Query`
これらは、他のFastAPI エンドポイント/*path operation* の場合と同じように機能します。
```Python hl_lines="58-65 68-83"
{!../../../docs_src/websockets/tutorial002.py!}
```
!!! info "情報"
WebSocket で `HTTPException` を発生させることはあまり意味がありません。したがって、WebSocketの接続を直接閉じる方がよいでしょう。
クロージングコードは、<a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">仕様で定義された有効なコード</a>の中から使用することができます。
将来的には、どこからでも `raise` できる `WebSocketException` が用意され、専用の例外ハンドラを追加できるようになる予定です。これは、Starlette の <a href="https://github.com/encode/starlette/pull/527" class="external-link" target="_blank">PR #527</a> に依存するものです。
### 依存関係を用いてWebSocketsを試してみる
ファイル名が `main.py` である場合、以下の方法でアプリケーションを実行します。
<div class="termy">
```console
$ uvicorn main:app --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
ブラウザで <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a> を開きます。
クライアントが設定できる項目は以下の通りです。
* パスで使用される「Item ID」
* クエリパラメータとして使用される「Token」
!!! tip "豆知識"
クエリ `token` は依存パッケージによって処理されることに注意してください。
これにより、WebSocketに接続してメッセージを送受信できます。
<img src="/img/tutorial/websockets/image05.png">
## 切断や複数クライアントへの対応
WebSocket接続が閉じられると、 `await websocket.receive_text()` は例外 `WebSocketDisconnect` を発生させ、この例のようにキャッチして処理することができます。
```Python hl_lines="81-83"
{!../../../docs_src/websockets/tutorial003.py!}
```
試してみるには、
* いくつかのブラウザタブでアプリを開きます。
* それらのタブでメッセージを記入してください。
* そして、タブのうち1つを閉じてください。
これにより例外 `WebSocketDisconnect` が発生し、他のすべてのクライアントは次のようなメッセージを受信します。
```
Client #1596980209979 left the chat
```
!!! tip "豆知識"
上記のアプリは、複数の WebSocket 接続に対してメッセージを処理し、ブロードキャストする方法を示すための最小限のシンプルな例です。
しかし、すべての接続がメモリ内の単一のリストで処理されるため、プロセスの実行中にのみ機能し、単一のプロセスでのみ機能することに注意してください。
もしFastAPIと簡単に統合できて、RedisやPostgreSQLなどでサポートされている、より堅牢なものが必要なら、<a href="https://github.com/encode/broadcaster" class="external-link" target="_blank">encode/broadcaster</a> を確認してください。
## その他のドキュメント
オプションの詳細については、Starletteのドキュメントを確認してください。
* <a href="https://www.starlette.io/websockets/" class="external-link" target="_blank"> `WebSocket` クラス</a>
* <a href="https://www.starlette.io/endpoints/#websocketendpoint" class="external-link" target="_blank">クラスベースのWebSocket処理</a>

View File

@@ -169,7 +169,7 @@ FastAPIには非常に使いやすく、非常に強力な<abbr title='also know
* **GraphQL**のサポート
* プロセス内バックグラウンドタスク
* 起動およびシャットダウンイベント
* `requests`に基づいて構築されたテストクライアント
* `httpx`に基づいて構築されたテストクライアント
* **CORS**、GZip、静的ファイル、ストリーミング応答
* **セッションとCookie**のサポート
* テストカバレッジ100%

View File

@@ -416,7 +416,7 @@ item: Item
- 以下のようなたくさんのおまけ機能(Starlette のおかげです):
- **WebSockets**
- **GraphQL**
- `requests` や `pytest`をもとにした極限に簡単なテスト
- `httpx` や `pytest`をもとにした極限に簡単なテスト
- **CORS**
- **クッキーセッション**
- ...などなど。
@@ -436,7 +436,7 @@ Pydantic によって使用されるもの:
Starlette によって使用されるもの:
- <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - `TestClient`を使用するために必要です。
- <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - `TestClient`を使用するために必要です。
- <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - デフォルトのテンプレート設定を使用する場合は必要です。
- <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>`request.form()`からの変換をサポートしたい場合は必要です。
- <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` サポートのためには必要です。

View File

@@ -64,7 +64,7 @@ http://127.0.0.1:8000/items/?skip=20
同様に、デフォルト値を `None` とすることで、オプショナルなクエリパラメータを宣言できます:
```Python hl_lines="7"
```Python hl_lines="9"
{!../../../docs_src/query_params/tutorial002.py!}
```
@@ -82,7 +82,7 @@ http://127.0.0.1:8000/items/?skip=20
`bool` 型も宣言できます。これは以下の様に変換されます:
```Python hl_lines="7"
```Python hl_lines="9"
{!../../../docs_src/query_params/tutorial003.py!}
```
@@ -126,7 +126,7 @@ http://127.0.0.1:8000/items/foo?short=yes
名前で判別されます:
```Python hl_lines="6 8"
```Python hl_lines="8 10"
{!../../../docs_src/query_params/tutorial004.py!}
```
@@ -184,7 +184,7 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
そして当然、あるパラメータを必須に、別のパラメータにデフォルト値を設定し、また別のパラメータをオプショナルにできます:
```Python hl_lines="7"
```Python hl_lines="10"
{!../../../docs_src/query_params/tutorial006.py!}
```

View File

@@ -2,7 +2,7 @@
<a href="https://www.starlette.io/testclient/" class="external-link" target="_blank">Starlette</a> のおかげで、**FastAPI** アプリケーションのテストは簡単で楽しいものになっています。
<a href="http://docs.python-requests.org" class="external-link" target="_blank">Requests</a> がベースなので、非常に使いやすく直感的です。
<a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> がベースなので、非常に使いやすく直感的です。
これを使用すると、**FastAPI** と共に <a href="https://docs.pytest.org/" class="external-link" target="_blank">pytest</a> を直接利用できます。
@@ -14,7 +14,7 @@
`test_` から始まる名前の関数を作成します (これは `pytest` の標準的なコンベンションです)。
`requests` と同じ様に `TestClient` オブジェクトを使用します。
`httpx` と同じ様に `TestClient` オブジェクトを使用します。
チェックしたい Python の標準的な式と共に、シンプルに `assert` 文を記述します。
@@ -94,7 +94,7 @@
{!> ../../../docs_src/app_testing/app_b/test_main.py!}
```
リクエストに情報を渡せるクライアントが必要で、その方法がわからない場合はいつでも、`requests` での実現方法を検索 (Google) できます。
リクエストに情報を渡せるクライアントが必要で、その方法がわからない場合はいつでも、`httpx` での実現方法を検索 (Google) できます。
テストでも同じことを行います。
@@ -106,7 +106,7 @@
* *ヘッダー* を渡すには、`headers` パラメータに `dict` を渡します。
* *cookies* の場合、 `cookies` パラメータに `dict` です。
(`requests` または `TestClient` を使用して) バックエンドにデータを渡す方法の詳細は、<a href="http://docs.python-requests.org" class="external-link" target="_blank">Requestsのドキュメント</a>を確認してください。
(`httpx` または `TestClient` を使用して) バックエンドにデータを渡す方法の詳細は、<a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPXのドキュメント</a>を確認してください。
!!! info "情報"
`TestClient` は、Pydanticモデルではなく、JSONに変換できるデータを受け取ることに注意してください。

View File

@@ -86,6 +86,7 @@ nav:
- advanced/response-directly.md
- advanced/custom-response.md
- advanced/nosql-databases.md
- advanced/websockets.md
- advanced/conditional-openapi.md
- async.md
- デプロイ:

View File

@@ -422,7 +422,7 @@ item: Item
* (Starlette 덕분에) 많은 추가 기능:
* **웹 소켓**
* **GraphQL**
* `requests` 및 `pytest`에 기반한 극히 쉬운 테스트
* HTTPX 및 `pytest`에 기반한 극히 쉬운 테스트
* **CORS**
* **쿠키 세션**
* ...기타 등등.
@@ -442,7 +442,7 @@ Pydantic이 사용하는:
Starlette이 사용하는:
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - `TestClient`를 사용하려면 필요.
* <a href="https://www.python-httpx.org" target="_blank"><code>HTTPX</code></a> - `TestClient`를 사용하려면 필요.
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - 기본 템플릿 설정을 사용하려면 필요.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - `request.form()`과 함께 <abbr title="HTTP 요청에서 파이썬 데이터로 가는 문자열 변환">"parsing"</abbr>의 지원을 원하면 필요.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` 지원을 위해 필요.

View File

@@ -0,0 +1,84 @@
# 교차 출처 리소스 공유
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">CORS 또는 "교차-출처 리소스 공유"</a>란, 브라우저에서 동작하는 프론트엔드가 자바스크립트로 코드로 백엔드와 통신하고, 백엔드는 해당 프론트엔드와 다른 "출처"에 존재하는 상황을 의미합니다.
## 출처
출처란 프로토콜(`http` , `https`), 도메인(`myapp.com`, `localhost`, `localhost.tiangolo.com` ), 그리고 포트(`80`, `443`, `8080` )의 조합을 의미합니다.
따라서, 아래는 모두 상이한 출처입니다:
* `http://localhost`
* `https://localhost`
* `http://localhost:8080`
모두 `localhost` 에 있지만, 서로 다른 프로토콜과 포트를 사용하고 있으므로 다른 "출처"입니다.
## 단계
브라우저 내 `http://localhost:8080`에서 동작하는 프론트엔드가 있고, 자바스크립트는 `http://localhost`를 통해 백엔드와 통신한다고 가정해봅시다(포트를 명시하지 않는 경우, 브라우저는 `80` 을 기본 포트로 간주합니다).
그러면 브라우저는 백엔드에 HTTP `OPTIONS` 요청을 보내고, 백엔드에서 이 다른 출처(`http://localhost:8080`)와의 통신을 허가하는 적절한 헤더를 보내면, 브라우저는 프론트엔드의 자바스크립트가 백엔드에 요청을 보낼 수 있도록 합니다.
이를 위해, 백엔드는 "허용된 출처(allowed origins)" 목록을 가지고 있어야만 합니다.
이 경우, 프론트엔드가 제대로 동작하기 위해 `http://localhost:8080`을 목록에 포함해야 합니다.
## 와일드카드
모든 출처를 허용하기 위해 목록을 `"*"` ("와일드카드")로 선언하는 것도 가능합니다.
하지만 이것은 특정한 유형의 통신만을 허용하며, 쿠키 및 액세스 토큰과 사용되는 인증 헤더(Authoriztion header) 등이 포함된 경우와 같이 자격 증명(credentials)이 포함된 통신은 허용되지 않습니다.
따라서 모든 작업을 의도한대로 실행하기 위해, 허용되는 출처를 명시적으로 지정하는 것이 좋습니다.
## `CORSMiddleware` 사용
`CORSMiddleware` 을 사용하여 **FastAPI** 응용 프로그램의 교차 출처 리소스 공유 환경을 설정할 수 있습니다.
* `CORSMiddleware` 임포트.
* 허용되는 출처(문자열 형식)의 리스트 생성.
* FastAPI 응용 프로그램에 "미들웨어(middleware)"로 추가.
백엔드에서 다음의 사항을 허용할지에 대해 설정할 수도 있습니다:
* 자격증명 (인증 헤더, 쿠키 등).
* 특정한 HTTP 메소드(`POST`, `PUT`) 또는 와일드카드 `"*"` 를 사용한 모든 HTTP 메소드.
* 특정한 HTTP 헤더 또는 와일드카드 `"*"` 를 사용한 모든 HTTP 헤더.
```Python hl_lines="2 6-11 13-19"
{!../../../docs_src/cors/tutorial001.py!}
```
`CORSMiddleware` 에서 사용하는 기본 매개변수는 제한적이므로, 브라우저가 교차-도메인 상황에서 특정한 출처, 메소드, 헤더 등을 사용할 수 있도록 하려면 이들을 명시적으로 허용해야 합니다.
다음의 인자들이 지원됩니다:
* `allow_origins` - 교차-출처 요청을 보낼 수 있는 출처의 리스트입니다. 예) `['https://example.org', 'https://www.example.org']`. 모든 출처를 허용하기 위해 `['*']` 를 사용할 수 있습니다.
* `allow_origin_regex` - 교차-출처 요청을 보낼 수 있는 출처를 정규표현식 문자열로 나타냅니다. `'https://.*\.example\.org'`.
* `allow_methods` - 교차-출처 요청을 허용하는 HTTP 메소드의 리스트입니다. 기본값은 `['GET']` 입니다. `['*']` 을 사용하여 모든 표준 메소드들을 허용할 수 있습니다.
* `allow_headers` - 교차-출처를 지원하는 HTTP 요청 헤더의 리스트입니다. 기본값은 `[]` 입니다. 모든 헤더들을 허용하기 위해 `['*']` 를 사용할 수 있습니다. `Accept`, `Accept-Language`, `Content-Language` 그리고 `Content-Type` 헤더는 CORS 요청시 언제나 허용됩니다.
* `allow_credentials` - 교차-출처 요청시 쿠키 지원 여부를 설정합니다. 기본값은 `False` 입니다. 또한 해당 항목을 허용할 경우 `allow_origins` 는 `['*']` 로 설정할 수 없으며, 출처를 반드시 특정해야 합니다.
* `expose_headers` - 브라우저에 접근할 수 있어야 하는 모든 응답 헤더를 가리킵니다. 기본값은 `[]` 입니다.
* `max_age` - 브라우저가 CORS 응답을 캐시에 저장하는 최대 시간을 초 단위로 설정합니다. 기본값은 `600` 입니다.
미들웨어는 두가지 특정한 종류의 HTTP 요청에 응답합니다...
### CORS 사전 요청
`Origin` 및 `Access-Control-Request-Method` 헤더와 함께 전송하는 모든 `OPTIONS` 요청입니다.
이 경우 미들웨어는 들어오는 요청을 가로채 적절한 CORS 헤더와, 정보 제공을 위한 `200` 또는 `400` 응답으로 응답합니다.
### 단순한 요청
`Origin` 헤더를 가진 모든 요청. 이 경우 미들웨어는 요청을 정상적으로 전달하지만, 적절한 CORS 헤더를 응답에 포함시킵니다.
## 더 많은 정보
<abbr title="교차-출처 리소스 공유">CORS</abbr>에 대한 더 많은 정보를 알고싶다면, <a href="https://developer.mozilla.org/ko/docs/Web/HTTP/CORS" class="external-link" target="_blank">Mozilla CORS 문서</a>를 참고하기 바랍니다.
!!! note "기술적 세부 사항"
`from starlette.middleware.cors import CORSMiddleware` 역시 사용할 수 있습니다.
**FastAPI**는 개발자인 당신의 편의를 위해 `fastapi.middleware` 에서 몇가지의 미들웨어를 제공합니다. 하지만 대부분의 미들웨어가 Stralette으로부터 직접 제공됩니다.

View File

@@ -69,6 +69,7 @@ nav:
- tutorial/request-files.md
- tutorial/request-forms-and-files.md
- tutorial/encoder.md
- tutorial/cors.md
markdown_extensions:
- toc:
permalink: true

View File

@@ -429,7 +429,7 @@ For a more complete example including more features, see the <a href="https://fa
* **GraphQL** integration with <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> and other libraries.
* Many extra features (thanks to Starlette) as:
* **WebSockets**
* extremely easy tests based on `requests` and `pytest`
* extremely easy tests based on HTTPX and `pytest`
* **CORS**
* **Cookie Sessions**
* ...and more.
@@ -449,7 +449,7 @@ Used by Pydantic:
Used by Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.

View File

@@ -420,7 +420,7 @@ Dla bardziej kompletnych przykładów posiadających więcej funkcjonalności, z
* Wiele dodatkowych funkcji (dzięki Starlette) takie jak:
* **WebSockety**
* **GraphQL**
* bardzo proste testy bazujące na `requests` oraz `pytest`
* bardzo proste testy bazujące na HTTPX oraz `pytest`
* **CORS**
* **Sesje cookie**
* ...i więcej.
@@ -440,7 +440,7 @@ Używane przez Pydantic:
Używane przez Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Wymagane jeżeli chcesz korzystać z `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Wymagane jeżeli chcesz korzystać z `TestClient`.
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Wymagane jeżeli chcesz korzystać z `FileResponse` albo `StaticFiles`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Wymagane jeżeli chcesz używać domyślnej konfiguracji szablonów.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Wymagane jeżelich chcesz wsparcie <abbr title="przetwarzania stringa którzy przychodzi z żądaniem HTTP na dane używane przez Pythona">"parsowania"</abbr> formularzy, używając `request.form()`.

View File

@@ -0,0 +1,701 @@
# FastAPI em contêineres - Docker
Ao fazer o deploy de aplicações FastAPI uma abordagem comum é construir uma **imagem de contêiner Linux**. Isso normalmente é feito usando o <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>. Você pode a partir disso fazer o deploy dessa imagem de algumas maneiras.
Usando contêineres Linux você tem diversas vantagens incluindo **segurança**, **replicabilidade**, **simplicidade**, entre outras.
!!! Dica
Está com pressa e já sabe dessas coisas? Pode ir direto para [`Dockerfile` abaixo 👇](#build-a-docker-image-for-fastapi).
<details>
<summary>Visualização do Dockerfile 👀</summary>
```Dockerfile
FROM python:3.9
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
# If running behind a proxy like Nginx or Traefik add --proxy-headers
# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers"]
```
</details>
## O que é um Contêiner
Contêineres (especificamente contêineres Linux) são um jeito muito **leve** de empacotar aplicações contendo todas as dependências e arquivos necessários enquanto os mantém isolados de outros contêineres (outras aplicações ou componentes) no mesmo sistema.
Contêineres Linux rodam usando o mesmo kernel Linux do hospedeiro (máquina, máquina virtual, servidor na nuvem, etc). Isso simplesmente significa que eles são muito leves (comparados com máquinas virtuais emulando um sistema operacional completo).
Dessa forma, contêineres consomem **poucos recursos**, uma quantidade comparável com rodar os processos diretamente (uma máquina virtual consumiria muito mais).
Contêineres também possuem seus próprios processos (comumente um único processo), sistema de arquivos e rede **isolados** simplificando deploy, segurança, desenvolvimento, etc.
## O que é uma Imagem de Contêiner
Um **contêiner** roda a partir de uma **imagem de contêiner**.
Uma imagem de contêiner é uma versão **estática** de todos os arquivos, variáveis de ambiente e do comando/programa padrão que deve estar presente num contêiner. **Estática** aqui significa que a **imagem** de contêiner não está rodando, não está sendo executada, somente contém os arquivos e metadados empacotados.
Em contraste com a "**imagem de contêiner**" que contém os conteúdos estáticos armazenados, um "**contêiner**" normalmente se refere à instância rodando, a coisa que está sendo **executada**.
Quando o **contêiner** é iniciado e está rodando (iniciado a partir de uma **imagem de contêiner**), ele pode criar ou modificar arquivos, variáveis de ambiente, etc. Essas mudanças vão existir somente nesse contêiner, mas não persistirão na imagem subjacente do container (não serão salvas no disco).
Uma imagem de contêiner é comparável ao arquivo de **programa** e seus conteúdos, ex.: `python` e algum arquivo `main.py`.
E o **contêiner** em si (em contraste à **imagem de contêiner**) é a própria instância da imagem rodando, comparável a um **processo**. Na verdade, um contêiner está rodando somente quando há um **processo rodando** (e normalmente é somente um processo). O contêiner finaliza quando não há um processo rodando nele.
## Imagens de contêiner
Docker tem sido uma das principais ferramentas para criar e gerenciar **imagens de contêiner** e **contêineres**.
E existe um <a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a> público com **imagens de contêiner oficiais** pré-prontas para diversas ferramentas, ambientes, bancos de dados e aplicações.
Por exemplo, há uma <a href="https://hub.docker.com/_/python" class="external-link" target="_blank">Imagem Python</a> oficial.
E existe muitas outras imagens para diferentes coisas, como bancos de dados, por exemplo:
* <a href="https://hub.docker.com/_/postgres" class="external-link" target="_blank">PostgreSQL</a>
* <a href="https://hub.docker.com/_/mysql" class="external-link" target="_blank">MySQL</a>
* <a href="https://hub.docker.com/_/mongo" class="external-link" target="_blank">MongoDB</a>
* <a href="https://hub.docker.com/_/redis" class="external-link" target="_blank">Redis</a>, etc.
Usando imagens de contêiner pré-prontas é muito fácil **combinar** e usar diferentes ferramentas. Por exemplo, para testar um novo banco de dados. Em muitos casos, você pode usar as **imagens oficiais** precisando somente de variáveis de ambiente para configurá-las.
Dessa forma, em muitos casos você pode aprender sobre contêineres e Docker e re-usar essa experiência com diversos componentes e ferramentas.
Então, você rodaria **vários contêineres** com coisas diferentes, como um banco de dados, uma aplicação Python, um servidor web com uma aplicação frontend React, e conectá-los juntos via sua rede interna.
Todos os sistemas de gerenciamento de contêineres (como Docker ou Kubernetes) possuem essas funcionalidades de rede integradas a eles.
## Contêineres e Processos
Uma **imagem de contêiner** normalmente inclui em seus metadados o programa padrão ou comando que deve ser executado quando o **contêiner** é iniciado e os parâmetros a serem passados para esse programa. Muito similar ao que seria se estivesse na linha de comando.
Quando um **contêiner** é iniciado, ele irá rodar esse comando/programa (embora você possa sobrescrevê-lo e fazer com que ele rode um comando/programa diferente).
Um contêiner está rodando enquanto o **processo principal** (comando ou programa) estiver rodando.
Um contêiner normalmente tem um **único processo**, mas também é possível iniciar sub-processos a partir do processo principal, e dessa forma você terá **vários processos** no mesmo contêiner.
Mas não é possível ter um contêiner rodando sem **pelo menos um processo rodando**. Se o processo principal parar, o contêiner também para.
## Construindo uma Imagem Docker para FastAPI
Okay, vamos construir algo agora! 🚀
Eu vou mostrar como construir uma **imagem Docker** para FastAPI **do zero**, baseado na **imagem oficial do Python**.
Isso é o que você quer fazer na **maioria dos casos**, por exemplo:
* Usando **Kubernetes** ou ferramentas similares
* Quando rodando em uma **Raspberry Pi**
* Usando um serviço em nuvem que irá rodar uma imagem de contêiner para você, etc.
### O Pacote Requirements
Você normalmente teria os **requisitos do pacote** para sua aplicação em algum arquivo.
Isso pode depender principalmente da ferramenta que você usa para **instalar** esses requisitos.
O caminho mais comum de fazer isso é ter um arquivo `requirements.txt` com os nomes dos pacotes e suas versões, um por linha.
Você, naturalmente, usaria as mesmas ideias que você leu em [Sobre Versões do FastAPI](./versions.md){.internal-link target=_blank} para definir os intervalos de versões.
Por exemplo, seu `requirements.txt` poderia parecer com:
```
fastapi>=0.68.0,<0.69.0
pydantic>=1.8.0,<2.0.0
uvicorn>=0.15.0,<0.16.0
```
E você normalmente instalaria essas dependências de pacote com `pip`, por exemplo:
<div class="termy">
```console
$ pip install -r requirements.txt
---> 100%
Successfully installed fastapi pydantic uvicorn
```
</div>
!!! info
Há outros formatos e ferramentas para definir e instalar dependências de pacote.
Eu vou mostrar um exemplo depois usando Poetry em uma seção abaixo. 👇
### Criando o Código do **FastAPI**
* Crie um diretório `app` e entre nele.
* Crie um arquivo vazio `__init__.py`.
* Crie um arquivo `main.py` com:
```Python
from typing import Optional
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
### Dockerfile
Agora, no mesmo diretório do projeto, crie um arquivo `Dockerfile` com:
```{ .dockerfile .annotate }
# (1)
FROM python:3.9
# (2)
WORKDIR /code
# (3)
COPY ./requirements.txt /code/requirements.txt
# (4)
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
# (5)
COPY ./app /code/app
# (6)
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
```
1. Inicie a partir da imagem base oficial do Python.
2. Defina o diretório de trabalho atual para `/code`.
Esse é o diretório onde colocaremos o arquivo `requirements.txt` e o diretório `app`.
3. Copie o arquivo com os requisitos para o diretório `/code`.
Copie **somente** o arquivo com os requisitos primeiro, não o resto do código.
Como esse arquivo **não muda com frequência**, o Docker irá detectá-lo e usar o **cache** para esse passo, habilitando o cache para o próximo passo também.
4. Instale as dependências de pacote vindas do arquivo de requisitos.
A opção `--no-cache-dir` diz ao `pip` para não salvar os pacotes baixados localmente, pois isso só aconteceria se `pip` fosse executado novamente para instalar os mesmos pacotes, mas esse não é o caso quando trabalhamos com contêineres.
!!! note
`--no-cache-dir` é apenas relacionado ao `pip`, não tem nada a ver com Docker ou contêineres.
A opção `--upgrade` diz ao `pip` para atualizar os pacotes se eles já estiverem instalados.
Por causa do passo anterior de copiar o arquivo, ele pode ser detectado pelo **cache do Docker**, esse passo também **usará o cache do Docker** quando disponível.
Usando o cache nesse passo irá **salvar** muito **tempo** quando você for construir a imagem repetidas vezes durante o desenvolvimento, ao invés de **baixar e instalar** todas as dependências **toda vez**.
5. Copie o diretório `./app` dentro do diretório `/code`.
Como isso tem todo o código contendo o que **muda com mais frequência**, o **cache do Docker** não será usado para esse passo ou para **qualquer passo seguinte** facilmente.
Então, é importante colocar isso **perto do final** do `Dockerfile`, para otimizar o tempo de construção da imagem do contêiner.
6. Defina o **comando** para rodar o servidor `uvicorn`.
`CMD` recebe uma lista de strings, cada uma dessas strings é o que você digitaria na linha de comando separado por espaços.
Esse comando será executado a partir do **diretório de trabalho atual**, o mesmo diretório `/code` que você definiu acima com `WORKDIR /code`.
Porque o programa será iniciado em `/code` e dentro dele está o diretório `./app` com seu código, o **Uvicorn** será capaz de ver e **importar** `app` de `app.main`.
!!! tip
Revise o que cada linha faz clicando em cada bolha com o número no código. 👆
Agora você deve ter uma estrutura de diretório como:
```
.
├── app
│   ├── __init__.py
│ └── main.py
├── Dockerfile
└── requirements.txt
```
#### Por Trás de um Proxy de Terminação TLS
Se você está executando seu contêiner atrás de um Proxy de Terminação TLS (load balancer) como Nginx ou Traefik, adicione a opção `--proxy-headers`, isso fará com que o Uvicorn confie nos cabeçalhos enviados por esse proxy, informando que o aplicativo está sendo executado atrás do HTTPS, etc.
```Dockerfile
CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
```
#### Cache Docker
Existe um truque importante nesse `Dockerfile`, primeiro copiamos o **arquivo com as dependências sozinho**, não o resto do código. Deixe-me te contar o porquê disso.
```Dockerfile
COPY ./requirements.txt /code/requirements.txt
```
Docker e outras ferramentas **constróem** essas imagens de contêiner **incrementalmente**, adicionando **uma camada em cima da outra**, começando do topo do `Dockerfile` e adicionando qualquer arquivo criado por cada uma das instruções do `Dockerfile`.
Docker e ferramentas similares também usam um **cache interno** ao construir a imagem, se um arquivo não mudou desde a última vez que a imagem do contêiner foi construída, então ele irá **reutilizar a mesma camada** criada na última vez, ao invés de copiar o arquivo novamente e criar uma nova camada do zero.
Somente evitar a cópia de arquivos não melhora muito as coisas, mas porque ele usou o cache para esse passo, ele pode **usar o cache para o próximo passo**. Por exemplo, ele pode usar o cache para a instrução que instala as dependências com:
```Dockerfile
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
```
O arquivo com os requisitos de pacote **não muda com frequência**. Então, ao copiar apenas esse arquivo, o Docker será capaz de **usar o cache** para esse passo.
E então, o Docker será capaz de **usar o cache para o próximo passo** que baixa e instala essas dependências. E é aqui que **salvamos muito tempo**. ✨ ...e evitamos tédio esperando. 😪😆
Baixar e instalar as dependências do pacote **pode levar minutos**, mas usando o **cache** leva **segundos** no máximo.
E como você estaria construindo a imagem do contêiner novamente e novamente durante o desenvolvimento para verificar se suas alterações de código estão funcionando, há muito tempo acumulado que isso economizaria.
A partir daí, perto do final do `Dockerfile`, copiamos todo o código. Como isso é o que **muda com mais frequência**, colocamos perto do final, porque quase sempre, qualquer coisa depois desse passo não será capaz de usar o cache.
```Dockerfile
COPY ./app /code/app
```
### Construindo a Imagem Docker
Agora que todos os arquivos estão no lugar, vamos construir a imagem do contêiner.
* Vá para o diretório do projeto (onde está o seu `Dockerfile`, contendo o diretório `app`).
* Construa sua imagem FastAPI:
<div class="termy">
```console
$ docker build -t myimage .
---> 100%
```
</div>
!!! tip
Note o `.` no final, é equivalente a `./`, ele diz ao Docker o diretório a ser usado para construir a imagem do contêiner.
Nesse caso, é o mesmo diretório atual (`.`).
### Inicie o contêiner Docker
* Execute um contêiner baseado na sua imagem:
<div class="termy">
```console
$ docker run -d --name mycontêiner -p 80:80 myimage
```
</div>
## Verifique
Você deve ser capaz de verificar isso no URL do seu contêiner Docker, por exemplo: <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> ou <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (ou equivalente, usando seu host Docker).
Você verá algo como:
```JSON
{"item_id": 5, "q": "somequery"}
```
## Documentação interativa da API
Agora você pode ir para <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> ou <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (ou equivalente, usando seu host Docker).
Você verá a documentação interativa automática da API (fornecida pelo <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
## Documentação alternativa da API
E você também pode ir para <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> ou <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (ou equivalente, usando seu host Docker).
Você verá a documentação alternativa automática (fornecida pela <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## Construindo uma Imagem Docker com um Arquivo Único FastAPI
Se seu FastAPI for um único arquivo, por exemplo, `main.py` sem um diretório `./app`, sua estrutura de arquivos poderia ser assim:
```
.
├── Dockerfile
├── main.py
└── requirements.txt
```
Então você só teria que alterar os caminhos correspondentes para copiar o arquivo dentro do `Dockerfile`:
```{ .dockerfile .annotate hl_lines="10 13" }
FROM python:3.9
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
# (1)
COPY ./main.py /code/
# (2)
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
```
1. Copie o arquivo `main.py` para o diretório `/code` diretamente (sem nenhum diretório `./app`).
2. Execute o Uvicorn e diga a ele para importar o objeto `app` de `main` (em vez de importar de `app.main`).
Então ajuste o comando Uvicorn para usar o novo módulo `main` em vez de `app.main` para importar o objeto FastAPI `app`.
## Conceitos de Implantação
Vamos falar novamente sobre alguns dos mesmos [Conceitos de Implantação](./concepts.md){.internal-link target=_blank} em termos de contêineres.
Contêineres são principalmente uma ferramenta para simplificar o processo de **construção e implantação** de um aplicativo, mas eles não impõem uma abordagem particular para lidar com esses **conceitos de implantação** e existem várias estratégias possíveis.
A **boa notícia** é que com cada estratégia diferente há uma maneira de cobrir todos os conceitos de implantação. 🎉
Vamos revisar esses **conceitos de implantação** em termos de contêineres:
* HTTPS
* Executando na inicialização
* Reinicializações
* Replicação (número de processos rodando)
* Memória
* Passos anteriores antes de começar
## HTTPS
Se nos concentrarmos apenas na **imagem do contêiner** para um aplicativo FastAPI (e posteriormente no **contêiner** em execução), o HTTPS normalmente seria tratado **externamente** por outra ferramenta.
Isso poderia ser outro contêiner, por exemplo, com <a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>, lidando com **HTTPS** e aquisição **automática** de **certificados**.
!!! tip
Traefik tem integrações com Docker, Kubernetes e outros, portanto, é muito fácil configurar e configurar o HTTPS para seus contêineres com ele.
Alternativamente, o HTTPS poderia ser tratado por um provedor de nuvem como um de seus serviços (enquanto ainda executasse o aplicativo em um contêiner).
## Executando na inicialização e reinicializações
Normalmente, outra ferramenta é responsável por **iniciar e executar** seu contêiner.
Ela poderia ser o **Docker** diretamente, **Docker Compose**, **Kubernetes**, um **serviço de nuvem**, etc.
Na maioria (ou em todos) os casos, há uma opção simples para habilitar a execução do contêiner na inicialização e habilitar reinicializações em falhas. Por exemplo, no Docker, é a opção de linha de comando `--restart`.
Sem usar contêineres, fazer aplicativos executarem na inicialização e com reinicializações pode ser trabalhoso e difícil. Mas quando **trabalhando com contêineres** em muitos casos essa funcionalidade é incluída por padrão. ✨
## Replicação - Número de Processos
Se você tiver um <abbr title="Um grupo de máquinas que são configuradas para estarem conectadas e trabalharem juntas de alguma forma">cluster</abbr> de máquinas com **Kubernetes**, Docker Swarm Mode, Nomad ou outro sistema complexo semelhante para gerenciar contêineres distribuídos em várias máquinas, então provavelmente desejará **lidar com a replicação** no **nível do cluster** em vez de usar um **gerenciador de processos** (como o Gunicorn com workers) em cada contêiner.
Um desses sistemas de gerenciamento de contêineres distribuídos como o Kubernetes normalmente tem alguma maneira integrada de lidar com a **replicação de contêineres** enquanto ainda oferece **balanceamento de carga** para as solicitações recebidas. Tudo no **nível do cluster**.
Nesses casos, você provavelmente desejará criar uma **imagem do contêiner do zero** como [explicado acima](#dockerfile), instalando suas dependências e executando **um único processo Uvicorn** em vez de executar algo como Gunicorn com trabalhadores Uvicorn.
### Balanceamento de Carga
Quando usando contêineres, normalmente você terá algum componente **escutando na porta principal**. Poderia ser outro contêiner que também é um **Proxy de Terminação TLS** para lidar com **HTTPS** ou alguma ferramenta semelhante.
Como esse componente assumiria a **carga** de solicitações e distribuiria isso entre os trabalhadores de uma maneira (esperançosamente) **balanceada**, ele também é comumente chamado de **Balanceador de Carga**.
!!! tip
O mesmo componente **Proxy de Terminação TLS** usado para HTTPS provavelmente também seria um **Balanceador de Carga**.
E quando trabalhar com contêineres, o mesmo sistema que você usa para iniciar e gerenciá-los já terá ferramentas internas para transmitir a **comunicação de rede** (por exemplo, solicitações HTTP) do **balanceador de carga** (que também pode ser um **Proxy de Terminação TLS**) para o(s) contêiner(es) com seu aplicativo.
### Um Balanceador de Carga - Múltiplos Contêineres de Workers
Quando trabalhando com **Kubernetes** ou sistemas similares de gerenciamento de contêiner distribuído, usando seus mecanismos de rede internos permitiria que o único **balanceador de carga** que estivesse escutando na **porta principal** transmitisse comunicação (solicitações) para possivelmente **múltiplos contêineres** executando seu aplicativo.
Cada um desses contêineres executando seu aplicativo normalmente teria **apenas um processo** (ex.: um processo Uvicorn executando seu aplicativo FastAPI). Todos seriam **contêineres idênticos**, executando a mesma coisa, mas cada um com seu próprio processo, memória, etc. Dessa forma, você aproveitaria a **paralelização** em **núcleos diferentes** da CPU, ou até mesmo em **máquinas diferentes**.
E o sistema de contêiner com o **balanceador de carga** iria **distribuir as solicitações** para cada um dos contêineres com seu aplicativo **em turnos**. Portanto, cada solicitação poderia ser tratada por um dos múltiplos **contêineres replicados** executando seu aplicativo.
E normalmente esse **balanceador de carga** seria capaz de lidar com solicitações que vão para *outros* aplicativos em seu cluster (por exemplo, para um domínio diferente, ou sob um prefixo de URL diferente), e transmitiria essa comunicação para os contêineres certos para *esse outro* aplicativo em execução em seu cluster.
### Um Processo por Contêiner
Nesse tipo de cenário, provavelmente você desejará ter **um único processo (Uvicorn) por contêiner**, pois já estaria lidando com a replicação no nível do cluster.
Então, nesse caso, você **não** desejará ter um gerenciador de processos como o Gunicorn com trabalhadores Uvicorn, ou o Uvicorn usando seus próprios trabalhadores Uvicorn. Você desejará ter apenas um **único processo Uvicorn** por contêiner (mas provavelmente vários contêineres).
Tendo outro gerenciador de processos dentro do contêiner (como seria com o Gunicorn ou o Uvicorn gerenciando trabalhadores Uvicorn) só adicionaria **complexidade desnecessária** que você provavelmente já está cuidando com seu sistema de cluster.
### Contêineres com Múltiplos Processos e Casos Especiais
Claro, existem **casos especiais** em que você pode querer ter um **contêiner** com um **gerenciador de processos Gunicorn** iniciando vários **processos trabalhadores Uvicorn** dentro.
Nesses casos, você pode usar a **imagem oficial do Docker** que inclui o **Gunicorn** como um gerenciador de processos executando vários **processos trabalhadores Uvicorn**, e algumas configurações padrão para ajustar o número de trabalhadores com base nos atuais núcleos da CPU automaticamente. Eu vou te contar mais sobre isso abaixo em [Imagem Oficial do Docker com Gunicorn - Uvicorn](#imagem-oficial-do-docker-com-gunicorn-uvicorn).
Aqui estão alguns exemplos de quando isso pode fazer sentido:
#### Um Aplicativo Simples
Você pode querer um gerenciador de processos no contêiner se seu aplicativo for **simples o suficiente** para que você não precise (pelo menos não agora) ajustar muito o número de processos, e você pode simplesmente usar um padrão automatizado (com a imagem oficial do Docker), e você está executando em um **único servidor**, não em um cluster.
#### Docker Compose
Você pode estar implantando em um **único servidor** (não em um cluster) com o **Docker Compose**, então você não teria uma maneira fácil de gerenciar a replicação de contêineres (com o Docker Compose) enquanto preserva a rede compartilhada e o **balanceamento de carga**.
Então você pode querer ter **um único contêiner** com um **gerenciador de processos** iniciando **vários processos trabalhadores** dentro.
#### Prometheus and Outros Motivos
Você também pode ter **outros motivos** que tornariam mais fácil ter um **único contêiner** com **múltiplos processos** em vez de ter **múltiplos contêineres** com **um único processo** em cada um deles.
Por exemplo (dependendo de sua configuração), você poderia ter alguma ferramenta como um exportador do Prometheus no mesmo contêiner que deve ter acesso a **cada uma das solicitações** que chegam.
Nesse caso, se você tivesse **múltiplos contêineres**, por padrão, quando o Prometheus fosse **ler as métricas**, ele receberia as métricas de **um único contêiner cada vez** (para o contêiner que tratou essa solicitação específica), em vez de receber as **métricas acumuladas** de todos os contêineres replicados.
Então, nesse caso, poderia ser mais simples ter **um único contêiner** com **múltiplos processos**, e uma ferramenta local (por exemplo, um exportador do Prometheus) no mesmo contêiner coletando métricas do Prometheus para todos os processos internos e expor essas métricas no único contêiner.
---
O ponto principal é que **nenhum** desses são **regras escritas em pedra** que você deve seguir cegamente. Você pode usar essas idéias para **avaliar seu próprio caso de uso** e decidir qual é a melhor abordagem para seu sistema, verificando como gerenciar os conceitos de:
* Segurança - HTTPS
* Executando na inicialização
* Reinicializações
* Replicação (o número de processos em execução)
* Memória
* Passos anteriores antes de inicializar
## Memória
Se você executar **um único processo por contêiner**, terá uma quantidade mais ou menos bem definida, estável e limitada de memória consumida por cada um desses contêineres (mais de um se eles forem replicados).
E então você pode definir esses mesmos limites e requisitos de memória em suas configurações para seu sistema de gerenciamento de contêineres (por exemplo, no **Kubernetes**). Dessa forma, ele poderá **replicar os contêineres** nas **máquinas disponíveis** levando em consideração a quantidade de memória necessária por eles e a quantidade disponível nas máquinas no cluster.
Se sua aplicação for **simples**, isso provavelmente **não será um problema**, e você pode não precisar especificar limites de memória rígidos. Mas se você estiver **usando muita memória** (por exemplo, com **modelos de aprendizado de máquina**), deve verificar quanta memória está consumindo e ajustar o **número de contêineres** que executa em **cada máquina** (e talvez adicionar mais máquinas ao seu cluster).
Se você executar **múltiplos processos por contêiner** (por exemplo, com a imagem oficial do Docker), deve garantir que o número de processos iniciados não **consuma mais memória** do que o disponível.
## Passos anteriores antes de inicializar e contêineres
Se você estiver usando contêineres (por exemplo, Docker, Kubernetes), existem duas abordagens principais que você pode usar.
### Contêineres Múltiplos
Se você tiver **múltiplos contêineres**, provavelmente cada um executando um **único processo** (por exemplo, em um cluster do **Kubernetes**), então provavelmente você gostaria de ter um **contêiner separado** fazendo o trabalho dos **passos anteriores** em um único contêiner, executando um único processo, **antes** de executar os contêineres trabalhadores replicados.
!!! info
Se você estiver usando o Kubernetes, provavelmente será um <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init Container</a>.
Se no seu caso de uso não houver problema em executar esses passos anteriores **em paralelo várias vezes** (por exemplo, se você não estiver executando migrações de banco de dados, mas apenas verificando se o banco de dados está pronto), então você também pode colocá-los em cada contêiner logo antes de iniciar o processo principal.
### Contêiner Único
Se você tiver uma configuração simples, com um **único contêiner** que então inicia vários **processos trabalhadores** (ou também apenas um processo), então poderia executar esses passos anteriores no mesmo contêiner, logo antes de iniciar o processo com o aplicativo. A imagem oficial do Docker suporta isso internamente.
## Imagem Oficial do Docker com Gunicorn - Uvicorn
Há uma imagem oficial do Docker que inclui o Gunicorn executando com trabalhadores Uvicorn, conforme detalhado em um capítulo anterior: [Server Workers - Gunicorn com Uvicorn](./server-workers.md){.internal-link target=_blank}.
Essa imagem seria útil principalmente nas situações descritas acima em: [Contêineres com Múltiplos Processos e Casos Especiais](#contêineres-com-múltiplos-processos-e-casos-Especiais).
* <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
!!! warning
Existe uma grande chance de que você **não** precise dessa imagem base ou de qualquer outra semelhante, e seria melhor construir a imagem do zero, como [descrito acima em: Construa uma Imagem Docker para o FastAPI](#construa-uma-imagem-docker-para-o-fastapi).
Essa imagem tem um mecanismo de **auto-ajuste** incluído para definir o **número de processos trabalhadores** com base nos núcleos de CPU disponíveis.
Isso tem **padrões sensíveis**, mas você ainda pode alterar e atualizar todas as configurações com **variáveis de ambiente** ou arquivos de configuração.
Há também suporte para executar <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker#pre_start_path" class="external-link" target="_blank">**passos anteriores antes de iniciar**</a> com um script.
!!! tip
Para ver todas as configurações e opções, vá para a página da imagem Docker: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
### Número de Processos na Imagem Oficial do Docker
O **número de processos** nesta imagem é **calculado automaticamente** a partir dos **núcleos de CPU** disponíveis.
Isso significa que ele tentará **aproveitar** o máximo de **desempenho** da CPU possível.
Você também pode ajustá-lo com as configurações usando **variáveis de ambiente**, etc.
Mas isso também significa que, como o número de processos depende da CPU do contêiner em execução, a **quantidade de memória consumida** também dependerá disso.
Então, se seu aplicativo consumir muito memória (por exemplo, com modelos de aprendizado de máquina), e seu servidor tiver muitos núcleos de CPU **mas pouca memória**, então seu contêiner pode acabar tentando usar mais memória do que está disponível e degradar o desempenho muito (ou até mesmo travar). 🚨
### Criando um `Dockerfile`
Aqui está como você criaria um `Dockerfile` baseado nessa imagem:
```Dockerfile
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
COPY ./requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
COPY ./app /app
```
### Aplicações Maiores
Se você seguiu a seção sobre a criação de [Aplicações Maiores com Múltiplos Arquivos](../tutorial/bigger-applications.md){.internal-link target=_blank}, seu `Dockerfile` pode parecer com isso:
```Dockerfile
```Dockerfile hl_lines="7"
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
COPY ./requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
COPY ./app /app/app
```
### Quando Usar
Você provavelmente **não** deve usar essa imagem base oficial (ou qualquer outra semelhante) se estiver usando **Kubernetes** (ou outros) e já estiver definindo **replicação** no nível do cluster, com vários **contêineres**. Nesses casos, é melhor **construir uma imagem do zero** conforme descrito acima: [Construindo uma Imagem Docker para FastAPI](#construindo-uma-imagem-docker-para-fastapi).
Essa imagem seria útil principalmente nos casos especiais descritos acima em [Contêineres com Múltiplos Processos e Casos Especiais](#contêineres-com-múltiplos-processos-e-casos-Especiais). Por exemplo, se sua aplicação for **simples o suficiente** para que a configuração padrão de número de processos com base na CPU funcione bem, você não quer se preocupar com a configuração manual da replicação no nível do cluster e não está executando mais de um contêiner com seu aplicativo. Ou se você estiver implantando com **Docker Compose**, executando em um único servidor, etc.
## Deploy da Imagem do Contêiner
Depois de ter uma imagem de contêiner (Docker), existem várias maneiras de implantá-la.
Por exemplo:
* Com **Docker Compose** em um único servidor
* Com um cluster **Kubernetes**
* Com um cluster Docker Swarm Mode
* Com outra ferramenta como o Nomad
* Com um serviço de nuvem que pega sua imagem de contêiner e a implanta
## Imagem Docker com Poetry
Se você usa <a href="https://python-poetry.org/" class="external-link" target="_blank">Poetry</a> para gerenciar as dependências do seu projeto, pode usar a construção multi-estágio do Docker:
```{ .dockerfile .annotate }
# (1)
FROM python:3.9 as requirements-stage
# (2)
WORKDIR /tmp
# (3)
RUN pip install poetry
# (4)
COPY ./pyproject.toml ./poetry.lock* /tmp/
# (5)
RUN poetry export -f requirements.txt --output requirements.txt --without-hashes
# (6)
FROM python:3.9
# (7)
WORKDIR /code
# (8)
COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt
# (9)
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
# (10)
COPY ./app /code/app
# (11)
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
```
1. Esse é o primeiro estágio, ele é chamado `requirements-stage`.
2. Defina `/tmp` como o diretório de trabalho atual.
Aqui é onde geraremos o arquivo `requirements.txt`
3. Instale o Poetry nesse estágio do Docker.
4. Copie os arquivos `pyproject.toml` e `poetry.lock` para o diretório `/tmp`.
Porque está usando `./poetry.lock*` (terminando com um `*`), não irá falhar se esse arquivo ainda não estiver disponível.
5. Gere o arquivo `requirements.txt`.
6. Este é o estágio final, tudo aqui será preservado na imagem final do contêiner.
7. Defina o diretório de trabalho atual como `/code`.
8. Copie o arquivo `requirements.txt` para o diretório `/code`.
Essse arquivo só existe no estágio anterior do Docker, é por isso que usamos `--from-requirements-stage` para copiá-lo.
9. Instale as dependências de pacote do arquivo `requirements.txt` gerado.
10. Copie o diretório `app` para o diretório `/code`.
11. Execute o comando `uvicorn`, informando-o para usar o objeto `app` importado de `app.main`.
!!! tip
Clique nos números das bolhas para ver o que cada linha faz.
Um **estágio do Docker** é uma parte de um `Dockerfile` que funciona como uma **imagem temporária do contêiner** que só é usada para gerar alguns arquivos para serem usados posteriormente.
O primeiro estágio será usado apenas para **instalar Poetry** e para **gerar o `requirements.txt`** com as dependências do seu projeto a partir do arquivo `pyproject.toml` do Poetry.
Esse arquivo `requirements.txt` será usado com `pip` mais tarde no **próximo estágio**.
Na imagem final do contêiner, **somente o estágio final** é preservado. Os estágios anteriores serão descartados.
Quando usar Poetry, faz sentido usar **construções multi-estágio do Docker** porque você realmente não precisa ter o Poetry e suas dependências instaladas na imagem final do contêiner, você **apenas precisa** ter o arquivo `requirements.txt` gerado para instalar as dependências do seu projeto.
Então, no próximo (e último) estágio, você construiria a imagem mais ou menos da mesma maneira descrita anteriormente.
### Por trás de um proxy de terminação TLS - Poetry
Novamente, se você estiver executando seu contêiner atrás de um proxy de terminação TLS (balanceador de carga) como Nginx ou Traefik, adicione a opção `--proxy-headers` ao comando:
```Dockerfile
CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
```
## Recapitulando
Usando sistemas de contêiner (por exemplo, com **Docker** e **Kubernetes**), torna-se bastante simples lidar com todos os **conceitos de implantação**:
* HTTPS
* Executando na inicialização
* Reinícios
* Replicação (o número de processos rodando)
* Memória
* Passos anteriores antes de inicializar
Na maioria dos casos, você provavelmente não desejará usar nenhuma imagem base e, em vez disso, **construir uma imagem de contêiner do zero** baseada na imagem oficial do Docker Python.
Tendo cuidado com a **ordem** das instruções no `Dockerfile` e o **cache do Docker**, você pode **minimizar os tempos de construção**, para maximizar sua produtividade (e evitar a tédio). 😎
Em alguns casos especiais, você pode querer usar a imagem oficial do Docker para o FastAPI. 🤓

View File

@@ -167,7 +167,7 @@ Com **FastAPI**, você terá todos os recursos do **Starlette** (já que FastAPI
* Suporte a **GraphQL**.
* Tarefas em processo _background_.
* Eventos na inicialização e encerramento.
* Cliente de testes construído sobre `requests`.
* Cliente de testes construído sobre HTTPX.
* Respostas em **CORS**, GZip, Static Files, Streaming.
* Suporte a **Session e Cookie**.
* 100% de cobertura de testes.

View File

@@ -415,7 +415,7 @@ Para um exemplo mais completo incluindo mais recursos, veja <a href="https://fas
* Muitos recursos extras (graças ao Starlette) como:
* **WebSockets**
* **GraphQL**
* testes extrememamente fáceis baseados em `requests` e `pytest`
* testes extrememamente fáceis baseados em HTTPX e `pytest`
* **CORS**
* **Cookie Sessions**
* ...e mais.
@@ -435,7 +435,7 @@ Usados por Pydantic:
Usados por Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Necessário se você quiser utilizar o `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Necessário se você quiser utilizar o `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Necessário se você quiser utilizar a configuração padrão de templates.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Necessário se você quiser suporte com <abbr title="converte uma string que chega de uma requisição HTTP para dados Python">"parsing"</abbr> de formulário, com `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Necessário para suporte a `SessionMiddleware`.

View File

@@ -0,0 +1,42 @@
# Codificador Compatível com JSON
Existem alguns casos em que você pode precisar converter um tipo de dados (como um modelo Pydantic) para algo compatível com JSON (como um `dict`, `list`, etc).
Por exemplo, se você precisar armazená-lo em um banco de dados.
Para isso, **FastAPI** fornece uma função `jsonable_encoder()`.
## Usando a função `jsonable_encoder`
Vamos imaginar que você tenha um banco de dados `fake_db` que recebe apenas dados compatíveis com JSON.
Por exemplo, ele não recebe objetos `datetime`, pois estes objetos não são compatíveis com JSON.
Então, um objeto `datetime` teria que ser convertido em um `str` contendo os dados no formato <a href="https://en.wikipedia.org/wiki/ISO_8601" class="external-link" target="_blank">ISO</a>.
Da mesma forma, este banco de dados não receberia um modelo Pydantic (um objeto com atributos), apenas um `dict`.
Você pode usar a função `jsonable_encoder` para resolver isso.
A função recebe um objeto, como um modelo Pydantic e retorna uma versão compatível com JSON:
=== "Python 3.6 e acima"
```Python hl_lines="5 22"
{!> ../../../docs_src/encoder/tutorial001.py!}
```
=== "Python 3.10 e acima"
```Python hl_lines="4 21"
{!> ../../../docs_src/encoder/tutorial001_py310.py!}
```
Neste exemplo, ele converteria o modelo Pydantic em um `dict`, e o `datetime` em um `str`.
O resultado de chamar a função é algo que pode ser codificado com o padrão do Python <a href="https://docs.python.org/3/library/json.html#json.dumps" class="external-link" target="_blank">`json.dumps()`</a>.
A função não retorna um grande `str` contendo os dados no formato JSON (como uma string). Mas sim, retorna uma estrutura de dados padrão do Python (por exemplo, um `dict`) com valores e subvalores compatíveis com JSON.
!!! nota
`jsonable_encoder` é realmente usado pelo **FastAPI** internamente para converter dados. Mas também é útil em muitos outros cenários.

View File

@@ -0,0 +1,36 @@
# Formulários e Arquivos da Requisição
Você pode definir arquivos e campos de formulário ao mesmo tempo usando `File` e `Form`.
!!! info "Informação"
Para receber arquivos carregados e/ou dados de formulário, primeiro instale <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>.
Por exemplo: `pip install python-multipart`.
## Importe `File` e `Form`
```Python hl_lines="1"
{!../../../docs_src/request_forms_and_files/tutorial001.py!}
```
## Defina parâmetros de `File` e `Form`
Crie parâmetros de arquivo e formulário da mesma forma que você faria para `Body` ou `Query`:
```Python hl_lines="8"
{!../../../docs_src/request_forms_and_files/tutorial001.py!}
```
Os arquivos e campos de formulário serão carregados como dados de formulário e você receberá os arquivos e campos de formulário.
E você pode declarar alguns dos arquivos como `bytes` e alguns como `UploadFile`.
!!! warning "Aviso"
Você pode declarar vários parâmetros `File` e `Form` em uma *operação de caminho*, mas não é possível declarar campos `Body` para receber como JSON, pois a requisição terá o corpo codificado usando `multipart/form-data` ao invés de `application/json`.
Isso não é uma limitação do **FastAPI** , é parte do protocolo HTTP.
## Recapitulando
Usar `File` e `Form` juntos quando precisar receber dados e arquivos na mesma requisição.

View File

@@ -0,0 +1,39 @@
# Arquivos Estáticos
Você pode servir arquivos estáticos automaticamente de um diretório usando `StaticFiles`.
## Use `StaticFiles`
* Importe `StaticFiles`.
* "Monte" uma instância de `StaticFiles()` em um caminho específico.
```Python hl_lines="2 6"
{!../../../docs_src/static_files/tutorial001.py!}
```
!!! note "Detalhes técnicos"
Você também pode usar `from starlette.staticfiles import StaticFiles`.
O **FastAPI** fornece o mesmo que `starlette.staticfiles` como `fastapi.staticfiles` apenas como uma conveniência para você, o desenvolvedor. Mas na verdade vem diretamente da Starlette.
### O que é "Montagem"
"Montagem" significa adicionar um aplicativo completamente "independente" em uma rota específica, que então cuida de todas as subrotas.
Isso é diferente de usar um `APIRouter`, pois um aplicativo montado é completamente independente. A OpenAPI e a documentação do seu aplicativo principal não incluirão nada do aplicativo montado, etc.
Você pode ler mais sobre isso no **Guia Avançado do Usuário**.
## Detalhes
O primeiro `"/static"` refere-se à subrota em que este "subaplicativo" será "montado". Portanto, qualquer caminho que comece com `"/static"` será tratado por ele.
O `directory="static"` refere-se ao nome do diretório que contém seus arquivos estáticos.
O `name="static"` dá a ela um nome que pode ser usado internamente pelo FastAPI.
Todos esses parâmetros podem ser diferentes de "`static`", ajuste-os de acordo com as necessidades e detalhes específicos de sua própria aplicação.
## Mais informações
Para mais detalhes e opções, verifique <a href="https://www.starlette.io/staticfiles/" class="external-link" target="_blank">Starlette's docs about Static Files</a>.

View File

@@ -75,10 +75,13 @@ nav:
- tutorial/header-params.md
- tutorial/response-status-code.md
- tutorial/request-forms.md
- tutorial/request-forms-and-files.md
- tutorial/handling-errors.md
- tutorial/encoder.md
- Segurança:
- tutorial/security/index.md
- tutorial/background-tasks.md
- tutorial/static-files.md
- Guia de Usuário Avançado:
- advanced/index.md
- Implantação:
@@ -86,6 +89,7 @@ nav:
- deployment/versions.md
- deployment/https.md
- deployment/deta.md
- deployment/docker.md
- alternatives.md
- history-design-future.md
- external-links.md

View File

@@ -0,0 +1,469 @@
# Участие в разработке фреймворка
Возможно, для начала Вам стоит ознакомиться с основными способами [помочь FastAPI или получить помощь](help-fastapi.md){.internal-link target=_blank}.
## Разработка
Если Вы уже склонировали репозиторий и знаете, что Вам нужно более глубокое погружение в код фреймворка, то здесь представлены некоторые инструкции по настройке виртуального окружения.
### Виртуальное окружение с помощью `venv`
Находясь в нужной директории, Вы можете создать виртуальное окружение при помощи Python модуля `venv`.
<div class="termy">
```console
$ python -m venv env
```
</div>
Эта команда создаст директорию `./env/` с бинарными (двоичными) файлами Python, а затем Вы сможете скачивать и устанавливать необходимые библиотеки в изолированное виртуальное окружение.
### Активация виртуального окружения
Активируйте виртуально окружение командой:
=== "Linux, macOS"
<div class="termy">
```console
$ source ./env/bin/activate
```
</div>
=== "Windows PowerShell"
<div class="termy">
```console
$ .\env\Scripts\Activate.ps1
```
</div>
=== "Windows Bash"
Если Вы пользуетесь Bash для Windows (например: <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
<div class="termy">
```console
$ source ./env/Scripts/activate
```
</div>
Проверьте, что всё сработало:
=== "Linux, macOS, Windows Bash"
<div class="termy">
```console
$ which pip
some/directory/fastapi/env/bin/pip
```
</div>
=== "Windows PowerShell"
<div class="termy">
```console
$ Get-Command pip
some/directory/fastapi/env/bin/pip
```
</div>
Ели в терминале появится ответ, что бинарник `pip` расположен по пути `.../env/bin/pip`, значит всё в порядке. 🎉
Во избежание ошибок в дальнейших шагах, удостоверьтесь, что в Вашем виртуальном окружении установлена последняя версия `pip`:
<div class="termy">
```console
$ python -m pip install --upgrade pip
---> 100%
```
</div>
!!! tip "Подсказка"
Каждый раз, перед установкой новой библиотеки в виртуальное окружение при помощи `pip`, не забудьте активировать это виртуальное окружение.
Это гарантирует, что если Вы используете библиотеку, установленную этим пакетом, то Вы используете библиотеку из Вашего локального окружения, а не любую другую, которая может быть установлена глобально.
### pip
После активации виртуального окружения, как было указано ранее, введите следующую команду:
<div class="termy">
```console
$ pip install -e ."[dev,doc,test]"
---> 100%
```
</div>
Это установит все необходимые зависимости в локальное окружение для Вашего локального FastAPI.
#### Использование локального FastAPI
Если Вы создаёте Python файл, который импортирует и использует FastAPI,а затем запускаете его интерпретатором Python из Вашего локального окружения, то он будет использовать код из локального FastAPI.
И, так как при вводе вышеупомянутой команды был указан флаг `-e`, если Вы измените код локального FastAPI, то при следующем запуске этого файла, он будет использовать свежую версию локального FastAPI, который Вы только что изменили.
Таким образом, Вам не нужно "переустанавливать" Вашу локальную версию, чтобы протестировать каждое изменение.
### Форматировние
Скачанный репозиторий содержит скрипт, который может отформатировать и подчистить Ваш код:
<div class="termy">
```console
$ bash scripts/format.sh
```
</div>
Заодно он упорядочит Ваши импорты.
Чтобы он сортировал их правильно, необходимо, чтобы FastAPI был установлен локально в Вашей среде, с помощью команды из раздела выше, использующей флаг `-e`.
## Документация
Прежде всего, убедитесь, что Вы настроили своё окружение, как описано выше, для установки всех зависимостей.
Документация использует <a href="https://www.mkdocs.org/" class="external-link" target="_blank">MkDocs</a>.
Также существуют дополнительные инструменты/скрипты для работы с переводами в `./scripts/docs.py`.
!!! tip "Подсказка"
Нет необходимости заглядывать в `./scripts/docs.py`, просто используйте это в командной строке.
Вся документация имеет формат Markdown и расположена в директории `./docs/en/`.
Многие руководства содержат блоки кода.
В большинстве случаев эти блоки кода представляют собой вполне законченные приложения, которые можно запускать как есть.
На самом деле, эти блоки кода не написаны внутри Markdown, это Python файлы в директории `./docs_src/`.
И эти Python файлы включаются/вводятся в документацию при создании сайта.
### Тестирование документации
Фактически, большинство тестов запускаются с примерами исходных файлов в документации.
Это помогает убедиться, что:
* Документация находится в актуальном состоянии.
* Примеры из документации могут быть запущены как есть.
* Большинство функций описаны в документации и покрыты тестами.
Существует скрипт, который во время локальной разработки создаёт сайт и проверяет наличие любых изменений, перезагружая его в реальном времени:
<div class="termy">
```console
$ python ./scripts/docs.py live
<span style="color: green;">[INFO]</span> Serving on http://127.0.0.1:8008
<span style="color: green;">[INFO]</span> Start watching changes
<span style="color: green;">[INFO]</span> Start detecting changes
```
</div>
Он запустит сайт документации по адресу: `http://127.0.0.1:8008`.
Таким образом, Вы сможете редактировать файлы с документацией или кодом и наблюдать изменения вживую.
#### Typer CLI (опционально)
Приведенная ранее инструкция показала Вам, как запускать скрипт `./scripts/docs.py` непосредственно через интерпретатор `python` .
Но также можно использовать <a href="https://typer.tiangolo.com/typer-cli/" class="external-link" target="_blank">Typer CLI</a>, что позволит Вам воспользоваться автозаполнением команд в Вашем терминале.
Если Вы установили Typer CLI, то для включения функции автозаполнения, введите эту команду:
<div class="termy">
```console
$ typer --install-completion
zsh completion installed in /home/user/.bashrc.
Completion will take effect once you restart the terminal.
```
</div>
### Приложения и документация одновременно
Если Вы запускаете приложение, например так:
<div class="termy">
```console
$ uvicorn tutorial001:app --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
По умолчанию Uvicorn будет использовать порт `8000` и не будет конфликтовать с сайтом документации, использующим порт `8008`.
### Переводы на другие языки
Помощь с переводами ценится КРАЙНЕ ВЫСОКО! И переводы не могут быть сделаны без помощи сообщества. 🌎 🚀
Ниже приведены шаги, как помочь с переводами.
#### Подсказки и инструкции
* Проверьте <a href="https://github.com/tiangolo/fastapi/pulls" class="external-link" target="_blank">существующие пул-реквесты</a> для Вашего языка. Добавьте отзывы с просьбой внести изменения, если они необходимы, или одобрите их.
!!! tip "Подсказка"
Вы можете <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/commenting-on-a-pull-request" class="external-link" target="_blank">добавлять комментарии с предложениями по изменению</a> в существующие пул-реквесты.
Ознакомьтесь с документацией о <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-reviews" class="external-link" target="_blank">добавлении отзыва к пул-реквесту</a>, чтобы утвердить его или запросить изменения.
* Проверьте <a href="https://github.com/tiangolo/fastapi/issues" class="external-link" target="_blank">проблемы и вопросы</a>, чтобы узнать, есть ли кто-то, координирующий переводы для Вашего языка.
* Добавляйте один пул-реквест для каждой отдельной переведённой страницы. Это значительно облегчит другим его просмотр.
Для языков, которые я не знаю, прежде чем добавить перевод в основную ветку, я подожду пока несколько других участников сообщества проверят его.
* Вы также можете проверить, есть ли переводы для Вашего языка и добавить к ним отзыв, который поможет мне убедиться в правильности перевода. Тогда я смогу объединить его с основной веткой.
* Используйте те же самые примеры кода Python. Переводите только текст документации. Вам не нужно ничего менять, чтобы эти примеры работали.
* Используйте те же самые изображения, имена файлов и ссылки. Вы не должны менять ничего для сохранения работоспособности.
* Чтобы узнать 2-буквенный код языка, на который Вы хотите сделать перевод, Вы можете воспользоваться таблицей <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes" class="external-link" target="_blank">Список кодов языков ISO 639-1</a>.
#### Существующий язык
Допустим, Вы хотите перевести страницу на язык, на котором уже есть какие-то переводы, например, на испанский.
Кодом испанского языка является `es`. А значит директория для переводов на испанский язык: `docs/es/`.
!!! tip "Подсказка"
Главный ("официальный") язык - английский, директория для него `docs/en/`.
Вы можете запустить сервер документации на испанском:
<div class="termy">
```console
// Используйте команду "live" и передайте код языка в качестве аргумента командной строки
$ python ./scripts/docs.py live es
<span style="color: green;">[INFO]</span> Serving on http://127.0.0.1:8008
<span style="color: green;">[INFO]</span> Start watching changes
<span style="color: green;">[INFO]</span> Start detecting changes
```
</div>
Теперь Вы можете перейти по адресу: <a href="http://127.0.0.1:8008" class="external-link" target="_blank">http://127.0.0.1:8008</a> и наблюдать вносимые Вами изменения вживую.
Если Вы посмотрите на сайт документации FastAPI, то увидите, что все страницы есть на каждом языке. Но некоторые страницы не переведены и имеют уведомление об отсутствующем переводе.
Но когда Вы запускаете сайт локально, Вы видите только те страницы, которые уже переведены.
Предположим, что Вы хотите добавить перевод страницы [Основные свойства](features.md){.internal-link target=_blank}.
* Скопируйте файл:
```
docs/en/docs/features.md
```
* Вставьте его точно в то же место, но в директорию языка, на который Вы хотите сделать перевод, например:
```
docs/es/docs/features.md
```
!!! tip "Подсказка"
Заметьте, что в пути файла мы изменили только код языка с `en` на `es`.
* Теперь откройте файл конфигурации MkDocs для английского языка, расположенный тут:
```
docs/en/mkdocs.yml
```
* Найдите в файле конфигурации место, где расположена строка `docs/features.md`. Похожее на это:
```YAML hl_lines="8"
site_name: FastAPI
# More stuff
nav:
- FastAPI: index.md
- Languages:
- en: /
- es: /es/
- features.md
```
* Откройте файл конфигурации MkDocs для языка, на который Вы переводите, например:
```
docs/es/mkdocs.yml
```
* Добавьте строку `docs/features.md` точно в то же место, как и в случае для английского, как-то так:
```YAML hl_lines="8"
site_name: FastAPI
# More stuff
nav:
- FastAPI: index.md
- Languages:
- en: /
- es: /es/
- features.md
```
Убедитесь, что при наличии других записей, новая запись с Вашим переводом находится точно в том же порядке, что и в английской версии.
Если Вы зайдёте в свой браузер, то увидите, что в документации стал отображаться Ваш новый раздел.🎉
Теперь Вы можете переводить эту страницу и смотреть, как она выглядит при сохранении файла.
#### Новый язык
Допустим, Вы хотите добавить перевод для языка, на который пока что не переведена ни одна страница.
Скажем, Вы решили сделать перевод для креольского языка, но его еще нет в документации.
Перейдите в таблицу кодов языков по ссылке указанной выше, где найдёте, что кодом креольского языка является `ht`.
Затем запустите скрипт, генерирующий директорию для переводов на новые языки:
<div class="termy">
```console
// Используйте команду new-lang и передайте код языка в качестве аргумента командной строки
$ python ./scripts/docs.py new-lang ht
Successfully initialized: docs/ht
Updating ht
Updating en
```
</div>
После чего Вы можете проверить в своем редакторе кода, что появился новый каталог `docs/ht/`.
!!! tip "Подсказка"
Создайте первый пул-реквест, который будет содержать только пустую директорию для нового языка, прежде чем добавлять переводы.
Таким образом, другие участники могут переводить другие страницы, пока Вы работаете над одной. 🚀
Начните перевод с главной страницы `docs/ht/index.md`.
В дальнейшем можно действовать, как указано в предыдущих инструкциях для "существующего языка".
##### Новый язык не поддерживается
Если при запуске скрипта `./scripts/docs.py live` Вы получаете сообщение об ошибке, что язык не поддерживается, что-то вроде:
```
raise TemplateNotFound(template)
jinja2.exceptions.TemplateNotFound: partials/language/xx.html
```
Сие означает, что тема не поддерживает этот язык (в данном случае с поддельным 2-буквенным кодом `xx`).
Но не стоит переживать. Вы можете установить языком темы английский, а затем перевести текст документации.
Если возникла такая необходимость, отредактируйте `mkdocs.yml` для Вашего нового языка. Это будет выглядеть как-то так:
```YAML hl_lines="5"
site_name: FastAPI
# More stuff
theme:
# More stuff
language: xx
```
Измените `xx` (код Вашего языка) на `en` и перезапустите сервер.
#### Предпросмотр результата
Когда Вы запускаете скрипт `./scripts/docs.py` с командой `live`, то будут показаны файлы и переводы для указанного языка.
Но когда Вы закончите, то можете посмотреть, как это будет выглядеть по-настоящему.
Для этого сначала создайте всю документацию:
<div class="termy">
```console
// Используйте команду "build-all", это займёт немного времени
$ python ./scripts/docs.py build-all
Updating es
Updating en
Building docs for: en
Building docs for: es
Successfully built docs for: es
Copying en index.md to README.md
```
</div>
Скрипт сгенерирует `./docs_build/` для каждого языка. Он добавит все файлы с отсутствующими переводами с пометкой о том, что "у этого файла еще нет перевода". Но Вам не нужно ничего делать с этим каталогом.
Затем он создаст независимые сайты MkDocs для каждого языка, объединит их и сгенерирует конечный результат на `./site/`.
После чего Вы сможете запустить сервер со всеми языками командой `serve`:
<div class="termy">
```console
// Используйте команду "serve" после того, как отработает команда "build-all"
$ python ./scripts/docs.py serve
Warning: this is a very simple server. For development, use mkdocs serve instead.
This is here only to preview a site with translations already built.
Make sure you run the build-all command first.
Serving at: http://127.0.0.1:8008
```
</div>
## Тесты
Также в репозитории есть скрипт, который Вы можете запустить локально, чтобы протестировать весь код и сгенерировать отчеты о покрытии тестами в HTML:
<div class="termy">
```console
$ bash scripts/test-cov-html.sh
```
</div>
Эта команда создаст директорию `./htmlcov/`, в которой будет файл `./htmlcov/index.html`. Открыв его в Вашем браузере, Вы можете в интерактивном режиме изучить, все ли части кода охвачены тестами.

View File

@@ -0,0 +1,21 @@
# Развёртывание - Введение
Развернуть приложение **FastAPI** довольно просто.
## Да что такое это ваше - "развёртывание"?!
Термин **развёртывание** (приложения) означает выполнение необходимых шагов, чтобы сделать приложение **доступным для пользователей**.
Обычно **веб-приложения** размещают на удалённом компьютере с серверной программой, которая обеспечивает хорошую производительность, стабильность и т. д., Чтобы ваши пользователи могли эффективно, беспрерывно и беспроблемно обращаться к приложению.
Это отличется от **разработки**, когда вы постоянно меняете код, делаете в нём намеренные ошибки и исправляете их, останавливаете и перезапускаете сервер разработки и т. д.
## Стратегии развёртывания
В зависимости от вашего конкретного случая, есть несколько способов сделать это.
Вы можете **развернуть сервер** самостоятельно, используя различные инструменты. Например, можно использовать **облачный сервис**, который выполнит часть работы за вас. Также возможны и другие варианты.
В этом блоке я покажу вам некоторые из основных концепций, которые вы, вероятно, должны иметь в виду при развертывании приложения **FastAPI** (хотя большинство из них применимо к любому другому типу веб-приложений).
В последующих разделах вы узнаете больше деталей и методов, необходимых для этого. ✨

View File

@@ -0,0 +1,180 @@
# Люди, поддерживающие FastAPI
У FastAPI замечательное сообщество, которое доброжелательно к людям с любым уровнем знаний.
## Создатель и хранитель
Ку! 👋
Это я:
{% if people %}
<div class="user-list user-list-center">
{% for user in people.maintainers %}
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Answers: {{ user.answers }}</div><div class="count">Pull Requests: {{ user.prs }}</div></div>
{% endfor %}
</div>
{% endif %}
Я создал и продолжаю поддерживать **FastAPI**. Узнать обо мне больше можно тут [Помочь FastAPI - Получить помощь - Связаться с автором](help-fastapi.md#connect-with-the-author){.internal-link target=_blank}.
... но на этой странице я хочу показать вам наше сообщество.
---
**FastAPI** получает огромную поддержку от своего сообщества. И я хочу отметить вклад его участников.
Это люди, которые:
* [Помогают другим с их проблемами (вопросами) на GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank}.
* [Создают пул-реквесты](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}.
* Делают ревью пул-реквестов, [что особенно важно для переводов на другие языки](contributing.md#translations){.internal-link target=_blank}.
Поаплодируем им! 👏 🙇
## Самые активные участники за прошедший месяц
Эти участники [оказали наибольшую помощь другим с решением их проблем (вопросов) на GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} в течение последнего месяца. ☕
{% if people %}
<div class="user-list user-list-center">
{% for user in people.last_month_active %}
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Issues replied: {{ user.count }}</div></div>
{% endfor %}
</div>
{% endif %}
## Эксперты
Здесь представлены **Эксперты FastAPI**. 🤓
Эти участники [оказали наибольшую помощь другим с решением их проблем (вопросов) на GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} за *всё время*.
Оказывая помощь многим другим, они подтвердили свой уровень знаний. ✨
{% if people %}
<div class="user-list user-list-center">
{% for user in people.experts %}
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Issues replied: {{ user.count }}</div></div>
{% endfor %}
</div>
{% endif %}
## Рейтинг участников, внёсших вклад в код
Здесь представлен **Рейтинг участников, внёсших вклад в код**. 👷
Эти люди [сделали наибольшее количество пул-реквестов](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}, *включённых в основной код*.
Они сделали наибольший вклад в исходный код, документацию, переводы и т.п. 📦
{% if people %}
<div class="user-list user-list-center">
{% for user in people.top_contributors %}
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Pull Requests: {{ user.count }}</div></div>
{% endfor %}
</div>
{% endif %}
На самом деле таких людей довольно много (более сотни), вы можете увидеть всех на этой странице <a href="https://github.com/tiangolo/fastapi/graphs/contributors" class="external-link" target="_blank">FastAPI GitHub Contributors page</a>. 👷
## Рейтинг ревьюеров
Здесь представлен **Рейтинг ревьюеров**. 🕵️
### Проверки переводов на другие языки
Я знаю не очень много языков (и не очень хорошо 😅).
Итак, ревьюеры - это люди, которые могут [**подтвердить предложенный вами перевод** документации](contributing.md#translations){.internal-link target=_blank}. Без них не было бы документации на многих языках.
---
В **Рейтинге ревьюеров** 🕵️ представлены те, кто проверил наибольшее количество пул-реквестов других участников, обеспечивая качество кода, документации и, особенно, **переводов на другие языки**.
{% if people %}
<div class="user-list user-list-center">
{% for user in people.top_reviewers %}
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Reviews: {{ user.count }}</div></div>
{% endfor %}
</div>
{% endif %}
## Спонсоры
Здесь представлены **Спонсоры**. 😎
Спонсоры поддерживают мою работу над **FastAPI** (и другими проектами) главным образом через <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub Sponsors</a>.
{% if sponsors %}
{% if sponsors.gold %}
### Золотые спонсоры
{% for sponsor in sponsors.gold -%}
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
{% endfor %}
{% endif %}
{% if sponsors.silver %}
### Серебрянные спонсоры
{% for sponsor in sponsors.silver -%}
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
{% endfor %}
{% endif %}
{% if sponsors.bronze %}
### Бронзовые спонсоры
{% for sponsor in sponsors.bronze -%}
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
{% endfor %}
{% endif %}
{% endif %}
### Индивидуальные спонсоры
{% if github_sponsors %}
{% for group in github_sponsors.sponsors %}
<div class="user-list user-list-center">
{% for user in group %}
{% if user.login not in sponsors_badge.logins %}
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a></div>
{% endif %}
{% endfor %}
</div>
{% endfor %}
{% endif %}
## О данных - технические детали
Основная цель этой страницы - подчеркнуть усилия сообщества по оказанию помощи другим.
Особенно это касается усилий, которые обычно менее заметны и во многих случаях более трудоемки, таких как помощь другим в решении проблем и проверка пул-реквестов с переводами.
Данные рейтинги подсчитываются каждый месяц, ознакомиться с тем, как это работает можно <a href="https://github.com/tiangolo/fastapi/blob/master/.github/actions/people/app/main.py" class="external-link" target="_blank">тут</a>.
Кроме того, я также подчеркиваю вклад спонсоров.
И я оставляю за собой право обновлять алгоритмы подсчёта, виды рейтингов, пороговые значения и т.д. (так, на всякий случай 🤷).

View File

@@ -169,7 +169,7 @@ FastAPI включает в себя чрезвычайно простую в и
* Поддержка **WebSocket**.
* Фоновые задачи для процессов.
* События запуска и выключения.
* Тестовый клиент построен на библиотеке `requests`.
* Тестовый клиент построен на библиотеке HTTPX.
* **CORS**, GZip, статические файлы, потоковые ответы.
* Поддержка **сессий и cookie**.
* 100% покрытие тестами.

View File

@@ -0,0 +1,257 @@
# Помочь FastAPI - Получить помощь
Нравится ли Вам **FastAPI**?
Хотели бы Вы помочь FastAPI, его пользователям и автору?
Может быть у Вас возникли трудности с **FastAPI** и Вам нужна помощь?
Есть несколько очень простых способов оказания помощи (иногда достаточно всего лишь одного или двух кликов).
И также есть несколько способов получить помощь.
## Подписаться на новостную рассылку
Вы можете подписаться на редкую [новостную рассылку **FastAPI и его друзья**](/newsletter/){.internal-link target=_blank} и быть в курсе о:
* Новостях о FastAPI и его друзьях 🚀
* Руководствах 📝
* Возможностях ✨
* Исправлениях 🚨
* Подсказках и хитростях ✅
## Подписаться на FastAPI в Twitter
<a href="https://twitter.com/fastapi" class="external-link" target="_blank">Подписаться на @fastapi в **Twitter**</a> для получения наисвежайших новостей о **FastAPI**. 🐦
## Добавить **FastAPI** звезду на GitHub
Вы можете добавить FastAPI "звезду" на GitHub (кликнуть на кнопку звезды в верхнем правом углу экрана): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. ⭐️
Чем больше звёзд, тем легче другим пользователям найти нас и увидеть, что проект уже стал полезным для многих.
## Отслеживать свежие выпуски в репозитории на GitHub
Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. 👀
Там же Вы можете указать в настройках - "Releases only".
С такой настройкой Вы будете получать уведомления на вашу электронную почту каждый раз, когда появится новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми возможностями.
## Связаться с автором
Можно связаться со <a href="https://tiangolo.com" class="external-link" target="_blank">мной (Себястьян Рамирез / `tiangolo`)</a>, автором FastAPI.
Вы можете:
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">Подписаться на меня на **GitHub**</a>.
* Посмотреть другие мои проекты с открытым кодом, которые могут быть полезны Вам.
* Подписавшись на меня Вы сможете получать уведомления, что я создал новый проект с открытым кодом,.
* <a href="https://twitter.com/tiangolo" class="external-link" target="_blank">Подписаться на меня в **Twitter**</a> или в <a href="https://fosstodon.org/@tiangolo" class="external-link" target="_blank">Mastodon</a>.
* Поделиться со мной, как Вы используете FastAPI (я обожаю читать про это).
* Получать уведомления, когда я делаю объявления и представляю новые инструменты.
* Вы также можете <a href="https://twitter.com/fastapi" class="external-link" target="_blank">подписаться на @fastapi в Twitter</a> (это отдельный аккаунт).
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Подписаться на меня в **Linkedin**</a>.
* Получать уведомления, когда я делаю объявления и представляю новые инструменты (правда чаще всего я использую Twitter 🤷‍♂).
* Читать, что я пишу (или подписаться на меня) в <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> или в <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a>.
* Читать другие идеи, статьи и читать об инструментах созданных мной.
* Подпишитесь на меня, чтобы прочитать, когда я опубликую что-нибудь новое.
## Оставить сообщение в Twitter о **FastAPI**
<a href="https://twitter.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/tiangolo/fastapi" class="external-link" target="_blank">Оставьте сообщение в Twitter о **FastAPI**</a> и позвольте мне и другим узнать - почему он Вам нравится. 🎉
Я люблю узнавать о том, как **FastAPI** используется, что Вам понравилось в нём, в каких проектах/компаниях Вы используете его и т.п.
## Оставить голос за FastAPI
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Голосуйте за **FastAPI** в Slant</a>.
* <a href="https://alternativeto.net/software/fastapi/" class="external-link" target="_blank">Голосуйте за **FastAPI** в AlternativeTo</a>.
* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">Расскажите, как Вы используете **FastAPI** на StackShare</a>.
## Помочь другим с их проблемами на GitHub
Вы можете посмотреть, какие <a href="https://github.com/tiangolo/fastapi/issues" class="external-link" target="_blank">проблемы</a> испытывают другие люди и попытаться помочь им. Чаще всего это вопросы, на которые, весьма вероятно, Вы уже знаете ответ. 🤓
Если Вы будете много помогать людям с решением их проблем, Вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#experts){.internal-link target=_blank}. 🎉
Только помните, самое важное при этом - доброта. Столкнувшись с проблемой, люди расстраиваются и часто задают вопросы не лучшим образом, но постарайтесь быть максимально доброжелательным. 🤗
Идея сообщества **FastAPI** в том, чтобы быть добродушным и гостеприимными. Не допускайте издевательств или неуважительного поведения по отношению к другим. Мы должны заботиться друг о друге.
---
Как помочь другим с их проблемами:
### Понять вопрос
* Удостоверьтесь, что поняли **цель** и обстоятельства случая вопрошающего.
* Затем проверьте, что вопрос (в подавляющем большинстве - это вопросы) Вам **ясен**.
* Во многих случаях вопрос касается решения, которое пользователь придумал сам, но может быть и решение **получше**. Если Вы поймёте проблему и обстоятельства случая, то сможете предложить **альтернативное решение**.
* Ежели вопрос Вам непонятен, запросите больше **деталей**.
### Воспроизвести проблему
В большинстве случаев есть что-то связанное с **исходным кодом** вопрошающего.
И во многих случаях будет предоставлен только фрагмент этого кода, которого недостаточно для **воспроизведения проблемы**.
* Попросите предоставить <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">минимальный воспроизводимый пример</a>, который можно **скопировать** и запустить локально дабы увидеть такую же ошибку, или поведение, или лучше понять обстоятельства случая.
* Если на Вас нахлынуло великодушие, то можете попытаться **создать похожий пример** самостоятельно, основываясь только на описании проблемы. Но имейте в виду, что это может занять много времени и, возможно, стоит сначала позадавать вопросы для прояснения проблемы.
### Предложить решение
* После того как Вы поняли вопрос, Вы можете дать **ответ**.
* Следует понять **основную проблему и обстоятельства случая**, потому что может быть решение лучше, чем то, которое пытались реализовать.
### Попросить закрыть проблему
Если Вам ответили, высоки шансы, что Вам удалось решить проблему, поздравляю, **Вы - герой**! 🦸
* В таком случае, если вопрос решён, попросите **закрыть проблему**.
## Отслеживать репозиторий на GitHub
Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. 👀
Если Вы выберете "Watching" вместо "Releases only", то будете получать уведомления когда кто-либо попросит о помощи с решением его проблемы.
Тогда Вы можете попробовать решить эту проблему.
## Запросить помощь с решением проблемы
Вы можете <a href="https://github.com/tiangolo/fastapi/issues/new/choose" class="external-link" target="_blank">создать новый запрос с просьбой о помощи</a> в репозитории на GitHub, например:
* Задать **вопрос** или попросить помощи в решении **проблемы**.
* Предложить новое **улучшение**.
**Заметка**: Если Вы создаёте подобные запросы, то я попрошу Вас также оказывать аналогичную помощь другим. 😉
## Проверять пул-реквесты
Вы можете помочь мне проверять пул-реквесты других участников.
И повторюсь, постарайтесь быть доброжелательным. 🤗
---
О том, что нужно иметь в виду при проверке пул-реквестов:
### Понять проблему
* Во-первых, убедитесь, что **поняли проблему**, которую пул-реквест пытается решить. Для этого может потребоваться продолжительное обсуждение.
* Также есть вероятность, что пул-реквест не актуален, так как проблему можно решить **другим путём**. В таком случае Вы можете указать на этот факт.
### Не переживайте о стиле
* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах или количество коммитов. При слиянии пул-реквеста с основной веткой, я буду сжимать и настраивать всё вручную.
* Также не беспокойтесь о правилах стиля, для проверки сего есть автоматизированные инструменты.
И если всё же потребуется какой-то другой стиль, я попрошу Вас об этом напрямую или добавлю сам коммиты с необходимыми изменениями.
### Проверить код
* Проверьте и прочитайте код, посмотрите, какой он имеет смысл, **запустите его локально** и посмотрите, действительно ли он решает поставленную задачу.
* Затем, используя **комментарий**, сообщите, что Вы сделали проверку, тогда я буду знать, что Вы действительно проверили код.
!!! Информация
К сожалению, я не могу так просто доверять пул-реквестам, у которых уже есть несколько одобрений.
Бывали случаи, что пул-реквесты имели 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я проверял эти пул-реквесты, они оказывались сломаны, содержали ошибки или вовсе не решали проблему, которую, как они утверждали, должны были решить. 😅
Потому это действительно важно - проверять и запускать код, и комментарием уведомлять меня, что Вы проделали эти действия. 🤓
* Если Вы считаете, что пул-реквест можно упростить, то можете попросить об этом, но не нужно быть слишком придирчивым, может быть много субъективных точек зрения (и у меня тоже будет своя 🙈), поэтому будет лучше, если Вы сосредоточитесь на фундаментальных вещах.
### Тестировать
* Помогите мне проверить, что у пул-реквеста есть **тесты**.
* Проверьте, что тесты **падали** до пул-реквеста. 🚨
* Затем проверьте, что тесты **не валятся** после пул-реквеста. ✅
* Многие пул-реквесты не имеют тестов, Вы можете **напомнить** о необходимости добавления тестов или даже **предложить** какие-либо свои тесты. Это одна из тех вещей, которые отнимают много времени и Вы можете помочь с этим.
* Затем добавьте комментарий, что Вы испробовали в ходе проверки. Таким образом я буду знать, как Вы произвели проверку. 🤓
## Создать пул-реквест
Вы можете [сделать вклад](contributing.md){.internal-link target=_blank} в код фреймворка используя пул-реквесты, например:
* Исправить опечатку, которую Вы нашли в документации.
* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли <a href="https://github.com/tiangolo/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">изменив этот файл</a>.
* Убедитесь, что Вы добавили свою ссылку в начало соответствующего раздела.
* Помочь с [переводом документации](contributing.md#translations){.internal-link target=_blank} на Ваш язык.
* Вы также можете проверять переводы сделанные другими.
* Предложить новые разделы документации.
* Исправить существующуе проблемы/баги.
* Убедитесь, что добавили тесты.
* Добавить новую возможность.
* Убедитесь, что добавили тесты.
* Убедитесь, что добавили документацию, если она необходима.
## Помочь поддерживать FastAPI
Помогите мне поддерживать **FastAPI**! 🤓
Предстоит ещё много работы и, по большей части, **ВЫ** можете её сделать.
Основные задачи, которые Вы можете выполнить прямо сейчас:
* [Помочь другим с их проблемами на GitHub](#help-others-with-issues-in-github){.internal-link target=_blank} (смотрите вышестоящую секцию).
* [Проверить пул-реквесты](#review-pull-requests){.internal-link target=_blank} (смотрите вышестоящую секцию).
Эти две задачи **отнимают больше всего времени**. Это основная работа по поддержке FastAPI.
Если Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и следить за тем, чтобы он продолжал **развиваться быстрее и лучше**. 🚀
## Подключиться к чату
Подключайтесь к 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank"> чату в Discord</a> 👥 и общайтесь с другими участниками сообщества FastAPI.
!!! Подсказка
Вопросы по проблемам с фреймворком лучше задавать в <a href="https://github.com/tiangolo/fastapi/issues/new/choose" class="external-link" target="_blank">GitHub issues</a>, так больше шансов, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#experts){.internal-link target=_blank}.
Используйте этот чат только для бесед на отвлечённые темы.
Существует также <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">чат в Gitter</a>, но поскольку в нем нет каналов и расширенных функций, общение в нём сложнее, потому рекомендуемой системой является Discord.
### Не использовать чаты для вопросов
Имейте в виду, что чаты позволяют больше "свободного общения", потому там легко задавать вопросы, которые слишком общие и на которые труднее ответить, так что Вы можете не получить нужные Вам ответы.
В разделе "проблемы" на GitHub, есть шаблон, который поможет Вам написать вопрос правильно, чтобы Вам было легче получить хороший ответ или даже решить проблему самостоятельно, прежде чем Вы зададите вопрос. В GitHub я могу быть уверен, что всегда отвечаю на всё, даже если это займет какое-то время. И я не могу сделать то же самое в чатах. 😅
Кроме того, общение в чатах не так легкодоступно для поиска, как в GitHub, потому вопросы и ответы могут потеряться среди другого общения. И только проблемы решаемые на GitHub учитываются в получении лычки [Эксперт FastAPI](fastapi-people.md#experts){.internal-link target=_blank}, так что весьма вероятно, что Вы получите больше внимания на GitHub.
С другой стороны, в чатах тысячи пользователей, а значит есть большие шансы в любое время найти там кого-то, с кем можно поговорить. 😄
## Спонсировать автора
Вы также можете оказать мне финансовую поддержку посредством <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">спонсорства через GitHub</a>.
Там можно просто купить мне кофе ☕️ в знак благодарности. 😄
А ещё Вы можете стать Серебряным или Золотым спонсором для FastAPI. 🏅🎉
## Спонсировать инструменты, на которых зиждется мощь FastAPI
Как Вы могли заметить в документации, FastAPI опирается на плечи титанов: Starlette и Pydantic.
Им тоже можно оказать спонсорскую поддержку:
* <a href="https://github.com/sponsors/samuelcolvin" class="external-link" target="_blank">Samuel Colvin (Pydantic)</a>
* <a href="https://github.com/sponsors/encode" class="external-link" target="_blank">Encode (Starlette, Uvicorn)</a>
---
Благодарствую! 🚀

View File

@@ -424,7 +424,7 @@ item: Item
* **GraphQL** интеграция с <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> и другими библиотеками.
* Множество дополнительных функций (благодаря Starlette), таких как:
* **Веб-сокеты**
* очень простые тесты на основе `requests` и `pytest`
* очень простые тесты на основе HTTPX и `pytest`
* **CORS**
* **Cookie сеансы(сессии)**
* ...и многое другое.
@@ -444,7 +444,7 @@ item: Item
Используется Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Обязательно, если вы хотите использовать `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>HTTPX</code></a> - Обязательно, если вы хотите использовать `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Обязательно, если вы хотите использовать конфигурацию шаблона по умолчанию.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Обязательно, если вы хотите поддерживать форму <abbr title="преобразование строки, полученной из HTTP-запроса, в данные Python">"парсинга"</abbr> с помощью `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Обязательно, для поддержки `SessionMiddleware`.

View File

@@ -0,0 +1,69 @@
# Body - Поля
Таким же способом, как вы объявляете дополнительную валидацию и метаданные в параметрах *функции обработки пути* с помощью функций `Query`, `Path` и `Body`, вы можете объявлять валидацию и метаданные внутри Pydantic моделей, используя функцию `Field` из Pydantic.
## Импорт `Field`
Сначала вы должны импортировать его:
=== "Python 3.6 и выше"
```Python hl_lines="4"
{!> ../../../docs_src/body_fields/tutorial001.py!}
```
=== "Python 3.10 и выше"
```Python hl_lines="2"
{!> ../../../docs_src/body_fields/tutorial001_py310.py!}
```
!!! warning "Внимание"
Обратите внимание, что функция `Field` импортируется непосредственно из `pydantic`, а не из `fastapi`, как все остальные функции (`Query`, `Path`, `Body` и т.д.).
## Объявление атрибутов модели
Вы можете использовать функцию `Field` с атрибутами модели:
=== "Python 3.6 и выше"
```Python hl_lines="11-14"
{!> ../../../docs_src/body_fields/tutorial001.py!}
```
=== "Python 3.10 и выше"
```Python hl_lines="9-12"
{!> ../../../docs_src/body_fields/tutorial001_py310.py!}
```
Функция `Field` работает так же, как `Query`, `Path` и `Body`, у ее такие же параметры и т.д.
!!! note "Технические детали"
На самом деле, `Query`, `Path` и другие функции, которые вы увидите в дальнейшем, создают объекты подклассов общего класса `Param`, который сам по себе является подклассом `FieldInfo` из Pydantic.
И `Field` (из Pydantic), и `Body`, оба возвращают объекты подкласса `FieldInfo`.
У класса `Body` есть и другие подклассы, с которыми вы ознакомитесь позже.
Помните, что когда вы импортируете `Query`, `Path` и другое из `fastapi`, это фактически функции, которые возвращают специальные классы.
!!! tip "Подсказка"
Обратите внимание, что каждый атрибут модели с типом, значением по умолчанию и `Field` имеет ту же структуру, что и параметр *функции обработки пути* с `Field` вместо `Path`, `Query` и `Body`.
## Добавление дополнительной информации
Вы можете объявлять дополнительную информацию в `Field`, `Query`, `Body` и т.п. Она будет включена в сгенерированную JSON схему.
Вы узнаете больше о добавлении дополнительной информации позже в документации, когда будете изучать, как задавать примеры принимаемых данных.
!!! warning "Внимание"
Дополнительные ключи, переданные в функцию `Field`, также будут присутствовать в сгенерированной OpenAPI схеме вашего приложения.
Поскольку эти ключи не являются обязательной частью спецификации OpenAPI, некоторые инструменты OpenAPI, например, [валидатор OpenAPI](https://validator.swagger.io/), могут не работать с вашей сгенерированной схемой.
## Резюме
Вы можете использовать функцию `Field` из Pydantic, чтобы задавать дополнительную валидацию и метаданные для атрибутов модели.
Вы также можете использовать дополнительные ключевые аргументы, чтобы добавить метаданные JSON схемы.

View File

@@ -59,13 +59,17 @@ nav:
- uk: /uk/
- zh: /zh/
- features.md
- fastapi-people.md
- python-types.md
- Учебник - руководство пользователя:
- tutorial/body-fields.md
- tutorial/background-tasks.md
- external-links.md
- async.md
- Развёртывание:
- deployment/index.md
- deployment/versions.md
- external-links.md
- contributing.md
markdown_extensions:
- toc:
permalink: true

View File

@@ -426,7 +426,7 @@ For a more complete example including more features, see the <a href="https://fa
* Many extra features (thanks to Starlette) as:
* **WebSockets**
* **GraphQL**
* extremely easy tests based on `requests` and `pytest`
* extremely easy tests based on HTTPX and `pytest`
* **CORS**
* **Cookie Sessions**
* ...and more.
@@ -446,7 +446,7 @@ Used by Pydantic:
Used by Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.

View File

@@ -429,7 +429,7 @@ For a more complete example including more features, see the <a href="https://fa
* **GraphQL** integration with <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> and other libraries.
* Many extra features (thanks to Starlette) as:
* **WebSockets**
* extremely easy tests based on `requests` and `pytest`
* extremely easy tests based on HTTPX and `pytest`
* **CORS**
* **Cookie Sessions**
* ...and more.
@@ -449,7 +449,7 @@ Used by Pydantic:
Used by Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.

View File

@@ -174,7 +174,7 @@ Bütün entegrasyonlar kullanımı kolay olmak üzere (zorunluluklar ile beraber
* **GraphQL** desteği.
* Kullanım halinde arka plan işlevleri.
* Başlatma ve kapatma eventleri(startup and shutdown).
* Test sunucusu `requests` üzerine kurulu.
* Test sunucusu HTTPX üzerine kurulu.
* **CORS**, GZip, Static dosyalar, Streaming responseları.
* **Session and Cookie** desteği.
* 100% test kapsayıcılığı.

View File

@@ -434,7 +434,7 @@ Daha fazla örnek ve özellik için <a href="https://fastapi.tiangolo.com/tutori
* Diğer ekstra özellikler (Starlette sayesinde):
* **WebSockets**
* **GraphQL**
* `requests` ve `pytest` sayesinde aşırı kolay testler.
* HTTPX ve `pytest` sayesinde aşırı kolay testler.
* **CORS**
* **Cookie Sessions**
* ...ve daha fazlası.
@@ -454,7 +454,7 @@ Pydantic tarafında kullanılan:
Starlette tarafında kullanılan:
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - Eğer `TestClient` kullanmak istiyorsan gerekli.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Eğer `TestClient` kullanmak istiyorsan gerekli.
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Eğer kendine ait template konfigürasyonu oluşturmak istiyorsan gerekli
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Form kullanmak istiyorsan gerekli <abbr title="HTTP bağlantısından gelen stringi Python objesine çevirmek için">("dönüşümü")</abbr>.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` desteği için gerekli.

View File

@@ -0,0 +1,336 @@
# İlk Adımlar
En basit FastAPI dosyası şu şekildedir:
```Python
{!../../../docs_src/first_steps/tutorial001.py!}
```
Bunu bir `main.py` dosyasına kopyalayın.
Projeyi çalıştırın:
<div class="termy">
```console
$ uvicorn main:app --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<span style="color: green;">INFO</span>: Started reloader process [28720]
<span style="color: green;">INFO</span>: Started server process [28722]
<span style="color: green;">INFO</span>: Waiting for application startup.
<span style="color: green;">INFO</span>: Application startup complete.
```
</div>
!!! note
`uvicorn main:app` komutu şunu ifade eder:
* `main`: `main.py` dosyası (the Python "module").
* `app`: `main.py` dosyası içerisinde `app = FastAPI()` satırıyla oluşturulan nesne.
* `--reload`: Kod değişikliği sonrasında sunucunun yeniden başlatılmasını sağlar. Yalnızca geliştirme için kullanın.
Çıktıda şu şekilde bir satır vardır:
```hl_lines="4"
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
Bu satır, yerel makinenizde uygulamanızın sunulduğu URL'yi gösterir.
### Kontrol Et
Tarayıcınızda <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a> adresini açın.
Bir JSON yanıtı göreceksiniz:
```JSON
{"message": "Hello World"}
```
### İnteraktif API dokümantasyonu
<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresine gidin.
Otomatik oluşturulmuş( <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a> tarafından sağlanan) interaktif bir API dokümanı göreceksiniz:
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### Alternatif API dokümantasyonu
Şimdi, <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> adresine gidin.
Otomatik oluşturulmuş(<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> tarafından sağlanan) bir API dokümanı göreceksiniz:
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
### OpenAPI
**FastAPI**, **OpenAPI** standardını kullanarak tüm API'lerinizi açıklayan bir "şema" oluşturur.
#### "Şema"
Bir "şema", bir şeyin tanımı veya açıklamasıdır. Soyut bir açıklamadır, uygulayan kod değildir.
#### API "şemaları"
Bu durumda, <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a>, API şemasını nasıl tanımlayacağınızı belirten şartnamelerdir.
Bu şema tanımı, API yollarınızı, aldıkları olası parametreleri vb. içerir.
#### Data "şema"
"Şema" terimi, JSON içeriği gibi bazı verilerin şeklini de ifade edebilir.
Bu durumda, JSON öznitelikleri ve sahip oldukları veri türleri vb. anlamına gelir.
#### OpenAPI and JSON Şema
OpenAPI, API'niz için bir API şeması tanımlar. Ve bu şema, JSON veri şemaları standardı olan **JSON Şema** kullanılarak API'niz tarafından gönderilen ve alınan verilerin tanımlarını (veya "şemalarını") içerir.
#### `openapi.json` kontrol et
OpenAPI şemasının nasıl göründüğünü merak ediyorsanız, FastAPI otomatik olarak tüm API'nizin açıklamalarını içeren bir JSON (şema) oluşturur.
Doğrudan şu adreste görebilirsiniz: <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
Aşağıdaki gibi bir şeyle başlayan bir JSON gösterecektir:
```JSON
{
"openapi": "3.0.2",
"info": {
"title": "FastAPI",
"version": "0.1.0"
},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
...
```
#### OpenAPI ne içindir?
OpenAPI şeması, dahili olarak bulunan iki etkileşimli dokümantasyon sistemine güç veren şeydir.
Ve tamamen OpenAPI'ye dayalı düzinelerce alternatif vardır. **FastAPI** ile oluşturulmuş uygulamanıza bu alternatiflerden herhangi birini kolayca ekleyebilirsiniz.
API'nizle iletişim kuran istemciler için otomatik olarak kod oluşturmak için de kullanabilirsiniz. Örneğin, frontend, mobil veya IoT uygulamaları.
## Adım adım özet
### Adım 1: `FastAPI`yi içe aktarın
```Python hl_lines="1"
{!../../../docs_src/first_steps/tutorial001.py!}
```
`FastAPI`, API'niz için tüm fonksiyonları sağlayan bir Python sınıfıdır.
!!! note "Teknik Detaylar"
`FastAPI` doğrudan `Starlette` kalıtım alan bir sınıftır.
Tüm <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> fonksiyonlarını `FastAPI` ile de kullanabilirsiniz.
### Adım 2: Bir `FastAPI` örneği oluşturun
```Python hl_lines="3"
{!../../../docs_src/first_steps/tutorial001.py!}
```
Burada `app` değişkeni `FastAPI` sınıfının bir örneği olacaktır.
Bu tüm API'yi oluşturmak için ana etkileşim noktası olacaktır.
`uvicorn` komutunda atıfta bulunulan `app` ile aynıdır.
<div class="termy">
```console
$ uvicorn main:app --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
Uygulamanızı aşağıdaki gibi oluşturursanız:
```Python hl_lines="3"
{!../../../docs_src/first_steps/tutorial002.py!}
```
Ve bunu `main.py` dosyasına koyduktan sonra `uvicorn` komutunu şu şekilde çağırabilirsiniz:
<div class="termy">
```console
$ uvicorn main:my_awesome_api --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
### Adım 3: *Path işlemleri* oluşturmak
#### Path
Burada "Path" URL'de ilk "\" ile başlayan son bölümü ifade eder.
Yani, şu şekilde bir URL'de:
```
https://example.com/items/foo
```
... path şöyle olabilir:
```
/items/foo
```
!!! info
Genellikle bir "path", "endpoint" veya "route" olarak adlandırılabilir.
Bir API oluştururken, "path", "resource" ile "concern" ayırmanın ana yoludur.
#### İşlemler
Burada "işlem" HTTP methodlarından birini ifade eder.
Onlardan biri:
* `POST`
* `GET`
* `PUT`
* `DELETE`
... ve daha egzotik olanları:
* `OPTIONS`
* `HEAD`
* `PATCH`
* `TRACE`
HTTP protokolünde, bu "methodlardan" birini (veya daha fazlasını) kullanarak her path ile iletişim kurabilirsiniz.
---
API'lerinizi oluştururkan, belirli bir işlemi gerçekleştirirken belirli HTTP methodlarını kullanırsınız.
Normalde kullanılan:
* `POST`: veri oluşturmak.
* `GET`: veri okumak.
* `PUT`: veriyi güncellemek.
* `DELETE`: veriyi silmek.
Bu nedenle, OpenAPI'de HTTP methodlarından her birine "işlem" denir.
Bizde onlara "**işlemler**" diyeceğiz.
#### Bir *Path işlem decoratorleri* tanımlanmak
```Python hl_lines="6"
{!../../../docs_src/first_steps/tutorial001.py!}
```
`@app.get("/")` **FastAPI'ye** aşağıdaki fonksiyonun adresine giden istekleri işlemekten sorumlu olduğunu söyler:
* path `/`
* <abbr title="an HTTP GET method"><code>get</code> işlemi</abbr> kullanılarak
!!! info "`@decorator` Bilgisi"
Python `@something` şeklinde ifadeleri "decorator" olarak adlandırır.
Decoratoru bir fonksiyonun üzerine koyarsınız. Dekoratif bir şapka gibi (Sanırım terim buradan gelmektedir).
Bir "decorator" fonksiyonu alır ve bazı işlemler gerçekleştir.
Bizim durumumzda decarator **FastAPI'ye** fonksiyonun bir `get` işlemi ile `/` pathine geldiğini söyler.
Bu **path işlem decoratordür**
Ayrıca diğer işlemleri de kullanabilirsiniz:
* `@app.post()`
* `@app.put()`
* `@app.delete()`
Ve daha egzotik olanları:
* `@app.options()`
* `@app.head()`
* `@app.patch()`
* `@app.trace()`
!!! tip
Her işlemi (HTTP method) istediğiniz gibi kullanmakta özgürsünüz.
**FastAPI** herhangi bir özel anlamı zorlamaz.
Buradaki bilgiler bir gereklilik değil, bir kılavuz olarak sunulmaktadır.
Örneğin, GraphQL kullanırkan normalde tüm işlemleri yalnızca `POST` işlemini kullanarak gerçekleştirirsiniz.
### Adım 4: **path işlem fonksiyonunu** tanımlayın
Aşağıdakiler bizim **path işlem fonksiyonlarımızdır**:
* **path**: `/`
* **işlem**: `get`
* **function**: "decorator"ün altındaki fonksiyondur (`@app.get("/")` altında).
```Python hl_lines="7"
{!../../../docs_src/first_steps/tutorial001.py!}
```
Bu bir Python fonksiyonudur.
Bir `GET` işlemi kullanarak "`/`" URL'sine bir istek geldiğinde **FastAPI** tarafından çağrılır.
Bu durumda bir `async` fonksiyonudur.
---
Bunu `async def` yerine normal bir fonksiyon olarakta tanımlayabilirsiniz.
```Python hl_lines="7"
{!../../../docs_src/first_steps/tutorial003.py!}
```
!!! note
Eğer farkı bilmiyorsanız, [Async: *"Acelesi var?"*](../async.md#in-a-hurry){.internal-link target=_blank} kontrol edebilirsiniz.
### Adım 5: İçeriği geri döndürün
```Python hl_lines="8"
{!../../../docs_src/first_steps/tutorial001.py!}
```
Bir `dict`, `list` döndürebilir veya `str`, `int` gibi tekil değerler döndürebilirsiniz.
Ayrıca, Pydantic modellerini de döndürebilirsiniz. (Bununla ilgili daha sonra ayrıntılı bilgi göreceksiniz.)
Otomatik olarak JSON'a dönüştürülecek(ORM'ler vb. dahil) başka birçok nesne ve model vardır. En beğendiklerinizi kullanmayı deneyin, yüksek ihtimalle destekleniyordur.
## Özet
* `FastAPI`'yi içe aktarın.
* Bir `app` örneği oluşturun.
* **path işlem decorator** yazın. (`@app.get("/")` gibi)
* **path işlem fonksiyonu** yazın. (`def root(): ...` gibi)
* Development sunucunuzu çalıştırın. (`uvicorn main:app --reload` gibi)

View File

@@ -61,6 +61,8 @@ nav:
- features.md
- fastapi-people.md
- python-types.md
- Tutorial - User Guide:
- tutorial/first-steps.md
markdown_extensions:
- toc:
permalink: true

View File

@@ -426,7 +426,7 @@ For a more complete example including more features, see the <a href="https://fa
* Many extra features (thanks to Starlette) as:
* **WebSockets**
* **GraphQL**
* extremely easy tests based on `requests` and `pytest`
* extremely easy tests based on HTTPX and `pytest`
* **CORS**
* **Cookie Sessions**
* ...and more.
@@ -446,7 +446,7 @@ Used by Pydantic:
Used by Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.

View File

@@ -1,6 +1,6 @@
# 基准测试
第三方机构 TechEmpower 的基准测试表明在 Uvicorn 下运行的 **FastAPI** 应用程序是 <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">可用的最快的 Python 框架之一</a>,仅次 Starlette 和 Uvicorn 本身 (由 FastAPI 内部使用)。(*)
第三方机构 TechEmpower 的基准测试表明在 Uvicorn 下运行的 **FastAPI** 应用程序是 <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">可用的最快的 Python 框架之一</a>,仅次 Starlette 和 Uvicorn 本身 (由 FastAPI 内部使用)。(*)
但是在查看基准得分和对比时,请注意以下几点。

View File

@@ -171,7 +171,7 @@ FastAPI 有一个使用非常简单,但是非常强大的<abbr title='也叫
* **支持 GraphQL** 。
* 后台任务处理。
* Startup 和 shutdown 事件。
* 测试客户端基于 `requests`
* 测试客户端基于 HTTPX
* **CORS**, GZip, 静态文件, 流响应。
* 支持 **Session 和 Cookie**
* 100% 测试覆盖率。

View File

@@ -28,7 +28,7 @@ FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框
关键特性:
* **快速**:可与 **NodeJS****Go** 肩的极高性能(归功于 Starlette 和 Pydantic。[最快的 Python web 框架之一](#_11)。
* **快速**:可与 **NodeJS****Go** 肩的极高性能(归功于 Starlette 和 Pydantic。[最快的 Python web 框架之一](#_11)。
* **高效编码**:提高功能开发速度约 200 至 300。*
* **更少 bug**:减少约 40 的人为(开发者)导致错误。*
@@ -422,7 +422,7 @@ item: Item
* 许多额外功能(归功于 Starlette比如
* **WebSockets**
* **GraphQL**
* 基于 `requests` 和 `pytest` 的极其简单的测试
* 基于 HTTPX 和 `pytest` 的极其简单的测试
* **CORS**
* **Cookie Sessions**
* ......以及更多
@@ -442,7 +442,7 @@ item: Item
用于 Starlette
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - 使用 `TestClient` 时安装。
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - 使用 `TestClient` 时安装。
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - 使用默认模板配置时安装。
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - 需要通过 `request.form()` 对表单进行<abbr title="将来自 HTTP 请求中的字符串转换为 Python 数据类型">「解析」</abbr>时安装。
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - 需要 `SessionMiddleware` 支持时安装。

View File

@@ -194,7 +194,7 @@ John Doe
这表示:
* 变量 `items_t` 是一个 `tuple`,其中的个元素都是 `int` 类型。
* 变量 `items_t` 是一个 `tuple`,其中的前两个元素都是 `int` 类型, 最后一个元素是 `str` 类型。
* 变量 `items_s` 是一个 `set`,其中的每个元素都是 `bytes` 类型。
#### 字典

View File

@@ -1,34 +1,34 @@
# 使用(哈希)密码和 JWT Bearer 令牌的 OAuth2
# OAuth2 实现密码哈希与 Bearer JWT 令牌验证
既然我们已经了所有安全流程,就让我们来使用 <abbr title="JSON Web Tokens">JWT</abbr> 令牌和安全哈希密码让应用程序真正安全
至此,我们已经编写了所有安全流,本章学习如何使用 <abbr title="JSON Web Tokens">JWT</abbr> 令牌Token和安全密码哈希Hash实现真正安全机制
你可以在应用程序中真正地使用这些代码,在数据库中保存密码哈希值,等等
本章的示例代码真正实现了在应用的数据库中保存哈希密码等功能
我们将从上一章结束的位置开始,然后对示例进行扩充
接下来,我们紧接上一章,继续完善安全机制
## 关于 JWT
## JWT 简介
JWT 表示 「JSON Web Tokens
JWT 即**JSON 网络令牌**JSON Web Tokens
是一将 JSON 对象编码为密集且没有空格的长字符串的标准。字符串看起来像这样
JWT 是一将 JSON 对象编码为没有空格,且难以理解的长字符串的标准。JWT 的内容如下所示
```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
```
没有加密,因此任何人都可以从字符串内容中还原数据
JWT 字符串没有加密,任何人都能用它恢复原始信息
它经过了签名。因此,当你收到一个由你发出的令牌时,可以校验令牌是否真的由你发出
JWT 使用了签名机制。接受令牌时,可以用签名校验令牌。
通过这种方式,你可以创建一个有效期为 1 周的令牌。然后当用户第二天使用令牌重新访问时,你知道该用户仍然处于登入状态。
使用 JWT 创建有效期为周的令牌。第二天,用户持令牌再次访问时,仍为登录状态。
一周后令牌将会过期,用户将不会通过认证,必须再次登录才能获得一个新令牌。而且如果用户(或第三方)试图修改令牌以篡改过期时间,你将因为签名不匹配而能够发觉
令牌于一周后过期,届时,用户身份验证就会失败。只有再次登录才能获得新令牌。如果用户(或第三方)篡改令牌的过期时间,因为签名不匹配会导致身份验证失败
果你想上手体验 JWT 令牌了解工作方式,可访问 <a href="https://jwt.io/" class="external-link" target="_blank">https://jwt.io</a>。
需深入了解 JWT 令牌了解它的工作方式,请参阅 <a href="https://jwt.io/" class="external-link" target="_blank">https://jwt.io</a>。
## 安装 `python-jose`
我们需要安装 `python-jose`在 Python 中生成和校验 JWT 令牌:
安装 `python-jose`在 Python 中生成和校验 JWT 令牌:
<div class="termy">
@@ -40,38 +40,39 @@ $ pip install python-jose[cryptography]
</div>
<a href="https://github.com/mpdavis/python-jose" class="external-link" target="_blank">Python-jose</a> 需要一个额外的加密后端。
<a href="https://github.com/mpdavis/python-jose" class="external-link" target="_blank">Python-jose</a> 需要安装配套的加密后端。
这里我们使用的是推荐的后端:<a href="https://cryptography.io/" class="external-link" target="_blank">pyca/cryptography</a>。
本教程推荐的后端<a href="https://cryptography.io/" class="external-link" target="_blank">pyca/cryptography</a>。
!!! tip
本教程曾经使用过 <a href="https://pyjwt.readthedocs.io/" class="external-link" target="_blank">PyJWT</a>。
!!! tip "提示"
但是后来更新为使用 Python-jose因为它提供了 PyJWT 的所有功能,以及之后与其他工具进行集成时你可能需要的一些其他功能
本教程以前使用 <a href="https://pyjwt.readthedocs.io/" class="external-link" target="_blank">PyJWT</a>
## 哈希密码
但后来换成了 Python-jose因为 Python-jose 支持 PyJWT 的所有功能,还支持与其它工具集成时可能会用到的一些其它功能。
「哈希」的意思是:将某些内容(在本例中为密码)转换为看起来像乱码的字节序列(只是一个字符串)。
## 密码哈希
每次你传入完全相同的内容(完全相同的密码)时,你都会得到完全相同的乱码
**哈希**是指把特定内容(本例中为密码)转换为乱码形式的字节序列(其实就是字符串)
但是你不能从乱码转换回密码。
每次传入完全相同的内容时(比如,完全相同的密码),返回的都是完全相同的乱码。
### 为什么使用哈希密码
但这个乱码无法转换回传入的密码
如果你的数据库被盗,小偷将无法获得用户的明文密码,只能拿到哈希值。
### 为什么使用密码哈希
因此,小偷将无法尝试在另一个系统中使用这些相同的密码(由于许多用户在任何地方都使用相同的密码,因此这很危险)
原因很简单,假如数据库被盗,窃贼无法获取用户的明文密码,得到的只是哈希值
这样一来,窃贼就无法在其它应用中使用窃取的密码,要知道,很多用户在所有系统中都使用相同的密码,风险超大)。
## 安装 `passlib`
PassLib 是一个用于处理哈希密码的很棒的 Python 包。
Passlib 是处理密码哈希的 Python 包。
它支持多安全哈希算法及配合算法使用的实用程序
它支持多安全哈希算法及配套工具
推荐的算法是 Bcrypt
本教程推荐的算法是 **Bcrypt**
因此,安装附带 Bcrypt 的 PassLib
因此,请先安装附带 Bcrypt 的 PassLib
<div class="termy">
@@ -83,46 +84,49 @@ $ pip install passlib[bcrypt]
</div>
!!! tip
使用 `passlib`,你甚至可以将其配置为能够读取 DjangoFlask 的安全扩展或许多其他工具创建的密码。
!!! tip "提示"
因此,你将能够,举个例子,将数据库中来自 Django 应用的数据共享给一个 FastAPI 应用。或者使用同一数据库但逐渐将应用从 Django 迁移到 FastAPI
`passlib` 甚至可以读取 Django、Flask 的安全插件等工具创建的密码
而你的用户将能够同时从 Django 应用 FastAPI 应用登录
例如,把 Django 应用的数据共享给 FastAPI 应用的数据库。或利用同一个数据库,可以逐步把应用从 Django 迁移到 FastAPI
## 哈希并校验密码
并且,用户可以同时从 Django 应用或 FastAPI 应用登录。
`passlib` 导入我们需要的工具。
## 密码哈希与校验
创建一个 PassLib 「上下文」。这将用于哈希和校验密码
`passlib` 导入所需工具
!!! tip
PassLib 上下文还具有使用不同哈希算法的功能,包括仅允许用于校验的已弃用的旧算法等。
创建用于密码哈希和身份校验的 PassLib **上下文**
例如你可以使用它来读取和校验由另一个系统例如Django生成的密码但是使用其他算法例如 Bcrypt 生成新的密码哈希值。
!!! tip "提示"
并同时兼容所有的这些功能
PassLib 上下文还支持使用不同哈希算法的功能,包括只能校验的已弃用旧算法等
创建一个工具函数以哈希来自用户的密码。
例如,用它读取和校验其它系统(如 Django生成的密码但要使用其它算法如 Bcrypt生成新的哈希密码。
然后创建另一个工具函数,用于校验接收的密码是否与存储的哈希值匹配
同时,这些功能都是兼容的
再创建另一个工具函数用于认证并返回用户
接下来,创建三个工具函数,其中一个函数用于哈希用户的密码
第一个函数用于校验接收的密码是否匹配存储的哈希值。
第三个函数用于身份验证,并返回用户。
```Python hl_lines="7 48 55-56 59-60 69-75"
{!../../../docs_src/security/tutorial004.py!}
```
!!! note
如果你查看新的(伪)数据库 `fake_users_db`,你将看到哈希后的密码现在的样子:`"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`。
!!! note "笔记"
查看新的(伪)数据库 `fake_users_db`,就能看到哈希后的密码:`"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`。
## 处理 JWT 令牌
导入已安装的模块。
创建一个随机密钥,该密钥将用于 JWT 令牌进行签名。
创建用于 JWT 令牌签名的随机密钥
要生成一个安全的随机密钥,可使用以下命令:
使用以下命令,生成安全的随机密钥
<div class="termy">
@@ -134,15 +138,15 @@ $ openssl rand -hex 32
</div>
然后将输出复制到变量SECRET_KEY」 中(不要使用示例中的这个)
然后,把生成的密钥复制到变量**SECRET_KEY**,注意,不要使用本例所示的密钥
创建用于设定 JWT 令牌签名算法的变量 ALGORITHM」,并将其设置为 `"HS256"`。
创建定 JWT 令牌签名算法的变量 **ALGORITHM**,本例中的值为 `"HS256"`。
创建一个设置令牌过期时间的变量。
创建设置令牌过期时间的变量。
定义一个将在令牌端点中用于响应的 Pydantic 模型。
定义令牌端点响应的 Pydantic 模型。
创建一个生成新的访问令牌的工具函数。
创建生成新的访问令牌的工具函数。
```Python hl_lines="6 12-14 28-30 78-86"
{!../../../docs_src/security/tutorial004.py!}
@@ -150,11 +154,11 @@ $ openssl rand -hex 32
## 更新依赖项
更新 `get_current_user` 以接收与之前相同的令牌,但这次使用的是 JWT 令牌。
更新 `get_current_user` 以接收与之前相同的令牌,但这用的是 JWT 令牌。
解码接收到的令牌,对其进行校验,然后返回当前用户。
解码并校验接收到的令牌,然后返回当前用户。
如果令牌无效,立即返回一个 HTTP 错误。
如果令牌无效,则直接返回 HTTP 错误。
```Python hl_lines="89-106"
{!../../../docs_src/security/tutorial004.py!}
@@ -162,57 +166,57 @@ $ openssl rand -hex 32
## 更新 `/token` *路径操作*
使用令牌过期时间创建一个 `timedelta` 对象。
用令牌过期时间创建 `timedelta` 对象。
创建一个真实的 JWT 访问令牌并返回它
创建并返回真正的 JWT 访问令牌。
```Python hl_lines="115-128"
{!../../../docs_src/security/tutorial004.py!}
```
### 关于 JWT 「主题」 `sub` 的技术细节
### JWT `sub` 的技术细节
JWT 规范中提到有一个 `sub` 键,值为该令牌的主题。
JWT 规范还包括 `sub` 键,值令牌的主题。
使用它并不是必须的,但这是你放置用户标识的地方,所以我们在示例中使用了
该键是可选的,但要把用户标识放在这个键里,所以本例使用了该键
除了识别用户并允许他们直接在你的 API 上执行操作之外JWT 还可用于其事情。
除了识别用户与许可用户在 API 上直接执行操作之外JWT 还可用于其事情。
例如,你可以识别一个 「汽车」 或 「博客文章」
例如,识别**汽车**或**博客**
然后你可以添加关于该实体的权限,比如「驾驶」(汽车)或「编辑」(博客)。
接着,为实体添加权限,比如**驾驶**(汽车)或**编辑**(博客)。
然后,你可以将 JWT 令牌交给用户(或机器人),他们可以使用它来执行这些操作(驾驶汽车,或编辑博客文章),甚至不需要有一个账户,只需使用你的 API 为其生成的 JWT 令牌。
然后, JWT 令牌交给用户(或机器人),他们可以执行驾驶汽车,或编辑博客等操作。无需注册账户,只要有 API 生成的 JWT 令牌就可以
使用这样的思路JWT 可以用于更复杂的场景。
同理JWT 可以用于更复杂的场景。
在这些情况下,个实体可能相同的 ID,比如说 `foo`(一个用户 `foo`一辆车 `foo`一篇博客文章 `foo`
在这些情况下,个实体的 ID 可能相同的,以 ID `foo` 为例,用户的 ID 是 `foo`,车的 ID 是 `foo`博客的 ID 也是 `foo`。
因此,为了避免 ID 冲突,当为用户创建 JWT 令牌时,可以 `sub` 键的值加上前缀,例如 `username:`。所以,在这个例子中,`sub` 的值可以是:`username:johndoe`。
为了避免 ID 冲突,在给用户创建 JWT 令牌时,可以 `sub` 键的值加上前缀,例如 `username:`。因此,在本例中,`sub` 的值可以是:`username:johndoe`。
要记住的重点`sub` 键在整个应用程序中应该有一个唯一的标识符,而且应该是一个字符串。
注意,划重点,`sub` 键在整个应用中应该有一个唯一的标识符,而且应该是字符串。
## 检查效果
## 检查
运行服务器并访问文档: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>。
你会看到如下用户界面:
可以看到如下用户界面:
<img src="https://fastapi.tiangolo.com/img/tutorial/security/image07.png">
像以前一样对应用程序进行认证
用与上一章同样的方式实现应用授权
使用如下凭证:
用户名: `johndoe`
密码: `secret`
用户名: `johndoe` 密码: `secret`
!!! check
请注意,代码中没有任何地方记录了明文密码 「`secret`」,我们只保存了其哈希值。
!!! check "检查"
注意,代码中没有明文密码**`secret`**,只保存了它的哈希值。
<img src="https://fastapi.tiangolo.com/img/tutorial/security/image08.png">
访问 `/users/me/` 端点,你将获得如下响应:
调用 `/users/me/` 端点,收到下面的响应:
```JSON
{
@@ -225,41 +229,42 @@ JWT 的规范中提到有一个 `sub` 键,值为该令牌的主题。
<img src="https://fastapi.tiangolo.com/img/tutorial/security/image09.png">
如果你打开开发者工具,将看到数据是如何发送的并且其中仅包含了令牌,只有第一个请求发送密码以校验用户身份并获取访问令牌,但之后不会再发送密码:
打开浏览器的开发者工具,查看数据是怎么发送的,而且数据里只包含了令牌,只有验证用户的第一个请求发送密码并获取访问令牌,但之后不会再发送密码:
<img src="https://fastapi.tiangolo.com/img/tutorial/security/image10.png">
!!! note
注意请求中的 `Authorization` 首部,其值以 `Bearer` 开头。
!!! note "笔记"
## 使用 `scopes` 的进阶用法
注意,请求中 `Authorization` 响应头的值以 `Bearer` 开头。
OAuth2 具有「作用域」的概念。
## `scopes` 高级用法
你可以使用它们向 JWT 令牌添加一组特定的权限
OAuth2 支持**`scopes`**(作用域)
然后,你可以将此令牌直接提供给用户或第三方,使其在一些限制下与你的 API 进行交互
**`scopes`**为 JWT 令牌添加指定权限
你可以在之后的**进阶用户指南**中了解如何使用它们以及如何将它们集成到 **FastAPI** 中
让持有令牌的用户或第三方在指定限制条件下与 API 交互
## 总结
**高级用户指南**中将介绍如何使用 `scopes`,及如何把 `scopes` 集成至 **FastAPI**。
通过目前你所看到的,你可以使用像 OAuth2 和 JWT 这样的标准来构建一个安全的 **FastAPI** 应用程序。
## 小结
在几乎所有的框架中,处理安全性问题都很容易成为一个相当复杂的话题
至此,您可以使用 OAuth2 和 JWT 等标准配置安全的 **FastAPI** 应用
许多高度简化了安全流程的软件包不得不在数据模型、数据库和可用功能上做出很多妥协。而这些过于简化流程的软件包中,有些其实隐含了安全漏洞
几乎在所有框架中,处理安全问题很快都会变得非常复杂
有些包为了简化安全流,不得不在数据模型、数据库和功能上做出妥协。而有些过于简化的软件包其实存在了安全隐患。
---
**FastAPI** 不任何数据库、数据模型或工具做任何妥协。
**FastAPI** 不任何数据库、数据模型或工具做妥协。
它给了你所有的灵活性来选择最适合项目的前者
开发者可以灵活选择最适合项目的安全机制
可以直接使用许多维护良好且使用广泛的包,如 `passlib` 和 `python-jose`因为 **FastAPI** 不需要任何复杂机制集成外部包。
可以直接使用 `passlib` 和 `python-jose` 等维护良好、使用广泛的包,这是因为 **FastAPI** 不需要任何复杂机制,就能集成外部包。
但它为你提供了一些工具,在不影响灵活性、健壮性和安全的前提下,尽可能地简化这个过程
而且,**FastAPI** 还提供了一些工具,在不影响灵活、稳定和安全的前提下,尽可能地简化安全机制
而且你可以用相对简单的方式使用和实现安全、标准的协议,比如 OAuth2
**FastAPI** 还支持以相对简单的方式使用 OAuth2 等安全、标准的协议
你可以在**进阶用户指南**中了解更多关于如何使用 OAuth2 「作用域」的信息,以实现更精的权限系统,并同样遵循这些标准。带有作用域的 OAuth2 是很多大的认证提供商使用的机制,比如 Facebook、Google、GitHub、微软、Twitter 等,授权第三方应用代表用户与他们的 API 进行交互。
**高级用户指南**中详细介绍了 OAuth2**`scopes`**的内容,遵循同样的标准,实现更精的权限系统。OAuth2 的作用域是脸书、谷歌、GitHub、微软、推特等第三方身份验证应用使用的机制让用户授权第三方应用与 API 交互。

View File

@@ -10,7 +10,7 @@ async def read_main():
return {"msg": "Hello World"}
@app.websocket_route("/ws")
@app.websocket("/ws")
async def websocket(websocket: WebSocket):
await websocket.accept()
await websocket.send_json({"msg": "Hello WebSocket"})

View File

@@ -1,4 +1,4 @@
from typing import List, Union
from typing import Any, List, Union
from fastapi import FastAPI
from pydantic import BaseModel
@@ -15,5 +15,13 @@ class Item(BaseModel):
@app.post("/items/", response_model=Item)
async def create_item(item: Item):
async def create_item(item: Item) -> Any:
return item
@app.get("/items/", response_model=List[Item])
async def read_items() -> Any:
return [
{"name": "Portal Gun", "price": 42.0},
{"name": "Plumbus", "price": 32.0},
]

View File

@@ -0,0 +1,27 @@
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
tags: List[str] = []
@app.post("/items/")
async def create_item(item: Item) -> Item:
return item
@app.get("/items/")
async def read_items() -> List[Item]:
return [
Item(name="Portal Gun", price=42.0),
Item(name="Plumbus", price=32.0),
]

View File

@@ -0,0 +1,25 @@
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: list[str] = []
@app.post("/items/")
async def create_item(item: Item) -> Item:
return item
@app.get("/items/")
async def read_items() -> list[Item]:
return [
Item(name="Portal Gun", price=42.0),
Item(name="Plumbus", price=32.0),
]

View File

@@ -0,0 +1,27 @@
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
tags: list[str] = []
@app.post("/items/")
async def create_item(item: Item) -> Item:
return item
@app.get("/items/")
async def read_items() -> list[Item]:
return [
Item(name="Portal Gun", price=42.0),
Item(name="Plumbus", price=32.0),
]

View File

@@ -1,3 +1,5 @@
from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel
@@ -13,5 +15,13 @@ class Item(BaseModel):
@app.post("/items/", response_model=Item)
async def create_item(item: Item):
async def create_item(item: Item) -> Any:
return item
@app.get("/items/", response_model=list[Item])
async def read_items() -> Any:
return [
{"name": "Portal Gun", "price": 42.0},
{"name": "Plumbus", "price": 32.0},
]

View File

@@ -1,4 +1,4 @@
from typing import Union
from typing import Any, Union
from fastapi import FastAPI
from pydantic import BaseModel
@@ -15,5 +15,13 @@ class Item(BaseModel):
@app.post("/items/", response_model=Item)
async def create_item(item: Item):
async def create_item(item: Item) -> Any:
return item
@app.get("/items/", response_model=list[Item])
async def read_items() -> Any:
return [
{"name": "Portal Gun", "price": 42.0},
{"name": "Plumbus", "price": 32.0},
]

View File

@@ -14,6 +14,6 @@ class UserIn(BaseModel):
# Don't do this in production!
@app.post("/user/", response_model=UserIn)
async def create_user(user: UserIn):
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
return user

View File

@@ -12,6 +12,6 @@ class UserIn(BaseModel):
# Don't do this in production!
@app.post("/user/", response_model=UserIn)
async def create_user(user: UserIn):
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
return user

View File

@@ -1,4 +1,4 @@
from typing import Union
from typing import Any, Union
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
@@ -20,5 +20,5 @@ class UserOut(BaseModel):
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
async def create_user(user: UserIn) -> Any:
return user

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