Compare commits

...

182 Commits

Author SHA1 Message Date
Sebastián Ramírez
b1e25e8857 📝 Add notes about PEP 727 2023-08-29 23:20:39 +02:00
Sebastián Ramírez
fa2e70641e 📝 Update doc from changes while writing the PEP 727 2023-08-29 23:17:23 +02:00
Sebastián Ramírez
e3360367f7 📝 Update DocInfo to not be a dataclass, Jelle's feedback, avoid bootstrapping problems, make it hashable 2023-08-28 16:10:18 +02:00
Sebastián Ramírez
c1616eb92f 📝 Update Alternate Form, point to annotated-types 2023-08-28 16:06:22 +02:00
Sebastián Ramírez
4cbcd52169 📝 Simplify phrase from Jelle's feedback, typing_extension not only includes typing objects 2023-08-28 16:05:42 +02:00
Timothée Mazzucotelli
f7feb0fa48 ✏️ Fix typos in typing_doc page (#10162) 2023-08-28 14:48:16 +02:00
Sebastián Ramírez
b13ed4c578 📝 Update recommendation for supporting last doc() 2023-08-27 20:03:57 +02:00
Sebastián Ramírez
f3691a6fd3 📝 Add example of nested Annotated with doc 2023-08-27 19:35:34 +02:00
Sebastián Ramírez
56231a8944 ✏️ Fix typo: implementor -> implementer 2023-08-27 19:26:46 +02:00
Sebastián Ramírez
54c7064936 📝 Add notes about edge case scenarios 2023-08-27 19:23:50 +02:00
Sebastián Ramírez
5260793a07 📝 Add Bike Shedding to typing-doc 2023-08-27 17:27:26 +02:00
Sebastián Ramírez
d5207e603a 📝 Update Typing Doc, make doc() be only for Annotated and exclusively for documentation 2023-08-27 16:26:53 +02:00
Sebastián Ramírez
4372430092 🔀 Merge branch 'master' into typing-doc 2023-08-27 16:26:10 +02:00
Sebastián Ramírez
a3f1689d78 📝 Update release notes 2023-08-26 20:14:42 +02:00
Sebastián Ramírez
415eb1405a 🔖 Release version 0.103.0 2023-08-26 20:10:27 +02:00
Sebastián Ramírez
bd32bca55c 📝 Update release notes 2023-08-26 20:09:59 +02:00
github-actions
df16699dd8 📝 Update release notes 2023-08-26 18:03:56 +00:00
Sebastián Ramírez
1b714b3177 Add support for openapi_examples in all FastAPI parameters (#10152)
* ♻️ Refactor model for OpenAPI Examples to use a reusable TypedDict

*  Add support for openapi_examples in parameters

* 📝 Add new docs examples for new parameter openapi_examples

* 📝 Update docs for Schema Extra to include OpenAPI examples

*  Add tests for new source examples, for openapi_examples

*  Add tests for openapi_examples corner cases and all parameters

* 💡 Tweak and ignore type annotation checks for custom TypedDict
2023-08-26 20:03:13 +02:00
github-actions
5f855b1179 📝 Update release notes 2023-08-26 13:20:54 +00:00
Sebastián Ramírez
594b1ae0c3 📝 Add note to docs about Separate Input and Output Schemas with FastAPI version (#10150) 2023-08-26 15:20:04 +02:00
Sebastián Ramírez
f3ab547c0c 📝 Update release notes 2023-08-25 21:23:44 +02:00
Sebastián Ramírez
9cf9e1084d 🔖 Release version 0.102.0 2023-08-25 21:18:38 +02:00
Sebastián Ramírez
859d40407c 📝 Update release notes 2023-08-25 21:18:09 +02:00
github-actions
098778e07f 📝 Update release notes 2023-08-25 19:11:02 +00:00
Sebastián Ramírez
ea43f227e5 Add support for disabling the separation of input and output JSON Schemas in OpenAPI with Pydantic v2 (#10145)
* 📝 Add docs for Separate OpenAPI Schemas for Input and Output

* 🔧 Add new docs page to MkDocs config

*  Add separate_input_output_schemas parameter to FastAPI class

* 📝 Add source examples for separating OpenAPI schemas

*  Add tests for separated OpenAPI schemas

* 📝 Add source examples for Python 3.10, 3.9, and 3.7+

* 📝 Update docs for Separate OpenAPI Schemas with new multi-version examples

*  Add and update tests for different Python versions

*  Add tests for corner cases with separate_input_output_schemas

* 📝 Update tutorial to use Union instead of Optional

* 🐛 Fix type annotations

* 🐛 Fix correct import in test

* 💄 Add CSS to simulate browser windows for screenshots

*  Add playwright as a dev dependency to automate generating screenshots

* 🔨 Add Playwright scripts to generate screenshots for new docs

* 📝 Update docs, tweak text to match screenshots

* 🍱 Add screenshots for new docs
2023-08-25 21:10:22 +02:00
github-actions
10a127ea4a 📝 Update release notes 2023-08-19 19:54:40 +00:00
Sebastián Ramírez
8cd7cfc2b6 📝 Add new docs section, How To - Recipes, move docs that don't have to be read by everyone to How To (#10114)
* 📝 Start How To docs section, move Peewee, remove Peewee from dependencies

* 🚚 Move em files to new locations

* 🚚 Move and re-structure advanced docs, move relevant to How To

* 🔧 Update MkDocs config, new files in How To

* 📝 Move docs for Conditional OpenAPI for Japanese to How To

* 📝 Move example source files for Extending OpenAPI into each of the new sections

*  Update tests with new locations for source files

* 🔥 Remove init from Peewee examples
2023-08-19 21:54:04 +02:00
github-actions
3971c44a38 📝 Update release notes 2023-08-19 18:48:35 +00:00
Sebastián Ramírez
7a06de2bb9 ♻️ Refactor tests for new Pydantic 2.2.1 (#10115) 2023-08-19 20:47:59 +02:00
github-actions
b406dd9174 📝 Update release notes 2023-08-19 14:09:02 +00:00
Sebastián Ramírez
8e38261787 📝 Update Advanced docs, add links to sponsor courses (#10113) 2023-08-19 16:08:16 +02:00
github-actions
486cd139a9 📝 Update release notes 2023-08-19 13:51:12 +00:00
Sebastián Ramírez
08feaf0cc4 📝 Update docs for generating clients (#10112) 2023-08-19 15:49:54 +02:00
github-actions
0fe434ca68 📝 Update release notes 2023-08-19 13:34:10 +00:00
Sebastián Ramírez
d1c0e5a89f 📝 Tweak MkDocs and add redirects (#10111) 2023-08-19 13:33:32 +00:00
github-actions
e04953a9e0 📝 Update release notes 2023-08-19 13:12:09 +00:00
Sebastián Ramírez
d4201a49bc 📝 Restructure docs for cloud providers, include links to sponsors (#10110) 2023-08-19 15:11:35 +02:00
github-actions
a6ae5af7d6 📝 Update release notes 2023-08-17 08:52:40 +00:00
Sebastián Ramírez
e93d15cf9a 🔧 Update sponsors, add Speakeasy (#10098) 2023-08-17 10:51:58 +02:00
Sebastián Ramírez
63e7edb295 🔖 Release version 0.101.1 2023-08-14 12:03:14 +02:00
Sebastián Ramírez
50b6ff7da6 📝 Update release notes 2023-08-14 12:02:43 +02:00
github-actions
d46cd0b1f0 📝 Update release notes 2023-08-14 09:50:40 +00:00
Sebastián Ramírez
5e8f7f13d7 Add ResponseValidationError printable details, to show up in server error logs (#10078) 2023-08-14 11:49:57 +02:00
github-actions
dafaf6a34c 📝 Update release notes 2023-08-14 09:17:05 +00:00
github-actions
87cc40e483 📝 Update release notes 2023-08-14 09:15:26 +00:00
Yusuke Tamura
25059a7717 🌐 Add Japanese translation for docs/ja/docs/deployment/concepts.md (#10062)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-14 11:14:37 +02:00
Yusuke Tamura
2a5cc5fff3 🌐 Add Japanese translation for docs/ja/docs/deployment/server-workers.md (#10064)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-14 11:13:28 +02:00
github-actions
014262c203 📝 Update release notes 2023-08-14 09:13:05 +00:00
Yusuke Tamura
9d6ce823c1 🌐 Update Japanese translation for docs/ja/docs/deployment/docker.md (#10073)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-14 11:12:14 +02:00
github-actions
48d203a1e7 📝 Update release notes 2023-08-14 09:10:51 +00:00
Rostyslav
47166ed56c 🌐 Add Ukrainian translation for docs/uk/docs/fastapi-people.md (#10059) 2023-08-14 11:10:06 +02:00
github-actions
78f38c6bfd 📝 Update release notes 2023-08-10 15:59:15 +00:00
Rostyslav
e6afc5911b 🌐 Add Ukrainian translation for docs/uk/docs/tutorial/cookie-params.md (#10032) 2023-08-10 17:58:13 +02:00
github-actions
5c2a155809 📝 Update release notes 2023-08-10 15:55:32 +00:00
Vladislav Kramorenko
fe3eaf63e6 🌐 Add Russian translation for docs/ru/docs/deployment/docker.md (#9971)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Yois4101 <119609381+Yois4101@users.noreply.github.com>
2023-08-10 17:53:26 +02:00
github-actions
1f0d9086b3 📝 Update release notes 2023-08-10 15:53:06 +00:00
Nguyễn Khắc Thành
f0ab797de4 🌐 Add Vietnamese translation for docs/vi/docs/python-types.md (#10047)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-10 17:52:25 +02:00
github-actions
82fafcc7ea 📝 Update release notes 2023-08-09 17:05:31 +00:00
Sebastián Ramírez
87398723f9 🔧 Add sponsor Porter (#10051) 2023-08-09 19:04:49 +02:00
github-actions
01383a57cb 📝 Update release notes 2023-08-09 13:27:14 +00:00
Sebastián Ramírez
14c96ef31b 🔧 Update sponsors, add Jina back as bronze sponsor (#10050) 2023-08-09 15:26:33 +02:00
github-actions
942ee69d85 📝 Update release notes 2023-08-05 08:46:58 +00:00
github-actions
6df10c9753 📝 Update release notes 2023-08-05 08:44:36 +00:00
github-actions
0f4a962c20 📝 Update release notes 2023-08-05 08:43:01 +00:00
Russ Biggs
bdd991244d ✏️ Fix typo in deprecation warnings in fastapi/params.py (#9854)
fix typo for deprecation warnings depreacated -> deprecated
2023-08-05 10:41:21 +02:00
Francis Bergin
69d5ebf34d ✏️ Fix typo in release notes (#9835) 2023-08-05 10:40:24 +02:00
ElliottLarsen
5e59acd35b ✏️ Fix typos in comments on internal code in fastapi/concurrency.py and fastapi/routing.py (#9590)
Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
2023-08-05 10:39:38 +02:00
github-actions
bb7bbafb5f 📝 Update release notes 2023-08-05 08:38:32 +00:00
github-actions
87e126be2e 📝 Update release notes 2023-08-05 08:36:27 +00:00
Adejumo Ridwan Suleiman
33e77b6e25 📝 Add external article: Build an SMS Spam Classifier Serverless Database with FaunaDB and FastAPI (#9847) 2023-08-05 10:36:05 +02:00
github-actions
51f5497f3f 📝 Update release notes 2023-08-05 08:35:55 +00:00
Vicente Merino
0b496ea1f8 📝 Fix typo in docs/en/docs/contributing.md (#9878)
Co-authored-by: Vicente Merino <vmerino@rexmas.com>
2023-08-05 10:34:07 +02:00
Reza Rohani
b76112f1a5 📝 Fix code highlighting in docs/en/docs/tutorial/bigger-applications.md (#9806)
Update bigger-applications.md
2023-08-05 10:33:08 +02:00
github-actions
f2e80fae09 📝 Update release notes 2023-08-05 08:28:26 +00:00
github-actions
d86a695db9 📝 Update release notes 2023-08-05 08:26:40 +00:00
Aleksandr Pavlov
1c919dee3c 🌐 Add Russian translation for docs/ru/docs/tutorial/dependencies/global-dependencies.md (#9970)
Co-authored-by: dedkot <dedkot01@gmail.com>
Co-authored-by: Vladislav Kramorenko <85196001+Xewus@users.noreply.github.com>
2023-08-05 10:26:03 +02:00
Ahsan Sheraz
5891be5ff1 🌐 Add Urdu translation for docs/ur/docs/benchmarks.md (#9974) 2023-08-05 10:24:21 +02:00
github-actions
abfcb59fd0 📝 Update release notes 2023-08-05 08:23:39 +00:00
github-actions
0148c9508c 📝 Update release notes 2023-08-05 08:23:14 +00:00
dependabot[bot]
8f316be088 ⬆ Bump mypy from 1.4.0 to 1.4.1 (#9756)
Bumps [mypy](https://github.com/python/mypy) from 1.4.0 to 1.4.1.
- [Commits](https://github.com/python/mypy/compare/v1.4.0...v1.4.1)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-05 10:22:58 +02:00
dependabot[bot]
d48a184dd8 ⬆ Bump mkdocs-material from 9.1.17 to 9.1.21 (#9960)
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.1.17 to 9.1.21.
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.1.17...9.1.21)

---
updated-dependencies:
- dependency-name: mkdocs-material
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-05 10:22:39 +02:00
Sebastián Ramírez
8adbafc076 🔖 Release version 0.101.0 2023-08-04 23:00:17 +02:00
Sebastián Ramírez
4b5277744a 📝 Update release notes 2023-08-04 22:59:44 +02:00
github-actions
89a7cea561 📝 Update release notes 2023-08-04 20:58:08 +00:00
Sebastián Ramírez
77d1f69b1f 📌 Do not allow Pydantic 2.1.0 that breaks (require 2.1.1) (#10012) 2023-08-04 22:57:30 +02:00
Sebastián Ramírez
944c591803 📝 Update release notes 2023-08-04 22:50:34 +02:00
github-actions
1c20514738 📝 Update release notes 2023-08-04 20:47:42 +00:00
Sebastián Ramírez
19a2c3bb54 Enable Pydantic's serialization mode for responses, add support for Pydantic's computed_field, better OpenAPI for response models, proper required attributes, better generated clients (#10011)
*  Enable Pydantic's serialization mode for responses

*  Update tests with new Pydantic v2 serialization mode

*  Add a test for Pydantic v2's computed_field
2023-08-04 22:47:07 +02:00
github-actions
d943e02232 📝 Update release notes 2023-08-04 18:19:22 +00:00
Sebastián Ramírez
ebdf952545 👷 Add GitHub Actions step dump context to debug external failures (#10008) 2023-08-04 20:18:38 +02:00
github-actions
b3a1f91004 📝 Update release notes 2023-08-04 17:48:24 +00:00
Sebastián Ramírez
86e4e9f8f9 🔧 Restore MkDocs Material pin after the fix (#10001) 2023-08-04 19:47:42 +02:00
github-actions
3af7265a43 📝 Update release notes 2023-08-03 16:00:19 +00:00
Sebastián Ramírez
059fb12892 🔧 Update the Question template to ask for the Pydantic version (#10000) 2023-08-03 17:59:41 +02:00
github-actions
10b4c31f06 📝 Update release notes 2023-08-03 15:47:35 +00:00
David Montague
25694f5ae1 Fix tests for compatibility with pydantic 2.1.1 (#9943)
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-08-03 17:46:57 +02:00
github-actions
94c48cfc8c 📝 Update release notes 2023-08-03 15:25:10 +00:00
Sebastián Ramírez
4ab0363ad7 Remove direct dependency on MkDocs, Material for MkDocs defines its own dependency (#9986) 2023-08-03 17:24:31 +02:00
github-actions
a73cdaed35 📝 Update release notes 2023-08-03 14:25:48 +00:00
Sebastián Ramírez
3fa6cfbcc5 👥 Update FastAPI People (#9999)
Co-authored-by: github-actions <github-actions@github.com>
2023-08-03 16:25:11 +02:00
github-actions
ad1d7f539e 📝 Update release notes 2023-08-03 14:13:59 +00:00
Sebastián Ramírez
89537a0497 🐳 Update Dockerfile with compatibility versions, to upgrade later (#9998) 2023-08-03 16:12:28 +02:00
github-actions
3829129245 📝 Update release notes 2023-08-02 18:58:29 +00:00
Sebastián Ramírez
53220b9832 Add pydantic-settings to FastAPI People dependencies (#9988) 2023-08-02 20:57:48 +02:00
github-actions
165f29fe5e 📝 Update release notes 2023-08-02 15:57:57 +00:00
Sebastián Ramírez
1e6bfa1f39 ♻️ Update FastAPI People logic with new Pydantic (#9985) 2023-08-02 17:57:20 +02:00
github-actions
b473cdd88d 📝 Update release notes 2023-08-02 15:29:13 +00:00
Irfanuddin Shafi Ahmed
37818f553d Fix test error in Windows for jsonable_encoder (#9840)
Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
2023-08-02 17:28:34 +02:00
github-actions
2d8a776836 📝 Update release notes 2023-08-02 15:15:10 +00:00
Nikita
88d96799b1 🌐 Add Russian translation for docs/ru/docs/tutorial/security/index.md (#9963)
Co-authored-by: dedkot <dedkot01@gmail.com>
Co-authored-by: Vladislav Kramorenko <85196001+Xewus@users.noreply.github.com>
2023-08-02 17:14:19 +02:00
github-actions
01f91fdb57 📝 Update release notes 2023-08-01 21:40:00 +00:00
Sebastián Ramírez
c2a33f1087 🍱 Update sponsors, Fern badge (#9982) 2023-08-01 23:39:22 +02:00
github-actions
6c8c3b788b 📝 Update release notes 2023-08-01 09:20:23 +00:00
Sebastián Ramírez
d2169fbad9 👷 Deploy docs to Cloudflare Pages (#9978) 2023-08-01 11:19:44 +02:00
github-actions
74de15d0df 📝 Update release notes 2023-07-31 21:49:56 +00:00
Sebastián Ramírez
1da0a7afbd 🔧 Update sponsor Fern (#9979) 2023-07-31 23:49:19 +02:00
github-actions
d38e86ef20 📝 Update release notes 2023-07-31 19:54:46 +00:00
Sebastián Ramírez
a0b987224a 👷 Update CI debug mode with Tmate (#9977) 2023-07-31 21:54:07 +02:00
github-actions
cd6d75e451 📝 Update release notes 2023-07-28 12:16:16 +00:00
Sebastián Ramírez
076bdea671 🌐 Remove Vietnamese note about missing translation (#9957) 2023-07-28 14:15:29 +02:00
Sebastián Ramírez
8d27236648 🔖 Release version 0.100.1 2023-07-27 21:16:01 +02:00
Sebastián Ramírez
effa578b8d 📝 Update release notes 2023-07-27 21:15:16 +02:00
github-actions
bec5530ac8 📝 Update release notes 2023-07-27 19:14:48 +00:00
Orest Furda
7b3d770d65 🌐 Add Ukrainian translation for docs/uk/docs/tutorial/body.md (#4574)
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-07-27 21:09:34 +02:00
github-actions
643d8e41c4 📝 Update release notes 2023-07-27 19:08:23 +00:00
github-actions
c52c940066 📝 Update release notes 2023-07-27 19:04:24 +00:00
Nguyễn Khắc Thành
1d088eaf18 🌐 Add Vietnamese translation for docs/vi/docs/features.md and docs/vi/docs/index.md (#3006)
Co-authored-by: Nguyen Khac Thanh <nkthanh@Nguyens-MacBook-Pro.local>
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-07-27 21:01:57 +02:00
github-actions
77cfb3c822 📝 Update release notes 2023-07-27 18:59:56 +00:00
Nina Hwang
55871036db 🌐 Add Korean translation for docs/ko/docs/async.md (#4179)
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-07-27 20:59:18 +02:00
github-actions
e334065d10 📝 Update release notes 2023-07-27 18:57:37 +00:00
github-actions
5d3f51c8bc 📝 Update release notes 2023-07-27 18:56:19 +00:00
吴定焕
e081145c7d 🌐 Add Chinese translation for docs/zh/docs/tutorial/background-tasks.md (#9812)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-07-27 20:55:40 +02:00
github-actions
a52875c656 📝 Update release notes 2023-07-27 18:54:32 +00:00
Sebastián Ramírez
570ca011f9 🔧 Update sponsors, add Fern (#9956) 2023-07-27 20:53:51 +02:00
Sam Courtemanche
04b9a67cbb 🌐 Add French translation for docs/fr/docs/tutorial/query-params-str-validations.md (#4075)
Co-authored-by: Julian Maurin <julian.maurin.perso@pm.me>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-07-27 20:53:21 +02:00
github-actions
02ed00cc47 📝 Update release notes 2023-07-27 18:53:03 +00:00
github-actions
35707a1b29 📝 Update release notes 2023-07-27 18:51:59 +00:00
Julian Maurin
e79dc9697c 🌐 Add French translation for docs/fr/docs/tutorial/index.md (#2234)
Co-authored-by: Ruidy <ruidy.nemausat@gmail.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-07-27 20:51:55 +02:00
Julian Maurin
2dcf78f295 🌐 Add French translation for docs/fr/docs/contributing.md (#2132)
Co-authored-by: Ruidy <ruidy.nemausat@gmail.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-07-27 20:51:07 +02:00
github-actions
d7c6894b8b 📝 Update release notes 2023-07-27 18:50:16 +00:00
Clément Sauvage
3ffebbcf01 🌐 Add French translation for docs/fr/docs/benchmarks.md (#2155)
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>
Co-authored-by: Sam Courtemanche <smlep.pro@gmail.com>
Co-authored-by: Ruidy <ruidy.nemausat@gmail.com>
2023-07-27 20:49:56 +02:00
mahone3297
943baa387f 🌐 Update Chinese translations with new source files (#9738)
Co-authored-by: mkdir700 <mkdir700@gmail.com>
2023-07-27 20:49:03 +02:00
github-actions
6a95a3a8e7 📝 Update release notes 2023-07-27 18:48:28 +00:00
dedkot
608cc4fea3 🌐 Add Russian translation for docs/tutorial/request-forms.md (#9841) 2023-07-27 20:47:42 +02:00
github-actions
39318a39f4 📝 Update release notes 2023-07-27 18:43:30 +00:00
Creat55
703a1f200a 🌐 Update Chinese translation for docs/zh/docs/tutorial/handling-errors.md (#9485)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-07-27 20:42:48 +02:00
github-actions
7cdea41431 📝 Update release notes 2023-07-27 18:23:13 +00:00
Marcelo Trylesinski
6c99e90a6b 🐛 Replace MultHostUrl to AnyUrl for compatibility with older versions of Pydantic v1 (#9852) 2023-07-27 20:22:23 +02:00
github-actions
f7e3559bd5 📝 Update release notes 2023-07-09 15:45:55 +00:00
github-actions
2d69531509 📝 Update release notes 2023-07-09 15:44:58 +00:00
Sebastián Ramírez
fe91def515 👷 Update FastAPI People token (#9844) 2023-07-09 17:44:40 +02:00
Sebastián Ramírez
73c39745d8 👥 Update FastAPI People (#9775)
Co-authored-by: github-actions <github-actions@github.com>
2023-07-09 17:44:21 +02:00
github-actions
ea92dcaa01 📝 Update release notes 2023-07-09 15:40:19 +00:00
Sebastián Ramírez
9213b72115 👷 Update MkDocs Material token (#9843) 2023-07-09 17:39:42 +02:00
github-actions
eaa14e18d3 📝 Update release notes 2023-07-09 14:37:16 +00:00
Sebastián Ramírez
69df2fa1e5 👷 Update token for latest changes (#9842) 2023-07-09 16:34:45 +02:00
github-actions
c165be380f 📝 Update release notes 2023-07-07 18:15:42 +00:00
Sebastián Ramírez
5f85e2cf58 📝 Update links for self-hosted Swagger UI, point to v5, for OpenAPI 31.0 (#9834)
📝 Update links for self-hosted Swagger UI, point to v5, for OpenAPI 3.1.0
2023-07-07 20:15:08 +02:00
Sebastián Ramírez
f8356d9fff 🔖 Release version 0.100.0 2023-07-07 19:25:59 +02:00
Sebastián Ramírez
179e409159 📝 Update release notes 2023-07-07 19:14:54 +02:00
github-actions
bb7e5b7261 📝 Update release notes 2023-07-07 17:12:58 +00:00
Sebastián Ramírez
0976185af9 Add support for Pydantic v2 (#9816)
*  Pydantic v2 migration, initial implementation (#9500)

*  Add compat layer, for Pydantic v1 and v2

*  Re-export Pydantic needed internals from compat, to later patch them for v1

* ♻️ Refactor internals to use new compatibility layers and run with Pydantic v2

* 📝 Update examples to run with Pydantic v2

*  Update tests to use Pydantic v2

* 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks

*  Temporarily disable Peewee tests, afterwards I'll enable them only for Pydantic v1

* 🐛 Fix JSON Schema generation and OpenAPI ref template

* 🐛 Fix model field creation with defaults from Pydantic v2

* 🐛 Fix body field creation, with new FieldInfo

*  Use and check new ResponseValidationError for server validation errors

*  Fix test_schema_extra_examples tests with ResponseValidationError

*  Add dirty-equals to tests for compatibility with Pydantic v1 and v2

*  Add util to regenerate errors with custom loc

*  Generate validation errors with loc

*  Update tests for compatibility with Pydantic v1 and v2

*  Update tests for Pydantic v2 in tests/test_filter_pydantic_sub_model.py

*  Refactor tests in tests/test_dependency_overrides.py for Pydantic v2, separate parameterized into independent tests to use insert_assert

*  Refactor OpenAPI test for tests/test_infer_param_optionality.py for consistency, and make it compatible with Pydantic v1 and v2

*  Update tests for tests/test_multi_query_errors.py for Pydantic v1 and v2

*  Update tests for tests/test_multi_body_errors.py for Pydantic v1 and v2

*  Update tests for tests/test_multi_body_errors.py for Pydantic v1 and v2

* 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks

* ♻️ Refactor tests for tests/test_path.py to inline pytest parameters, to make it easier to make them compatible with Pydantic v2

*  Refactor and udpate tests for tests/test_path.py for Pydantic v1 and v2

* ♻️ Refactor and update tests for tests/test_query.py with compatibility for Pydantic v1 and v2

*  Fix test with optional field without default None

*  Update tests for compatibility with Pydantic v2

*  Update tutorial tests for Pydantic v2

* ♻️ Update OAuth2 dependencies for Pydantic v2

* ♻️ Refactor str check when checking for sequence types

* ♻️ Rename regex to pattern to keep in sync with Pydantic v2

* ♻️ Refactor _compat.py, start moving conditional imports and declarations to specifics of Pydantic v1 or v2

*  Update tests for OAuth2 security optional

*  Refactor tests for OAuth2 optional for Pydantic v2

*  Refactor tests for OAuth2 security for compatibility with Pydantic v2

* 🐛 Fix location in compat layer for Pydantic v2 ModelField

*  Refactor tests for Pydantic v2 in tests/test_tutorial/test_bigger_applications/test_main_an_py39.py

* 🐛 Add missing markers in Python 3.9 tests

*  Refactor tests for bigger apps for consistency with annotated ones and with support for Pydantic v2

* 🐛 Fix jsonable_encoder with new Pydantic v2 data types and Url

* 🐛 Fix invalid JSON error for compatibility with Pydantic v2

*  Update tests for behind_a_proxy for Pydantic v2

*  Update tests for tests/test_tutorial/test_body/test_tutorial001_py310.py for Pydantic v2

*  Update tests for tests/test_tutorial/test_body/test_tutorial001.py with Pydantic v2 and consistency with Python 3.10 tests

*  Fix tests for tutorial/body_fields for Pydantic v2

*  Refactor tests for tutorial/body_multiple_params with Pydantic v2

*  Update tests for tutorial/body_nested_models for Pydantic v2

*  Update tests for tutorial/body_updates for Pydantic v2

*  Update test for tutorial/cookie_params for Pydantic v2

*  Fix tests for tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py for Pydantic v2

*  Update tests for tutorial/dataclasses for Pydantic v2

*  Update tests for tutorial/dependencies for Pydantic v2

*  Update tests for tutorial/extra_data_types for Pydantic v2

*  Update tests for tutorial/handling_errors for Pydantic v2

*  Fix test markers for Python 3.9

*  Update tests for tutorial/header_params for Pydantic v2

*  Update tests for Pydantic v2 in tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py

*  Fix extra tests for Pydantic v2

*  Refactor test for parameters, to later fix Pydantic v2

*  Update tests for tutorial/query_params for Pydantic v2

* ♻️ Update examples in docs to use new pattern instead of the old regex

*  Fix several tests for Pydantic v2

*  Update and fix test for ResponseValidationError

* 🐛 Fix check for sequences vs scalars, include bytes as scalar

* 🐛 Fix check for complex data types, include UploadFile

* 🐛 Add list to sequence annotation types

* 🐛 Fix checks for uploads and add utils to find if an annotation is an upload (or bytes)

*  Add UnionType and NoneType to compat layer

*  Update tests for request_files for compatibility with Pydantic v2 and consistency with other tests

*  Fix testsw for request_forms for Pydantic v2

*  Fix tests for request_forms_and_files for Pydantic v2

*  Fix tests in tutorial/security for compatibility with Pydantic v2

* ⬆️ Upgrade required version of email_validator

*  Fix tests for params repr

*  Add Pydantic v2 pytest markers

* Use match_pydantic_error_url

* 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks

* Use field_serializer instead of encoders in some tests

* Show Undefined as ... in repr

* Mark custom encoders test with xfail

* Update test to reflect new serialization of Decimal as str

* Use `model_validate` instead of `from_orm`

* Update JSON schema to reflect required nullable

* Add dirty-equals to pyproject.toml

* Fix locs and error creation for use with pydantic 2.0a4

* Use the type adapter for serialization. This is hacky.

* 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks

*  Refactor test_multi_body_errors for compatibility with Pydantic v1 and v2

*  Refactor test_custom_encoder for Pydantic v1 and v2

*  Set input to None for now, for compatibility with current tests

* 🐛 Fix passing serialization params to model field when handling the response

* ♻️ Refactor exceptions to not depend on Pydantic ValidationError class

* ♻️ Revert/refactor params to simplify repr

*  Tweak tests for custom class encoders for Pydantic v1 and v2

*  Tweak tests for jsonable_encoder for Pydantic v1 and v2

*  Tweak test for compatibility with Pydantic v1 and v2

* 🐛 Fix filtering data with subclasses

* 🐛 Workaround examples in OpenAPI schema

*  Add skip marker for SQL tutorial, needs to be updated either way

*  Update test for broken JSON

*  Fix test for broken JSON

*  Update tests for timedeltas

*  Fix test for plain text validation errors

*  Add markers for Pydantic v1 exclusive tests (for now)

*  Update test for path_params with enums for compatibility with Pydantic v1 and v2

*  Update tests for extra examples in OpenAPI

*  Fix tests for response_model with compatibility with Pydantic v1 and v2

* 🐛 Fix required double serialization for different types of models

*  Fix tests for response model with compatibility with new Pydantic v2

* 🐛 Import Undefined from compat layer

*  Fix tests for response_model for Pydantic v2

*  Fix tests for schema_extra for Pydantic v2

*  Add markers and update tests for Pydantic v2

* 💡 Comment out logic for double encoding that breaks other usecases

*  Update errors for int parsing

* ♻️ Refactor re-enabling compatibility for Pydantic v1

* ♻️ Refactor OpenAPI utils to re-enable support for Pydantic v1

* ♻️ Refactor dependencies/utils and _compat for compatibility with Pydantic v1

* 🐛 Fix and tweak compatibility with Pydantic v1 and v2 in dependencies/utils

*  Tweak tests and examples for Pydantic v1

* ♻️ Tweak call to ModelField.validate for compatibility with Pydantic v1

*  Use new global override TypeAdapter from_attributes

*  Update tests after updating from_attributes

* 🔧 Update pytest config to avoid collecting tests from docs, useful for editor-integrated tests

*  Add test for data filtering, including inheritance and models in fields or lists of models

* ♻️ Make OpenAPI models compatible with both Pydantic v1 and v2

* ♻️ Fix compatibility for Pydantic v1 and v2 in jsonable_encoder

* ♻️ Fix compatibility in params with Pydantic v1 and v2

* ♻️ Fix compatibility when creating a FieldInfo in Pydantic v1 and v2 in utils.py

* ♻️ Fix generation of flat_models and JSON Schema definitions in _compat.py for Pydantic v1 and v2

* ♻️ Update handling of ErrorWrappers for Pydantic v1

* ♻️ Refactor checks and handling of types an sequences

* ♻️ Refactor and cleanup comments with compatibility for Pydantic v1 and v2

* ♻️ Update UploadFile for compatibility with both Pydantic v1 and v2

* 🔥 Remove commented out unneeded code

* 🐛 Fix mock of get_annotation_from_field_info for Pydantic v1 and v2

* 🐛 Fix params with compatibility for Pydantic v1 and v2, with schemas and new pattern vs regex

* 🐛 Fix check if field is sequence for Pydantic v1

*  Fix tests for custom_schema_fields, for compatibility with Pydantic v1 and v2

*  Simplify and fix tests for jsonable_encoder with compatibility for Pydantic v1 and v2

*  Fix tests for orm_mode with Pydantic v1 and compatibility with Pydantic v2

* ♻️ Refactor logic for normalizing Pydantic v1 ErrorWrappers

* ♻️ Workaround for params with examples, before defining what to deprecate in Pydantic v1 and v2 for examples with JSON Schema vs OpenAPI

*  Fix tests for Pydantic v1 and v2 for response_by_alias

*  Fix test for schema_extra with compatibility with Pydantic v1 and v2

* ♻️ Tweak error regeneration with loc

* ♻️ Update error handling and serializationwith compatibility for Pydantic v1 and v2

* ♻️ Re-enable custom encoders for Pydantic v1

* ♻️ Update ErrorWrapper reserialization in Pydantic v1, do it outside of FastAPI ValidationExceptions

*  Update test for filter_submodel, re-structure to simplify testing while keeping division of Pydantic v1 and v2

*  Refactor Pydantic v1 only test that requires modifying environment variables

* 🔥 Update test for plaintext error responses, for Pydantic v1 and v2

* ️ Revert changes in DB tutorial to use Pydantic v1 (the new guide will have SQLModel)

*  Mark current SQL DB tutorial tests as Pydantic only

* ♻️ Update datastructures for compatibility with Pydantic v1, not requiring pydantic-core

* ♻️ Update encoders.py for compatibility with Pydantic v1

* ️ Revert changes to Peewee, the docs for that are gonna live in a new HowTo section, not in the main tutorials

* ♻️ Simplify response body kwargs generation

* 🔥 Clean up comments

* 🔥 Clean some tests and comments

*  Refactor tests to match new Pydantic error string URLs

*  Refactor tests for recursive models for Pydantic v1 and v2

*  Update tests for Peewee, re-enable, Pydantic-v1-only

* ♻️ Update FastAPI params to take regex and pattern arguments

* ️ Revert tutorial examples for pattern, it will be done in a subsequent PR

* ️ Revert changes in schema extra examples, it will be added later in a docs-specific PR

* 💡 Add TODO comment to document str validations with pattern

* 🔥 Remove unneeded comment

* 📌 Upgrade Pydantic pin dependency

* ⬆️ Upgrade email_validator dependency

* 🐛 Tweak type annotations in _compat.py

* 🔇 Tweak mypy errors for compat, for Pydantic v1 re-imports

* 🐛 Tweak and fix type annotations

*  Update requirements-test.txt, re-add dirty-equals

* 🔥 Remove unnecessary config

* 🐛 Tweak type annotations

* 🔥 Remove unnecessary type in dependencies/utils.py

* 💡 Update comment in routing.py

---------

Co-authored-by: David Montague <35119617+dmontagu@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* 👷 Add CI for both Pydantic v1 and v2 (#9688)

* 👷 Test and install Pydantic v1 and v2 in CI

* 💚 Tweak CI config for Pydantic v1 and v2

* 💚 Fix Pydantic v2 specification in CI

* 🐛 Fix type annotations for compatibility with Python 3.7

* 💚 Install Pydantic v2 for lints

* 🐛 Fix type annotations for Pydantic v2

* 💚 Re-use test cache for lint

* ♻️ Refactor internals for test coverage and performance (#9691)

* ♻️ Tweak import of Annotated from typing_extensions, they are installed anyway

* ♻️ Refactor _compat to define functions for Pydantic v1 or v2 once instead of checking inside

*  Add test for UploadFile for Pydantic v2

* ♻️ Refactor types and remove logic for impossible cases

*  Add missing tests from test refactor for path params

*  Add tests for new decimal encoder

* 💡 Add TODO comment for decimals in encoders

* 🔥 Remove unneeded dummy function

* 🔥 Remove section of code in field_annotation_is_scalar covered by sub-call to field_annotation_is_complex

* ♻️ Refactor and tweak variables and types in _compat

*  Add tests for corner cases and compat with Pydantic v1 and v2

* ♻️ Refactor type annotations

* 🔖 Release version 0.100.0-beta1

* ♻️ Refactor parts that use optional requirements to make them compatible with installations without them (#9707)

* ♻️ Refactor parts that use optional requirements to make them compatible with installations without them

* ♻️ Update JSON Schema for email field without email-validator installed

* 🐛 Fix support for Pydantic v2.0, small changes in their final release (#9771)

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>

* 🔖 Release version 0.100.0-beta2

*  OpenAPI 3.1.0 with Pydantic v2, merge `master` (#9773)

*  Add dirty-equals as a testing dependency (#9778)

 Add dirty-equals as a testing dependency, it seems it got lsot at some point

* 🔀 Merge master, fix valid JSON Schema accepting bools (#9782)

* ️ Revert usage of custom logic for TypeAdapter JSON Schema, solved on the Pydantic side (#9787)

️ Revert usage of custom logic for TypeAdapter JSON Schema, solved on Pydantic side

* ♻️ Deprecate parameter `regex`, use `pattern` instead (#9786)

* 📝 Update docs to deprecate regex, recommend pattern

* ♻️ Update examples to use new pattern instead of regex

* 📝 Add new example with deprecated regex

* ♻️ Add deprecation notes and warnings for regex

*  Add tests for regex deprecation

*  Update tests for compatibility with Pydantic v1

*  Update docs to use Pydantic v2 settings and add note and example about v1 (#9788)

*  Add pydantic-settings to all extras

* 📝 Update docs for Pydantic settings

* 📝 Update Settings source examples to use Pydantic v2, and add a Pydantic v1 version

*  Add tests for settings with Pydantic v1 and v2

* 🔥 Remove solved TODO comment

* ♻️ Update conditional OpenAPI to use new Pydantic v2 settings

*  Update tests to import Annotated from typing_extensions for Python < 3.9 (#9795)

*  Add pydantic-extra-types to fastapi[extra]

*  temp: Install Pydantic from source to test JSON Schema metadata fixes (#9777)

*  Install Pydantic from source, from branch for JSON Schema with metadata

*  Update dependencies, install Pydantic main

*  Fix dependency URL for Pydantic from source

*  Add pydantic-settings for test requirements

* 💡 Add TODO comments to re-enable Pydantic main (not from source) (#9796)

*  Add new Pydantic Field param options to Query, Cookie, Body, etc. (#9797)

* 📝 Add docs for Pydantic v2 for `docs/en/docs/advanced/path-operation-advanced-configuration.md` (#9798)

* 📝 Update docs in examples for settings with Pydantic v2 (#9799)

* 📝 Update JSON Schema `examples` docs with Pydantic v2 (#9800)

* ♻️ Use new Pydantic v2 JSON Schema generator (#9813)

Co-authored-by: David Montague <35119617+dmontagu@users.noreply.github.com>

* ♻️ Tweak type annotations and Pydantic version range (#9801)

* 📌 Re-enable GA Pydantic, for v2, require minimum 2.0.2 (#9814)

* 🔖 Release version 0.100.0-beta3

* 🔥 Remove duplicate type declaration from merge conflicts (#9832)

* 👷‍♂️ Run tests with Pydantic v2 GA (#9830)

👷 Run tests for Pydantic v2 GA

* 📝 Add notes to docs expecting Pydantic v2 and future updates (#9833)

* 📝 Update index with new extras

* 📝 Update release notes

---------

Co-authored-by: David Montague <35119617+dmontagu@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Pastukhov Nikita <diementros@yandex.ru>
2023-07-07 19:12:13 +02:00
Sebastián Ramírez
dd4e78ca7b 🔖 Release version 0.99.1 2023-07-02 18:00:39 +02:00
Sebastián Ramírez
8a198fc1ed 📝 Update release notes 2023-07-02 18:00:12 +02:00
github-actions
6bd4f53531 📝 Update release notes 2023-07-02 15:59:00 +00:00
Sebastián Ramírez
07e1dea467 🐛 Fix JSON Schema accepting bools as valid JSON Schemas, e.g. additionalProperties: false (#9781)
* 🐛 Fix JSON Schema accepting bools as valid JSON Schemas, e.g. additionalProperties: false

*  Add test to ensure additionalProperties can be false

* ♻️ Tweak OpenAPI models to support Pydantic v1's JSON Schema for tuples
2023-07-02 17:58:23 +02:00
github-actions
0f105d9076 📝 Update release notes 2023-07-01 16:44:12 +00:00
Sebastián Ramírez
4d83f984cc 📝 Update source examples to use new JSON Schema examples field (#9776)
* 📝 Update source examples to use new JSON Schema examples field

*  Update tests for JSON Schema examples

* 📝 Update highlights in JSON Schema examples
2023-07-01 18:43:29 +02:00
Sebastián Ramírez
89c6e4b56f 📝 Add note about sections, achievable with extra 2022-12-20 17:11:25 +04:00
Sebastián Ramírez
094744c2fe 📝 Add Additional Features to Open Issues with future suggestions/ideas by @pawamoy 2022-12-20 00:10:28 +04:00
Sebastián Ramírez
d80a8fce5f 📝 Tweak doc structure for clarity and completeness 2022-12-20 00:00:49 +04:00
Sebastián Ramírez
9c116b4ed5 📝 Add support for exception descriptions as suggested by @pawamoy 2022-12-19 23:59:16 +04:00
Sebastián Ramírez
439ee24b74 📝 Add section about duplicated effort and connection between doc() and exceptions/warnings as suggested by @brettcannon 2022-12-19 23:58:01 +04:00
Sebastián Ramírez
167bd74306 📝 Move additional future parameters to its own section in Open Issues, as suggested by @brettcannon 2022-12-19 23:40:18 +04:00
Sebastián Ramírez
116749ac7f 📝 Use BaseException instead of Exception in raises as suggested by @Kludex 2022-12-05 21:19:31 +01:00
Sebastián Ramírez
901514e32b 📝 Add note about early adopters on Alternate Form 2022-12-05 21:16:08 +01:00
Sebastián Ramírez
507fda0c71 ✏️ Fix typo 2022-12-05 21:15:53 +01:00
Sebastián Ramírez
ca47f5c0d4 📝 Add Alternate Form for early adopters 2022-12-05 21:08:41 +01:00
Sebastián Ramírez
1ca7f25af4 📝 Add note clarifying that parameters should allow static evaluation as suggested by @pawamoy 2022-12-05 21:06:20 +01:00
Sebastián Ramírez
836b6838f5 📝 📝 Add raises parameter as suggested in an informal chat with @Kludex 2022-12-05 21:04:10 +01:00
Sebastián Ramírez
932356ff82 📝 Add **kwargs parameter to follow the design in the final version of dataclass_transform 2022-12-05 20:58:17 +01:00
Sebastián Ramírez
0c6ff8e44c 📝 Add first version of typing.doc proposal 2022-08-18 15:10:00 +02:00
426 changed files with 29555 additions and 7751 deletions

View File

@@ -123,6 +123,20 @@ body:
```
validations:
required: true
- type: input
id: pydantic-version
attributes:
label: Pydantic Version
description: |
What Pydantic version are you using?
You can find the Pydantic version with:
```bash
python -c "import pydantic; print(pydantic.version.VERSION)"
```
validations:
required: true
- type: input
id: python-version
attributes:

View File

@@ -1,6 +1,6 @@
FROM python:3.7
FROM python:3.9
RUN pip install httpx PyGithub "pydantic==1.5.1" "pyyaml>=5.3.1,<6.0.0"
RUN pip install httpx PyGithub "pydantic==2.0.2" pydantic-settings "pyyaml>=5.3.1,<6.0.0"
COPY ./app /app

View File

@@ -3,10 +3,7 @@ description: "Generate the data for the FastAPI People page"
author: "Sebastián Ramírez <tiangolo@gmail.com>"
inputs:
token:
description: 'User token, to read the GitHub API. Can be passed in using {{ secrets.ACTION_TOKEN }}'
required: true
standard_token:
description: 'Default GitHub Action token, used for the PR. Can be passed in using {{ secrets.GITHUB_TOKEN }}'
description: 'User token, to read the GitHub API. Can be passed in using {{ secrets.FASTAPI_PEOPLE }}'
required: true
runs:
using: 'docker'

View File

@@ -9,7 +9,8 @@ from typing import Any, Container, DefaultDict, Dict, List, Set, Union
import httpx
import yaml
from github import Github
from pydantic import BaseModel, BaseSettings, SecretStr
from pydantic import BaseModel, SecretStr
from pydantic_settings import BaseSettings
github_graphql_url = "https://api.github.com/graphql"
questions_category_id = "MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMyMDAxNDM0"
@@ -352,7 +353,6 @@ class SponsorsResponse(BaseModel):
class Settings(BaseSettings):
input_token: SecretStr
input_standard_token: SecretStr
github_repository: str
httpx_timeout: int = 30
@@ -383,6 +383,7 @@ def get_graphql_response(
data = response.json()
if "errors" in data:
logging.error(f"Errors in response, after: {after}, category_id: {category_id}")
logging.error(data["errors"])
logging.error(response.text)
raise RuntimeError(response.text)
return data
@@ -390,7 +391,7 @@ def get_graphql_response(
def get_graphql_issue_edges(*, settings: Settings, after: Union[str, None] = None):
data = get_graphql_response(settings=settings, query=issues_query, after=after)
graphql_response = IssuesResponse.parse_obj(data)
graphql_response = IssuesResponse.model_validate(data)
return graphql_response.data.repository.issues.edges
@@ -405,19 +406,19 @@ def get_graphql_question_discussion_edges(
after=after,
category_id=questions_category_id,
)
graphql_response = DiscussionsResponse.parse_obj(data)
graphql_response = DiscussionsResponse.model_validate(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)
graphql_response = PRsResponse.model_validate(data)
return graphql_response.data.repository.pullRequests.edges
def get_graphql_sponsor_edges(*, settings: Settings, after: Union[str, None] = None):
data = get_graphql_response(settings=settings, query=sponsors_query, after=after)
graphql_response = SponsorsResponse.parse_obj(data)
graphql_response = SponsorsResponse.model_validate(data)
return graphql_response.data.user.sponsorshipsAsMaintainer.edges
@@ -608,8 +609,8 @@ def get_top_users(
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
settings = Settings()
logging.info(f"Using config: {settings.json()}")
g = Github(settings.input_standard_token.get_secret_value())
logging.info(f"Using config: {settings.model_dump_json()}")
g = Github(settings.input_token.get_secret_value())
repo = g.get_repo(settings.github_repository)
question_commentors, question_last_month_commentors, question_authors = get_experts(
settings=settings

View File

@@ -44,14 +44,14 @@ jobs:
id: cache
with:
path: ${{ env.pythonLocation }}
key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v05
key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v06
- name: Install docs extras
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-docs.txt
# Install MkDocs Material Insiders here just to put it in the cache for the rest of the steps
- name: Install Material for MkDocs Insiders
if: ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false ) && steps.cache.outputs.cache-hit != 'true'
run: pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git
run: pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/squidfunk/mkdocs-material-insiders.git
- name: Export Language Codes
id: show-langs
run: |
@@ -80,13 +80,13 @@ jobs:
id: cache
with:
path: ${{ env.pythonLocation }}
key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v05
key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v06
- name: Install docs extras
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-docs.txt
- name: Install Material for MkDocs Insiders
if: ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false ) && steps.cache.outputs.cache-hit != 'true'
run: pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git
run: pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/squidfunk/mkdocs-material-insiders.git
- name: Update Languages
run: python ./scripts/docs.py update-languages
- uses: actions/cache@v3

View File

@@ -29,21 +29,20 @@ jobs:
run_id: ${{ github.event.workflow_run.id }}
name: docs-site
path: ./site/
- name: Deploy to Netlify
- name: Deploy to Cloudflare Pages
if: steps.download.outputs.found_artifact == 'true'
id: netlify
uses: nwtgck/actions-netlify@v2.0.0
id: deploy
uses: cloudflare/pages-action@v1
with:
publish-dir: './site'
production-deploy: ${{ github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'master' }}
github-token: ${{ secrets.FASTAPI_PREVIEW_DOCS_NETLIFY }}
enable-commit-comment: false
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: fastapitiangolo
directory: './site'
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ ( github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'master' && 'main' ) || ( github.event.workflow_run.head_sha ) }}
- name: Comment Deploy
if: steps.netlify.outputs.deploy-url != ''
if: steps.deploy.outputs.url != ''
uses: ./.github/actions/comment-docs-preview-in-pr
with:
token: ${{ secrets.FASTAPI_PREVIEW_DOCS_COMMENT_DEPLOY }}
deploy_url: "${{ steps.netlify.outputs.deploy-url }}"
deploy_url: "${{ steps.deploy.outputs.url }}"

View File

@@ -19,6 +19,10 @@ jobs:
if: github.repository_owner == 'tiangolo'
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: tiangolo/issue-manager@0.4.0
with:
token: ${{ secrets.FASTAPI_ISSUE_MANAGER }}

View File

@@ -9,6 +9,10 @@ jobs:
if: github.repository_owner == 'tiangolo'
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: docker://tiangolo/label-approved:0.0.2
with:
token: ${{ secrets.FASTAPI_LABEL_APPROVED }}

View File

@@ -14,25 +14,29 @@ on:
debug_enabled:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false
default: false
default: 'false'
jobs:
latest-changes:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3
with:
# To allow latest-changes to commit to master
token: ${{ secrets.ACTIONS_TOKEN }}
# To allow latest-changes to commit to the main branch
token: ${{ secrets.FASTAPI_LATEST_CHANGES }}
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
with:
limit-access-to-actor: true
- uses: docker://tiangolo/latest-changes:0.0.3
with:
token: ${{ secrets.FASTAPI_LATEST_CHANGES }}
token: ${{ secrets.GITHUB_TOKEN }}
latest_changes_file: docs/en/docs/release-notes.md
latest_changes_header: '## Latest Changes\n\n'
debug_logs: true

View File

@@ -5,16 +5,29 @@ on:
types:
- labeled
- closed
workflow_dispatch:
inputs:
number:
description: PR number
required: true
debug_enabled:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false
default: 'false'
jobs:
notify-translations:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
with:
limit-access-to-actor: true
- uses: ./.github/actions/notify-translations

View File

@@ -8,13 +8,17 @@ on:
debug_enabled:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false
default: false
default: 'false'
jobs:
fastapi-people:
if: github.repository_owner == 'tiangolo'
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3
# Ref: https://github.com/actions/runner/issues/2033
- name: Fix git safe.directory in container
@@ -22,10 +26,9 @@ jobs:
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
with:
limit-access-to-actor: true
- uses: ./.github/actions/people
with:
token: ${{ secrets.ACTIONS_TOKEN }}
standard_token: ${{ secrets.FASTAPI_PEOPLE }}
token: ${{ secrets.FASTAPI_PEOPLE }}

View File

@@ -14,6 +14,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/setup-python@v4
with:
python-version: '3.9'

View File

@@ -13,6 +13,10 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
@@ -25,10 +29,12 @@ jobs:
id: cache
with:
path: ${{ env.pythonLocation }}
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v03
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-pydantic-v2-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v05
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-tests.txt
- name: Install Pydantic v2
run: pip install "pydantic>=2.0.2,<3.0.0"
- name: Lint
run: bash scripts/lint.sh
@@ -37,8 +43,13 @@ jobs:
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
pydantic-version: ["pydantic-v1", "pydantic-v2"]
fail-fast: false
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
@@ -51,10 +62,16 @@ jobs:
id: cache
with:
path: ${{ env.pythonLocation }}
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v03
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ matrix.pydantic-version }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v05
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-tests.txt
- name: Install Pydantic v1
if: matrix.pydantic-version == 'pydantic-v1'
run: pip install "pydantic>=1.10.0,<2.0.0"
- name: Install Pydantic v2
if: matrix.pydantic-version == 'pydantic-v2'
run: pip install "pydantic>=2.0.2,<3.0.0"
- run: mkdir coverage
- name: Test
run: bash scripts/test.sh
@@ -71,6 +88,10 @@ jobs:
needs: [test]
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
@@ -101,6 +122,10 @@ jobs:
- coverage-combine
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1
with:

3
.gitignore vendored
View File

@@ -25,3 +25,6 @@ archive.zip
*~
.*.sw?
.cache
# macOS
.DS_Store

View File

@@ -48,6 +48,8 @@ The key features are:
<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://platform.sh/try-it-now/?utm_source=fastapi-signup&utm_medium=banner&utm_campaign=FastAPI-signup-June-2023" target="_blank" title="Build, run and scale your apps on a modern, reliable, and secure PaaS."><img src="https://fastapi.tiangolo.com/img/sponsors/platform-sh.png"></a>
<a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=main-badge" target="_blank" title="Fern | SDKs and API docs"><img src="https://fastapi.tiangolo.com/img/sponsors/fern.svg"></a>
<a href="https://www.porter.run" target="_blank" title="Deploy FastAPI on AWS with a few clicks"><img src="https://fastapi.tiangolo.com/img/sponsors/porter.png"></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://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>
@@ -55,6 +57,7 @@ The key features are:
<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>
<a href="https://databento.com/" target="_blank" title="Pay as you go for market data"><img src="https://fastapi.tiangolo.com/img/sponsors/databento.svg"></a>
<a href="https://speakeasyapi.dev?utm_source=fastapi+repo&utm_medium=github+sponsorship" target="_blank" title="SDKs for your API | Speakeasy"><img src="https://fastapi.tiangolo.com/img/sponsors/speakeasy.png"></a>
<!-- /sponsors -->
@@ -447,6 +450,8 @@ To understand more about it, see the section <a href="https://fastapi.tiangolo.c
Used by Pydantic:
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - for settings management.
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - for extra types to be used with Pydantic.
Used by Starlette:

View File

@@ -1,314 +0,0 @@
# ↔ 🗄
!!! warning
👉 👍 🏧 ⚒. 👆 🎲 💪 🚶 ⚫️.
🚥 👆 📄 🔰 - 👩‍💻 🦮, 👆 💪 🎲 🚶 👉 📄.
🚥 👆 ⏪ 💭 👈 👆 💪 🔀 🏗 🗄 🔗, 😣 👂.
📤 💼 🌐❔ 👆 💪 💪 🔀 🏗 🗄 🔗.
👉 📄 👆 🔜 👀 ❔.
## 😐 🛠️
😐 (🔢) 🛠️, ⏩.
`FastAPI` 🈸 (👐) ✔️ `.openapi()` 👩‍🔬 👈 📈 📨 🗄 🔗.
🍕 🈸 🎚 🏗, *➡ 🛠️* `/openapi.json` (⚖️ ⚫️❔ 👆 ⚒ 👆 `openapi_url`) ®.
⚫️ 📨 🎻 📨 ⏮️ 🏁 🈸 `.openapi()` 👩‍🔬.
🔢, ⚫️❔ 👩‍🔬 `.openapi()` 🔨 ✅ 🏠 `.openapi_schema` 👀 🚥 ⚫️ ✔️ 🎚 &amp; 📨 👫.
🚥 ⚫️ 🚫, ⚫️ 🏗 👫 ⚙️ 🚙 🔢 `fastapi.openapi.utils.get_openapi`.
&amp; 👈 🔢 `get_openapi()` 📨 🔢:
* `title`: 🗄 📛, 🎦 🩺.
* `version`: ⏬ 👆 🛠️, ✅ `2.5.0`.
* `openapi_version`: ⏬ 🗄 🔧 ⚙️. 🔢, ⏪: `3.0.2`.
* `description`: 📛 👆 🛠️.
* `routes`: 📇 🛣, 👫 🔠 ® *➡ 🛠️*. 👫 ✊ ⚪️➡️ `app.routes`.
## 🔑 🔢
⚙️ 🔛, 👆 💪 ⚙️ 🎏 🚙 🔢 🏗 🗄 🔗 &amp; 🔐 🔠 🍕 👈 👆 💪.
🖼, ➡️ 🚮 <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">📄 🗄 ↔ 🔌 🛃 🔱</a>.
### 😐 **FastAPI**
🥇, ✍ 🌐 👆 **FastAPI** 🈸 🛎:
```Python hl_lines="1 4 7-9"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### 🏗 🗄 🔗
⤴️, ⚙️ 🎏 🚙 🔢 🏗 🗄 🔗, 🔘 `custom_openapi()` 🔢:
```Python hl_lines="2 15-20"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### 🔀 🗄 🔗
🔜 👆 💪 🚮 📄 ↔, ❎ 🛃 `x-logo` `info` "🎚" 🗄 🔗:
```Python hl_lines="21-23"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### 💾 🗄 🔗
👆 💪 ⚙️ 🏠 `.openapi_schema` "💾", 🏪 👆 🏗 🔗.
👈 🌌, 👆 🈸 🏆 🚫 ✔️ 🏗 🔗 🔠 🕰 👩‍💻 📂 👆 🛠️ 🩺.
⚫️ 🔜 🏗 🕴 🕐, &amp; ⤴️ 🎏 💾 🔗 🔜 ⚙️ ⏭ 📨.
```Python hl_lines="13-14 24-25"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### 🔐 👩‍🔬
🔜 👆 💪 ❎ `.openapi()` 👩‍🔬 ⏮️ 👆 🆕 🔢.
```Python hl_lines="28"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### ✅ ⚫️
🕐 👆 🚶 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> 👆 🔜 👀 👈 👆 ⚙️ 👆 🛃 🔱 (👉 🖼, **FastAPI**'Ⓜ 🔱):
<img src="/img/tutorial/extending-openapi/image01.png">
## 👤-🕸 🕸 &amp; 🎚 🩺
🛠️ 🩺 ⚙️ **🦁 🎚** &amp; **📄**, &amp; 🔠 👈 💪 🕸 &amp; 🎚 📁.
🔢, 👈 📁 🍦 ⚪️➡️ <abbr title="Content Delivery Network: A service, normally composed of several servers, that provides static files, like JavaScript and CSS. It's commonly used to serve those files from the server closer to the client, improving performance.">💲</abbr>.
✋️ ⚫️ 💪 🛃 ⚫️, 👆 💪 ⚒ 🎯 💲, ⚖️ 🍦 📁 👆.
👈 ⚠, 🖼, 🚥 👆 💪 👆 📱 🚧 👷 ⏪ 📱, 🍵 📂 🕸 🔐, ⚖️ 🇧🇿 🕸.
📥 👆 🔜 👀 ❔ 🍦 👈 📁 👆, 🎏 FastAPI 📱, &amp; 🔗 🩺 ⚙️ 👫.
### 🏗 📁 📊
➡️ 💬 👆 🏗 📁 📊 👀 💖 👉:
```
.
├── app
│ ├── __init__.py
│ ├── main.py
```
🔜 ✍ 📁 🏪 📚 🎻 📁.
👆 🆕 📁 📊 💪 👀 💖 👉:
```
.
├── app
│   ├── __init__.py
│   ├── main.py
└── static/
```
### ⏬ 📁
⏬ 🎻 📁 💪 🩺 &amp; 🚮 👫 🔛 👈 `static/` 📁.
👆 💪 🎲 ▶️️-🖊 🔠 🔗 &amp; 🖊 🎛 🎏 `Save link as...`.
**🦁 🎚** ⚙️ 📁:
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a>
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a>
&amp; **📄** ⚙️ 📁:
* <a href="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js" class="external-link" target="_blank">`redoc.standalone.js`</a>
⏮️ 👈, 👆 📁 📊 💪 👀 💖:
```
.
├── app
│   ├── __init__.py
│   ├── main.py
└── static
├── redoc.standalone.js
├── swagger-ui-bundle.js
└── swagger-ui.css
```
### 🍦 🎻 📁
* 🗄 `StaticFiles`.
* "🗻" `StaticFiles()` 👐 🎯 ➡.
```Python hl_lines="7 11"
{!../../../docs_src/extending_openapi/tutorial002.py!}
```
### 💯 🎻 📁
▶️ 👆 🈸 &amp; 🚶 <a href="http://127.0.0.1:8000/static/redoc.standalone.js" class="external-link" target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a>.
👆 🔜 👀 📶 📏 🕸 📁 **📄**.
⚫️ 💪 ▶️ ⏮️ 🕳 💖:
```JavaScript
/*!
* ReDoc - OpenAPI/Swagger-generated API Reference Documentation
* -------------------------------------------------------------
* Version: "2.0.0-rc.18"
* Repo: https://github.com/Redocly/redoc
*/
!function(e,t){"object"==typeof exports&&"object"==typeof m
...
```
👈 ✔ 👈 👆 💆‍♂ 💪 🍦 🎻 📁 ⚪️➡️ 👆 📱, &amp; 👈 👆 🥉 🎻 📁 🩺 ☑ 🥉.
🔜 👥 💪 🔗 📱 ⚙️ 📚 🎻 📁 🩺.
### ❎ 🏧 🩺
🥇 🔁 ❎ 🏧 🩺, 📚 ⚙️ 💲 🔢.
❎ 👫, ⚒ 👫 📛 `None` 🕐❔ 🏗 👆 `FastAPI` 📱:
```Python hl_lines="9"
{!../../../docs_src/extending_openapi/tutorial002.py!}
```
### 🔌 🛃 🩺
🔜 👆 💪 ✍ *➡ 🛠️* 🛃 🩺.
👆 💪 🏤-⚙️ FastAPI 🔗 🔢 ✍ 🕸 📃 🩺, &amp; 🚶‍♀️ 👫 💪 ❌:
* `openapi_url`: 📛 🌐❔ 🕸 📃 🩺 💪 🤚 🗄 🔗 👆 🛠️. 👆 💪 ⚙️ 📥 🔢 `app.openapi_url`.
* `title`: 📛 👆 🛠️.
* `oauth2_redirect_url`: 👆 💪 ⚙️ `app.swagger_ui_oauth2_redirect_url` 📥 ⚙️ 🔢.
* `swagger_js_url`: 📛 🌐❔ 🕸 👆 🦁 🎚 🩺 💪 🤚 **🕸** 📁. 👉 1⃣ 👈 👆 👍 📱 🔜 🍦.
* `swagger_css_url`: 📛 🌐❔ 🕸 👆 🦁 🎚 🩺 💪 🤚 **🎚** 📁. 👉 1⃣ 👈 👆 👍 📱 🔜 🍦.
&amp; ➡ 📄...
```Python hl_lines="2-6 14-22 25-27 30-36"
{!../../../docs_src/extending_openapi/tutorial002.py!}
```
!!! tip
*➡ 🛠️* `swagger_ui_redirect` 👩‍🎓 🕐❔ 👆 ⚙️ Oauth2⃣.
🚥 👆 🛠️ 👆 🛠️ ⏮️ Oauth2⃣ 🐕‍🦺, 👆 🔜 💪 🔓 &amp; 👟 🔙 🛠️ 🩺 ⏮️ 📎 🎓. &amp; 🔗 ⏮️ ⚫️ ⚙️ 🎰 Oauth2⃣ 🤝.
🦁 🎚 🔜 🍵 ⚫️ ⛅ 🎑 👆, ✋️ ⚫️ 💪 👉 "❎" 👩‍🎓.
### ✍ *➡ 🛠️* 💯 ⚫️
🔜, 💪 💯 👈 🌐 👷, ✍ *➡ 🛠️*:
```Python hl_lines="39-41"
{!../../../docs_src/extending_openapi/tutorial002.py!}
```
### 💯 ⚫️
🔜, 👆 🔜 💪 🔌 👆 📻, 🚶 👆 🩺 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, &amp; 🔃 📃.
&amp; 🍵 🕸, 👆 🔜 💪 👀 🩺 👆 🛠️ &amp; 🔗 ⏮️ ⚫️.
## 🛠️ 🦁 🎚
👆 💪 🔗 <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">🦁 🎚 🔢</a>.
🔗 👫, 🚶‍♀️ `swagger_ui_parameters` ❌ 🕐❔ 🏗 `FastAPI()` 📱 🎚 ⚖️ `get_swagger_ui_html()` 🔢.
`swagger_ui_parameters` 📨 📖 ⏮️ 📳 🚶‍♀️ 🦁 🎚 🔗.
FastAPI 🗜 📳 **🎻** ⚒ 👫 🔗 ⏮️ 🕸, 👈 ⚫️❔ 🦁 🎚 💪.
### ❎ ❕ 🎦
🖼, 👆 💪 ❎ ❕ 🎦 🦁 🎚.
🍵 🔀 ⚒, ❕ 🎦 🛠️ 🔢:
<img src="/img/tutorial/extending-openapi/image02.png">
✋️ 👆 💪 ❎ ⚫️ ⚒ `syntaxHighlight` `False`:
```Python hl_lines="3"
{!../../../docs_src/extending_openapi/tutorial003.py!}
```
...&amp; ⤴️ 🦁 🎚 🏆 🚫 🎦 ❕ 🎦 🚫🔜:
<img src="/img/tutorial/extending-openapi/image03.png">
### 🔀 🎢
🎏 🌌 👆 💪 ⚒ ❕ 🎦 🎢 ⏮️ 🔑 `"syntaxHighlight.theme"` (👀 👈 ⚫️ ✔️ ❣ 🖕):
```Python hl_lines="3"
{!../../../docs_src/extending_openapi/tutorial004.py!}
```
👈 📳 🔜 🔀 ❕ 🎦 🎨 🎢:
<img src="/img/tutorial/extending-openapi/image04.png">
### 🔀 🔢 🦁 🎚 🔢
FastAPI 🔌 🔢 📳 🔢 ☑ 🌅 ⚙️ 💼.
⚫️ 🔌 👫 🔢 📳:
```Python
{!../../../fastapi/openapi/docs.py[ln:7-13]!}
```
👆 💪 🔐 🙆 👫 ⚒ 🎏 💲 ❌ `swagger_ui_parameters`.
🖼, ❎ `deepLinking` 👆 💪 🚶‍♀️ 👉 ⚒ `swagger_ui_parameters`:
```Python hl_lines="3"
{!../../../docs_src/extending_openapi/tutorial005.py!}
```
### 🎏 🦁 🎚 🔢
👀 🌐 🎏 💪 📳 👆 💪 ⚙️, ✍ 🛂 <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">🩺 🦁 🎚 🔢</a>.
### 🕸-🕴 ⚒
🦁 🎚 ✔ 🎏 📳 **🕸-🕴** 🎚 (🖼, 🕸 🔢).
FastAPI 🔌 👫 🕸-🕴 `presets` ⚒:
```JavaScript
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
]
```
👫 **🕸** 🎚, 🚫 🎻, 👆 💪 🚫 🚶‍♀️ 👫 ⚪️➡️ 🐍 📟 🔗.
🚥 👆 💪 ⚙️ 🕸-🕴 📳 💖 📚, 👆 💪 ⚙️ 1⃣ 👩‍🔬 🔛. 🔐 🌐 🦁 🎚 *➡ 🛠️* &amp; ❎ ✍ 🙆 🕸 👆 💪.

View File

@@ -1,258 +0,0 @@
# 🛠️ FastAPI 🔛 🪔
👉 📄 👆 🔜 💡 ❔ 💪 🛠️ **FastAPI** 🈸 🔛 <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">🪔</a> ⚙️ 🆓 📄. 👶
⚫️ 🔜 ✊ 👆 🔃 **1⃣0⃣ ⏲**.
!!! info
<a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">🪔</a> **FastAPI** 💰. 👶
## 🔰 **FastAPI** 📱
* ✍ 📁 👆 📱, 🖼, `./fastapideta/` &amp; ⛔ 🔘 ⚫️.
### FastAPI 📟
*`main.py` 📁 ⏮️:
```Python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}
```
### 📄
🔜, 🎏 📁 ✍ 📁 `requirements.txt` ⏮️:
```text
fastapi
```
!!! tip
👆 🚫 💪 ❎ Uvicorn 🛠️ 🔛 🪔, 👐 👆 🔜 🎲 💚 ❎ ⚫️ 🌐 💯 👆 📱.
### 📁 📊
👆 🔜 🔜 ✔️ 1⃣ 📁 `./fastapideta/` ⏮️ 2⃣ 📁:
```
.
└── main.py
└── requirements.txt
```
## ✍ 🆓 🪔 🏧
🔜 ✍ <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">🆓 🏧 🔛 🪔</a>, 👆 💪 📧 &amp; 🔐.
👆 🚫 💪 💳.
## ❎ ✳
🕐 👆 ✔️ 👆 🏧, ❎ 🪔 <abbr title="Command Line Interface application">✳</abbr>:
=== "💾, 🇸🇻"
<div class="termy">
```console
$ curl -fsSL https://get.deta.dev/cli.sh | sh
```
</div>
=== "🚪 📋"
<div class="termy">
```console
$ iwr https://get.deta.dev/cli.ps1 -useb | iex
```
</div>
⏮️ ❎ ⚫️, 📂 🆕 📶 👈 ❎ ✳ 🔍.
🆕 📶, ✔ 👈 ⚫️ ☑ ❎ ⏮️:
<div class="termy">
```console
$ deta --help
Deta command line interface for managing deta micros.
Complete documentation available at https://docs.deta.sh
Usage:
deta [flags]
deta [command]
Available Commands:
auth Change auth settings for a deta micro
...
```
</div>
!!! tip
🚥 👆 ✔️ ⚠ ❎ ✳, ✅ <a href="https://docs.deta.sh/docs/micros/getting_started?ref=fastapi" class="external-link" target="_blank">🛂 🪔 🩺</a>.
## 💳 ⏮️ ✳
🔜 💳 🪔 ⚪️➡️ ✳ ⏮️:
<div class="termy">
```console
$ deta login
Please, log in from the web page. Waiting..
Logged in successfully.
```
</div>
👉 🔜 📂 🕸 🖥 &amp; 🔓 🔁.
## 🛠️ ⏮️ 🪔
⏭, 🛠️ 👆 🈸 ⏮️ 🪔 ✳:
<div class="termy">
```console
$ deta new
Successfully created a new micro
// Notice the "endpoint" 🔍
{
"name": "fastapideta",
"runtime": "python3.7",
"endpoint": "https://qltnci.deta.dev",
"visor": "enabled",
"http_auth": "enabled"
}
Adding dependencies...
---> 100%
Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6
```
</div>
👆 🔜 👀 🎻 📧 🎏:
```JSON hl_lines="4"
{
"name": "fastapideta",
"runtime": "python3.7",
"endpoint": "https://qltnci.deta.dev",
"visor": "enabled",
"http_auth": "enabled"
}
```
!!! tip
👆 🛠️ 🔜 ✔️ 🎏 `"endpoint"` 📛.
## ✅ ⚫️
🔜 📂 👆 🖥 👆 `endpoint` 📛. 🖼 🔛 ⚫️ `https://qltnci.deta.dev`, ✋️ 👆 🔜 🎏.
👆 🔜 👀 🎻 📨 ⚪️➡️ 👆 FastAPI 📱:
```JSON
{
"Hello": "World"
}
```
&amp; 🔜 🚶 `/docs` 👆 🛠️, 🖼 🔛 ⚫️ 🔜 `https://qltnci.deta.dev/docs`.
⚫️ 🔜 🎦 👆 🩺 💖:
<img src="/img/deployment/deta/image01.png">
## 🛠️ 📢 🔐
🔢, 🪔 🔜 🍵 🤝 ⚙️ 🍪 👆 🏧.
✋️ 🕐 👆 🔜, 👆 💪 ⚒ ⚫️ 📢 ⏮️:
<div class="termy">
```console
$ deta auth disable
Successfully disabled http auth
```
</div>
🔜 👆 💪 💰 👈 📛 ⏮️ 🙆 &amp; 👫 🔜 💪 🔐 👆 🛠️. 👶
## 🇺🇸🔍
㊗ ❗ 👆 🛠️ 👆 FastAPI 📱 🪔 ❗ 👶 👶
, 👀 👈 🪔 ☑ 🍵 🇺🇸🔍 👆, 👆 🚫 ✔️ ✊ 💅 👈 &amp; 💪 💭 👈 👆 👩‍💻 🔜 ✔️ 🔐 🗜 🔗. 👶 👶
## ✅ 🕶
⚪️➡️ 👆 🩺 🎚 (👫 🔜 📛 💖 `https://qltnci.deta.dev/docs`) 📨 📨 👆 *➡ 🛠️* `/items/{item_id}`.
🖼 ⏮️ 🆔 `5`.
🔜 🚶 <a href="https://web.deta.sh/" class="external-link" target="_blank">https://web.deta.sh</a>.
👆 🔜 👀 📤 📄 ◀️ 🤙 <abbr title="it comes from Micro(server)">"◾"</abbr> ⏮️ 🔠 👆 📱.
👆 🔜 👀 📑 ⏮️ "", &amp; 📑 "🕶", 🚶 📑 "🕶".
📤 👆 💪 ✔ ⏮️ 📨 📨 👆 📱.
👆 💪 ✍ 👫 &amp; 🏤-🤾 👫.
<img src="/img/deployment/deta/image02.png">
## 💡 🌅
☝, 👆 🔜 🎲 💚 🏪 💽 👆 📱 🌌 👈 😣 🔘 🕰. 👈 👆 💪 ⚙️ <a href="https://docs.deta.sh/docs/base/py_tutorial?ref=fastapi" class="external-link" target="_blank">🪔 🧢</a>, ⚫️ ✔️ 👍 **🆓 🎚**.
👆 💪 ✍ 🌅 <a href="https://docs.deta.sh?ref=fastapi" class="external-link" target="_blank">🪔 🩺</a>.
## 🛠️ 🔧
👟 🔙 🔧 👥 🔬 [🛠️ 🔧](./concepts.md){.internal-link target=_blank}, 📥 ❔ 🔠 👫 🔜 🍵 ⏮️ 🪔:
* **🇺🇸🔍**: 🍵 🪔, 👫 🔜 🤝 👆 📁 &amp; 🍵 🇺🇸🔍 🔁.
* **🏃‍♂ 🔛 🕴**: 🍵 🪔, 🍕 👫 🐕‍🦺.
* **⏏**: 🍵 🪔, 🍕 👫 🐕‍🦺.
* **🧬**: 🍵 🪔, 🍕 👫 🐕‍🦺.
* **💾**: 📉 🔁 🪔, 👆 💪 📧 👫 📈 ⚫️.
* **⏮️ 🔁 ⏭ ▶️**: 🚫 🔗 🐕‍🦺, 👆 💪 ⚒ ⚫️ 👷 ⏮️ 👫 💾 ⚙️ ⚖️ 🌖 ✍.
!!! note
🪔 🔧 ⚒ ⚫️ ⏩ (&amp; 🆓) 🛠️ 🙅 🈸 🔜.
⚫️ 💪 📉 📚 ⚙️ 💼, ✋️ 🎏 🕰, ⚫️ 🚫 🐕‍🦺 🎏, 💖 ⚙️ 🔢 💽 (↖️ ⚪️➡️ 🪔 👍 ☁ 💽 ⚙️), 🛃 🕹 🎰, ♒️.
👆 💪 ✍ 🌅 <a href="https://docs.deta.sh/docs/micros/about/" class="external-link" target="_blank">🪔 🩺</a> 👀 🚥 ⚫️ ▶️️ ⚒ 👆.

View File

@@ -0,0 +1,90 @@
# ↔ 🗄
!!! warning
👉 👍 🏧 ⚒. 👆 🎲 💪 🚶 ⚫️.
🚥 👆 📄 🔰 - 👩‍💻 🦮, 👆 💪 🎲 🚶 👉 📄.
🚥 👆 ⏪ 💭 👈 👆 💪 🔀 🏗 🗄 🔗, 😣 👂.
📤 💼 🌐❔ 👆 💪 💪 🔀 🏗 🗄 🔗.
👉 📄 👆 🔜 👀 ❔.
## 😐 🛠️
😐 (🔢) 🛠️, ⏩.
`FastAPI` 🈸 (👐) ✔️ `.openapi()` 👩‍🔬 👈 📈 📨 🗄 🔗.
🍕 🈸 🎚 🏗, *➡ 🛠️* `/openapi.json` (⚖️ ⚫️❔ 👆 ⚒ 👆 `openapi_url`) ®.
⚫️ 📨 🎻 📨 ⏮️ 🏁 🈸 `.openapi()` 👩‍🔬.
🔢, ⚫️❔ 👩‍🔬 `.openapi()` 🔨 ✅ 🏠 `.openapi_schema` 👀 🚥 ⚫️ ✔️ 🎚 &amp; 📨 👫.
🚥 ⚫️ 🚫, ⚫️ 🏗 👫 ⚙️ 🚙 🔢 `fastapi.openapi.utils.get_openapi`.
&amp; 👈 🔢 `get_openapi()` 📨 🔢:
* `title`: 🗄 📛, 🎦 🩺.
* `version`: ⏬ 👆 🛠️, ✅ `2.5.0`.
* `openapi_version`: ⏬ 🗄 🔧 ⚙️. 🔢, ⏪: `3.0.2`.
* `description`: 📛 👆 🛠️.
* `routes`: 📇 🛣, 👫 🔠 ® *➡ 🛠️*. 👫 ✊ ⚪️➡️ `app.routes`.
## 🔑 🔢
⚙️ 🔛, 👆 💪 ⚙️ 🎏 🚙 🔢 🏗 🗄 🔗 &amp; 🔐 🔠 🍕 👈 👆 💪.
🖼, ➡️ 🚮 <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">📄 🗄 ↔ 🔌 🛃 🔱</a>.
### 😐 **FastAPI**
🥇, ✍ 🌐 👆 **FastAPI** 🈸 🛎:
```Python hl_lines="1 4 7-9"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### 🏗 🗄 🔗
⤴️, ⚙️ 🎏 🚙 🔢 🏗 🗄 🔗, 🔘 `custom_openapi()` 🔢:
```Python hl_lines="2 15-20"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### 🔀 🗄 🔗
🔜 👆 💪 🚮 📄 ↔, ❎ 🛃 `x-logo` `info` "🎚" 🗄 🔗:
```Python hl_lines="21-23"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### 💾 🗄 🔗
👆 💪 ⚙️ 🏠 `.openapi_schema` "💾", 🏪 👆 🏗 🔗.
👈 🌌, 👆 🈸 🏆 🚫 ✔️ 🏗 🔗 🔠 🕰 👩‍💻 📂 👆 🛠️ 🩺.
⚫️ 🔜 🏗 🕴 🕐, &amp; ⤴️ 🎏 💾 🔗 🔜 ⚙️ ⏭ 📨.
```Python hl_lines="13-14 24-25"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### 🔐 👩‍🔬
🔜 👆 💪 ❎ `.openapi()` 👩‍🔬 ⏮️ 👆 🆕 🔢.
```Python hl_lines="28"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### ✅ ⚫️
🕐 👆 🚶 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> 👆 🔜 👀 👈 👆 ⚙️ 👆 🛃 🔱 (👉 🖼, **FastAPI**'Ⓜ 🔱):
<img src="/img/tutorial/extending-openapi/image01.png">

View File

@@ -1,5 +1,9 @@
articles:
english:
- author: Adejumo Ridwan Suleiman
author_link: https://www.linkedin.com/in/adejumoridwan/
link: https://medium.com/python-in-plain-english/build-an-sms-spam-classifier-serverless-database-with-faunadb-and-fastapi-23dbb275bc5b
title: Build an SMS Spam Classifier Serverless Database with FaunaDB and FastAPI
- author: Raf Rasenberg
author_link: https://rafrasenberg.com/about/
link: https://rafrasenberg.com/fastapi-lambda/

View File

@@ -2,6 +2,12 @@ sponsors:
- - login: cryptapi
avatarUrl: https://avatars.githubusercontent.com/u/44925437?u=61369138589bc7fee6c417f3fbd50fbd38286cc4&v=4
url: https://github.com/cryptapi
- login: fern-api
avatarUrl: https://avatars.githubusercontent.com/u/102944815?v=4
url: https://github.com/fern-api
- login: nanram22
avatarUrl: https://avatars.githubusercontent.com/u/116367316?v=4
url: https://github.com/nanram22
- - login: nihpo
avatarUrl: https://avatars.githubusercontent.com/u/1841030?u=0264956d7580f7e46687a762a7baa629f84cf97c&v=4
url: https://github.com/nihpo
@@ -26,48 +32,54 @@ sponsors:
- login: VincentParedes
avatarUrl: https://avatars.githubusercontent.com/u/103889729?v=4
url: https://github.com/VincentParedes
- - login: arcticfly
avatarUrl: https://avatars.githubusercontent.com/u/41524992?u=03c88529a86cf51f7a380e890d84d84c71468848&v=4
url: https://github.com/arcticfly
- - login: getsentry
avatarUrl: https://avatars.githubusercontent.com/u/1396951?v=4
url: https://github.com/getsentry
- - login: takashi-yoneya
- - login: acsone
avatarUrl: https://avatars.githubusercontent.com/u/7601056?v=4
url: https://github.com/acsone
- 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
- login: xoflare
avatarUrl: https://avatars.githubusercontent.com/u/74335107?v=4
url: https://github.com/xoflare
- login: marvin-robot
avatarUrl: https://avatars.githubusercontent.com/u/41086007?u=091c5cb75af363123d66f58194805a97220ee1a7&v=4
url: https://github.com/marvin-robot
- login: Flint-company
avatarUrl: https://avatars.githubusercontent.com/u/48908872?u=355cd3d8992d4be8173058e7000728757c55ad49&v=4
url: https://github.com/Flint-company
- login: BoostryJP
avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4
url: https://github.com/BoostryJP
- login: jina-ai
avatarUrl: https://avatars.githubusercontent.com/u/60539444?v=4
url: https://github.com/jina-ai
- - login: HiredScore
avatarUrl: https://avatars.githubusercontent.com/u/3908850?v=4
url: https://github.com/HiredScore
- login: Trivie
avatarUrl: https://avatars.githubusercontent.com/u/8161763?v=4
url: https://github.com/Trivie
- - login: JonasKs
avatarUrl: https://avatars.githubusercontent.com/u/5310116?u=98a049f3e1491bffb91e1feb7e93def6881a9389&v=4
url: https://github.com/JonasKs
- - 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: yasyf
avatarUrl: https://avatars.githubusercontent.com/u/709645?u=f36736b3c6a85f578886ecc42a740e7b436e7a01&v=4
url: https://github.com/yasyf
- 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: americanair
avatarUrl: https://avatars.githubusercontent.com/u/12281813?v=4
url: https://github.com/americanair
@@ -83,21 +95,24 @@ sponsors:
- - login: indeedeng
avatarUrl: https://avatars.githubusercontent.com/u/2905043?v=4
url: https://github.com/indeedeng
- login: iguit0
avatarUrl: https://avatars.githubusercontent.com/u/12905770?u=63a1a96d1e6c27d85c4f946b84836599de047f65&v=4
url: https://github.com/iguit0
- login: JacobKochems
avatarUrl: https://avatars.githubusercontent.com/u/41692189?u=a75f62ddc0d060ee6233a91e19c433d2687b8eb6&v=4
url: https://github.com/JacobKochems
- - login: Kludex
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: samuelcolvin
avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4
avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=42eb3b833047c8c4b4f647a031eaef148c16d93f&v=4
url: https://github.com/samuelcolvin
- login: jefftriplett
avatarUrl: https://avatars.githubusercontent.com/u/50527?u=af1ddfd50f6afd6d99f333ba2ac8d0a5b245ea74&v=4
url: https://github.com/jefftriplett
- login: medecau
avatarUrl: https://avatars.githubusercontent.com/u/59870?u=f9341c95adaba780828162fd4c7442357ecfcefa&v=4
url: https://github.com/medecau
- login: kamalgill
avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4
url: https://github.com/kamalgill
- login: jstanden
avatarUrl: https://avatars.githubusercontent.com/u/63288?u=c3658d57d2862c607a0e19c2101c3c51876e36ad&v=4
url: https://github.com/jstanden
- login: dekoza
avatarUrl: https://avatars.githubusercontent.com/u/210980?u=c03c78a8ae1039b500dfe343665536ebc51979b2&v=4
url: https://github.com/dekoza
@@ -119,9 +134,6 @@ sponsors:
- login: jqueguiner
avatarUrl: https://avatars.githubusercontent.com/u/690878?u=bd65cc1f228ce6455e56dfaca3ef47c33bc7c3b0&v=4
url: https://github.com/jqueguiner
- login: iobruno
avatarUrl: https://avatars.githubusercontent.com/u/901651?u=460bc34ac298dca9870aafe3a1560a2ae789bc4a&v=4
url: https://github.com/iobruno
- login: tcsmith
avatarUrl: https://avatars.githubusercontent.com/u/989034?u=7d8d741552b3279e8f4d3878679823a705a46f8f&v=4
url: https://github.com/tcsmith
@@ -143,6 +155,9 @@ sponsors:
- login: zsinx6
avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4
url: https://github.com/zsinx6
- login: kennywakeland
avatarUrl: https://avatars.githubusercontent.com/u/3631417?u=7c8f743f1ae325dfadea7c62bbf1abd6a824fc55&v=4
url: https://github.com/kennywakeland
- login: aacayaco
avatarUrl: https://avatars.githubusercontent.com/u/3634801?u=eaadda178c964178fcb64886f6c732172c8f8219&v=4
url: https://github.com/aacayaco
@@ -173,6 +188,9 @@ sponsors:
- login: iwpnd
avatarUrl: https://avatars.githubusercontent.com/u/6152183?u=c485eefca5c6329600cae63dd35e4f5682ce6924&v=4
url: https://github.com/iwpnd
- login: FernandoCelmer
avatarUrl: https://avatars.githubusercontent.com/u/6262214?u=ab6108a843a2fb9df0934f482375d2907609f3ff&v=4
url: https://github.com/FernandoCelmer
- login: simw
avatarUrl: https://avatars.githubusercontent.com/u/6322526?v=4
url: https://github.com/simw
@@ -185,12 +203,12 @@ sponsors:
- login: Shackelford-Arden
avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4
url: https://github.com/Shackelford-Arden
- login: savannahostrowski
avatarUrl: https://avatars.githubusercontent.com/u/8949415?u=c3177aa099fb2b8c36aeba349278b77f9a8df211&v=4
url: https://github.com/savannahostrowski
- login: wdwinslow
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4
url: https://github.com/wdwinslow
- login: joeds13
avatarUrl: https://avatars.githubusercontent.com/u/13631604?u=628eb122e08bef43767b3738752b883e8e7f6259&v=4
url: https://github.com/joeds13
- login: dannywade
avatarUrl: https://avatars.githubusercontent.com/u/13680237?u=418ee985bd41577b20fde81417fb2d901e875e8a&v=4
url: https://github.com/dannywade
@@ -209,12 +227,6 @@ sponsors:
- login: Filimoa
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
url: https://github.com/shuheng-liu
- login: SebTota
avatarUrl: https://avatars.githubusercontent.com/u/25122511?v=4
url: https://github.com/SebTota
- login: LarryGF
avatarUrl: https://avatars.githubusercontent.com/u/26148349?u=431bb34d36d41c172466252242175281ae132152&v=4
url: https://github.com/LarryGF
@@ -230,9 +242,6 @@ sponsors:
- login: ygorpontelo
avatarUrl: https://avatars.githubusercontent.com/u/32963605?u=35f7103f9c4c4c2589ae5737ee882e9375ef072e&v=4
url: https://github.com/ygorpontelo
- login: AlrasheedA
avatarUrl: https://avatars.githubusercontent.com/u/33544979?u=7fe66bf62b47682612b222e3e8f4795ef3be769b&v=4
url: https://github.com/AlrasheedA
- login: ProteinQure
avatarUrl: https://avatars.githubusercontent.com/u/33707203?v=4
url: https://github.com/ProteinQure
@@ -245,6 +254,9 @@ sponsors:
- login: thenickben
avatarUrl: https://avatars.githubusercontent.com/u/40610922?u=1e907d904041b7c91213951a3cb344cd37c14aaf&v=4
url: https://github.com/thenickben
- login: adtalos
avatarUrl: https://avatars.githubusercontent.com/u/40748353?v=4
url: https://github.com/adtalos
- login: ybressler
avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=41e2c00f1eebe3c402635f0325e41b4e6511462c&v=4
url: https://github.com/ybressler
@@ -257,9 +269,6 @@ sponsors:
- 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
@@ -284,9 +293,9 @@ sponsors:
- login: Dagmaara
avatarUrl: https://avatars.githubusercontent.com/u/115501964?v=4
url: https://github.com/Dagmaara
- - login: Yarden-zamir
avatarUrl: https://avatars.githubusercontent.com/u/8178413?u=ee177a8b0f87ea56747f4d96f34cd4e9604a8217&v=4
url: https://github.com/Yarden-zamir
- - login: SebTota
avatarUrl: https://avatars.githubusercontent.com/u/25122511?v=4
url: https://github.com/SebTota
- - login: pawamoy
avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4
url: https://github.com/pawamoy
@@ -318,7 +327,7 @@ sponsors:
avatarUrl: https://avatars.githubusercontent.com/u/861044?u=5abfca5588f3e906b31583d7ee62f6de4b68aa24&v=4
url: https://github.com/browniebroke
- login: janfilips
avatarUrl: https://avatars.githubusercontent.com/u/870699?u=96df18ad355e58b9397accc55f4eeb7a86e959b0&v=4
avatarUrl: https://avatars.githubusercontent.com/u/870699?u=80702ec63f14e675cd4cdcc6ce3821d2ed207fd7&v=4
url: https://github.com/janfilips
- login: WillHogan
avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=7036c064cf29781470573865264ec8e60b6b809f&v=4
@@ -326,27 +335,24 @@ sponsors:
- login: my3
avatarUrl: https://avatars.githubusercontent.com/u/1825270?v=4
url: https://github.com/my3
- login: leobiscassi
avatarUrl: https://avatars.githubusercontent.com/u/1977418?u=f9f82445a847ab479bd7223debd677fcac6c49a0&v=4
url: https://github.com/leobiscassi
- login: cbonoz
avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4
url: https://github.com/cbonoz
- login: Patechoc
avatarUrl: https://avatars.githubusercontent.com/u/2376641?u=23b49e9eda04f078cb74fa3f93593aa6a57bb138&v=4
url: https://github.com/Patechoc
- 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
- login: jonathanhle
avatarUrl: https://avatars.githubusercontent.com/u/3851599?u=76b9c5d2fecd6c3a16e7645231878c4507380d4d&v=4
url: https://github.com/jonathanhle
- login: nikeee
avatarUrl: https://avatars.githubusercontent.com/u/4068864?u=bbe73151f2b409c120160d032dc9aa6875ef0c4b&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
- login: piotrgredowski
avatarUrl: https://avatars.githubusercontent.com/u/4294480?v=4
url: https://github.com/piotrgredowski
- login: danielunderwood
avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4
url: https://github.com/danielunderwood
@@ -371,6 +377,9 @@ sponsors:
- login: mattwelke
avatarUrl: https://avatars.githubusercontent.com/u/7719209?u=80f02a799323b1472b389b836d95957c93a6d856&v=4
url: https://github.com/mattwelke
- login: harsh183
avatarUrl: https://avatars.githubusercontent.com/u/7780198?v=4
url: https://github.com/harsh183
- login: hcristea
avatarUrl: https://avatars.githubusercontent.com/u/7814406?u=61d7a4fcf846983a4606788eac25e1c6c1209ba8&v=4
url: https://github.com/hcristea
@@ -413,15 +422,15 @@ sponsors:
- login: jangia
avatarUrl: https://avatars.githubusercontent.com/u/17927101?u=9261b9bb0c3e3bb1ecba43e8915dc58d8c9a077e&v=4
url: https://github.com/jangia
- login: ghandic
avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
url: https://github.com/ghandic
- login: shuheng-liu
avatarUrl: https://avatars.githubusercontent.com/u/22414322?u=813c45f30786c6b511b21a661def025d8f7b609e&v=4
url: https://github.com/shuheng-liu
- login: pers0n4
avatarUrl: https://avatars.githubusercontent.com/u/24864600?u=f211a13a7b572cbbd7779b9c8d8cb428cc7ba07e&v=4
url: https://github.com/pers0n4
- login: kadekillary
- login: kxzk
avatarUrl: https://avatars.githubusercontent.com/u/25046261?u=e185e58080090f9e678192cd214a14b14a2b232b&v=4
url: https://github.com/kadekillary
url: https://github.com/kxzk
- login: hoenie-ams
avatarUrl: https://avatars.githubusercontent.com/u/25708487?u=cda07434f0509ac728d9edf5e681117c0f6b818b&v=4
url: https://github.com/hoenie-ams
@@ -441,7 +450,7 @@ sponsors:
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=9fbf76b9bf7786275e2900efa51d1394bcf1f06a&v=4
avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=527044d90b5ebb7f8dad517db5da1f45253b774b&v=4
url: https://github.com/bnkc
- login: declon
avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4
@@ -458,6 +467,9 @@ sponsors:
- login: ArtyomVancyan
avatarUrl: https://avatars.githubusercontent.com/u/44609997?v=4
url: https://github.com/ArtyomVancyan
- login: josehenriqueroveda
avatarUrl: https://avatars.githubusercontent.com/u/46685746?u=2e672057a7dbe1dba47e57c378fc0cac336022eb&v=4
url: https://github.com/josehenriqueroveda
- login: hgalytoby
avatarUrl: https://avatars.githubusercontent.com/u/50397689?u=f4888c2c54929bd86eed0d3971d09fcb306e5088&v=4
url: https://github.com/hgalytoby
@@ -467,30 +479,36 @@ sponsors:
- login: conservative-dude
avatarUrl: https://avatars.githubusercontent.com/u/55538308?u=f250c44942ea6e73a6bd90739b381c470c192c11&v=4
url: https://github.com/conservative-dude
- login: leo-jp-edwards
avatarUrl: https://avatars.githubusercontent.com/u/58213433?u=2c128e8b0794b7a66211cd7d8ebe05db20b7e9c0&v=4
url: https://github.com/leo-jp-edwards
- login: tamtam-fitness
avatarUrl: https://avatars.githubusercontent.com/u/62091034?u=8da19a6bd3d02f5d6ba30c7247d5b46c98dd1403&v=4
url: https://github.com/tamtam-fitness
- login: 0417taehyun
avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4
url: https://github.com/0417taehyun
- - login: ssbarnea
avatarUrl: https://avatars.githubusercontent.com/u/102495?u=b4bf6818deefe59952ac22fec6ed8c76de1b8f7c&v=4
url: https://github.com/ssbarnea
- login: Patechoc
avatarUrl: https://avatars.githubusercontent.com/u/2376641?u=23b49e9eda04f078cb74fa3f93593aa6a57bb138&v=4
url: https://github.com/Patechoc
- login: LanceMoe
avatarUrl: https://avatars.githubusercontent.com/u/18505474?u=7fd3ead4364bdf215b6d75cb122b3811c391ef6b&v=4
url: https://github.com/LanceMoe
- login: sadikkuzu
avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=d179c06bb9f65c4167fcab118526819f8e0dac17&v=4
url: https://github.com/sadikkuzu
- login: ruizdiazever
avatarUrl: https://avatars.githubusercontent.com/u/29817086?u=2df54af55663d246e3a4dc8273711c37f1adb117&v=4
url: https://github.com/ruizdiazever
- login: samnimoh
avatarUrl: https://avatars.githubusercontent.com/u/33413170?u=147bc516be6cb647b28d7e3b3fea3a018a331145&v=4
url: https://github.com/samnimoh
- login: danburonline
avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4
url: https://github.com/danburonline
- login: iharshgor
avatarUrl: https://avatars.githubusercontent.com/u/35490011?u=2dea054476e752d9e92c9d71a9a7cc919b1c2f8e&v=4
url: https://github.com/iharshgor
- login: rwxd
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=cd04a39e3655923be4f25c2ba8a5a07b3da3230a&v=4
url: https://github.com/rwxd
- login: xNykram
avatarUrl: https://avatars.githubusercontent.com/u/55030025?u=2c1ba313fd79d29273b5ff7c9c5cf4edfb271b29&v=4
url: https://github.com/xNykram
- login: ThomasPalma1
avatarUrl: https://avatars.githubusercontent.com/u/66331874?u=5763f7402d784ba189b60d704ff5849b4d0a63fb&v=4
url: https://github.com/ThomasPalma1

View File

@@ -1,17 +1,17 @@
maintainers:
- login: tiangolo
answers: 1839
prs: 398
answers: 1849
prs: 466
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4
url: https://github.com/tiangolo
experts:
- login: Kludex
count: 410
count: 463
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: dmontagu
count: 237
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
count: 239
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4
url: https://github.com/dmontagu
- login: Mause
count: 220
@@ -25,34 +25,34 @@ experts:
count: 193
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
url: https://github.com/JarroVGIT
- login: jgould22
count: 157
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
url: https://github.com/jgould22
- login: euri10
count: 152
count: 153
avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
url: https://github.com/euri10
- login: phy25
count: 126
avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4
url: https://github.com/phy25
- login: jgould22
count: 124
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
url: https://github.com/jgould22
- login: iudeen
count: 118
count: 121
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: raphaelauv
count: 83
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
url: https://github.com/raphaelauv
- login: ghandic
count: 71
avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
url: https://github.com/ghandic
- login: ArcLightSlavik
count: 71
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4
url: https://github.com/ArcLightSlavik
- login: ghandic
count: 71
avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
url: https://github.com/ghandic
- login: falkben
count: 57
avatarUrl: https://avatars.githubusercontent.com/u/653031?u=ad9838e089058c9e5a0bab94c0eec7cc181e0cd0&v=4
@@ -61,14 +61,14 @@ experts:
count: 49
avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4
url: https://github.com/sm-Fifteen
- login: yinziyan1206
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
url: https://github.com/yinziyan1206
- login: insomnes
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4
url: https://github.com/insomnes
- login: yinziyan1206
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
url: https://github.com/yinziyan1206
- login: acidjunk
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
@@ -78,16 +78,16 @@ experts:
avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4
url: https://github.com/Dustyposa
- login: adriangb
count: 43
avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=1e2c2c9b39f5c9b780fb933d8995cf08ec235a47&v=4
count: 44
avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4
url: https://github.com/adriangb
- login: frankie567
count: 43
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
url: https://github.com/frankie567
- login: odiseo0
count: 42
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=2da05dab6cc8e1ade557801634760a56e4101796&v=4
count: 43
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=241a71f6b7068738b81af3e57f45ffd723538401&v=4
url: https://github.com/odiseo0
- login: includeamin
count: 40
@@ -121,18 +121,22 @@ experts:
count: 25
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
url: https://github.com/wshayes
- login: acnebs
count: 23
avatarUrl: https://avatars.githubusercontent.com/u/9054108?v=4
url: https://github.com/acnebs
- login: SirTelemak
count: 23
avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4
url: https://github.com/SirTelemak
- login: acnebs
count: 22
avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=c27e50269f1ef8ea950cc6f0268c8ec5cebbe9c9&v=4
url: https://github.com/acnebs
- login: rafsaf
count: 21
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
url: https://github.com/rafsaf
- login: n8sty
count: 20
avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4
url: https://github.com/n8sty
- login: nsidnev
count: 20
avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4
@@ -153,10 +157,6 @@ experts:
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4
url: https://github.com/Hultner
- login: n8sty
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4
url: https://github.com/n8sty
- login: harunyasar
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4
@@ -177,6 +177,14 @@ experts:
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4
url: https://github.com/dstlny
- login: abhint
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/25699289?u=b5d219277b4d001ac26fb8be357fddd88c29d51b&v=4
url: https://github.com/abhint
- login: nymous
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/4216559?u=360a36fb602cded27273cbfc0afc296eece90662&v=4
url: https://github.com/nymous
- login: ghost
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/10137?u=b1951d34a583cf12ec0d3b0781ba19be97726318&v=4
@@ -189,39 +197,31 @@ experts:
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4
url: https://github.com/jorgerpo
- login: ebottos94
count: 14
avatarUrl: https://avatars.githubusercontent.com/u/100039558?u=e2c672da5a7977fd24d87ce6ab35f8bf5b1ed9fa&v=4
url: https://github.com/ebottos94
- login: hellocoldworld
count: 14
avatarUrl: https://avatars.githubusercontent.com/u/47581948?u=3d2186796434c507a6cb6de35189ab0ad27c356f&v=4
url: https://github.com/hellocoldworld
last_month_active:
- login: jgould22
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
url: https://github.com/jgould22
- login: Kludex
count: 7
count: 24
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: abhint
count: 5
avatarUrl: https://avatars.githubusercontent.com/u/25699289?u=5b9f9f6192c83ca86a411eafd4be46d9e5828585&v=4
url: https://github.com/abhint
- login: chrisK824
- login: jgould22
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
url: https://github.com/jgould22
- login: arjwilliams
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/22227620?v=4
url: https://github.com/arjwilliams
- login: Ahmed-Abdou14
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/79946379?u=03d85b22d696a58a9603e55fbbbe2de6b0f4face&v=4
url: https://github.com/chrisK824
- login: djimontyp
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/53098395?u=583bade70950b277c322d35f1be2b75c7b0f189c&v=4
url: https://github.com/djimontyp
- login: JavierSanchezCastro
avatarUrl: https://avatars.githubusercontent.com/u/104530599?u=05365b155a1ff911532e8be316acfad2e0736f98&v=4
url: https://github.com/Ahmed-Abdou14
- login: iudeen
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4
url: https://github.com/JavierSanchezCastro
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: mikeedjones
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/4087139?u=cc4a242896ac2fcf88a53acfaf190d0fe0a1f0c9&v=4
url: https://github.com/mikeedjones
top_contributors:
- login: waynerv
count: 25
@@ -232,7 +232,7 @@ top_contributors:
avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
url: https://github.com/tokusumi
- login: Kludex
count: 17
count: 21
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: jaystone776
@@ -241,22 +241,22 @@ top_contributors:
url: https://github.com/jaystone776
- login: dmontagu
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4
url: https://github.com/dmontagu
- login: euri10
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
url: https://github.com/euri10
- login: Xewus
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4
url: https://github.com/Xewus
- login: mariacamilagl
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
url: https://github.com/mariacamilagl
- login: Xewus
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4
url: https://github.com/Xewus
- login: Smlep
count: 10
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4
url: https://github.com/Smlep
- login: Serrones
@@ -275,6 +275,14 @@ top_contributors:
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4
url: https://github.com/hard-coders
- login: Alexandrhub
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4
url: https://github.com/Alexandrhub
- login: NinaHwang
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=eee6bfe9224c71193025ab7477f4f96ceaa05c62&v=4
url: https://github.com/NinaHwang
- login: batlopes
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4
@@ -285,7 +293,7 @@ top_contributors:
url: https://github.com/wshayes
- login: samuelcolvin
count: 5
avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4
avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=42eb3b833047c8c4b4f647a031eaef148c16d93f&v=4
url: https://github.com/samuelcolvin
- login: SwftAlpc
count: 5
@@ -299,10 +307,6 @@ top_contributors:
count: 5
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=eee6bfe9224c71193025ab7477f4f96ceaa05c62&v=4
url: https://github.com/NinaHwang
- login: jekirl
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4
@@ -323,25 +327,37 @@ top_contributors:
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/3360631?u=5fa1f475ad784d64eb9666bdd43cc4d285dcc773&v=4
url: https://github.com/hitrust
- login: JulianMaurin
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/63545168?u=b7d15ac865268cbefc2d739e2f23d9aeeac1a622&v=4
url: https://github.com/JulianMaurin
- login: lsglucas
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
url: https://github.com/lsglucas
- login: iudeen
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: axel584
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/1334088?u=9667041f5b15dc002b6f9665fda8c0412933ac04&v=4
url: https://github.com/axel584
- login: ivan-abc
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/36765187?u=c6e0ba571c1ccb6db9d94e62e4b8b5eda811a870&v=4
url: https://github.com/ivan-abc
top_reviewers:
- login: Kludex
count: 117
count: 136
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: BilalAlpaslan
count: 75
count: 79
avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4
url: https://github.com/BilalAlpaslan
- login: yezz123
count: 74
count: 78
avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=d7062cbc6eb7671d5dc9cc0e32a24ae335e0f225&v=4
url: https://github.com/yezz123
- login: tokusumi
@@ -356,18 +372,22 @@ top_reviewers:
count: 47
avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4
url: https://github.com/Laineyzhang55
- login: iudeen
count: 46
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: ycd
count: 45
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: Xewus
count: 38
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4
url: https://github.com/Xewus
- login: JarroVGIT
count: 34
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
@@ -376,10 +396,6 @@ top_reviewers:
count: 33
avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=b2ea249c6b41ddf98679c8d110d0f67d4a3ebf93&v=4
url: https://github.com/AdrianDeAnda
- login: Xewus
count: 32
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4
url: https://github.com/Xewus
- login: ArcLightSlavik
count: 31
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4
@@ -396,18 +412,18 @@ top_reviewers:
count: 26
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
url: https://github.com/lsglucas
- login: LorhanSohaky
count: 24
avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4
url: https://github.com/LorhanSohaky
- login: Ryandaydev
count: 24
avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=809f3d1074d04bbc28012a7f17f06ea56f5bd71a&v=4
url: https://github.com/Ryandaydev
- login: dmontagu
count: 23
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4
url: https://github.com/dmontagu
- login: LorhanSohaky
count: 23
avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4
url: https://github.com/LorhanSohaky
- login: rjNemo
count: 21
avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
@@ -418,7 +434,7 @@ top_reviewers:
url: https://github.com/hard-coders
- login: odiseo0
count: 20
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=2da05dab6cc8e1ade557801634760a56e4101796&v=4
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=241a71f6b7068738b81af3e57f45ffd723538401&v=4
url: https://github.com/odiseo0
- login: 0417taehyun
count: 19
@@ -440,6 +456,10 @@ top_reviewers:
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4
url: https://github.com/SwftAlpc
- login: axel584
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/1334088?u=9667041f5b15dc002b6f9665fda8c0412933ac04&v=4
url: https://github.com/axel584
- login: DevDae
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/87962045?u=08e10fa516e844934f4b3fc7c38b33c61697e4a1&v=4
@@ -452,6 +472,10 @@ top_reviewers:
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4
url: https://github.com/delhi09
- login: Alexandrhub
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4
url: https://github.com/Alexandrhub
- login: sh0nk
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4
@@ -468,14 +492,18 @@ top_reviewers:
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=494ecc298e3f26197495bb357ad0f57cfd5f7a32&v=4
url: https://github.com/RunningIkkyu
- login: axel584
- login: ivan-abc
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/1334088?u=9667041f5b15dc002b6f9665fda8c0412933ac04&v=4
url: https://github.com/axel584
avatarUrl: https://avatars.githubusercontent.com/u/36765187?u=c6e0ba571c1ccb6db9d94e62e4b8b5eda811a870&v=4
url: https://github.com/ivan-abc
- login: solomein-sv
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=789927ee09cfabd752d3bd554fa6baf4850d2777&v=4
url: https://github.com/solomein-sv
- login: wdh99
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/108172295?u=8a8fb95d5afe3e0fa33257b2aecae88d436249eb&v=4
url: https://github.com/wdh99
- login: mariacamilagl
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
@@ -496,10 +524,6 @@ top_reviewers:
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=f440bc9062afb3c43b9b9c6cdfdcfe31d58699ef&v=4
url: https://github.com/ComicShrimp
- login: Alexandrhub
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4
url: https://github.com/Alexandrhub
- login: izaguerreiro
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4
@@ -520,11 +544,3 @@ top_reviewers:
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4
url: https://github.com/bezaca
- login: oandersonmagalhaes
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/83456692?v=4
url: https://github.com/oandersonmagalhaes
- login: NinaHwang
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=eee6bfe9224c71193025ab7477f4f96ceaa05c62&v=4
url: https://github.com/NinaHwang

View File

@@ -5,6 +5,12 @@ gold:
- url: https://platform.sh/try-it-now/?utm_source=fastapi-signup&utm_medium=banner&utm_campaign=FastAPI-signup-June-2023
title: "Build, run and scale your apps on a modern, reliable, and secure PaaS."
img: https://fastapi.tiangolo.com/img/sponsors/platform-sh.png
- url: https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=main-badge
title: Fern | SDKs and API docs
img: https://fastapi.tiangolo.com/img/sponsors/fern.svg
- url: https://www.porter.run
title: Deploy FastAPI on AWS with a few clicks
img: https://fastapi.tiangolo.com/img/sponsors/porter.png
silver:
- url: https://www.deta.sh/?ref=fastapi
title: The launchpad for all your (team's) ideas
@@ -27,6 +33,9 @@ silver:
- url: https://databento.com/
title: Pay as you go for market data
img: https://fastapi.tiangolo.com/img/sponsors/databento.svg
- url: https://speakeasyapi.dev?utm_source=fastapi+repo&utm_medium=github+sponsorship
title: SDKs for your API | Speakeasy
img: https://fastapi.tiangolo.com/img/sponsors/speakeasy.png
bronze:
- url: https://www.exoflare.com/open-source/?utm_source=FastAPI&utm_campaign=open_source
title: Biosecurity risk assessments made easy.
@@ -34,3 +43,6 @@ bronze:
- url: https://www.flint.sh
title: IT expertise, consulting and development by passionate people
img: https://fastapi.tiangolo.com/img/sponsors/flint.png
- url: https://bit.ly/3JJ7y5C
title: Build cross-modal and multimodal applications on the cloud
img: https://fastapi.tiangolo.com/img/sponsors/jina2.svg

View File

@@ -17,3 +17,6 @@ logins:
- databento-bot
- nanram22
- Flint-company
- porter-dev
- fern-api
- ndimares

View File

@@ -1,318 +0,0 @@
# Extending OpenAPI
!!! warning
This is a rather advanced feature. You probably can skip it.
If you are just following the tutorial - user guide, you can probably skip this section.
If you already know that you need to modify the generated OpenAPI schema, continue reading.
There are some cases where you might need to modify the generated OpenAPI schema.
In this section you will see how.
## The normal process
The normal (default) process, is as follows.
A `FastAPI` application (instance) has an `.openapi()` method that is expected to return the OpenAPI schema.
As part of the application object creation, a *path operation* for `/openapi.json` (or for whatever you set your `openapi_url`) is registered.
It just returns a JSON response with the result of the application's `.openapi()` method.
By default, what the method `.openapi()` does is check the property `.openapi_schema` to see if it has contents and return them.
If it doesn't, it generates them using the utility function at `fastapi.openapi.utils.get_openapi`.
And that function `get_openapi()` receives as parameters:
* `title`: The OpenAPI title, shown in the docs.
* `version`: The version of your API, e.g. `2.5.0`.
* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.1.0`.
* `summary`: A short summary of the API.
* `description`: The description of your API, this can include markdown and will be shown in the docs.
* `routes`: A list of routes, these are each of the registered *path operations*. They are taken from `app.routes`.
!!! info
The parameter `summary` is available in OpenAPI 3.1.0 and above, supported by FastAPI 0.99.0 and above.
## Overriding the defaults
Using the information above, you can use the same utility function to generate the OpenAPI schema and override each part that you need.
For example, let's add <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">ReDoc's OpenAPI extension to include a custom logo</a>.
### Normal **FastAPI**
First, write all your **FastAPI** application as normally:
```Python hl_lines="1 4 7-9"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Generate the OpenAPI schema
Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function:
```Python hl_lines="2 15-21"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Modify the OpenAPI schema
Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema:
```Python hl_lines="22-24"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Cache the OpenAPI schema
You can use the property `.openapi_schema` as a "cache", to store your generated schema.
That way, your application won't have to generate the schema every time a user opens your API docs.
It will be generated only once, and then the same cached schema will be used for the next requests.
```Python hl_lines="13-14 25-26"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Override the method
Now you can replace the `.openapi()` method with your new function.
```Python hl_lines="29"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Check it
Once you go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> you will see that you are using your custom logo (in this example, **FastAPI**'s logo):
<img src="/img/tutorial/extending-openapi/image01.png">
## Self-hosting JavaScript and CSS for docs
The API docs use **Swagger UI** and **ReDoc**, and each of those need some JavaScript and CSS files.
By default, those files are served from a <abbr title="Content Delivery Network: A service, normally composed of several servers, that provides static files, like JavaScript and CSS. It's commonly used to serve those files from the server closer to the client, improving performance.">CDN</abbr>.
But it's possible to customize it, you can set a specific CDN, or serve the files yourself.
That's useful, for example, if you need your app to keep working even while offline, without open Internet access, or in a local network.
Here you'll see how to serve those files yourself, in the same FastAPI app, and configure the docs to use them.
### Project file structure
Let's say your project file structure looks like this:
```
.
├── app
│ ├── __init__.py
│ ├── main.py
```
Now create a directory to store those static files.
Your new file structure could look like this:
```
.
├── app
│   ├── __init__.py
│   ├── main.py
└── static/
```
### Download the files
Download the static files needed for the docs and put them on that `static/` directory.
You can probably right-click each link and select an option similar to `Save link as...`.
**Swagger UI** uses the files:
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a>
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a>
And **ReDoc** uses the file:
* <a href="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js" class="external-link" target="_blank">`redoc.standalone.js`</a>
After that, your file structure could look like:
```
.
├── app
│   ├── __init__.py
│   ├── main.py
└── static
├── redoc.standalone.js
├── swagger-ui-bundle.js
└── swagger-ui.css
```
### Serve the static files
* Import `StaticFiles`.
* "Mount" a `StaticFiles()` instance in a specific path.
```Python hl_lines="7 11"
{!../../../docs_src/extending_openapi/tutorial002.py!}
```
### Test the static files
Start your application and go to <a href="http://127.0.0.1:8000/static/redoc.standalone.js" class="external-link" target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a>.
You should see a very long JavaScript file for **ReDoc**.
It could start with something like:
```JavaScript
/*!
* ReDoc - OpenAPI/Swagger-generated API Reference Documentation
* -------------------------------------------------------------
* Version: "2.0.0-rc.18"
* Repo: https://github.com/Redocly/redoc
*/
!function(e,t){"object"==typeof exports&&"object"==typeof m
...
```
That confirms that you are being able to serve static files from your app, and that you placed the static files for the docs in the correct place.
Now we can configure the app to use those static files for the docs.
### Disable the automatic docs
The first step is to disable the automatic docs, as those use the CDN by default.
To disable them, set their URLs to `None` when creating your `FastAPI` app:
```Python hl_lines="9"
{!../../../docs_src/extending_openapi/tutorial002.py!}
```
### Include the custom docs
Now you can create the *path operations* for the custom docs.
You can re-use FastAPI's internal functions to create the HTML pages for the docs, and pass them the needed arguments:
* `openapi_url`: the URL where the HTML page for the docs can get the OpenAPI schema for your API. You can use here the attribute `app.openapi_url`.
* `title`: the title of your API.
* `oauth2_redirect_url`: you can use `app.swagger_ui_oauth2_redirect_url` here to use the default.
* `swagger_js_url`: the URL where the HTML for your Swagger UI docs can get the **JavaScript** file. This is the one that your own app is now serving.
* `swagger_css_url`: the URL where the HTML for your Swagger UI docs can get the **CSS** file. This is the one that your own app is now serving.
And similarly for ReDoc...
```Python hl_lines="2-6 14-22 25-27 30-36"
{!../../../docs_src/extending_openapi/tutorial002.py!}
```
!!! tip
The *path operation* for `swagger_ui_redirect` is a helper for when you use OAuth2.
If you integrate your API with an OAuth2 provider, you will be able to authenticate and come back to the API docs with the acquired credentials. And interact with it using the real OAuth2 authentication.
Swagger UI will handle it behind the scenes for you, but it needs this "redirect" helper.
### Create a *path operation* to test it
Now, to be able to test that everything works, create a *path operation*:
```Python hl_lines="39-41"
{!../../../docs_src/extending_openapi/tutorial002.py!}
```
### Test it
Now, you should be able to disconnect your WiFi, go to your docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, and reload the page.
And even without Internet, you would be able to see the docs for your API and interact with it.
## Configuring Swagger UI
You can configure some extra <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">Swagger UI parameters</a>.
To configure them, pass the `swagger_ui_parameters` argument when creating the `FastAPI()` app object or to the `get_swagger_ui_html()` function.
`swagger_ui_parameters` receives a dictionary with the configurations passed to Swagger UI directly.
FastAPI converts the configurations to **JSON** to make them compatible with JavaScript, as that's what Swagger UI needs.
### Disable Syntax Highlighting
For example, you could disable syntax highlighting in Swagger UI.
Without changing the settings, syntax highlighting is enabled by default:
<img src="/img/tutorial/extending-openapi/image02.png">
But you can disable it by setting `syntaxHighlight` to `False`:
```Python hl_lines="3"
{!../../../docs_src/extending_openapi/tutorial003.py!}
```
...and then Swagger UI won't show the syntax highlighting anymore:
<img src="/img/tutorial/extending-openapi/image03.png">
### Change the Theme
The same way you could set the syntax highlighting theme with the key `"syntaxHighlight.theme"` (notice that it has a dot in the middle):
```Python hl_lines="3"
{!../../../docs_src/extending_openapi/tutorial004.py!}
```
That configuration would change the syntax highlighting color theme:
<img src="/img/tutorial/extending-openapi/image04.png">
### Change Default Swagger UI Parameters
FastAPI includes some default configuration parameters appropriate for most of the use cases.
It includes these default configurations:
```Python
{!../../../fastapi/openapi/docs.py[ln:7-13]!}
```
You can override any of them by setting a different value in the argument `swagger_ui_parameters`.
For example, to disable `deepLinking` you could pass these settings to `swagger_ui_parameters`:
```Python hl_lines="3"
{!../../../docs_src/extending_openapi/tutorial005.py!}
```
### Other Swagger UI Parameters
To see all the other possible configurations you can use, read the official <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">docs for Swagger UI parameters</a>.
### JavaScript-only settings
Swagger UI also allows other configurations to be **JavaScript-only** objects (for example, JavaScript functions).
FastAPI also includes these JavaScript-only `presets` settings:
```JavaScript
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
]
```
These are **JavaScript** objects, not strings, so you can't pass them from Python code directly.
If you need to use JavaScript-only configurations like those, you can use one of the methods above. Override all the Swagger UI *path operation* and manually write any JavaScript you need.

View File

@@ -12,6 +12,19 @@ A common tool is <a href="https://openapi-generator.tech/" class="external-link"
If you are building a **frontend**, a very interesting alternative is <a href="https://github.com/ferdikoomen/openapi-typescript-codegen" class="external-link" target="_blank">openapi-typescript-codegen</a>.
## Client and SDK Generators - Sponsor
There are also some **company-backed** Client and SDK generators based on OpenAPI (FastAPI), in some cases they can offer you **additional features** on top of high-quality generated SDKs/clients.
Some of them also ✨ [**sponsor FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, this ensures the continued and healthy **development** of FastAPI and its **ecosystem**.
And it shows their true commitment to FastAPI and its **community** (you), as they not only want to provide you a **good service** but also want to make sure you have a **good and healthy framework**, FastAPI. 🙇
You might want to try their services and follow their guides:
* <a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=docs-generate-clients" class="external-link" target="_blank">Fern</a>
* <a href="https://speakeasyapi.dev/?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
## Generate a TypeScript Frontend Client
Let's start with a simple FastAPI application:

View File

@@ -17,8 +17,17 @@ You could still use most of the features in **FastAPI** with the knowledge from
And the next sections assume you already read it, and assume that you know those main ideas.
## TestDriven.io course
## External Courses
If you would like to take an advanced-beginner course to complement this section of the docs, you might want to check: <a href="https://testdriven.io/courses/tdd-fastapi/" class="external-link" target="_blank">Test-Driven Development with FastAPI and Docker</a> by **TestDriven.io**.
Although the [Tutorial - User Guide](../tutorial/){.internal-link target=_blank} and this **Advanced User Guide** are written as a guided tutorial (like a book) and should be enough for you to **learn FastAPI**, you might want to complement it with additional courses.
They are currently donating 10% of all profits to the development of **FastAPI**. 🎉 😄
Or it might be the case that you just prefer to take other courses because they adapt better to your learning style.
Some course providers ✨ [**sponsor FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, this ensures the continued and healthy **development** of FastAPI and its **ecosystem**.
And it shows their true commitment to FastAPI and its **community** (you), as they not only want to provide you a **good learning experience** but also want to make sure you have a **good and healthy framework**, FastAPI. 🙇
You might want to try their courses:
* <a href="https://training.talkpython.fm/fastapi-courses" class="external-link" target="_blank">Talk Python Training</a>
* <a href="https://testdriven.io/courses/tdd-fastapi/" class="external-link" target="_blank">Test-Driven Development</a>

View File

@@ -150,9 +150,20 @@ And you could do this even if the data type in the request is not JSON.
For example, in this application we don't use FastAPI's integrated functionality to extract the JSON Schema from Pydantic models nor the automatic validation for JSON. In fact, we are declaring the request content type as YAML, not JSON:
```Python hl_lines="17-22 24"
{!../../../docs_src/path_operation_advanced_configuration/tutorial007.py!}
```
=== "Pydantic v2"
```Python hl_lines="17-22 24"
{!> ../../../docs_src/path_operation_advanced_configuration/tutorial007.py!}
```
=== "Pydantic v1"
```Python hl_lines="17-22 24"
{!> ../../../docs_src/path_operation_advanced_configuration/tutorial007_pv1.py!}
```
!!! info
In Pydantic version 1 the method to get the JSON Schema for a model was called `Item.schema()`, in Pydantic version 2, the method is called `Item.model_schema_json()`.
Nevertheless, although we are not using the default integrated functionality, we are still using a Pydantic model to manually generate the JSON Schema for the data that we want to receive in YAML.
@@ -160,9 +171,20 @@ Then we use the request directly, and extract the body as `bytes`. This means th
And then in our code, we parse that YAML content directly, and then we are again using the same Pydantic model to validate the YAML content:
```Python hl_lines="26-33"
{!../../../docs_src/path_operation_advanced_configuration/tutorial007.py!}
```
=== "Pydantic v2"
```Python hl_lines="26-33"
{!> ../../../docs_src/path_operation_advanced_configuration/tutorial007.py!}
```
=== "Pydantic v1"
```Python hl_lines="26-33"
{!> ../../../docs_src/path_operation_advanced_configuration/tutorial007_pv1.py!}
```
!!! info
In Pydantic version 1 the method to parse and validate an object was `Item.parse_obj()`, in Pydantic version 2, the method is called `Item.model_validate()`.
!!! tip
Here we re-use the same Pydantic model.

View File

@@ -125,7 +125,34 @@ That means that any value read in Python from an environment variable will be a
## Pydantic `Settings`
Fortunately, Pydantic provides a great utility to handle these settings coming from environment variables with <a href="https://pydantic-docs.helpmanual.io/usage/settings/" class="external-link" target="_blank">Pydantic: Settings management</a>.
Fortunately, Pydantic provides a great utility to handle these settings coming from environment variables with <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" class="external-link" target="_blank">Pydantic: Settings management</a>.
### Install `pydantic-settings`
First, install the `pydantic-settings` package:
<div class="termy">
```console
$ pip install pydantic-settings
---> 100%
```
</div>
It also comes included when you install the `all` extras with:
<div class="termy">
```console
$ pip install "fastapi[all]"
---> 100%
```
</div>
!!! info
In Pydantic v1 it came included with the main package. Now it is distributed as this independent package so that you can choose to install it or not if you don't need that functionality.
### Create the `Settings` object
@@ -135,9 +162,20 @@ The same way as with Pydantic models, you declare class attributes with type ann
You can use all the same validation features and tools you use for Pydantic models, like different data types and additional validations with `Field()`.
```Python hl_lines="2 5-8 11"
{!../../../docs_src/settings/tutorial001.py!}
```
=== "Pydantic v2"
```Python hl_lines="2 5-8 11"
{!> ../../../docs_src/settings/tutorial001.py!}
```
=== "Pydantic v1"
!!! info
In Pydantic v1 you would import `BaseSettings` directly from `pydantic` instead of from `pydantic_settings`.
```Python hl_lines="2 5-8 11"
{!> ../../../docs_src/settings/tutorial001_pv1.py!}
```
!!! tip
If you want something quick to copy and paste, don't use this example, use the last one below.
@@ -306,14 +344,28 @@ APP_NAME="ChimichangApp"
And then update your `config.py` with:
```Python hl_lines="9-10"
{!../../../docs_src/settings/app03/config.py!}
```
=== "Pydantic v2"
Here we create a class `Config` inside of your Pydantic `Settings` class, and set the `env_file` to the filename with the dotenv file we want to use.
```Python hl_lines="9"
{!> ../../../docs_src/settings/app03_an/config.py!}
```
!!! tip
The `Config` class is used just for Pydantic configuration. You can read more at <a href="https://pydantic-docs.helpmanual.io/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>
!!! tip
The `model_config` attribute is used just for Pydantic configuration. You can read more at <a href="https://docs.pydantic.dev/latest/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>.
=== "Pydantic v1"
```Python hl_lines="9-10"
{!> ../../../docs_src/settings/app03_an/config_pv1.py!}
```
!!! tip
The `Config` class is used just for Pydantic configuration. You can read more at <a href="https://docs.pydantic.dev/1.10/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>.
!!! info
In Pydantic version 1 the configuration was done in an internal class `Config`, in Pydantic version 2 it's done in an attribute `model_config`. This attribute takes a `dict`, and to get autocompletion and inline errors you can import and use `SettingsConfigDict` to define that `dict`.
Here we define the config `env_file` inside of your Pydantic `Settings` class, and set the value to the filename with the dotenv file we want to use.
### Creating the `Settings` only once with `lru_cache`

View File

@@ -1,5 +1,12 @@
# Testing a Database
!!! info
These docs are about to be updated. 🎉
The current version assumes Pydantic v1, and SQLAlchemy versions less than 2.0.
The new docs will include Pydantic v2 and will use <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel</a> (which is also based on SQLAlchemy) once it is updated to use Pydantic v2 as well.
You can use the same dependency overrides from [Testing Dependencies with Overrides](testing-dependencies.md){.internal-link target=_blank} to alter a database for testing.
You could want to set up a different database for testing, rollback the data after the tests, pre-fill it with some testing data, etc.

View File

@@ -119,6 +119,8 @@ That's why when talking about version 2.0 it's common to say "Swagger", and for
These two were chosen for being fairly popular and stable, but doing a quick search, you could find dozens of additional alternative user interfaces for OpenAPI (that you can use with **FastAPI**).
For example, you could try <a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=docs-alternatives" class="external-link" target="_blank">Fern</a> which is also a FastAPI sponsor. 😎🎉
### Flask REST frameworks
There are several Flask REST frameworks, but after investing the time and work into investigating them, I found that many are discontinued or abandoned, with several standing issues that made them unfit.

View File

@@ -126,7 +126,7 @@ And if you update that local FastAPI source code when you run that Python file a
That way, you don't have to "install" your local version to be able to test every change.
!!! note "Technical Details"
This only happens when you install using this included `requiements.txt` instead of installing `pip install fastapi` directly.
This only happens when you install using this included `requirements.txt` instead of installing `pip install fastapi` directly.
That is because inside of the `requirements.txt` file, the local version of FastAPI is marked to be installed in "editable" mode, with the `-e` option.

View File

@@ -144,3 +144,39 @@ code {
margin-top: 2em;
margin-bottom: 2em;
}
/* Screenshots */
/*
Simulate a browser window frame.
Inspired by Termynal's CSS tricks with modifications
*/
.screenshot {
display: block;
background-color: #d3e0de;
border-radius: 4px;
padding: 45px 5px 5px;
position: relative;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.screenshot img {
display: block;
border-radius: 2px;
}
.screenshot:before {
content: '';
position: absolute;
top: 15px;
left: 15px;
display: inline-block;
width: 15px;
height: 15px;
border-radius: 50%;
/* A little hack to display the window buttons in one pseudo element. */
background: #d9515d;
-webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;
}

View File

@@ -0,0 +1,17 @@
# Deploy FastAPI on Cloud Providers
You can use virtually **any cloud provider** to deploy your FastAPI application.
In most of the cases, the main cloud providers have guides to deploy FastAPI with them.
## Cloud Providers - Sponsors
Some cloud providers ✨ [**sponsor FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, this ensures the continued and healthy **development** of FastAPI and its **ecosystem**.
And it shows their true commitment to FastAPI and its **community** (you), as they not only want to provide you a **good service** but also want to make sure you have a **good and healthy framework**, FastAPI. 🙇
You might want to try their services and follow their guides:
* <a href="https://docs.platform.sh/languages/python.html?utm_source=fastapi-signup&utm_medium=banner&utm_campaign=FastAPI-signup-June-2023" class="external-link" target="_blank">Platform.sh</a>
* <a href="https://docs.porter.run/language-specific-guides/fastapi" class="external-link" target="_blank">Porter</a>
* <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a>

View File

@@ -1,391 +0,0 @@
# Deploy FastAPI on Deta Space
In this section you will learn how to easily deploy a **FastAPI** application on <a href="https://deta.space?ref=fastapi" class="external-link" target="_blank">Deta Space</a>, for free. 🎁
It will take you about **10 minutes** to deploy an API that you can use. After that, you can optionally release it to anyone.
Let's dive in.
!!! info
<a href="https://deta.space?ref=fastapi" class="external-link" target="_blank">Deta</a> is a **FastAPI** sponsor. 🎉
## A simple **FastAPI** app
* To start, create an empty directory with the name of your app, for example `./fastapi-deta/`, and then navigate into it.
```console
$ mkdir fastapi-deta
$ cd fastapi-deta
```
### FastAPI code
* Create a `main.py` file with:
```Python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}
```
### Requirements
Now, in the same directory create a file `requirements.txt` with:
```text
fastapi
uvicorn[standard]
```
### Directory structure
You will now have a directory `./fastapi-deta/` with two files:
```
.
└── main.py
└── requirements.txt
```
## Create a free **Deta Space** account
Next, create a free account on <a href="https://deta.space/signup?dev_mode=true&ref=fastapi" class="external-link" target="_blank">Deta Space</a>, you just need an email and password.
You don't even need a credit card, but make sure **Developer Mode** is enabled when you sign up.
## Install the CLI
Once you have your account, install the Deta Space <abbr title="Command Line Interface application">CLI</abbr>:
=== "Linux, macOS"
<div class="termy">
```console
$ curl -fsSL https://get.deta.dev/space-cli.sh | sh
```
</div>
=== "Windows PowerShell"
<div class="termy">
```console
$ iwr https://get.deta.dev/space-cli.ps1 -useb | iex
```
</div>
After installing it, open a new terminal so that the installed CLI is detected.
In a new terminal, confirm that it was correctly installed with:
<div class="termy">
```console
$ space --help
Deta command line interface for managing deta micros.
Complete documentation available at https://deta.space/docs
Usage:
space [flags]
space [command]
Available Commands:
help Help about any command
link link code to project
login login to space
new create new project
push push code for project
release create release for a project
validate validate spacefile in dir
version Space CLI version
...
```
</div>
!!! tip
If you have problems installing the CLI, check the official <a href="https://deta.space/docs/en/basics/cli?ref=fastapi" class="external-link" target="_blank">Deta Space Documentation</a>.
## Login with the CLI
In order to authenticate your CLI with Deta Space, you will need an access token.
To obtain this token, open your <a href="https://deta.space/login?ref=fastapi" class="external-link" target="_blank">Deta Space Canvas</a>, open the **Teletype** (command bar at the bottom of the Canvas), and then click on **Settings**. From there, select **Generate Token** and copy the resulting token.
<img src="/img/deployment/deta/image03.png">
Now run `space login` from the Space CLI. Upon pasting the token into the CLI prompt and pressing enter, you should see a confirmation message.
<div class="termy">
```console
$ space login
To authenticate the Space CLI with your Space account, generate a new access token in your Space settings and paste it below:
# Enter access token (41 chars) >$ *****************************************
👍 Login Successful!
```
</div>
## Create a new project in Space
Now that you've authenticated with the Space CLI, use it to create a new <a href="https://deta.space/docs/en/basics/projects" class="external-link" target="_blank">Space Project</a>:
```console
$ space new
# What is your project's name? >$ fastapi-deta
```
The Space CLI will ask you to name the project, we will call ours `fastapi-deta`.
Then, it will try to automatically detect which framework or language you are using, showing you what it finds. In our case it will identify the Python app with the following message, prompting you to confirm:
```console
⚙️ No Spacefile found, trying to auto-detect configuration ...
👇 Deta detected the following configuration:
Micros:
name: fastapi-deta
L src: .
L engine: python3.9
# Do you want to bootstrap "fastapi-deta" with this configuration? (y/n)$ y
```
After you confirm, your project will be created in Deta Space inside a special app called <a href="https://deta.space/docs/en/basics/projects#projects-in-builder?ref=fastapi" class="external-link" target="_blank">Builder</a>. Builder is a toolbox that helps you to create and manage your apps in Deta Space.
The CLI will also create a `Spacefile` locally in the `fastapi-deta` directory. The <a href="https://deta.space/docs/en/reference/spacefile?ref=fastapi" class="external-link" target="_blank">Spacefile</a> is a configuration file which tells Deta Space how to run your app. The `Spacefile` for your app will be as follows:
```yaml
v: 0
micros:
- name: fastapi-deta
src: .
engine: python3.9
```
It is a `yaml` file, and you can use it to add features like scheduled tasks or modify how your app functions, which we'll do later. To learn more, read <a href="https://deta.space/docs/en/reference/spacefile" class="external-link" target="_blank">the `Spacefile` documentation</a>.
!!! tip
The Space CLI will also create a hidden `.space` folder in your local directory to link your local environment with Deta Space. This folder should not be included in your version control and will automatically be added to your `.gitignore` file, if you have initialized a Git repository.
## Define the run command in the Spacefile
The `run` command in the Spacefile tells Space what command should be executed to start your app. In this case it would be `uvicorn main:app`.
```diff
v: 0
micros:
- name: fastapi-deta
src: .
engine: python3.9
+ run: uvicorn main:app
```
## Deploy to Deta Space
To get your FastAPI live in the cloud, use one more CLI command:
<div class="termy">
```console
$ space push
---> 100%
build complete... created revision: satyr-jvjk
✔ Successfully pushed your code and created a new Revision!
Updating your development instance with the latest Revision, it will be available on your Canvas shortly.
```
</div>
This command will package your code, upload all the necessary files to Deta Space, and run a remote build of your app, resulting in a **revision**. Whenever you run `space push` successfully, a live instance of your API is automatically updated with the latest revision.
!!! tip
You can manage your <a href="https://deta.space/docs/en/basics/revisions#whats-a-revision" class="external-link" target="_blank">revisions</a> by opening your project in the Builder app. The live copy of your API will be visible under the **Develop** tab in Builder.
## Check it
The live instance of your API will also be added automatically to your Canvas (the dashboard) on Deta Space.
<img src="/img/deployment/deta/image04.png">
Click on the new app called `fastapi-deta`, and it will open your API in a new browser tab on a URL like `https://fastapi-deta-gj7ka8.deta.app/`.
You will get a JSON response from your FastAPI app:
```JSON
{
"Hello": "World"
}
```
And now you can head over to the `/docs` of your API. For this example, it would be `https://fastapi-deta-gj7ka8.deta.app/docs`.
<img src="/img/deployment/deta/image05.png">
## Enable public access
Deta will handle authentication for your account using cookies. By default, every app or API that you `push` or install to your Space is personal - it's only accessible to you.
But you can also make your API public using the `Spacefile` from earlier.
With a `public_routes` parameter, you can specify which paths of your API should be available to the public.
Set your `public_routes` to `"*"` to open every route of your API to the public:
```yaml
v: 0
micros:
- name: fastapi-deta
src: .
engine: python3.9
public_routes:
- "/*"
```
Then run `space push` again to update your live API on Deta Space.
Once it deploys, you can share your URL with anyone and they will be able to access your API. 🚀
## HTTPS
Congrats! You deployed your FastAPI app to Deta Space! 🎉 🍰
Also, notice that Deta Space correctly handles HTTPS for you, so you don't have to take care of that and can be sure that your users will have a secure encrypted connection. ✅ 🔒
## Create a release
Space also allows you to publish your API. When you publish it, anyone else can install their own copy of your API, in their own Deta Space cloud.
To do so, run `space release` in the Space CLI to create an **unlisted release**:
<div class="termy">
```console
$ space release
# Do you want to use the latest revision (buzzard-hczt)? (y/n)$ y
~ Creating a Release with the latest Revision
---> 100%
creating release...
publishing release in edge locations..
completed...
released: fastapi-deta-exp-msbu
https://deta.space/discovery/r/5kjhgyxewkdmtotx
Lift off -- successfully created a new Release!
Your Release is available globally on 5 Deta Edges
Anyone can install their own copy of your app.
```
</div>
This command publishes your revision as a release and gives you a link. Anyone you give this link to can install your API.
You can also make your app publicly discoverable by creating a **listed release** with `space release --listed` in the Space CLI:
<div class="termy">
```console
$ space release --listed
# Do you want to use the latest revision (buzzard-hczt)? (y/n)$ y
~ Creating a listed Release with the latest Revision ...
creating release...
publishing release in edge locations..
completed...
released: fastapi-deta-exp-msbu
https://deta.space/discovery/@user/fastapi-deta
Lift off -- successfully created a new Release!
Your Release is available globally on 5 Deta Edges
Anyone can install their own copy of your app.
Listed on Discovery for others to find!
```
</div>
This will allow anyone to find and install your app via <a href="https://deta.space/discovery?ref=fastapi" class="external-link" target="_blank">Deta Discovery</a>. Read more about <a href="https://deta.space/docs/en/basics/releases?ref=fastapi" class="external-link" target="_blank">releasing your app in the docs</a>.
## Check runtime logs
Deta Space also lets you inspect the logs of every app you build or install.
Add some logging functionality to your app by adding a `print` statement to your `main.py` file.
```py
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):
print(item_id)
return {"item_id": item_id}
```
The code within the `read_item` function includes a print statement that will output the `item_id` that is included in the URL. Send a request to your _path operation_ `/items/{item_id}` from the docs UI (which will have a URL like `https://fastapi-deta-gj7ka8.deta.app/docs`), using an ID like `5` as an example.
Now go to your <a href="https://deta.space?ref=fastapi" class="external-link" target="_blank">Space's Canvas</a>. Click on the context menu (`...`) of your live app instance, and then click on **View Logs**. Here you can view your app's logs, sorted by time.
<img src="/img/deployment/deta/image06.png">
## Learn more
At some point, you will probably want to store some data for your app in a way that persists through time. For that you can use <a href="https://deta.space/docs/en/basics/data#deta-base?ref=fastapi" class="external-link" target="_blank">Deta Base</a> and <a href="https://deta.space/docs/en/basics/data#deta-drive?ref=fastapi" class="external-link" target="_blank">Deta Drive</a>, both of which have a generous **free tier**.
You can also read more in the <a href="https://deta.space/docs/?ref=fastapi" class="external-link" target="_blank">Deta Space Documentation</a>.
!!! tip
If you have any Deta related questions, comments, or feedback, head to the <a href="https://go.deta.dev/discord" class="external-link" target="_blank">Deta Discord server</a>.
## Deployment Concepts
Coming back to the concepts we discussed in [Deployments Concepts](./concepts.md){.internal-link target=_blank}, here's how each of them would be handled with Deta Space:
- **HTTPS**: Handled by Deta Space, they will give you a subdomain and handle HTTPS automatically.
- **Running on startup**: Handled by Deta Space, as part of their service.
- **Restarts**: Handled by Deta Space, as part of their service.
- **Replication**: Handled by Deta Space, as part of their service.
- **Authentication**: Handled by Deta Space, as part of their service.
- **Memory**: Limit predefined by Deta Space, you could contact them to increase it.
- **Previous steps before starting**: Can be configured using the <a href="https://deta.space/docs/en/reference/spacefile?ref=fastapi" class="external-link" target="_blank">`Spacefile`</a>.
!!! note
Deta Space is designed to make it easy and free to build cloud applications for yourself. Then you can optionally share them with anyone.
It can simplify several use cases, but at the same time, it doesn't support others, like using external databases (apart from Deta's own NoSQL database system), custom virtual machines, etc.
You can read more details in the <a href="https://deta.space/docs/en/basics/micros?ref=fastapi" class="external-link" target="_blank">Deta Space Documentation</a> to see if it's the right choice for you.

View File

@@ -1,4 +1,11 @@
# Async SQL (Relational) Databases
# Async SQL (Relational) Databases with Encode/Databases
!!! info
These docs are about to be updated. 🎉
The current version assumes Pydantic v1.
The new docs will include Pydantic v2 and will use <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel</a> once it is updated to use Pydantic v2 as well.
You can also use <a href="https://github.com/encode/databases" class="external-link" target="_blank">`encode/databases`</a> with **FastAPI** to connect to databases using `async` and `await`.

View File

@@ -0,0 +1,78 @@
# Configure Swagger UI
You can configure some extra <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">Swagger UI parameters</a>.
To configure them, pass the `swagger_ui_parameters` argument when creating the `FastAPI()` app object or to the `get_swagger_ui_html()` function.
`swagger_ui_parameters` receives a dictionary with the configurations passed to Swagger UI directly.
FastAPI converts the configurations to **JSON** to make them compatible with JavaScript, as that's what Swagger UI needs.
## Disable Syntax Highlighting
For example, you could disable syntax highlighting in Swagger UI.
Without changing the settings, syntax highlighting is enabled by default:
<img src="/img/tutorial/extending-openapi/image02.png">
But you can disable it by setting `syntaxHighlight` to `False`:
```Python hl_lines="3"
{!../../../docs_src/configure_swagger_ui/tutorial001.py!}
```
...and then Swagger UI won't show the syntax highlighting anymore:
<img src="/img/tutorial/extending-openapi/image03.png">
## Change the Theme
The same way you could set the syntax highlighting theme with the key `"syntaxHighlight.theme"` (notice that it has a dot in the middle):
```Python hl_lines="3"
{!../../../docs_src/configure_swagger_ui/tutorial002.py!}
```
That configuration would change the syntax highlighting color theme:
<img src="/img/tutorial/extending-openapi/image04.png">
## Change Default Swagger UI Parameters
FastAPI includes some default configuration parameters appropriate for most of the use cases.
It includes these default configurations:
```Python
{!../../../fastapi/openapi/docs.py[ln:7-13]!}
```
You can override any of them by setting a different value in the argument `swagger_ui_parameters`.
For example, to disable `deepLinking` you could pass these settings to `swagger_ui_parameters`:
```Python hl_lines="3"
{!../../../docs_src/configure_swagger_ui/tutorial003.py!}
```
## Other Swagger UI Parameters
To see all the other possible configurations you can use, read the official <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">docs for Swagger UI parameters</a>.
## JavaScript-only settings
Swagger UI also allows other configurations to be **JavaScript-only** objects (for example, JavaScript functions).
FastAPI also includes these JavaScript-only `presets` settings:
```JavaScript
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
]
```
These are **JavaScript** objects, not strings, so you can't pass them from Python code directly.
If you need to use JavaScript-only configurations like those, you can use one of the methods above. Override all the Swagger UI *path operation* and manually write any JavaScript you need.

View File

@@ -0,0 +1,199 @@
# Custom Docs UI Static Assets (Self-Hosting)
The API docs use **Swagger UI** and **ReDoc**, and each of those need some JavaScript and CSS files.
By default, those files are served from a <abbr title="Content Delivery Network: A service, normally composed of several servers, that provides static files, like JavaScript and CSS. It's commonly used to serve those files from the server closer to the client, improving performance.">CDN</abbr>.
But it's possible to customize it, you can set a specific CDN, or serve the files yourself.
## Custom CDN for JavaScript and CSS
Let's say that you want to use a different <abbr title="Content Delivery Network">CDN</abbr>, for example you want to use `https://unpkg.com/`.
This could be useful if for example you live in a country that restricts some URLs.
### Disable the automatic docs
The first step is to disable the automatic docs, as by default, those use the default CDN.
To disable them, set their URLs to `None` when creating your `FastAPI` app:
```Python hl_lines="8"
{!../../../docs_src/custom_docs_ui/tutorial001.py!}
```
### Include the custom docs
Now you can create the *path operations* for the custom docs.
You can re-use FastAPI's internal functions to create the HTML pages for the docs, and pass them the needed arguments:
* `openapi_url`: the URL where the HTML page for the docs can get the OpenAPI schema for your API. You can use here the attribute `app.openapi_url`.
* `title`: the title of your API.
* `oauth2_redirect_url`: you can use `app.swagger_ui_oauth2_redirect_url` here to use the default.
* `swagger_js_url`: the URL where the HTML for your Swagger UI docs can get the **JavaScript** file. This is the custom CDN URL.
* `swagger_css_url`: the URL where the HTML for your Swagger UI docs can get the **CSS** file. This is the custom CDN URL.
And similarly for ReDoc...
```Python hl_lines="2-6 11-19 22-24 27-33"
{!../../../docs_src/custom_docs_ui/tutorial001.py!}
```
!!! tip
The *path operation* for `swagger_ui_redirect` is a helper for when you use OAuth2.
If you integrate your API with an OAuth2 provider, you will be able to authenticate and come back to the API docs with the acquired credentials. And interact with it using the real OAuth2 authentication.
Swagger UI will handle it behind the scenes for you, but it needs this "redirect" helper.
### Create a *path operation* to test it
Now, to be able to test that everything works, create a *path operation*:
```Python hl_lines="36-38"
{!../../../docs_src/custom_docs_ui/tutorial001.py!}
```
### Test it
Now, you should be able to go to your docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, and reload the page, it will load those assets from the new CDN.
## Self-hosting JavaScript and CSS for docs
Self-hosting the JavaScript and CSS could be useful if, for example, you need your app to keep working even while offline, without open Internet access, or in a local network.
Here you'll see how to serve those files yourself, in the same FastAPI app, and configure the docs to use them.
### Project file structure
Let's say your project file structure looks like this:
```
.
├── app
│ ├── __init__.py
│ ├── main.py
```
Now create a directory to store those static files.
Your new file structure could look like this:
```
.
├── app
│   ├── __init__.py
│   ├── main.py
└── static/
```
### Download the files
Download the static files needed for the docs and put them on that `static/` directory.
You can probably right-click each link and select an option similar to `Save link as...`.
**Swagger UI** uses the files:
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a>
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a>
And **ReDoc** uses the file:
* <a href="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js" class="external-link" target="_blank">`redoc.standalone.js`</a>
After that, your file structure could look like:
```
.
├── app
│   ├── __init__.py
│   ├── main.py
└── static
├── redoc.standalone.js
├── swagger-ui-bundle.js
└── swagger-ui.css
```
### Serve the static files
* Import `StaticFiles`.
* "Mount" a `StaticFiles()` instance in a specific path.
```Python hl_lines="7 11"
{!../../../docs_src/custom_docs_ui/tutorial002.py!}
```
### Test the static files
Start your application and go to <a href="http://127.0.0.1:8000/static/redoc.standalone.js" class="external-link" target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a>.
You should see a very long JavaScript file for **ReDoc**.
It could start with something like:
```JavaScript
/*!
* ReDoc - OpenAPI/Swagger-generated API Reference Documentation
* -------------------------------------------------------------
* Version: "2.0.0-rc.18"
* Repo: https://github.com/Redocly/redoc
*/
!function(e,t){"object"==typeof exports&&"object"==typeof m
...
```
That confirms that you are being able to serve static files from your app, and that you placed the static files for the docs in the correct place.
Now we can configure the app to use those static files for the docs.
### Disable the automatic docs for static files
The same as when using a custom CDN, the first step is to disable the automatic docs, as those use the CDN by default.
To disable them, set their URLs to `None` when creating your `FastAPI` app:
```Python hl_lines="9"
{!../../../docs_src/custom_docs_ui/tutorial002.py!}
```
### Include the custom docs for static files
And the same way as with a custom CDN, now you can create the *path operations* for the custom docs.
Again, you can re-use FastAPI's internal functions to create the HTML pages for the docs, and pass them the needed arguments:
* `openapi_url`: the URL where the HTML page for the docs can get the OpenAPI schema for your API. You can use here the attribute `app.openapi_url`.
* `title`: the title of your API.
* `oauth2_redirect_url`: you can use `app.swagger_ui_oauth2_redirect_url` here to use the default.
* `swagger_js_url`: the URL where the HTML for your Swagger UI docs can get the **JavaScript** file. **This is the one that your own app is now serving**.
* `swagger_css_url`: the URL where the HTML for your Swagger UI docs can get the **CSS** file. **This is the one that your own app is now serving**.
And similarly for ReDoc...
```Python hl_lines="2-6 14-22 25-27 30-36"
{!../../../docs_src/custom_docs_ui/tutorial002.py!}
```
!!! tip
The *path operation* for `swagger_ui_redirect` is a helper for when you use OAuth2.
If you integrate your API with an OAuth2 provider, you will be able to authenticate and come back to the API docs with the acquired credentials. And interact with it using the real OAuth2 authentication.
Swagger UI will handle it behind the scenes for you, but it needs this "redirect" helper.
### Create a *path operation* to test static files
Now, to be able to test that everything works, create a *path operation*:
```Python hl_lines="39-41"
{!../../../docs_src/custom_docs_ui/tutorial002.py!}
```
### Test Static Files UI
Now, you should be able to disconnect your WiFi, go to your docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, and reload the page.
And even without Internet, you would be able to see the docs for your API and interact with it.

View File

@@ -0,0 +1,87 @@
# Extending OpenAPI
There are some cases where you might need to modify the generated OpenAPI schema.
In this section you will see how.
## The normal process
The normal (default) process, is as follows.
A `FastAPI` application (instance) has an `.openapi()` method that is expected to return the OpenAPI schema.
As part of the application object creation, a *path operation* for `/openapi.json` (or for whatever you set your `openapi_url`) is registered.
It just returns a JSON response with the result of the application's `.openapi()` method.
By default, what the method `.openapi()` does is check the property `.openapi_schema` to see if it has contents and return them.
If it doesn't, it generates them using the utility function at `fastapi.openapi.utils.get_openapi`.
And that function `get_openapi()` receives as parameters:
* `title`: The OpenAPI title, shown in the docs.
* `version`: The version of your API, e.g. `2.5.0`.
* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.1.0`.
* `summary`: A short summary of the API.
* `description`: The description of your API, this can include markdown and will be shown in the docs.
* `routes`: A list of routes, these are each of the registered *path operations*. They are taken from `app.routes`.
!!! info
The parameter `summary` is available in OpenAPI 3.1.0 and above, supported by FastAPI 0.99.0 and above.
## Overriding the defaults
Using the information above, you can use the same utility function to generate the OpenAPI schema and override each part that you need.
For example, let's add <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">ReDoc's OpenAPI extension to include a custom logo</a>.
### Normal **FastAPI**
First, write all your **FastAPI** application as normally:
```Python hl_lines="1 4 7-9"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Generate the OpenAPI schema
Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function:
```Python hl_lines="2 15-21"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Modify the OpenAPI schema
Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema:
```Python hl_lines="22-24"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Cache the OpenAPI schema
You can use the property `.openapi_schema` as a "cache", to store your generated schema.
That way, your application won't have to generate the schema every time a user opens your API docs.
It will be generated only once, and then the same cached schema will be used for the next requests.
```Python hl_lines="13-14 25-26"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Override the method
Now you can replace the `.openapi()` method with your new function.
```Python hl_lines="29"
{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Check it
Once you go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> you will see that you are using your custom logo (in this example, **FastAPI**'s logo):
<img src="/img/tutorial/extending-openapi/image01.png">

View File

@@ -0,0 +1,39 @@
# General - How To - Recipes
Here are several pointers to other places in the docs, for general or frequent questions.
## Filter Data - Security
To ensure that you don't return more data than you should, read the docs for [Tutorial - Response Model - Return Type](../tutorial/response-model.md){.internal-link target=_blank}.
## Documentation Tags - OpenAPI
To add tags to your *path operations*, and group them in the docs UI, read the docs for [Tutorial - Path Operation Configurations - Tags](../tutorial/path-operation-configuration.md#tags){.internal-link target=_blank}.
## Documentation Summary and Description - OpenAPI
To add a summary and description to your *path operations*, and show them in the docs UI, read the docs for [Tutorial - Path Operation Configurations - Summary and Description](../tutorial/path-operation-configuration.md#summary-and-description){.internal-link target=_blank}.
## Documentation Response description - OpenAPI
To define the description of the response, shown in the docs UI, read the docs for [Tutorial - Path Operation Configurations - Response description](../tutorial/path-operation-configuration.md#response-description){.internal-link target=_blank}.
## Documentation Deprecate a *Path Operation* - OpenAPI
To deprecate a *path operation*, and show it in the docs UI, read the docs for [Tutorial - Path Operation Configurations - Deprecation](../tutorial/path-operation-configuration.md#deprecate-a-path-operation){.internal-link target=_blank}.
## Convert any Data to JSON-compatible
To convert any data to JSON-compatible, read the docs for [Tutorial - JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}.
## OpenAPI Metadata - Docs
To add metadata to your OpenAPI schema, including a license, version, contact, etc, read the docs for [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md){.internal-link target=_blank}.
## OpenAPI Custom URL
To customize the OpenAPI URL (or remove it), read the docs for [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md#openapi-url){.internal-link target=_blank}.
## OpenAPI Docs URLs
To update the URLs used for the automatically generated docs user interfaces, read the docs for [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md#docs-urls){.internal-link target=_blank}.

View File

@@ -0,0 +1,11 @@
# How To - Recipes
Here you will see different recipes or "how to" guides for **several topics**.
Most of these ideas would be more or less **independent**, and in most cases you should only need to study them if they apply directly to **your project**.
If something seems interesting and useful to your project, go ahead and check it, but otherwise, you might probably just skip them.
!!! tip
If you want to **learn FastAPI** in a structured way (recommended), go and read the [Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} chapter by chapter instead.

View File

@@ -1,4 +1,11 @@
# NoSQL (Distributed / Big Data) Databases
# NoSQL (Distributed / Big Data) Databases with Couchbase
!!! info
These docs are about to be updated. 🎉
The current version assumes Pydantic v1.
The new docs will hopefully use Pydantic v2 and will use <a href="https://art049.github.io/odmantic/" class="external-link" target="_blank">ODMantic</a> with MongoDB.
**FastAPI** can also be integrated with any <abbr title="Distributed database (Big Data), also 'Not Only SQL'">NoSQL</abbr>.

View File

@@ -0,0 +1,231 @@
# Separate OpenAPI Schemas for Input and Output or Not
When using **Pydantic v2**, the generated OpenAPI is a bit more exact and **correct** than before. 😎
In fact, in some cases, it will even have **two JSON Schemas** in OpenAPI for the same Pydantic model, for input and output, depending on if they have **default values**.
Let's see how that works and how to change it if you need to do that.
## Pydantic Models for Input and Output
Let's say you have a Pydantic model with default values, like this one:
=== "Python 3.10+"
```Python hl_lines="7"
{!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-7]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py!}
```
</details>
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py[ln:1-9]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py!}
```
</details>
=== "Python 3.7+"
```Python hl_lines="9"
{!> ../../../docs_src/separate_openapi_schemas/tutorial001.py[ln:1-9]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!> ../../../docs_src/separate_openapi_schemas/tutorial001.py!}
```
</details>
### Model for Input
If you use this model as an input like here:
=== "Python 3.10+"
```Python hl_lines="14"
{!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-15]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py!}
```
</details>
=== "Python 3.9+"
```Python hl_lines="16"
{!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py[ln:1-17]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py!}
```
</details>
=== "Python 3.7+"
```Python hl_lines="16"
{!> ../../../docs_src/separate_openapi_schemas/tutorial001.py[ln:1-17]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!> ../../../docs_src/separate_openapi_schemas/tutorial001.py!}
```
</details>
...then the `description` field will **not be required**. Because it has a default value of `None`.
### Input Model in Docs
You can confirm that in the docs, the `description` field doesn't have a **red asterisk**, it's not marked as required:
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image01.png">
</div>
### Model for Output
But if you use the same model as an output, like here:
=== "Python 3.10+"
```Python hl_lines="19"
{!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="21"
{!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py!}
```
=== "Python 3.7+"
```Python hl_lines="21"
{!> ../../../docs_src/separate_openapi_schemas/tutorial001.py!}
```
...then because `description` has a default value, if you **don't return anything** for that field, it will still have that **default value**.
### Model for Output Response Data
If you interact with the docs and check the response, even though the code didn't add anything in one of the `description` fields, the JSON response contains the default value (`null`):
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image02.png">
</div>
This means that it will **always have a value**, it's just that sometimes the value could be `None` (or `null` in JSON).
That means that, clients using your API don't have to check if the value exists or not, they can **asume the field will always be there**, but just that in some cases it will have the default value of `None`.
The way to describe this in OpenAPI, is to mark that field as **required**, because it will always be there.
Because of that, the JSON Schema for a model can be different depending on if it's used for **input or output**:
* for **input** the `description` will **not be required**
* for **output** it will be **required** (and possibly `None`, or in JSON terms, `null`)
### Model for Output in Docs
You can check the output model in the docs too, **both** `name` and `description` are marked as **required** with a **red asterisk**:
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image03.png">
</div>
### Model for Input and Output in Docs
And if you check all the available Schemas (JSON Schemas) in OpenAPI, you will see that there are two, one `Item-Input` and one `Item-Output`.
For `Item-Input`, `description` is **not required**, it doesn't have a red asterisk.
But for `Item-Output`, `description` is **required**, it has a red asterisk.
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image04.png">
</div>
With this feature from **Pydantic v2**, your API documentation is more **precise**, and if you have autogenerated clients and SDKs, they will be more precise too, with a better **developer experience** and consistency. 🎉
## Do not Separate Schemas
Now, there are some cases where you might want to have the **same schema for input and output**.
Probably the main use case for this is if you already have some autogenerated client code/SDKs and you don't want to update all the autogenerated client code/SDKs yet, you probably will want to do it at some point, but maybe not right now.
In that case, you can disable this feature in **FastAPI**, with the parameter `separate_input_output_schemas=False`.
!!! info
Support for `separate_input_output_schemas` was added in FastAPI `0.102.0`. 🤓
=== "Python 3.10+"
```Python hl_lines="10"
{!> ../../../docs_src/separate_openapi_schemas/tutorial002_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="12"
{!> ../../../docs_src/separate_openapi_schemas/tutorial002_py39.py!}
```
=== "Python 3.7+"
```Python hl_lines="12"
{!> ../../../docs_src/separate_openapi_schemas/tutorial002.py!}
```
### Same Schema for Input and Output Models in Docs
And now there will be one single schema for input and output for the model, only `Item`, and it will have `description` as **not required**:
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
</div>
This is the same behavior as in Pydantic v1. 🤓

View File

@@ -5,6 +5,15 @@
Feel free to skip this.
Peewee is not recommended with FastAPI as it doesn't play well with anything async Python. There are several better alternatives.
!!! info
These docs assume Pydantic v1.
Because Pewee doesn't play well with anything async and there are better alternatives, I won't update these docs for Pydantic v2, they are kept for now only for historical purposes.
The examples here are no longer tested in CI (as they were before).
If you are starting a project from scratch, you are probably better off with SQLAlchemy ORM ([SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank}), or any other async ORM.
If you already have a code base that uses <a href="https://docs.peewee-orm.com/en/latest/" class="external-link" target="_blank">Peewee ORM</a>, you can check here how to use it with **FastAPI**.

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 40 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 349 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -446,6 +446,8 @@ To understand more about it, see the section <a href="https://fastapi.tiangolo.c
Used by Pydantic:
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - for settings management.
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - for extra types to be used with Pydantic.
Used by Starlette:

View File

@@ -3,6 +3,233 @@
## Latest Changes
## 0.103.0
### Features
* ✨ Add support for `openapi_examples` in all FastAPI parameters. PR [#10152](https://github.com/tiangolo/fastapi/pull/10152) by [@tiangolo](https://github.com/tiangolo).
* New docs: [OpenAPI-specific examples](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#openapi-specific-examples).
### Docs
* 📝 Add note to docs about Separate Input and Output Schemas with FastAPI version. PR [#10150](https://github.com/tiangolo/fastapi/pull/10150) by [@tiangolo](https://github.com/tiangolo).
## 0.102.0
### Features
* ✨ Add support for disabling the separation of input and output JSON Schemas in OpenAPI with Pydantic v2 with `separate_input_output_schemas=False`. PR [#10145](https://github.com/tiangolo/fastapi/pull/10145) by [@tiangolo](https://github.com/tiangolo).
* New docs [Separate OpenAPI Schemas for Input and Output or Not](https://fastapi.tiangolo.com/how-to/separate-openapi-schemas/).
* This PR also includes a new setup (internal tools) for generating screenshots for the docs.
### Refactors
* ♻️ Refactor tests for new Pydantic 2.2.1. PR [#10115](https://github.com/tiangolo/fastapi/pull/10115) by [@tiangolo](https://github.com/tiangolo).
### Docs
* 📝 Add new docs section, How To - Recipes, move docs that don't have to be read by everyone to How To. PR [#10114](https://github.com/tiangolo/fastapi/pull/10114) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update Advanced docs, add links to sponsor courses. PR [#10113](https://github.com/tiangolo/fastapi/pull/10113) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update docs for generating clients. PR [#10112](https://github.com/tiangolo/fastapi/pull/10112) by [@tiangolo](https://github.com/tiangolo).
* 📝 Tweak MkDocs and add redirects. PR [#10111](https://github.com/tiangolo/fastapi/pull/10111) by [@tiangolo](https://github.com/tiangolo).
* 📝 Restructure docs for cloud providers, include links to sponsors. PR [#10110](https://github.com/tiangolo/fastapi/pull/10110) by [@tiangolo](https://github.com/tiangolo).
### Internal
* 🔧 Update sponsors, add Speakeasy. PR [#10098](https://github.com/tiangolo/fastapi/pull/10098) by [@tiangolo](https://github.com/tiangolo).
## 0.101.1
### Fixes
* ✨ Add `ResponseValidationError` printable details, to show up in server error logs. PR [#10078](https://github.com/tiangolo/fastapi/pull/10078) by [@tiangolo](https://github.com/tiangolo).
### Refactors
* ✏️ Fix typo in deprecation warnings in `fastapi/params.py`. PR [#9854](https://github.com/tiangolo/fastapi/pull/9854) by [@russbiggs](https://github.com/russbiggs).
* ✏️ Fix typos in comments on internal code in `fastapi/concurrency.py` and `fastapi/routing.py`. PR [#9590](https://github.com/tiangolo/fastapi/pull/9590) by [@ElliottLarsen](https://github.com/ElliottLarsen).
### Docs
* ✏️ Fix typo in release notes. PR [#9835](https://github.com/tiangolo/fastapi/pull/9835) by [@francisbergin](https://github.com/francisbergin).
* 📝 Add external article: Build an SMS Spam Classifier Serverless Database with FaunaDB and FastAPI. PR [#9847](https://github.com/tiangolo/fastapi/pull/9847) by [@adejumoridwan](https://github.com/adejumoridwan).
* 📝 Fix typo in `docs/en/docs/contributing.md`. PR [#9878](https://github.com/tiangolo/fastapi/pull/9878) by [@VicenteMerino](https://github.com/VicenteMerino).
* 📝 Fix code highlighting in `docs/en/docs/tutorial/bigger-applications.md`. PR [#9806](https://github.com/tiangolo/fastapi/pull/9806) by [@theonlykingpin](https://github.com/theonlykingpin).
### Translations
* 🌐 Add Japanese translation for `docs/ja/docs/deployment/concepts.md`. PR [#10062](https://github.com/tiangolo/fastapi/pull/10062) by [@tamtam-fitness](https://github.com/tamtam-fitness).
* 🌐 Add Japanese translation for `docs/ja/docs/deployment/server-workers.md`. PR [#10064](https://github.com/tiangolo/fastapi/pull/10064) by [@tamtam-fitness](https://github.com/tamtam-fitness).
* 🌐 Update Japanese translation for `docs/ja/docs/deployment/docker.md`. PR [#10073](https://github.com/tiangolo/fastapi/pull/10073) by [@tamtam-fitness](https://github.com/tamtam-fitness).
* 🌐 Add Ukrainian translation for `docs/uk/docs/fastapi-people.md`. PR [#10059](https://github.com/tiangolo/fastapi/pull/10059) by [@rostik1410](https://github.com/rostik1410).
* 🌐 Add Ukrainian translation for `docs/uk/docs/tutorial/cookie-params.md`. PR [#10032](https://github.com/tiangolo/fastapi/pull/10032) by [@rostik1410](https://github.com/rostik1410).
* 🌐 Add Russian translation for `docs/ru/docs/deployment/docker.md`. PR [#9971](https://github.com/tiangolo/fastapi/pull/9971) by [@Xewus](https://github.com/Xewus).
* 🌐 Add Vietnamese translation for `docs/vi/docs/python-types.md`. PR [#10047](https://github.com/tiangolo/fastapi/pull/10047) by [@magiskboy](https://github.com/magiskboy).
* 🌐 Add Russian translation for `docs/ru/docs/tutorial/dependencies/global-dependencies.md`. PR [#9970](https://github.com/tiangolo/fastapi/pull/9970) by [@dudyaosuplayer](https://github.com/dudyaosuplayer).
* 🌐 Add Urdu translation for `docs/ur/docs/benchmarks.md`. PR [#9974](https://github.com/tiangolo/fastapi/pull/9974) by [@AhsanSheraz](https://github.com/AhsanSheraz).
### Internal
* 🔧 Add sponsor Porter. PR [#10051](https://github.com/tiangolo/fastapi/pull/10051) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update sponsors, add Jina back as bronze sponsor. PR [#10050](https://github.com/tiangolo/fastapi/pull/10050) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Bump mypy from 1.4.0 to 1.4.1. PR [#9756](https://github.com/tiangolo/fastapi/pull/9756) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump mkdocs-material from 9.1.17 to 9.1.21. PR [#9960](https://github.com/tiangolo/fastapi/pull/9960) by [@dependabot[bot]](https://github.com/apps/dependabot).
## 0.101.0
### Features
* ✨ Enable Pydantic's serialization mode for responses, add support for Pydantic's `computed_field`, better OpenAPI for response models, proper required attributes, better generated clients. PR [#10011](https://github.com/tiangolo/fastapi/pull/10011) by [@tiangolo](https://github.com/tiangolo).
### Refactors
* ✅ Fix tests for compatibility with pydantic 2.1.1. PR [#9943](https://github.com/tiangolo/fastapi/pull/9943) by [@dmontagu](https://github.com/dmontagu).
* ✅ Fix test error in Windows for `jsonable_encoder`. PR [#9840](https://github.com/tiangolo/fastapi/pull/9840) by [@iudeen](https://github.com/iudeen).
### Upgrades
* 📌 Do not allow Pydantic 2.1.0 that breaks (require 2.1.1). PR [#10012](https://github.com/tiangolo/fastapi/pull/10012) by [@tiangolo](https://github.com/tiangolo).
### Translations
* 🌐 Add Russian translation for `docs/ru/docs/tutorial/security/index.md`. PR [#9963](https://github.com/tiangolo/fastapi/pull/9963) by [@eVery1337](https://github.com/eVery1337).
* 🌐 Remove Vietnamese note about missing translation. PR [#9957](https://github.com/tiangolo/fastapi/pull/9957) by [@tiangolo](https://github.com/tiangolo).
### Internal
* 👷 Add GitHub Actions step dump context to debug external failures. PR [#10008](https://github.com/tiangolo/fastapi/pull/10008) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Restore MkDocs Material pin after the fix. PR [#10001](https://github.com/tiangolo/fastapi/pull/10001) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update the Question template to ask for the Pydantic version. PR [#10000](https://github.com/tiangolo/fastapi/pull/10000) by [@tiangolo](https://github.com/tiangolo).
* 📍 Update MkDocs Material dependencies. PR [#9986](https://github.com/tiangolo/fastapi/pull/9986) by [@tiangolo](https://github.com/tiangolo).
* 👥 Update FastAPI People. PR [#9999](https://github.com/tiangolo/fastapi/pull/9999) by [@tiangolo](https://github.com/tiangolo).
* 🐳 Update Dockerfile with compatibility versions, to upgrade later. PR [#9998](https://github.com/tiangolo/fastapi/pull/9998) by [@tiangolo](https://github.com/tiangolo).
* Add pydantic-settings to FastAPI People dependencies. PR [#9988](https://github.com/tiangolo/fastapi/pull/9988) by [@tiangolo](https://github.com/tiangolo).
* ♻️ Update FastAPI People logic with new Pydantic. PR [#9985](https://github.com/tiangolo/fastapi/pull/9985) by [@tiangolo](https://github.com/tiangolo).
* 🍱 Update sponsors, Fern badge. PR [#9982](https://github.com/tiangolo/fastapi/pull/9982) by [@tiangolo](https://github.com/tiangolo).
* 👷 Deploy docs to Cloudflare Pages. PR [#9978](https://github.com/tiangolo/fastapi/pull/9978) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update sponsor Fern. PR [#9979](https://github.com/tiangolo/fastapi/pull/9979) by [@tiangolo](https://github.com/tiangolo).
* 👷 Update CI debug mode with Tmate. PR [#9977](https://github.com/tiangolo/fastapi/pull/9977) by [@tiangolo](https://github.com/tiangolo).
## 0.100.1
### Fixes
* 🐛 Replace `MultHostUrl` to `AnyUrl` for compatibility with older versions of Pydantic v1. PR [#9852](https://github.com/tiangolo/fastapi/pull/9852) by [@Kludex](https://github.com/Kludex).
### Docs
* 📝 Update links for self-hosted Swagger UI, point to v5, for OpenAPI 31.0. PR [#9834](https://github.com/tiangolo/fastapi/pull/9834) by [@tiangolo](https://github.com/tiangolo).
### Translations
* 🌐 Add Ukrainian translation for `docs/uk/docs/tutorial/body.md`. PR [#4574](https://github.com/tiangolo/fastapi/pull/4574) by [@ss-o-furda](https://github.com/ss-o-furda).
* 🌐 Add Vietnamese translation for `docs/vi/docs/features.md` and `docs/vi/docs/index.md`. PR [#3006](https://github.com/tiangolo/fastapi/pull/3006) by [@magiskboy](https://github.com/magiskboy).
* 🌐 Add Korean translation for `docs/ko/docs/async.md`. PR [#4179](https://github.com/tiangolo/fastapi/pull/4179) by [@NinaHwang](https://github.com/NinaHwang).
* 🌐 Add Chinese translation for `docs/zh/docs/tutorial/background-tasks.md`. PR [#9812](https://github.com/tiangolo/fastapi/pull/9812) by [@wdh99](https://github.com/wdh99).
* 🌐 Add French translation for `docs/fr/docs/tutorial/query-params-str-validations.md`. PR [#4075](https://github.com/tiangolo/fastapi/pull/4075) by [@Smlep](https://github.com/Smlep).
* 🌐 Add French translation for `docs/fr/docs/tutorial/index.md`. PR [#2234](https://github.com/tiangolo/fastapi/pull/2234) by [@JulianMaurin](https://github.com/JulianMaurin).
* 🌐 Add French translation for `docs/fr/docs/contributing.md`. PR [#2132](https://github.com/tiangolo/fastapi/pull/2132) by [@JulianMaurin](https://github.com/JulianMaurin).
* 🌐 Add French translation for `docs/fr/docs/benchmarks.md`. PR [#2155](https://github.com/tiangolo/fastapi/pull/2155) by [@clemsau](https://github.com/clemsau).
* 🌐 Update Chinese translations with new source files. PR [#9738](https://github.com/tiangolo/fastapi/pull/9738) by [@mahone3297](https://github.com/mahone3297).
* 🌐 Add Russian translation for `docs/ru/docs/tutorial/request-forms.md`. PR [#9841](https://github.com/tiangolo/fastapi/pull/9841) by [@dedkot01](https://github.com/dedkot01).
* 🌐 Update Chinese translation for `docs/zh/docs/tutorial/handling-errors.md`. PR [#9485](https://github.com/tiangolo/fastapi/pull/9485) by [@Creat55](https://github.com/Creat55).
### Internal
* 🔧 Update sponsors, add Fern. PR [#9956](https://github.com/tiangolo/fastapi/pull/9956) by [@tiangolo](https://github.com/tiangolo).
* 👷 Update FastAPI People token. PR [#9844](https://github.com/tiangolo/fastapi/pull/9844) by [@tiangolo](https://github.com/tiangolo).
* 👥 Update FastAPI People. PR [#9775](https://github.com/tiangolo/fastapi/pull/9775) by [@tiangolo](https://github.com/tiangolo).
* 👷 Update MkDocs Material token. PR [#9843](https://github.com/tiangolo/fastapi/pull/9843) by [@tiangolo](https://github.com/tiangolo).
* 👷 Update token for latest changes. PR [#9842](https://github.com/tiangolo/fastapi/pull/9842) by [@tiangolo](https://github.com/tiangolo).
## 0.100.0
✨ Support for **Pydantic v2**
Pydantic version 2 has the **core** re-written in **Rust** and includes a lot of improvements and features, for example:
* Improved **correctness** in corner cases.
* **Safer** types.
* Better **performance** and **less energy** consumption.
* Better **extensibility**.
* etc.
...all this while keeping the **same Python API**. In most of the cases, for simple models, you can simply upgrade the Pydantic version and get all the benefits. 🚀
In some cases, for pure data validation and processing, you can get performance improvements of **20x** or more. This means 2,000% or more. 🤯
When you use **FastAPI**, there's a lot more going on, processing the request and response, handling dependencies, executing **your own code**, and particularly, **waiting for the network**. But you will probably still get some nice performance improvements just from the upgrade.
The focus of this release is **compatibility** with Pydantic v1 and v2, to make sure your current apps keep working. Later there will be more focus on refactors, correctness, code improvements, and then **performance** improvements. Some third-party early beta testers that ran benchmarks on the beta releases of FastAPI reported improvements of **2x - 3x**. Which is not bad for just doing `pip install --upgrade fastapi pydantic`. This was not an official benchmark and I didn't check it myself, but it's a good sign.
### Migration
Check out the [Pydantic migration guide](https://docs.pydantic.dev/2.0/migration/).
For the things that need changes in your Pydantic models, the Pydantic team built [`bump-pydantic`](https://github.com/pydantic/bump-pydantic).
A command line tool that will **process your code** and update most of the things **automatically** for you. Make sure you have your code in git first, and review each of the changes to make sure everything is correct before committing the changes.
### Pydantic v1
**This version of FastAPI still supports Pydantic v1**. And although Pydantic v1 will be deprecated at some point, it will still be supported for a while.
This means that you can install the new Pydantic v2, and if something fails, you can install Pydantic v1 while you fix any problems you might have, but having the latest FastAPI.
There are **tests for both Pydantic v1 and v2**, and test **coverage** is kept at **100%**.
### Changes
* There are **new parameter** fields supported by Pydantic `Field()` for:
* `Path()`
* `Query()`
* `Header()`
* `Cookie()`
* `Body()`
* `Form()`
* `File()`
* The new parameter fields are:
* `default_factory`
* `alias_priority`
* `validation_alias`
* `serialization_alias`
* `discriminator`
* `strict`
* `multiple_of`
* `allow_inf_nan`
* `max_digits`
* `decimal_places`
* `json_schema_extra`
...you can read about them in the Pydantic docs.
* The parameter `regex` has been deprecated and replaced by `pattern`.
* You can read more about it in the docs for [Query Parameters and String Validations: Add regular expressions](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#add-regular-expressions).
* New Pydantic models use an improved and simplified attribute `model_config` that takes a simple dict instead of an internal class `Config` for their configuration.
* You can read more about it in the docs for [Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/).
* The attribute `schema_extra` for the internal class `Config` has been replaced by the key `json_schema_extra` in the new `model_config` dict.
* You can read more about it in the docs for [Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/).
* When you install `"fastapi[all]"` it now also includes:
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - for settings management.
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - for extra types to be used with Pydantic.
* Now Pydantic Settings is an additional optional package (included in `"fastapi[all]"`). To use settings you should now import `from pydantic_settings import BaseSettings` instead of importing from `pydantic` directly.
* You can read more about it in the docs for [Settings and Environment Variables](https://fastapi.tiangolo.com/advanced/settings/).
* PR [#9816](https://github.com/tiangolo/fastapi/pull/9816) by [@tiangolo](https://github.com/tiangolo), included all the work done (in multiple PRs) on the beta branch (`main-pv2`).
## 0.99.1
### Fixes
* 🐛 Fix JSON Schema accepting bools as valid JSON Schemas, e.g. `additionalProperties: false`. PR [#9781](https://github.com/tiangolo/fastapi/pull/9781) by [@tiangolo](https://github.com/tiangolo).
### Docs
* 📝 Update source examples to use new JSON Schema examples field. PR [#9776](https://github.com/tiangolo/fastapi/pull/9776) by [@tiangolo](https://github.com/tiangolo).
## 0.99.0
### Features

View File

@@ -377,7 +377,7 @@ The `router` from `users` would overwrite the one from `items` and we wouldn't b
So, to be able to use both of them in the same file, we import the submodules directly:
```Python hl_lines="4"
```Python hl_lines="5"
{!../../../docs_src/bigger_applications/app/main.py!}
```

View File

@@ -277,7 +277,7 @@ You can also add a parameter `min_length`:
## Add regular expressions
You can define a <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings.">regular expression</abbr> that the parameter should match:
You can define a <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings.">regular expression</abbr> `pattern` that the parameter should match:
=== "Python 3.10+"
@@ -315,7 +315,7 @@ You can define a <abbr title="A regular expression, regex or regexp is a sequenc
{!> ../../../docs_src/query_params_str_validations/tutorial004.py!}
```
This specific regular expression checks that the received parameter value:
This specific regular expression pattern checks that the received parameter value:
* `^`: starts with the following characters, doesn't have characters before.
* `fixedquery`: has the exact value `fixedquery`.
@@ -325,6 +325,20 @@ If you feel lost with all these **"regular expression"** ideas, don't worry. The
But whenever you need them and go and learn them, know that you can already use them directly in **FastAPI**.
### Pydantic v1 `regex` instead of `pattern`
Before Pydantic version 2 and before FastAPI 0.100.0, the parameter was called `regex` instead of `pattern`, but it's now deprecated.
You could still see some code using it:
=== "Python 3.10+ Pydantic v1"
```Python hl_lines="11"
{!> ../../../docs_src/query_params_str_validations/tutorial004_an_py310_regex.py!}
```
But know that this is deprecated and it should be updated to use the new parameter `pattern`. 🤓
## Default values
You can, of course, use default values other than `None`.

View File

@@ -4,24 +4,48 @@ You can declare examples of the data your app can receive.
Here are several ways to do it.
## Pydantic `schema_extra`
## Extra JSON Schema data in Pydantic models
You can declare `examples` for a Pydantic model using `Config` and `schema_extra`, as described in <a href="https://pydantic-docs.helpmanual.io/usage/schema/#schema-customization" class="external-link" target="_blank">Pydantic's docs: Schema customization</a>:
You can declare `examples` for a Pydantic model that will be added to the generated JSON Schema.
=== "Python 3.10+"
=== "Python 3.10+ Pydantic v2"
```Python hl_lines="13-23"
```Python hl_lines="13-24"
{!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!}
```
=== "Python 3.6+"
=== "Python 3.10+ Pydantic v1"
```Python hl_lines="15-25"
```Python hl_lines="13-23"
{!> ../../../docs_src/schema_extra_example/tutorial001_py310_pv1.py!}
```
=== "Python 3.6+ Pydantic v2"
```Python hl_lines="15-26"
{!> ../../../docs_src/schema_extra_example/tutorial001.py!}
```
=== "Python 3.6+ Pydantic v1"
```Python hl_lines="15-25"
{!> ../../../docs_src/schema_extra_example/tutorial001_pv1.py!}
```
That extra info will be added as-is to the output **JSON Schema** for that model, and it will be used in the API docs.
=== "Pydantic v2"
In Pydantic version 2, you would use the attribute `model_config`, that takes a `dict` as described in <a href="https://docs.pydantic.dev/latest/usage/model_config/" class="external-link" target="_blank">Pydantic's docs: Model Config</a>.
You can set `"json_schema_extra"` with a `dict` containing any additonal data you would like to show up in the generated JSON Schema, including `examples`.
=== "Pydantic v1"
In Pydantic version 1, you would use an internal class `Config` and `schema_extra`, as described in <a href="https://docs.pydantic.dev/1.10/usage/schema/#schema-customization" class="external-link" target="_blank">Pydantic's docs: Schema customization</a>.
You can set `schema_extra` with a `dict` containing any additonal data you would like to show up in the generated JSON Schema, including `examples`.
!!! tip
You could use the same technique to extend the JSON Schema and add your own custom extra info.
@@ -50,7 +74,7 @@ When using `Field()` with Pydantic models, you can also declare additional `exam
{!> ../../../docs_src/schema_extra_example/tutorial002.py!}
```
## `examples` in OpenAPI
## `examples` in JSON Schema - OpenAPI
When using any of:
@@ -62,7 +86,7 @@ When using any of:
* `Form()`
* `File()`
you can also declare a group of `examples` with additional information that will be added to **OpenAPI**.
you can also declare a group of `examples` with additional information that will be added to their **JSON Schemas** inside of **OpenAPI**.
### `Body` with `examples`
@@ -116,19 +140,19 @@ You can of course also pass multiple `examples`:
=== "Python 3.10+"
```Python hl_lines="23-49"
```Python hl_lines="23-38"
{!> ../../../docs_src/schema_extra_example/tutorial004_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="23-49"
```Python hl_lines="23-38"
{!> ../../../docs_src/schema_extra_example/tutorial004_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="24-50"
```Python hl_lines="24-39"
{!> ../../../docs_src/schema_extra_example/tutorial004_an.py!}
```
@@ -137,7 +161,7 @@ You can of course also pass multiple `examples`:
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="19-45"
```Python hl_lines="19-34"
{!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!}
```
@@ -146,13 +170,88 @@ You can of course also pass multiple `examples`:
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="21-47"
```Python hl_lines="21-36"
{!> ../../../docs_src/schema_extra_example/tutorial004.py!}
```
### Examples in the docs UI
When you do this, the examples will be part of the internal **JSON Schema** for that body data.
With `examples` added to `Body()` the `/docs` would look like:
Nevertheless, at the <abbr title="2023-08-26">time of writing this</abbr>, Swagger UI, the tool in charge of showing the docs UI, doesn't support showing multiple examples for the data in **JSON Schema**. But read below for a workaround.
### OpenAPI-specific `examples`
Since before **JSON Schema** supported `examples` OpenAPI had support for a different field also called `examples`.
This **OpenAPI-specific** `examples` goes in another section in the OpenAPI specification. It goes in the **details for each *path operation***, not inside each JSON Schema.
And Swagger UI has supported this particular `examples` field for a while. So, you can use it to **show** different **examples in the docs UI**.
The shape of this OpenAPI-specific field `examples` is a `dict` with **multiple examples** (instead of a `list`), each with extra information that will be added to **OpenAPI** too.
This doesn't go inside of each JSON Schema contained in OpenAPI, this goes outside, in the *path operation* directly.
### Using the `openapi_examples` Parameter
You can declare the OpenAPI-specific `examples` in FastAPI with the parameter `openapi_examples` for:
* `Path()`
* `Query()`
* `Header()`
* `Cookie()`
* `Body()`
* `Form()`
* `File()`
The keys of the `dict` identify each example, and each value is another `dict`.
Each specific example `dict` in the `examples` can contain:
* `summary`: Short description for the example.
* `description`: A long description that can contain Markdown text.
* `value`: This is the actual example shown, e.g. a `dict`.
* `externalValue`: alternative to `value`, a URL pointing to the example. Although this might not be supported by as many tools as `value`.
You can use it like this:
=== "Python 3.10+"
```Python hl_lines="23-49"
{!> ../../../docs_src/schema_extra_example/tutorial005_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="23-49"
{!> ../../../docs_src/schema_extra_example/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="24-50"
{!> ../../../docs_src/schema_extra_example/tutorial005_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="19-45"
{!> ../../../docs_src/schema_extra_example/tutorial005_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="21-47"
{!> ../../../docs_src/schema_extra_example/tutorial005.py!}
```
### OpenAPI Examples in the Docs UI
With `openapi_examples` added to `Body()` the `/docs` would look like:
<img src="/img/tutorial/body-fields/image02.png">
@@ -186,20 +285,8 @@ OpenAPI also added `example` and `examples` fields to other parts of the specifi
* `File()`
* `Form()`
### OpenAPI's `examples` field
The shape of this field `examples` from OpenAPI is a `dict` with **multiple examples**, each with extra information that will be added to **OpenAPI** too.
The keys of the `dict` identify each example, and each value is another `dict`.
Each specific example `dict` in the `examples` can contain:
* `summary`: Short description for the example.
* `description`: A long description that can contain Markdown text.
* `value`: This is the actual example shown, e.g. a `dict`.
* `externalValue`: alternative to `value`, a URL pointing to the example. Although this might not be supported by as many tools as `value`.
This applies to those other parts of the OpenAPI specification apart from JSON Schema.
!!! info
This old OpenAPI-specific `examples` parameter is now `openapi_examples` since FastAPI `0.103.0`.
### JSON Schema's `examples` field
@@ -226,6 +313,12 @@ In versions of FastAPI before 0.99.0 (0.99.0 and above use the newer OpenAPI 3.1
But now that FastAPI 0.99.0 and above uses OpenAPI 3.1.0, that uses JSON Schema 2020-12, and Swagger UI 5.0.0 and above, everything is more consistent and the examples are included in JSON Schema.
### Swagger UI and OpenAPI-specific `examples`
Now, as Swagger UI didn't support multiple JSON Schema examples (as of 2023-08-26), users didn't have a way to show multiple examples in the docs.
To solve that, FastAPI `0.103.0` **added support** for declaring the same old **OpenAPI-specific** `examples` field with the new parameter `openapi_examples`. 🤓
### Summary
I used to say I didn't like history that much... and look at me now giving "tech history" lessons. 😅

View File

@@ -1,5 +1,12 @@
# SQL (Relational) Databases
!!! info
These docs are about to be updated. 🎉
The current version assumes Pydantic v1, and SQLAlchemy versions less than 2.0.
The new docs will include Pydantic v2 and will use <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel</a> (which is also based on SQLAlchemy) once it is updated to use Pydantic v2 as well.
**FastAPI** doesn't require you to use a SQL (relational) database.
But you can use any relational database that you want.

View File

@@ -42,6 +42,16 @@ plugins:
search: null
markdownextradata:
data: ../en/data
redirects:
redirect_maps:
deployment/deta.md: deployment/cloud.md
advanced/sql-databases-peewee.md: how-to/sql-databases-peewee.md
advanced/async-sql-databases.md: how-to/async-sql-encode-databases.md
advanced/nosql-databases.md: how-to/nosql-databases-couchbase.md
advanced/graphql.md: how-to/graphql.md
advanced/custom-request-and-route.md: how-to/custom-request-and-route.md
advanced/conditional-openapi.md: how-to/conditional-openapi.md
advanced/extending-openapi.md: how-to/extending-openapi.md
nav:
- FastAPI: index.md
- Languages:
@@ -59,6 +69,9 @@ nav:
- pt: /pt/
- ru: /ru/
- tr: /tr/
- uk: /uk/
- ur: /ur/
- vi: /vi/
- zh: /zh/
- features.md
- fastapi-people.md
@@ -128,24 +141,17 @@ nav:
- advanced/using-request-directly.md
- advanced/dataclasses.md
- advanced/middleware.md
- advanced/sql-databases-peewee.md
- advanced/async-sql-databases.md
- advanced/nosql-databases.md
- advanced/sub-applications.md
- advanced/behind-a-proxy.md
- advanced/templates.md
- advanced/graphql.md
- advanced/websockets.md
- advanced/events.md
- advanced/custom-request-and-route.md
- advanced/testing-websockets.md
- advanced/testing-events.md
- advanced/testing-dependencies.md
- advanced/testing-database.md
- advanced/async-tests.md
- advanced/settings.md
- advanced/conditional-openapi.md
- advanced/extending-openapi.md
- advanced/openapi-callbacks.md
- advanced/openapi-webhooks.md
- advanced/wsgi.md
@@ -157,9 +163,22 @@ nav:
- deployment/https.md
- deployment/manually.md
- deployment/concepts.md
- deployment/deta.md
- deployment/cloud.md
- deployment/server-workers.md
- deployment/docker.md
- How To - Recipes:
- how-to/index.md
- how-to/general.md
- how-to/sql-databases-peewee.md
- how-to/async-sql-encode-databases.md
- how-to/nosql-databases-couchbase.md
- how-to/graphql.md
- how-to/custom-request-and-route.md
- how-to/conditional-openapi.md
- how-to/extending-openapi.md
- how-to/separate-openapi-schemas.md
- how-to/custom-docs-ui-assets.md
- how-to/configure-swagger-ui.md
- project-generation.md
- alternatives.md
- history-design-future.md
@@ -176,9 +195,9 @@ markdown_extensions:
guess_lang: false
mdx_include:
base_path: docs
admonition:
codehilite:
extra:
admonition: null
codehilite: null
extra: null
pymdownx.superfences:
custom_fences:
- name: mermaid
@@ -186,8 +205,8 @@ markdown_extensions:
format: !!python/name:pymdownx.superfences.fence_code_format ''
pymdownx.tabbed:
alternate_style: true
attr_list:
md_in_html:
attr_list: null
md_in_html: null
extra:
analytics:
provider: google
@@ -236,6 +255,12 @@ extra:
name: ru - русский язык
- link: /tr/
name: tr - Türkçe
- link: /uk/
name: uk
- link: /ur/
name: ur
- link: /vi/
name: vi - Tiếng Việt
- link: /zh/
name: zh - 汉语
extra_css:

View File

@@ -34,6 +34,18 @@
<img class="sponsor-image" src="/img/sponsors/platform-sh-banner.png" />
</a>
</div>
<div class="item">
<a title="Fern | SDKs and API docs" style="display: block; position: relative;" href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=top-banner" target="_blank">
<span class="sponsor-badge">sponsor</span>
<img class="sponsor-image" src="/img/sponsors/fern-banner.svg" />
</a>
</div>
<div class="item">
<a title="Deploy FastAPI on AWS with a few clicks" style="display: block; position: relative;" href="https://www.porter.run" target="_blank">
<span class="sponsor-badge">sponsor</span>
<img class="sponsor-image" src="/img/sponsors/porter-banner.png" />
</a>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,34 @@
# Test de performance
Les tests de performance de TechEmpower montrent que les applications **FastAPI** tournant sous Uvicorn comme <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">étant l'un des frameworks Python les plus rapides disponibles</a>, seulement inférieur à Starlette et Uvicorn (tous deux utilisés au cœur de FastAPI). (*)
Mais en prêtant attention aux tests de performance et aux comparaisons, il faut tenir compte de ce qu'il suit.
## Tests de performance et rapidité
Lorsque vous vérifiez les tests de performance, il est commun de voir plusieurs outils de différents types comparés comme équivalents.
En particulier, on voit Uvicorn, Starlette et FastAPI comparés (parmi de nombreux autres outils).
Plus le problème résolu par un outil est simple, mieux seront les performances obtenues. Et la plupart des tests de performance ne prennent pas en compte les fonctionnalités additionnelles fournies par les outils.
La hiérarchie est la suivante :
* **Uvicorn** : un serveur ASGI
* **Starlette** : (utilise Uvicorn) un micro-framework web
* **FastAPI**: (utilise Starlette) un micro-framework pour API disposant de fonctionnalités additionnelles pour la création d'API, avec la validation des données, etc.
* **Uvicorn** :
* A les meilleures performances, étant donné qu'il n'a pas beaucoup de code mis-à-part le serveur en lui-même.
* On n'écrit pas une application avec uniquement Uvicorn. Cela signifie que le code devrait inclure plus ou moins, au minimum, tout le code offert par Starlette (ou **FastAPI**). Et si on fait cela, l'application finale apportera les mêmes complications que si on avait utilisé un framework et que l'on avait minimisé la quantité de code et de bugs.
* Si on compare Uvicorn, il faut le comparer à d'autre applications de serveurs comme Daphne, Hypercorn, uWSGI, etc.
* **Starlette** :
* A les seconde meilleures performances après Uvicorn. Starlette utilise en réalité Uvicorn. De ce fait, il ne peut quêtre plus "lent" qu'Uvicorn car il requiert l'exécution de plus de code.
* Cependant il nous apporte les outils pour construire une application web simple, avec un routage basé sur des chemins, etc.
* Si on compare Starlette, il faut le comparer à d'autres frameworks web (ou micorframework) comme Sanic, Flask, Django, etc.
* **FastAPI** :
* Comme Starlette, FastAPI utilise Uvicorn et ne peut donc pas être plus rapide que ce dernier.
* FastAPI apporte des fonctionnalités supplémentaires à Starlette. Des fonctionnalités qui sont nécessaires presque systématiquement lors de la création d'une API, comme la validation des données, la sérialisation. En utilisant FastAPI, on obtient une documentation automatiquement (qui ne requiert aucune manipulation pour être mise en place).
* Si on n'utilisait pas FastAPI mais directement Starlette (ou un outil équivalent comme Sanic, Flask, Responder, etc) il faudrait implémenter la validation des données et la sérialisation par nous-même. Le résultat serait donc le même dans les deux cas mais du travail supplémentaire serait à réaliser avec Starlette, surtout en considérant que la validation des données et la sérialisation représentent la plus grande quantité de code à écrire dans une application.
* De ce fait, en utilisant FastAPI on minimise le temps de développement, les bugs, le nombre de lignes de code, et on obtient les mêmes performances (si ce n'est de meilleurs performances) que l'on aurait pu avoir sans ce framework (en ayant à implémenter de nombreuses fonctionnalités importantes par nous-mêmes).
* Si on compare FastAPI, il faut le comparer à d'autres frameworks web (ou ensemble d'outils) qui fournissent la validation des données, la sérialisation et la documentation, comme Flask-apispec, NestJS, Molten, etc.

View File

@@ -0,0 +1,501 @@
# Développement - Contribuer
Tout d'abord, vous voudrez peut-être voir les moyens de base pour [aider FastAPI et obtenir de l'aide](help-fastapi.md){.internal-link target=_blank}.
## Développement
Si vous avez déjà cloné le dépôt et que vous savez que vous devez vous plonger dans le code, voici quelques directives pour mettre en place votre environnement.
### Environnement virtuel avec `venv`
Vous pouvez créer un environnement virtuel dans un répertoire en utilisant le module `venv` de Python :
<div class="termy">
```console
$ python -m venv env
```
</div>
Cela va créer un répertoire `./env/` avec les binaires Python et vous pourrez alors installer des paquets pour cet environnement isolé.
### Activer l'environnement
Activez le nouvel environnement avec :
=== "Linux, macOS"
<div class="termy">
```console
$ source ./env/bin/activate
```
</div>
=== "Windows PowerShell"
<div class="termy">
```console
$ .\env\Scripts\Activate.ps1
```
</div>
=== "Windows Bash"
Ou si vous utilisez Bash pour Windows (par exemple <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
<div class="termy">
```console
$ source ./env/Scripts/activate
```
</div>
Pour vérifier que cela a fonctionné, utilisez :
=== "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>
Si celui-ci montre le binaire `pip` à `env/bin/pip`, alors ça a fonctionné. 🎉
!!! tip
Chaque fois que vous installez un nouveau paquet avec `pip` sous cet environnement, activez à nouveau l'environnement.
Cela permet de s'assurer que si vous utilisez un programme terminal installé par ce paquet (comme `flit`), vous utilisez celui de votre environnement local et pas un autre qui pourrait être installé globalement.
### Flit
**FastAPI** utilise <a href="https://flit.readthedocs.io/en/latest/index.html" class="external-link" target="_blank">Flit</a> pour build, packager et publier le projet.
Après avoir activé l'environnement comme décrit ci-dessus, installez `flit` :
<div class="termy">
```console
$ pip install flit
---> 100%
```
</div>
Réactivez maintenant l'environnement pour vous assurer que vous utilisez le "flit" que vous venez d'installer (et non un environnement global).
Et maintenant, utilisez `flit` pour installer les dépendances de développement :
=== "Linux, macOS"
<div class="termy">
```console
$ flit install --deps develop --symlink
---> 100%
```
</div>
=== "Windows"
Si vous êtes sous Windows, utilisez `--pth-file` au lieu de `--symlink` :
<div class="termy">
```console
$ flit install --deps develop --pth-file
---> 100%
```
</div>
Il installera toutes les dépendances et votre FastAPI local dans votre environnement local.
#### Utiliser votre FastAPI local
Si vous créez un fichier Python qui importe et utilise FastAPI, et que vous l'exécutez avec le Python de votre environnement local, il utilisera votre code source FastAPI local.
Et si vous mettez à jour le code source local de FastAPI, tel qu'il est installé avec `--symlink` (ou `--pth-file` sous Windows), lorsque vous exécutez à nouveau ce fichier Python, il utilisera la nouvelle version de FastAPI que vous venez d'éditer.
De cette façon, vous n'avez pas à "installer" votre version locale pour pouvoir tester chaque changement.
### Formatage
Il existe un script que vous pouvez exécuter qui formatera et nettoiera tout votre code :
<div class="termy">
```console
$ bash scripts/format.sh
```
</div>
Il effectuera également un tri automatique de touts vos imports.
Pour qu'il puisse les trier correctement, vous devez avoir FastAPI installé localement dans votre environnement, avec la commande dans la section ci-dessus en utilisant `--symlink` (ou `--pth-file` sous Windows).
### Formatage des imports
Il existe un autre script qui permet de formater touts les imports et de s'assurer que vous n'avez pas d'imports inutilisés :
<div class="termy">
```console
$ bash scripts/format-imports.sh
```
</div>
Comme il exécute une commande après l'autre et modifie et inverse de nombreux fichiers, il prend un peu plus de temps à s'exécuter, il pourrait donc être plus facile d'utiliser fréquemment `scripts/format.sh` et `scripts/format-imports.sh` seulement avant de commit.
## Documentation
Tout d'abord, assurez-vous que vous configurez votre environnement comme décrit ci-dessus, qui installera toutes les exigences.
La documentation utilise <a href="https://www.mkdocs.org/" class="external-link" target="_blank">MkDocs</a>.
Et il y a des outils/scripts supplémentaires en place pour gérer les traductions dans `./scripts/docs.py`.
!!! tip
Vous n'avez pas besoin de voir le code dans `./scripts/docs.py`, vous l'utilisez simplement dans la ligne de commande.
Toute la documentation est au format Markdown dans le répertoire `./docs/fr/`.
De nombreux tutoriels comportent des blocs de code.
Dans la plupart des cas, ces blocs de code sont de véritables applications complètes qui peuvent être exécutées telles quelles.
En fait, ces blocs de code ne sont pas écrits à l'intérieur du Markdown, ce sont des fichiers Python dans le répertoire `./docs_src/`.
Et ces fichiers Python sont inclus/injectés dans la documentation lors de la génération du site.
### Documentation pour les tests
La plupart des tests sont en fait effectués par rapport aux exemples de fichiers sources dans la documentation.
Cela permet de s'assurer que :
* La documentation est à jour.
* Les exemples de documentation peuvent être exécutés tels quels.
* La plupart des fonctionnalités sont couvertes par la documentation, assurées par la couverture des tests.
Au cours du développement local, un script build le site et vérifie les changements éventuels, puis il est rechargé en direct :
<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>
Il servira la documentation sur `http://127.0.0.1:8008`.
De cette façon, vous pouvez modifier la documentation/les fichiers sources et voir les changements en direct.
#### Typer CLI (facultatif)
Les instructions ici vous montrent comment utiliser le script à `./scripts/docs.py` avec le programme `python` directement.
Mais vous pouvez également utiliser <a href="https://typer.tiangolo.com/typer-cli/" class="external-link" target="_blank">Typer CLI</a>, et vous obtiendrez l'auto-complétion dans votre terminal pour les commandes après l'achèvement de l'installation.
Si vous installez Typer CLI, vous pouvez installer la complétion avec :
<div class="termy">
```console
$ typer --install-completion
zsh completion installed in /home/user/.bashrc.
Completion will take effect once you restart the terminal.
```
</div>
### Apps et documentation en même temps
Si vous exécutez les exemples avec, par exemple :
<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>
Comme Uvicorn utilisera par défaut le port `8000`, la documentation sur le port `8008` n'entrera pas en conflit.
### Traductions
L'aide aux traductions est TRÈS appréciée ! Et cela ne peut se faire sans l'aide de la communauté. 🌎 🚀
Voici les étapes à suivre pour aider à la traduction.
#### Conseils et lignes directrices
* Vérifiez les <a href="https://github.com/tiangolo/fastapi/pulls" class="external-link" target="_blank">pull requests existantes</a> pour votre langue et ajouter des reviews demandant des changements ou les approuvant.
!!! tip
Vous pouvez <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/commenting-on-a-pull-request" class="external-link" target="_blank">ajouter des commentaires avec des suggestions de changement</a> aux pull requests existantes.
Consultez les documents concernant <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-reviews" class="external-link" target="_blank">l'ajout d'un review de pull request</a> pour l'approuver ou demander des modifications.
* Vérifiez dans <a href="https://github.com/tiangolo/fastapi/issues" class="external-link" target="_blank">issues</a> pour voir s'il y a une personne qui coordonne les traductions pour votre langue.
* Ajoutez une seule pull request par page traduite. Il sera ainsi beaucoup plus facile pour les autres de l'examiner.
Pour les langues que je ne parle pas, je vais attendre plusieurs autres reviews de la traduction avant de merge.
* Vous pouvez également vérifier s'il existe des traductions pour votre langue et y ajouter une review, ce qui m'aidera à savoir si la traduction est correcte et je pourrai la fusionner.
* Utilisez les mêmes exemples en Python et ne traduisez que le texte des documents. Vous n'avez pas besoin de changer quoi que ce soit pour que cela fonctionne.
* Utilisez les mêmes images, noms de fichiers et liens. Vous n'avez pas besoin de changer quoi que ce soit pour que cela fonctionne.
* Pour vérifier le code à 2 lettres de la langue que vous souhaitez traduire, vous pouvez utiliser le tableau <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes" class="external-link" target="_blank">Liste des codes ISO 639-1</a>.
#### Langue existante
Disons que vous voulez traduire une page pour une langue qui a déjà des traductions pour certaines pages, comme l'espagnol.
Dans le cas de l'espagnol, le code à deux lettres est `es`. Ainsi, le répertoire des traductions espagnoles se trouve à l'adresse `docs/es/`.
!!! tip
La langue principale ("officielle") est l'anglais, qui se trouve à l'adresse "docs/en/".
Maintenant, lancez le serveur en live pour les documents en espagnol :
<div class="termy">
```console
// Use the command "live" and pass the language code as a CLI argument
$ 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>
Vous pouvez maintenant aller sur <a href="http://127.0.0.1:8008" class="external-link" target="_blank">http://127.0.0.1:8008</a> et voir vos changements en direct.
Si vous regardez le site web FastAPI docs, vous verrez que chaque langue a toutes les pages. Mais certaines pages ne sont pas traduites et sont accompagnées d'une notification concernant la traduction manquante.
Mais si vous le gérez localement de cette manière, vous ne verrez que les pages déjà traduites.
Disons maintenant que vous voulez ajouter une traduction pour la section [Features](features.md){.internal-link target=_blank}.
* Copiez le fichier à :
```
docs/en/docs/features.md
```
* Collez-le exactement au même endroit mais pour la langue que vous voulez traduire, par exemple :
```
docs/es/docs/features.md
```
!!! tip
Notez que le seul changement dans le chemin et le nom du fichier est le code de langue, qui passe de `en` à `es`.
* Ouvrez maintenant le fichier de configuration de MkDocs pour l'anglais à
```
docs/en/docs/mkdocs.yml
```
* Trouvez l'endroit où cette `docs/features.md` se trouve dans le fichier de configuration. Quelque part comme :
```YAML hl_lines="8"
site_name: FastAPI
# More stuff
nav:
- FastAPI: index.md
- Languages:
- en: /
- es: /es/
- features.md
```
* Ouvrez le fichier de configuration MkDocs pour la langue que vous éditez, par exemple :
```
docs/es/docs/mkdocs.yml
```
* Ajoutez-le à l'endroit exact où il se trouvait pour l'anglais, par exemple :
```YAML hl_lines="8"
site_name: FastAPI
# More stuff
nav:
- FastAPI: index.md
- Languages:
- en: /
- es: /es/
- features.md
```
Assurez-vous que s'il y a d'autres entrées, la nouvelle entrée avec votre traduction est exactement dans le même ordre que dans la version anglaise.
Si vous allez sur votre navigateur, vous verrez que maintenant les documents montrent votre nouvelle section. 🎉
Vous pouvez maintenant tout traduire et voir à quoi cela ressemble au fur et à mesure que vous enregistrez le fichier.
#### Nouvelle langue
Disons que vous voulez ajouter des traductions pour une langue qui n'est pas encore traduite, pas même quelques pages.
Disons que vous voulez ajouter des traductions pour le Créole, et que ce n'est pas encore dans les documents.
En vérifiant le lien ci-dessus, le code pour "Créole" est `ht`.
L'étape suivante consiste à exécuter le script pour générer un nouveau répertoire de traduction :
<div class="termy">
```console
// Use the command new-lang, pass the language code as a CLI argument
$ python ./scripts/docs.py new-lang ht
Successfully initialized: docs/ht
Updating ht
Updating en
```
</div>
Vous pouvez maintenant vérifier dans votre éditeur de code le répertoire nouvellement créé `docs/ht/`.
!!! tip
Créez une première demande d'extraction à l'aide de cette fonction, afin de configurer la nouvelle langue avant d'ajouter des traductions.
Ainsi, d'autres personnes peuvent vous aider à rédiger d'autres pages pendant que vous travaillez sur la première. 🚀
Commencez par traduire la page principale, `docs/ht/index.md`.
Vous pouvez ensuite continuer avec les instructions précédentes, pour une "langue existante".
##### Nouvelle langue non prise en charge
Si, lors de l'exécution du script du serveur en direct, vous obtenez une erreur indiquant que la langue n'est pas prise en charge, quelque chose comme :
```
raise TemplateNotFound(template)
jinja2.exceptions.TemplateNotFound: partials/language/xx.html
```
Cela signifie que le thème ne supporte pas cette langue (dans ce cas, avec un faux code de 2 lettres de `xx`).
Mais ne vous inquiétez pas, vous pouvez définir la langue du thème en anglais et ensuite traduire le contenu des documents.
Si vous avez besoin de faire cela, modifiez le fichier `mkdocs.yml` pour votre nouvelle langue, il aura quelque chose comme :
```YAML hl_lines="5"
site_name: FastAPI
# More stuff
theme:
# More stuff
language: xx
```
Changez cette langue de `xx` (de votre code de langue) à `fr`.
Vous pouvez ensuite relancer le serveur live.
#### Prévisualisez le résultat
Lorsque vous utilisez le script à `./scripts/docs.py` avec la commande `live`, il n'affiche que les fichiers et les traductions disponibles pour la langue courante.
Mais une fois que vous avez terminé, vous pouvez tester le tout comme il le ferait en ligne.
Pour ce faire, il faut d'abord construire tous les documents :
<div class="termy">
```console
// Use the command "build-all", this will take a bit
$ 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>
Cela génère tous les documents à `./docs_build/` pour chaque langue. Cela inclut l'ajout de tout fichier dont la traduction est manquante, avec une note disant que "ce fichier n'a pas encore de traduction". Mais vous n'avez rien à faire avec ce répertoire.
Ensuite, il construit tous ces sites MkDocs indépendants pour chaque langue, les combine, et génère le résultat final à `./site/`.
Ensuite, vous pouvez servir cela avec le commandement `serve`:
<div class="termy">
```console
// Use the command "serve" after running "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>
## Tests
Il existe un script que vous pouvez exécuter localement pour tester tout le code et générer des rapports de couverture en HTML :
<div class="termy">
```console
$ bash scripts/test-cov-html.sh
```
</div>
Cette commande génère un répertoire `./htmlcov/`, si vous ouvrez le fichier `./htmlcov/index.html` dans votre navigateur, vous pouvez explorer interactivement les régions de code qui sont couvertes par les tests, et remarquer s'il y a une région manquante.

View File

@@ -1,245 +0,0 @@
# Déployer FastAPI sur Deta
Dans cette section, vous apprendrez à déployer facilement une application **FastAPI** sur <a href="https://www.deta.
sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> en utilisant le plan tarifaire gratuit. 🎁
Cela vous prendra environ **10 minutes**.
!!! info
<a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> sponsorise **FastAPI**. 🎉
## Une application **FastAPI** de base
* Créez un répertoire pour votre application, par exemple `./fastapideta/` et déplacez-vous dedans.
### Le code FastAPI
* Créer un fichier `main.py` avec :
```Python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}
```
### Dépendances
Maintenant, dans le même répertoire, créez un fichier `requirements.txt` avec :
```text
fastapi
```
!!! tip "Astuce"
Il n'est pas nécessaire d'installer Uvicorn pour déployer sur Deta, bien qu'il soit probablement souhaitable de l'installer localement pour tester votre application.
### Structure du répertoire
Vous aurez maintenant un répertoire `./fastapideta/` avec deux fichiers :
```
.
└── main.py
└── requirements.txt
```
## Créer un compte gratuit sur Deta
Créez maintenant un <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">compte gratuit
sur Deta</a>, vous avez juste besoin d'une adresse email et d'un mot de passe.
Vous n'avez même pas besoin d'une carte de crédit.
## Installer le CLI (Interface en Ligne de Commande)
Une fois que vous avez votre compte, installez le <abbr title="Command Line Interface application">CLI</abbr> de Deta :
=== "Linux, macOS"
<div class="termy">
```console
$ curl -fsSL https://get.deta.dev/cli.sh | sh
```
</div>
=== "Windows PowerShell"
<div class="termy">
```console
$ iwr https://get.deta.dev/cli.ps1 -useb | iex
```
</div>
Après l'avoir installé, ouvrez un nouveau terminal afin que la nouvelle installation soit détectée.
Dans un nouveau terminal, confirmez qu'il a été correctement installé avec :
<div class="termy">
```console
$ deta --help
Deta command line interface for managing deta micros.
Complete documentation available at https://docs.deta.sh
Usage:
deta [flags]
deta [command]
Available Commands:
auth Change auth settings for a deta micro
...
```
</div>
!!! tip "Astuce"
Si vous rencontrez des problèmes pour installer le CLI, consultez la <a href="https://docs.deta. sh/docs/micros/getting_started?ref=fastapi" class="external-link" target="_blank">documentation officielle de Deta (en anglais)</a>.
## Connexion avec le CLI
Maintenant, connectez-vous à Deta depuis le CLI avec :
<div class="termy">
```console
$ deta login
Please, log in from the web page. Waiting..
Logged in successfully.
```
</div>
Cela ouvrira un navigateur web et permettra une authentification automatique.
## Déployer avec Deta
Ensuite, déployez votre application avec le CLI de Deta :
<div class="termy">
```console
$ deta new
Successfully created a new micro
// Notice the "endpoint" 🔍
{
"name": "fastapideta",
"runtime": "python3.7",
"endpoint": "https://qltnci.deta.dev",
"visor": "enabled",
"http_auth": "enabled"
}
Adding dependencies...
---> 100%
Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6
```
</div>
Vous verrez un message JSON similaire à :
```JSON hl_lines="4"
{
"name": "fastapideta",
"runtime": "python3.7",
"endpoint": "https://qltnci.deta.dev",
"visor": "enabled",
"http_auth": "enabled"
}
```
!!! tip "Astuce"
Votre déploiement aura une URL `"endpoint"` différente.
## Vérifiez
Maintenant, dans votre navigateur ouvrez votre URL `endpoint`. Dans l'exemple ci-dessus, c'était
`https://qltnci.deta.dev`, mais la vôtre sera différente.
Vous verrez la réponse JSON de votre application FastAPI :
```JSON
{
"Hello": "World"
}
```
Et maintenant naviguez vers `/docs` dans votre API, dans l'exemple ci-dessus ce serait `https://qltnci.deta.dev/docs`.
Vous verrez votre documentation comme suit :
<img src="/img/deployment/deta/image01.png">
## Activer l'accès public
Par défaut, Deta va gérer l'authentification en utilisant des cookies pour votre compte.
Mais une fois que vous êtes prêt, vous pouvez le rendre public avec :
<div class="termy">
```console
$ deta auth disable
Successfully disabled http auth
```
</div>
Maintenant, vous pouvez partager cette URL avec n'importe qui et ils seront en mesure d'accéder à votre API. 🚀
## HTTPS
Félicitations! Vous avez déployé votre application FastAPI sur Deta! 🎉 🍰
Remarquez également que Deta gère correctement HTTPS pour vous, vous n'avez donc pas à vous en occuper et pouvez être sûr que vos clients auront une connexion cryptée sécurisée. ✅ 🔒
## Vérifiez le Visor
À partir de l'interface graphique de votre documentation (dans une URL telle que `https://qltnci.deta.dev/docs`)
envoyez une requête à votre *opération de chemin* `/items/{item_id}`.
Par exemple avec l'ID `5`.
Allez maintenant sur <a href="https://web.deta.sh/" class="external-link" target="_blank">https://web.deta.sh</a>.
Vous verrez qu'il y a une section à gauche appelée <abbr title="ça vient de Micro(server)">"Micros"</abbr> avec chacune de vos applications.
Vous verrez un onglet avec "Details", et aussi un onglet "Visor", allez à l'onglet "Visor".
Vous pouvez y consulter les requêtes récentes envoyées à votre application.
Vous pouvez également les modifier et les relancer.
<img src="/img/deployment/deta/image02.png">
## En savoir plus
À un moment donné, vous voudrez probablement stocker certaines données pour votre application d'une manière qui
persiste dans le temps. Pour cela, vous pouvez utiliser <a href="https://docs.deta.sh/docs/base/py_tutorial?ref=fastapi" class="external-link" target="_blank">Deta Base</a>, il dispose également d'un généreux **plan gratuit**.
Vous pouvez également en lire plus dans la <a href="https://docs.deta.sh?ref=fastapi" class="external-link" target="_blank">documentation Deta</a>.

View File

@@ -0,0 +1,80 @@
# Tutoriel - Guide utilisateur - Introduction
Ce tutoriel vous montre comment utiliser **FastAPI** avec la plupart de ses fonctionnalités, étape par étape.
Chaque section s'appuie progressivement sur les précédentes, mais elle est structurée de manière à séparer les sujets, afin que vous puissiez aller directement à l'un d'entre eux pour résoudre vos besoins spécifiques en matière d'API.
Il est également conçu pour fonctionner comme une référence future.
Vous pouvez donc revenir et voir exactement ce dont vous avez besoin.
## Exécuter le code
Tous les blocs de code peuvent être copiés et utilisés directement (il s'agit en fait de fichiers Python testés).
Pour exécuter l'un de ces exemples, copiez le code dans un fichier `main.py`, et commencez `uvicorn` avec :
<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>
Il est **FORTEMENT encouragé** que vous écriviez ou copiez le code, l'éditiez et l'exécutiez localement.
L'utiliser dans votre éditeur est ce qui vous montre vraiment les avantages de FastAPI, en voyant le peu de code que vous avez à écrire, toutes les vérifications de type, l'autocomplétion, etc.
---
## Installer FastAPI
La première étape consiste à installer FastAPI.
Pour le tutoriel, vous voudrez peut-être l'installer avec toutes les dépendances et fonctionnalités optionnelles :
<div class="termy">
```console
$ pip install fastapi[all]
---> 100%
```
</div>
... qui comprend également `uvicorn`, que vous pouvez utiliser comme serveur pour exécuter votre code.
!!! note
Vous pouvez également l'installer pièce par pièce.
C'est ce que vous feriez probablement une fois que vous voudrez déployer votre application en production :
```
pip install fastapi
```
Installez également `uvicorn` pour qu'il fonctionne comme serveur :
```
pip install uvicorn
```
Et la même chose pour chacune des dépendances facultatives que vous voulez utiliser.
## Guide utilisateur avancé
Il existe également un **Guide d'utilisation avancé** que vous pouvez lire plus tard après ce **Tutoriel - Guide d'utilisation**.
Le **Guide d'utilisation avancé**, qui s'appuie sur cette base, utilise les mêmes concepts et vous apprend quelques fonctionnalités supplémentaires.
Mais vous devez d'abord lire le **Tutoriel - Guide d'utilisation** (ce que vous êtes en train de lire en ce moment).
Il est conçu pour que vous puissiez construire une application complète avec seulement le **Tutoriel - Guide d'utilisation**, puis l'étendre de différentes manières, en fonction de vos besoins, en utilisant certaines des idées supplémentaires du **Guide d'utilisation avancé**.

View File

@@ -0,0 +1,305 @@
# Paramètres de requête et validations de chaînes de caractères
**FastAPI** vous permet de déclarer des informations et des validateurs additionnels pour vos paramètres de requêtes.
Commençons avec cette application pour exemple :
```Python hl_lines="9"
{!../../../docs_src/query_params_str_validations/tutorial001.py!}
```
Le paramètre de requête `q` a pour type `Union[str, None]` (ou `str | None` en Python 3.10), signifiant qu'il est de type `str` mais pourrait aussi être égal à `None`, et bien sûr, la valeur par défaut est `None`, donc **FastAPI** saura qu'il n'est pas requis.
!!! note
**FastAPI** saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `= None`.
Le `Union` dans `Union[str, None]` permettra à votre éditeur de vous offrir un meilleur support et de détecter les erreurs.
## Validation additionnelle
Nous allons imposer que bien que `q` soit un paramètre optionnel, dès qu'il est fourni, **sa longueur n'excède pas 50 caractères**.
## Importer `Query`
Pour cela, importez d'abord `Query` depuis `fastapi` :
```Python hl_lines="3"
{!../../../docs_src/query_params_str_validations/tutorial002.py!}
```
## Utiliser `Query` comme valeur par défaut
Construisez ensuite la valeur par défaut de votre paramètre avec `Query`, en choisissant 50 comme `max_length` :
```Python hl_lines="9"
{!../../../docs_src/query_params_str_validations/tutorial002.py!}
```
Comme nous devons remplacer la valeur par défaut `None` dans la fonction par `Query()`, nous pouvons maintenant définir la valeur par défaut avec le paramètre `Query(default=None)`, il sert le même objectif qui est de définir cette valeur par défaut.
Donc :
```Python
q: Union[str, None] = Query(default=None)
```
... rend le paramètre optionnel, et est donc équivalent à :
```Python
q: Union[str, None] = None
```
Mais déclare explicitement `q` comme étant un paramètre de requête.
!!! info
Gardez à l'esprit que la partie la plus importante pour rendre un paramètre optionnel est :
```Python
= None
```
ou :
```Python
= Query(None)
```
et utilisera ce `None` pour détecter que ce paramètre de requête **n'est pas requis**.
Le `Union[str, None]` est uniquement là pour permettre à votre éditeur un meilleur support.
Ensuite, nous pouvons passer d'autres paramètres à `Query`. Dans cet exemple, le paramètre `max_length` qui s'applique aux chaînes de caractères :
```Python
q: Union[str, None] = Query(default=None, max_length=50)
```
Cela va valider les données, montrer une erreur claire si ces dernières ne sont pas valides, et documenter le paramètre dans le schéma `OpenAPI` de cette *path operation*.
## Rajouter plus de validation
Vous pouvez aussi rajouter un second paramètre `min_length` :
```Python hl_lines="9"
{!../../../docs_src/query_params_str_validations/tutorial003.py!}
```
## Ajouter des validations par expressions régulières
On peut définir une <abbr title="Une expression régulière, regex ou regexp est une suite de caractères qui définit un pattern de correspondance pour les chaînes de caractères.">expression régulière</abbr> à laquelle le paramètre doit correspondre :
```Python hl_lines="10"
{!../../../docs_src/query_params_str_validations/tutorial004.py!}
```
Cette expression régulière vérifie que la valeur passée comme paramètre :
* `^` : commence avec les caractères qui suivent, avec aucun caractère avant ceux-là.
* `fixedquery` : a pour valeur exacte `fixedquery`.
* `$` : se termine directement ensuite, n'a pas d'autres caractères après `fixedquery`.
Si vous vous sentez perdu avec le concept d'**expression régulière**, pas d'inquiétudes. Il s'agit d'une notion difficile pour beaucoup, et l'on peut déjà réussir à faire beaucoup sans jamais avoir à les manipuler.
Mais si vous décidez d'apprendre à les utiliser, sachez qu'ensuite vous pouvez les utiliser directement dans **FastAPI**.
## Valeurs par défaut
De la même façon que vous pouvez passer `None` comme premier argument pour l'utiliser comme valeur par défaut, vous pouvez passer d'autres valeurs.
Disons que vous déclarez le paramètre `q` comme ayant une longueur minimale de `3`, et une valeur par défaut étant `"fixedquery"` :
```Python hl_lines="7"
{!../../../docs_src/query_params_str_validations/tutorial005.py!}
```
!!! note "Rappel"
Avoir une valeur par défaut rend le paramètre optionnel.
## Rendre ce paramètre requis
Quand on ne déclare ni validation, ni métadonnée, on peut rendre le paramètre `q` requis en ne lui déclarant juste aucune valeur par défaut :
```Python
q: str
```
à la place de :
```Python
q: Union[str, None] = None
```
Mais maintenant, on déclare `q` avec `Query`, comme ceci :
```Python
q: Union[str, None] = Query(default=None, min_length=3)
```
Donc pour déclarer une valeur comme requise tout en utilisant `Query`, il faut utiliser `...` comme premier argument :
```Python hl_lines="7"
{!../../../docs_src/query_params_str_validations/tutorial006.py!}
```
!!! info
Si vous n'avez jamais vu ce `...` auparavant : c'est une des constantes natives de Python <a href="https://docs.python.org/fr/3/library/constants.html#Ellipsis" class="external-link" target="_blank">appelée "Ellipsis"</a>.
Cela indiquera à **FastAPI** que la présence de ce paramètre est obligatoire.
## Liste de paramètres / valeurs multiples via Query
Quand on définit un paramètre de requête explicitement avec `Query` on peut aussi déclarer qu'il reçoit une liste de valeur, ou des "valeurs multiples".
Par exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans une URL, on écrit :
```Python hl_lines="9"
{!../../../docs_src/query_params_str_validations/tutorial011.py!}
```
Ce qui fait qu'avec une URL comme :
```
http://localhost:8000/items/?q=foo&q=bar
```
vous recevriez les valeurs des multiples paramètres de requête `q` (`foo` et `bar`) dans une `list` Python au sein de votre fonction de **path operation**, dans le paramètre de fonction `q`.
Donc la réponse de cette URL serait :
```JSON
{
"q": [
"foo",
"bar"
]
}
```
!!! tip "Astuce"
Pour déclarer un paramètre de requête de type `list`, comme dans l'exemple ci-dessus, il faut explicitement utiliser `Query`, sinon cela sera interprété comme faisant partie du corps de la requête.
La documentation sera donc mise à jour automatiquement pour autoriser plusieurs valeurs :
<img src="/img/tutorial/query-params-str-validations/image02.png">
### Combiner liste de paramètres et valeurs par défaut
Et l'on peut aussi définir une liste de valeurs par défaut si aucune n'est fournie :
```Python hl_lines="9"
{!../../../docs_src/query_params_str_validations/tutorial012.py!}
```
Si vous allez à :
```
http://localhost:8000/items/
```
la valeur par défaut de `q` sera : `["foo", "bar"]`
et la réponse sera :
```JSON
{
"q": [
"foo",
"bar"
]
}
```
#### Utiliser `list`
Il est aussi possible d'utiliser directement `list` plutôt que `List[str]` :
```Python hl_lines="7"
{!../../../docs_src/query_params_str_validations/tutorial013.py!}
```
!!! note
Dans ce cas-là, **FastAPI** ne vérifiera pas le contenu de la liste.
Par exemple, `List[int]` vérifiera (et documentera) que la liste est bien entièrement composée d'entiers. Alors qu'un simple `list` ne ferait pas cette vérification.
## Déclarer des métadonnées supplémentaires
On peut aussi ajouter plus d'informations sur le paramètre.
Ces informations seront incluses dans le schéma `OpenAPI` généré et utilisées par la documentation interactive ou les outils externes utilisés.
!!! note
Gardez en tête que les outils externes utilisés ne supportent pas forcément tous parfaitement OpenAPI.
Il se peut donc que certains d'entre eux n'utilisent pas toutes les métadonnées que vous avez déclarées pour le moment, bien que dans la plupart des cas, les fonctionnalités manquantes ont prévu d'être implémentées.
Vous pouvez ajouter un `title` :
```Python hl_lines="10"
{!../../../docs_src/query_params_str_validations/tutorial007.py!}
```
Et une `description` :
```Python hl_lines="13"
{!../../../docs_src/query_params_str_validations/tutorial008.py!}
```
## Alias de paramètres
Imaginez que vous vouliez que votre paramètre se nomme `item-query`.
Comme dans la requête :
```
http://127.0.0.1:8000/items/?item-query=foobaritems
```
Mais `item-query` n'est pas un nom de variable valide en Python.
Le nom le plus proche serait `item_query`.
Mais vous avez vraiment envie que ce soit exactement `item-query`...
Pour cela vous pouvez déclarer un `alias`, et cet alias est ce qui sera utilisé pour trouver la valeur du paramètre :
```Python hl_lines="9"
{!../../../docs_src/query_params_str_validations/tutorial009.py!}
```
## Déprécier des paramètres
Disons que vous ne vouliez plus utiliser ce paramètre désormais.
Il faut qu'il continue à exister pendant un certain temps car vos clients l'utilisent, mais vous voulez que la documentation mentionne clairement que ce paramètre est <abbr title="obsolète, recommandé de ne pas l'utiliser">déprécié</abbr>.
On utilise alors l'argument `deprecated=True` de `Query` :
```Python hl_lines="18"
{!../../../docs_src/query_params_str_validations/tutorial010.py!}
```
La documentation le présentera comme il suit :
<img src="/img/tutorial/query-params-str-validations/image01.png">
## Pour résumer
Il est possible d'ajouter des validateurs et métadonnées pour vos paramètres.
Validateurs et métadonnées génériques:
* `alias`
* `title`
* `description`
* `deprecated`
Validateurs spécifiques aux chaînes de caractères :
* `min_length`
* `max_length`
* `regex`
Parmi ces exemples, vous avez pu voir comment déclarer des validateurs pour les chaînes de caractères.
Dans les prochains chapitres, vous verrez comment déclarer des validateurs pour d'autres types, comme les nombres.

View File

@@ -0,0 +1,323 @@
# デプロイメントのコンセプト
**FastAPI**を用いたアプリケーションをデプロイするとき、もしくはどのようなタイプのWeb APIであっても、おそらく気になるコンセプトがいくつかあります。
それらを活用することでアプリケーションを**デプロイするための最適な方法**を見つけることができます。
重要なコンセプトのいくつかを紹介します:
* セキュリティ - HTTPS
* 起動時の実行
* 再起動
* レプリケーション(実行中のプロセス数)
* メモリー
* 開始前の事前のステップ
これらが**デプロイメント**にどのような影響を与えるかを見ていきましょう。
最終的な目的は、**安全な方法で**APIクライアントに**サービスを提供**し、**中断を回避**するだけでなく、**計算リソース**(例えばリモートサーバー/仮想マシン)を可能な限り効率的に使用することです。🚀
この章では前述した**コンセプト**についてそれぞれ説明します。
この説明を通して、普段とは非常に異なる環境や存在しないであろう**将来の**環境に対し、デプロイの方法を決める上で必要な**直感**を与えてくれることを願っています。
これらのコンセプトを意識することにより、**あなた自身のAPI**をデプロイするための最適な方法を**評価**し、**設計**することができるようになるでしょう。
次の章では、FastAPIアプリケーションをデプロイするための**具体的なレシピ**を紹介します。
しかし、今はこれらの重要な**コンセプトに基づくアイデア**を確認しましょう。これらのコンセプトは、他のどのタイプのWeb APIにも当てはまります。💡
## セキュリティ - HTTPS
<!-- NOTE: https.md written in Japanese does not exist, so it redirects to English one -->
[前チャプターのHTTPSについて](./https.md){.internal-link target=_blank}では、HTTPSがどのようにAPIを暗号化するのかについて学びました。
通常、アプリケーションサーバにとって**外部の**コンポーネントである**TLS Termination Proxy**によって提供されることが一般的です。このプロキシは通信の暗号化を担当します。
さらにセキュアな通信において、HTTPS証明書の定期的な更新を行いますが、これはTLS Termination Proxyと同じコンポーネントが担当することもあれば、別のコンポーネントが担当することもあります。
### HTTPS 用ツールの例
TLS Termination Proxyとして使用できるツールには以下のようなものがあります
* Traefik
* 証明書の更新を自動的に処理 ✨
* Caddy
* 証明書の更新を自動的に処理 ✨
* Nginx
* 証明書更新のためにCertbotのような外部コンポーネントを使用
* HAProxy
* 証明書更新のためにCertbotのような外部コンポーネントを使用
* Nginx のような Ingress Controller を持つ Kubernetes
* 証明書の更新に cert-manager のような外部コンポーネントを使用
* クラウド・プロバイダーがサービスの一部として内部的に処理(下記を参照👇)
もう1つの選択肢は、HTTPSのセットアップを含んだより多くの作業を行う**クラウド・サービス**を利用することです。 このサービスには制限があったり、料金が高くなったりする可能性があります。しかしその場合、TLS Termination Proxyを自分でセットアップする必要はないです。
次の章で具体例をいくつか紹介します。
---
次に考慮すべきコンセプトは、実際のAPIを実行するプログラムUvicornに関連するものすべてです。
## プログラム と プロセス
私たちは「**プロセス**」という言葉についてたくさん話すので、その意味や「**プログラム**」という言葉との違いを明確にしておくと便利です。
### プログラムとは何か
**プログラム**という言葉は、一般的にいろいろなものを表現するのに使われます:
* プログラマが書く**コード**、**Pythonファイル**
* OSによって実行することができるファイル例: `python`, `python.exe` or `uvicorn`
* OS上で**実行**している間、CPUを使用し、メモリ上に何かを保存する特定のプログラム**プロセス**とも呼ばれる)
### プロセスとは何か
**プロセス**という言葉は通常、より具体的な意味で使われ、OSで実行されているものだけを指します先ほどの最後の説明のように
* OS上で**実行**している特定のプログラム
* これはファイルやコードを指すのではなく、OSによって**実行**され、管理されているものを指します。
* どんなプログラムやコードも、それが**実行されているときにだけ機能**します。つまり、**プロセスとして実行されているときだけ**です。
* プロセスは、ユーザーにあるいはOSによって、 **終了**(あるいは "kill")させることができます。その時点で、プロセスは実行/実行されることを停止し、それ以降は**何もできなくなります**。
* コンピュータで実行されている各アプリケーションは、実行中のプログラムや各ウィンドウなど、その背後にいくつかのプロセスを持っています。そして通常、コンピュータが起動している間、**多くのプロセスが**同時に実行されています。
* **同じプログラム**の**複数のプロセス**が同時に実行されていることがあります。
OSの「タスク・マネージャー」や「システム・モニター」または同様のツールを確認すれば、これらのプロセスの多くが実行されているの見ることができるでしょう。
例えば、同じブラウザプログラムFirefox、Chrome、Edgeなどを実行しているプロセスが複数あることがわかります。通常、1つのタブにつき1つのプロセスが実行され、さらに他のプロセスも実行されます。
<img class="shadow" src="/img/deployment/concepts/image01.png">
---
さて、**プロセス**と**プログラム**という用語の違いを確認したところで、デプロイメントについて話を続けます。
## 起動時の実行
ほとんどの場合、Web APIを作成するときは、クライアントがいつでもアクセスできるように、**常に**中断されることなく**実行される**ことを望みます。もちろん、特定の状況でのみ実行させたい特別な理由がある場合は別ですが、その時間のほとんどは、常に実行され、**利用可能**であることを望みます。
### リモートサーバー上での実行
リモートサーバークラウドサーバー、仮想マシンなどをセットアップするときにできる最も簡単なことは、ローカルで開発するときと同じように、Uvicornまたは同様のものを手動で実行することです。 この方法は**開発中**には役に立つと思われます。
しかし、サーバーへの接続が切れた場合、**実行中のプロセス**はおそらくダウンしてしまうでしょう。
そしてサーバーが再起動された場合(アップデートやクラウドプロバイダーからのマイグレーションの後など)、おそらくあなたはそれに**気づかないでしょう**。そのため、プロセスを手動で再起動しなければならないことすら気づかないでしょう。つまり、APIはダウンしたままなのです。😱
### 起動時に自動的に実行
一般的に、サーバープログラムUvicornなどはサーバー起動時に自動的に開始され、**人の介入**を必要とせずに、APIと一緒にプロセスが常に実行されるようにしたいと思われますUvicornがFastAPIアプリを実行するなど
### 別のプログラムの用意
これを実現するために、通常は**別のプログラム**を用意し、起動時にアプリケーションが実行されるようにします。そして多くの場合、他のコンポーネントやアプリケーション、例えばデータベースも実行されるようにします。
### 起動時に実行するツールの例
実行するツールの例をいくつか挙げます:
* Docker
* Kubernetes
* Docker Compose
* Swarm モードによる Docker
* Systemd
* Supervisor
* クラウドプロバイダーがサービスの一部として内部的に処理
* そのほか...
次の章で、より具体的な例を挙げていきます。
## 再起動
起動時にアプリケーションが実行されることを確認するのと同様に、失敗後にアプリケーションが**再起動**されることも確認したいと思われます。
### 我々は間違いを犯す
私たち人間は常に**間違い**を犯します。ソフトウェアには、ほとんど常に**バグ**があらゆる箇所に隠されています。🐛
### 小さなエラーは自動的に処理される
FastAPIでWeb APIを構築する際に、コードにエラーがある場合、FastAPIは通常、エラーを引き起こした単一のリクエストにエラーを含めます。🛡
クライアントはそのリクエストに対して**500 Internal Server Error**を受け取りますが、アプリケーションは完全にクラッシュするのではなく、次のリクエストのために動作を続けます。
### 重大なエラー - クラッシュ
しかしながら、**アプリケーション全体をクラッシュさせるようなコードを書いて**UvicornとPythonをクラッシュさせるようなケースもあるかもしれません。💥
それでも、ある箇所でエラーが発生したからといって、アプリケーションを停止させたままにしたくないでしょう。 少なくとも壊れていない*パスオペレーション*については、**実行し続けたい**はずです。
### クラッシュ後の再起動
しかし、実行中の**プロセス**をクラッシュさせるような本当にひどいエラーの場合、少なくとも2〜3回ほどプロセスを**再起動**させる外部コンポーネントが必要でしょう。
!!! tip
...とはいえ、アプリケーション全体が**すぐにクラッシュする**のであれば、いつまでも再起動し続けるのは意味がないでしょう。しかし、その場合はおそらく開発中か少なくともデプロイ直後に気づくと思われます。
そこで、**将来**クラッシュする可能性があり、それでも再スタートさせることに意味があるような、主なケースに焦点を当ててみます。
あなたはおそらく**外部コンポーネント**がアプリケーションの再起動を担当することを望むと考えます。 なぜなら、その時点でUvicornとPythonを使った同じアプリケーションはすでにクラッシュしており、同じアプリケーションの同じコードに対して何もできないためです。
### 自動的に再起動するツールの例
ほとんどの場合、前述した**起動時にプログラムを実行する**ために使用されるツールは、自動で**再起動**することにも利用されます。
例えば、次のようなものがあります:
* Docker
* Kubernetes
* Docker Compose
* Swarm モードによる Docker
* Systemd
* Supervisor
* クラウドプロバイダーがサービスの一部として内部的に処理
* そのほか...
## レプリケーション - プロセスとメモリー
FastAPI アプリケーションでは、Uvicorn のようなサーバープログラムを使用し、**1つのプロセス**で1度に複数のクライアントに同時に対応できます。
しかし、多くの場合、複数のワーカー・プロセスを同時に実行したいと考えるでしょう。
### 複数のプロセス - Worker
クライアントの数が単一のプロセスで処理できる数を超えており(たとえば仮想マシンがそれほど大きくない場合)、かつサーバーの CPU に**複数のコア**がある場合、同じアプリケーションで同時に**複数のプロセス**を実行させ、すべてのリクエストを分散させることができます。
同じAPIプログラムの**複数のプロセス**を実行する場合、それらは一般的に**Workerワーカー**と呼ばれます。
### ワーカー・プロセス と ポート
<!-- NOTE: https.md written in Japanese does not exist, so it redirects to English one -->
[HTTPSについて](./https.md){.internal-link target=_blank}のドキュメントで、1つのサーバーで1つのポートとIPアドレスの組み合わせでリッスンできるのは1つのプロセスだけであることを覚えていますでしょうか
これはいまだに同じです。
そのため、**複数のプロセス**を同時に持つには**ポートでリッスンしている単一のプロセス**が必要であり、それが何らかの方法で各ワーカー・プロセスに通信を送信することが求められます。
### プロセスあたりのメモリー
さて、プログラムがメモリにロードする際には、例えば機械学習モデルや大きなファイルの内容を変数に入れたりする場合では、**サーバーのメモリRAM**を少し消費します。
そして複数のプロセスは通常、**メモリを共有しません**。これは、実行中の各プロセスがそれぞれ独自の変数やメモリ等を持っていることを意味します。つまり、コード内で大量のメモリを消費している場合、**各プロセス**は同等の量のメモリを消費することになります。
### サーバーメモリー
例えば、あなたのコードが **1GBのサイズの機械学習モデル**をロードする場合、APIで1つのプロセスを実行すると、少なくとも1GBのRAMを消費します。
また、**4つのプロセス**4つのワーカーを起動すると、それぞれが1GBのRAMを消費します。つまり、合計でAPIは**4GBのRAM**を消費することになります。
リモートサーバーや仮想マシンのRAMが3GBしかない場合、4GB以上のRAMをロードしようとすると問題が発生します。🚨
### 複数プロセス - 例
この例では、2つの**ワーカー・プロセス**を起動し制御する**マネージャー・ プロセス**があります。
このマネージャー・ プロセスは、おそらくIPの**ポート**でリッスンしているものです。そして、すべての通信をワーカー・プロセスに転送します。
これらのワーカー・プロセスは、アプリケーションを実行するものであり、**リクエスト**を受けて**レスポンス**を返すための主要な計算を行い、あなたが変数に入れたものは何でもRAMにロードします。
<img src="/img/deployment/concepts/process-ram.svg">
そしてもちろん、同じマシンでは、あなたのアプリケーションとは別に、**他のプロセス**も実行されているでしょう。
興味深いことに、各プロセスが使用する**CPU**の割合は時間とともに大きく**変動**する可能性がありますが、**メモリRAM**は通常、多かれ少なかれ**安定**します。
毎回同程度の計算を行うAPIがあり、多くのクライアントがいるのであれば、**CPU使用率**もおそらく**安定**するでしょう(常に急激に上下するのではなく)。
### レプリケーション・ツールと戦略の例
これを実現するにはいくつかのアプローチがありますが、具体的な戦略については次の章(Dockerやコンテナの章など)で詳しく説明します。
考慮すべき主な制約は、**パブリックIP**の**ポート**を処理する**単一の**コンポーネントが存在しなければならないということです。
そして、レプリケートされた**プロセス/ワーカー**に通信を**送信**する方法を持つ必要があります。
考えられる組み合わせと戦略をいくつか紹介します:
* **Gunicorn**が**Uvicornワーカー**を管理
* Gunicornは**IP**と**ポート**をリッスンする**プロセスマネージャ**で、レプリケーションは**複数のUvicornワーカー・プロセス**を持つことによって行われる。
* **Uvicorn**が**Uvicornワーカー**を管理
* 1つのUvicornの**プロセスマネージャー**が**IP**と**ポート**をリッスンし、**複数のUvicornワーカー・プロセス**を起動する。
* **Kubernetes**やその他の分散**コンテナ・システム**
* **Kubernetes**レイヤーの何かが**IP**と**ポート**をリッスンする。レプリケーションは、**複数のコンテナ**にそれぞれ**1つのUvicornプロセス**を実行させることで行われる。
* **クラウド・サービス**によるレプリケーション
* クラウド・サービスはおそらく**あなたのためにレプリケーションを処理**します。**実行するプロセス**や使用する**コンテナイメージ**を定義できるかもしれませんが、いずれにせよ、それはおそらく**単一のUvicornプロセス**であり、クラウドサービスはそのレプリケーションを担当するでしょう。
!!! tip
これらの**コンテナ**やDockerそしてKubernetesに関する項目が、まだあまり意味をなしていなくても心配しないでください。
<!-- NOTE: the current version of docker.md is outdated compared to English one. -->
コンテナ・イメージ、Docker、Kubernetesなどについては、次の章で詳しく説明します: [コンテナ内のFastAPI - Docker](./docker.md){.internal-link target=_blank}.
## 開始前の事前のステップ
アプリケーションを**開始する前**に、いくつかのステップを実行したい場合が多くあります。
例えば、**データベース・マイグレーション** を実行したいかもしれません。
しかしほとんどの場合、これらの手順を**1度**に実行したいと考えるでしょう。
そのため、アプリケーションを開始する前の**事前のステップ**を実行する**単一のプロセス**を用意したいと思われます。
そして、それらの事前のステップを実行しているのが単一のプロセスであることを確認する必要があります。このことはその後アプリケーション自体のために**複数のプロセス**(複数のワーカー)を起動した場合も同様です。
これらのステップが**複数のプロセス**によって実行された場合、**並列**に実行されることによって作業が**重複**することになります。そして、もしそのステップがデータベースのマイグレーションのような繊細なものであった場合、互いに競合を引き起こす可能性があります。
もちろん、事前のステップを何度も実行しても問題がない場合もあり、その際は対処がかなり楽になります。
!!! tip
また、セットアップによっては、アプリケーションを開始する前の**事前のステップ**が必要ない場合もあることを覚えておいてください。
その場合は、このようなことを心配する必要はないです。🤷
### 事前ステップの戦略例
これは**システムを**デプロイする方法に**大きく依存**するだろうし、おそらくプログラムの起動方法や再起動の処理などにも関係してくるでしょう。
考えられるアイデアをいくつか挙げてみます:
* アプリコンテナの前に実行されるKubernetesのInitコンテナ
* 事前のステップを実行し、アプリケーションを起動するbashスクリプト
* 利用するbashスクリプトを起動再起動したり、エラーを検出したりする方法は以前として必要になるでしょう。
!!! tip
<!-- NOTE: the current version of docker.md is outdated compared to English one. -->
コンテナを使った具体的な例については、次の章で紹介します: [コンテナ内のFastAPI - Docker](./docker.md){.internal-link target=_blank}.
## リソースの利用
あなたのサーバーは**リソース**であり、プログラムを実行しCPUの計算時間や利用可能なRAMメモリを消費または**利用**することができます。
システムリソースをどれくらい消費/利用したいですか? 「少ない方が良い」と考えるのは簡単かもしれないですが、実際には、**クラッシュせずに可能な限り**最大限に活用したいでしょう。
3台のサーバーにお金を払っているにも関わらず、そのRAMとCPUを少ししか使っていないとしたら、おそらく**お金を無駄にしている** 💸、おそらく**サーバーの電力を無駄にしている** 🌎ことになるでしょう。
その場合は、サーバーを2台だけにして、そのリソースCPU、メモリ、ディスク、ネットワーク帯域幅などをより高い割合で使用する方がよいでしょう。
一方、2台のサーバーがあり、そのCPUとRAMの**100%を使用している**場合、ある時点で1つのプロセスがより多くのメモリを要求し、サーバーはディスクを「メモリ」として使用しないといけません。何千倍も遅くなる可能性があります。
もしくは**クラッシュ**することもあれば、あるいはあるプロセスが何らかの計算をする必要があり、そしてCPUが再び空くまで待たなければならないかもしれません。
この場合、**1つ余分なサーバー**を用意し、その上でいくつかのプロセスを実行し、すべてのサーバーが**十分なRAMとCPU時間を持つようにする**のがよいでしょう。
また、何らかの理由でAPIの利用が急増する可能性もあります。もしかしたらそれが流行ったのかもしれないし、他のサービスやボットが使い始めたのかもしれないです。そのような場合に備えて、余分なリソースを用意しておくと安心でしょう。
例えば、リソース使用率の**50%から90%の範囲**で**任意の数字**をターゲットとすることができます。
重要なのは、デプロイメントを微調整するためにターゲットを設定し測定することが、おそらく使用したい主要な要素であることです。
`htop`のような単純なツールを使って、サーバーで使用されているCPUやRAM、あるいは各プロセスで使用されている量を見ることができます。あるいは、より複雑な監視ツールを使って、サーバに分散して使用することもできます。
## まとめ
アプリケーションのデプロイ方法を決定する際に、考慮すべきであろう主要なコンセプトのいくつかを紹介していきました:
* セキュリティ - HTTPS
* 起動時の実行
* 再起動
* レプリケーション(実行中のプロセス数)
* メモリー
* 開始前の事前ステップ
これらの考え方とその適用方法を理解することで、デプロイメントを設定したり調整したりする際に必要な直感的な判断ができるようになるはずです。🤓
次のセクションでは、あなたが取り得る戦略について、より具体的な例を挙げます。🚀

View File

@@ -1,240 +0,0 @@
# Deta にデプロイ
このセクションでは、**FastAPI** アプリケーションを <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> の無料プランを利用して、簡単にデプロイする方法を学習します。🎁
所要時間は約**10分**です。
!!! info "備考"
<a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> は **FastAPI** のスポンサーです。🎉
## ベーシックな **FastAPI** アプリ
* アプリのためのディレクトリ (例えば `./fastapideta/`) を作成し、その中に入ってください。
### FastAPI のコード
* 以下の `main.py` ファイルを作成してください:
```Python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}
```
### Requirements
では、同じディレクトリに以下の `requirements.txt` ファイルを作成してください:
```text
fastapi
```
!!! tip "豆知識"
アプリのローカルテストのために Uvicorn をインストールしたくなるかもしれませんが、Deta へのデプロイには不要です。
### ディレクトリ構造
以下の2つのファイルと1つの `./fastapideta/` ディレクトリがあるはずです:
```
.
└── main.py
└── requirements.txt
```
## Detaの無料アカウントの作成
それでは、<a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Detaの無料アカウント</a>を作成しましょう。必要なものはメールアドレスとパスワードだけです。
クレジットカードさえ必要ありません。
## CLIのインストール
アカウントを取得したら、Deta <abbr title="Command Line Interface application">CLI</abbr> をインストールしてください:
=== "Linux, macOS"
<div class="termy">
```console
$ curl -fsSL https://get.deta.dev/cli.sh | sh
```
</div>
=== "Windows PowerShell"
<div class="termy">
```console
$ iwr https://get.deta.dev/cli.ps1 -useb | iex
```
</div>
インストールしたら、インストールした CLI を有効にするために新たなターミナルを開いてください。
新たなターミナル上で、正しくインストールされたか確認します:
<div class="termy">
```console
$ deta --help
Deta command line interface for managing deta micros.
Complete documentation available at https://docs.deta.sh
Usage:
deta [flags]
deta [command]
Available Commands:
auth Change auth settings for a deta micro
...
```
</div>
!!! tip "豆知識"
CLI のインストールに問題が発生した場合は、<a href="https://docs.deta.sh/docs/micros/getting_started?ref=fastapi" class="external-link" target="_blank">Deta 公式ドキュメント</a>を参照してください。
## CLIでログイン
CLI から Deta にログインしてみましょう:
<div class="termy">
```console
$ deta login
Please, log in from the web page. Waiting..
Logged in successfully.
```
</div>
自動的にウェブブラウザが開いて、認証処理が行われます。
## Deta でデプロイ
次に、アプリケーションを Deta CLIでデプロイしましょう:
<div class="termy">
```console
$ deta new
Successfully created a new micro
// Notice the "endpoint" 🔍
{
"name": "fastapideta",
"runtime": "python3.7",
"endpoint": "https://qltnci.deta.dev",
"visor": "enabled",
"http_auth": "enabled"
}
Adding dependencies...
---> 100%
Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6
```
</div>
次のようなJSONメッセージが表示されます:
```JSON hl_lines="4"
{
"name": "fastapideta",
"runtime": "python3.7",
"endpoint": "https://qltnci.deta.dev",
"visor": "enabled",
"http_auth": "enabled"
}
```
!!! tip "豆知識"
あなたのデプロイでは異なる `"endpoint"` URLが表示されるでしょう。
## 確認
それでは、`endpoint` URLをブラウザで開いてみましょう。上記の例では `https://qltnci.deta.dev` ですが、あなたのURLは異なるはずです。
FastAPIアプリから返ってきたJSONレスポンスが表示されます:
```JSON
{
"Hello": "World"
}
```
そして `/docs` へ移動してください。上記の例では、`https://qltnci.deta.dev/docs` です。
次のようなドキュメントが表示されます:
<img src="/img/deployment/deta/image01.png">
## パブリックアクセスの有効化
デフォルトでは、Deta はクッキーを用いてアカウントの認証を行います。
しかし、準備が整えば、以下の様に公開できます:
<div class="termy">
```console
$ deta auth disable
Successfully disabled http auth
```
</div>
ここで、URLを共有するとAPIにアクセスできるようになります。🚀
## HTTPS
おめでとうございます!あなたの FastAPI アプリが Deta へデプロイされました!🎉 🍰
また、DetaがHTTPSを正しく処理するため、その処理を行う必要がなく、クライアントは暗号化された安全な通信が利用できます。✅ 🔒
## Visor を確認
ドキュメントUI (`https://qltnci.deta.dev/docs` のようなURLにある) は *path operation* `/items/{item_id}` へリクエストを送ることができます。
ID `5` の例を示します。
まず、<a href="https://web.deta.sh/" class="external-link" target="_blank">https://web.deta.sh</a> へアクセスします。
左側に各アプリの <abbr title="it comes from Micro(server)">「Micros」</abbr> というセクションが表示されます。
また、「Details」や「Visor」タブが表示されています。「Visor」タブへ移動してください。
そこでアプリに送られた直近のリクエストが調べられます。
また、それらを編集してリプレイできます。
<img src="/img/deployment/deta/image02.png">
## さらに詳しく知る
様々な箇所で永続的にデータを保存したくなるでしょう。そのためには <a href="https://docs.deta.sh/docs/base/py_tutorial?ref=fastapi" class="external-link" target="_blank">Deta Base</a> を使用できます。惜しみない **無料利用枠** もあります。
詳しくは <a href="https://docs.deta.sh?ref=fastapi" class="external-link" target="_blank">Deta ドキュメント</a>を参照してください。

View File

@@ -1,71 +1,157 @@
# Dockerを使用したデプロイ
# コンテナ内のFastAPI - Docker
このセクションでは以下の使い方の紹介とガイドへのリンクが確認できます:
FastAPIアプリケーションをデプロイする場合、一般的なアプローチは**Linuxコンテナ・イメージ**をビルドすることです。
* **5分**程度で、**FastAPI** のアプリケーションを、パフォーマンスを最大限に発揮するDockerイメージ (コンテナ)にする
* (オプション) 開発者として必要な範囲でHTTPSを理解する。
* **20分**程度で、自動的なHTTPS生成とともにDockerのSwarmモード クラスタをセットアップする (月5ドルのシンプルなサーバー上で)。
* **10分**程度で、DockerのSwarmモード クラスタを使って、HTTPSなどを使用した完全な**FastAPI** アプリケーションの作成とデプロイ。
基本的には <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>を用いて行われます。生成されたコンテナ・イメージは、いくつかの方法のいずれかでデプロイできます
デプロイのために、<a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a> を利用できます。セキュリティ、再現性、開発のシンプルさなどに利点があります。
Linuxコンテナの使用には、**セキュリティ**、**反復可能性(レプリカビリティ)**、**シンプリシティ**など、いくつかの利点があります。
Dockerを使う場合、公式のDockerイメージが利用できます:
!!! tip
TODO: なぜか遷移できない
お急ぎで、すでにこれらの情報をご存じですか? [以下の`Dockerfile`の箇所👇](#build-a-docker-image-for-fastapi)へジャンプしてください。
## <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>
このイメージは「自動チューニング」機構を含んでいます。犠牲を払うことなく、ただコードを加えるだけで自動的に高パフォーマンスを実現できます。
ただし、環境変数や設定ファイルを使って全ての設定の変更や更新を行えます。
!!! tip "豆知識"
全ての設定とオプションを確認するには、Dockerイメージページを開いて下さい: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
## `Dockerfile` の作成
* プロジェクトディレクトリへ移動。
* 以下の`Dockerfile` を作成:
<details>
<summary>Dockerfile プレビュー 👀</summary>
```Dockerfile
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
FROM python:3.9
COPY ./app /app
```
WORKDIR /code
### より大きなアプリケーション
COPY ./requirements.txt /code/requirements.txt
[Bigger Applications with Multiple Files](tutorial/bigger-applications.md){.internal-link target=_blank} セクションに倣う場合は、`Dockerfile` は上記の代わりに、以下の様になるかもしれません:
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
```Dockerfile
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
COPY ./app /app/app
```
### Raspberry Piなどのアーキテクチャ
Raspberry Pi (ARMプロセッサ搭載)やそれ以外のアーキテクチャでDockerが作動している場合、(マルチアーキテクチャである) Pythonベースイメージを使って、一から`Dockerfile`を作成し、Uvicornを単体で使用できます。
この場合、`Dockerfile` は以下の様になるかもしれません:
```Dockerfile
FROM python:3.7
RUN pip install fastapi uvicorn
EXPOSE 80
COPY ./app /app
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"]
```
## **FastAPI** コードの作成
</details>
* `app` ディレクトリを作成し、移動。
* 以下の`main.py` ファイルを作成:
## コンテナとは何か
コンテナ主にLinuxコンテナは、同じシステム内の他のコンテナ他のアプリケーションやコンポーネントから隔離された状態を保ちながら、すべての依存関係や必要なファイルを含むアプリケーションをパッケージ化する非常に**軽量**な方法です。
Linuxコンテナは、ホストマシン、仮想マシン、クラウドサーバーなどの同じLinuxカーネルを使用して実行されます。これは、OS全体をエミュレートする完全な仮想マシンと比べて非常に軽量であることを意味します。
このように、コンテナは**リソースをほとんど消費しません**が、プロセスを直接実行するのに匹敵する量です(仮想マシンはもっと消費します)。
コンテナはまた、独自の**分離された**実行プロセス通常は1つのプロセスのみや、ファイルシステム、ネットワークを持ちます。 このことはデプロイ、セキュリティ、開発などを簡素化させます。
## コンテナ・イメージとは何か
**コンテナ**は、**コンテナ・イメージ**から実行されます。
コンテナ・イメージは、コンテナ内に存在すべきすべてのファイルや環境変数、そしてデフォルトのコマンド/プログラムを**静的に**バージョン化したものです。 ここでの**静的**とは、コンテナ**イメージ**は実行されておらず、パッケージ化されたファイルとメタデータのみであることを意味します。
保存された静的コンテンツである「**コンテナイメージ**」とは対照的に、「**コンテナ**」は通常、実行中のインスタンス、つまり**実行**されているものを指します。
**コンテナ**が起動され実行されるとき(**コンテナイメージ**から起動されるとき)、ファイルや環境変数などが作成されたり変更されたりする可能性があります。
これらの変更はそのコンテナ内にのみ存在しますが、基盤となるコンテナ・イメージには残りません(ディスクに保存されません)。
コンテナイメージは **プログラム** ファイルやその内容、例えば `python``main.py` ファイルに匹敵します。
そして、**コンテナ**自体は(**コンテナイメージ**とは対照的に)イメージをもとにした実際の実行中のインスタンスであり、**プロセス**に匹敵します。
実際、コンテナが実行されているのは、**プロセスが実行されている**ときだけです(通常は単一のプロセスだけです)。 コンテナ内で実行中のプロセスがない場合、コンテナは停止します。
## コンテナ・イメージ
Dockerは、**コンテナ・イメージ**と**コンテナ**を作成・管理するための主要なツールの1つです。
そして、DockerにはDockerイメージコンテナを共有する<a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a>というものがあります。
Docker Hubは 多くのツールや環境、データベース、アプリケーションに対応している予め作成された**公式のコンテナ・イメージ**をパブリックに提供しています。
例えば、公式イメージの1つに<a href="https://hub.docker.com/_/python" class="external-link" target="_blank">Python Image</a>があります。
その他にも、データベースなどさまざまなイメージがあります:
* <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.
予め作成されたコンテナ・イメージを使用することで、異なるツールを**組み合わせて**使用することが非常に簡単になります。例えば、新しいデータベースを試す場合に特に便利です。ほとんどの場合、**公式イメージ**を使い、環境変数で設定するだけで良いです。
そうすれば多くの場合、コンテナとDockerについて学び、その知識をさまざまなツールやコンポーネントによって再利用することができます。
つまり、データベース、Pythonアプリケーション、Reactフロントエンド・アプリケーションを備えたウェブ・サーバーなど、さまざまなものを**複数のコンテナ**で実行し、それらを内部ネットワーク経由で接続します。
すべてのコンテナ管理システムDockerやKubernetesなどには、こうしたネットワーキング機能が統合されています。
## コンテナとプロセス
通常、**コンテナ・イメージ**はそのメタデータに**コンテナ**の起動時に実行されるデフォルトのプログラムまたはコマンドと、そのプログラムに渡されるパラメータを含みます。コマンドラインでの操作とよく似ています。
**コンテナ**が起動されると、そのコマンド/プログラムが実行されます(ただし、別のコマンド/プログラムをオーバーライドして実行させることもできます)。
コンテナは、**メイン・プロセス**(コマンドまたはプログラム)が実行されている限り実行されます。
コンテナは通常**1つのプロセス**を持ちますが、メイン・プロセスからサブ・プロセスを起動することも可能で、そうすれば同じコンテナ内に**複数のプロセス**を持つことになります。
しかし、**少なくとも1つの実行中のプロセス**がなければ、実行中のコンテナを持つことはできないです。メイン・プロセスが停止すれば、コンテナも停止します。
## Build a Docker Image for FastAPI
ということで、何か作りましょう!🚀
FastAPI用の**Dockerイメージ**を、**公式Python**イメージに基づいて**ゼロから**ビルドする方法をお見せします。
これは**ほとんどの場合**にやりたいことです。例えば:
* **Kubernetes**または同様のツールを使用する場合
* **Raspberry Pi**で実行する場合
* コンテナ・イメージを実行してくれるクラウド・サービスなどを利用する場合
### パッケージ要件package requirements
アプリケーションの**パッケージ要件**は通常、何らかのファイルに記述されているはずです。
パッケージ要件は主に**インストール**するために使用するツールに依存するでしょう。
最も一般的な方法は、`requirements.txt` ファイルにパッケージ名とそのバージョンを 1 行ずつ書くことです。
もちろん、[FastAPI バージョンについて](./versions.md){.internal-link target=_blank}で読んだのと同じアイデアを使用して、バージョンの範囲を設定します。
例えば、`requirements.txt` は次のようになります:
```
fastapi>=0.68.0,<0.69.0
pydantic>=1.8.0,<2.0.0
uvicorn>=0.15.0,<0.16.0
```
そして通常、例えば `pip` を使ってこれらのパッケージの依存関係をインストールします:
<div class="termy">
```console
$ pip install -r requirements.txt
---> 100%
Successfully installed fastapi pydantic uvicorn
```
</div>
!!! info
パッケージの依存関係を定義しインストールするためのフォーマットやツールは他にもあります。
Poetryを使った例は、後述するセクションでご紹介します。👇
### **FastAPI**コードを作成する
* `app` ディレクトリを作成し、その中に入ります
* 空のファイル `__init__.py` を作成します
* `main.py` ファイルを作成します:
```Python
from typing import Optional
from typing import Union
from fastapi import FastAPI
@@ -78,23 +164,136 @@ def read_root():
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Optional[str] = None):
def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
* ここでは、以下の様なディレクトリ構造になっているはずです:
### Dockerfile
同じプロジェクト・ディレクトリに`Dockerfile`というファイルを作成します:
```{ .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. 公式のPythonベースイメージから始めます
2. 現在の作業ディレクトリを `/code` に設定します
ここに `requirements.txt` ファイルと `app` ディレクトリを置きます。
3. 要件が書かれたファイルを `/code` ディレクトリにコピーします
残りのコードではなく、最初に必要なファイルだけをコピーしてください。
このファイルは**頻繁には変更されない**ので、Dockerはこのステップではそれを検知し**キャッシュ**を使用し、次のステップでもキャッシュを有効にします。
4. 要件ファイルにあるパッケージの依存関係をインストールします
`--no-cache-dir` オプションはダウンロードしたパッケージをローカルに保存しないように `pip` に指示します。これは、同じパッケージをインストールするために `pip` を再度実行する場合にのみ有効ですが、コンテナで作業する場合はそうではないです。
!!! note
`--no-cache-dir`は`pip`に関連しているだけで、Dockerやコンテナとは何の関係もないです。
`--upgrade` オプションは、パッケージが既にインストールされている場合、`pip` にアップグレードするように指示します。
何故ならファイルをコピーする前のステップは**Dockerキャッシュ**によって検出される可能性があるためであり、このステップも利用可能な場合は**Dockerキャッシュ**を使用します。
このステップでキャッシュを使用すると、開発中にイメージを何度もビルドする際に、**毎回**すべての依存関係を**ダウンロードしてインストールする**代わりに多くの**時間**を**節約**できます。
5. ./app` ディレクトリを `/code` ディレクトリの中にコピーする。
これには**最も頻繁に変更される**すべてのコードが含まれているため、Dockerの**キャッシュ**は**これ以降のステップ**に簡単に使用されることはありません。
そのため、コンテナイメージのビルド時間を最適化するために、`Dockerfile`**最後** にこれを置くことが重要です。
6. `uvicorn`サーバーを実行するための**コマンド**を設定します
`CMD` は文字列のリストを取り、それぞれの文字列はスペースで区切られたコマンドラインに入力するものです。
このコマンドは **現在の作業ディレクトリ**から実行され、上記の `WORKDIR /code` にて設定した `/code` ディレクトリと同じです。
そのためプログラムは `/code` で開始しその中にあなたのコードがある `./app` ディレクトリがあるので、**Uvicorn** は `app.main` から `app` を参照し、**インポート** することができます。
!!! tip
コード内の"+"の吹き出しをクリックして、各行が何をするのかをレビューしてください。👆
これで、次のようなディレクトリ構造になるはずです:
```
.
├── app
│   ├── __init__.py
│ └── main.py
── Dockerfile
── Dockerfile
└── requirements.txt
```
## Dockerイメージをビルド
#### TLS Termination Proxyの裏側
* プロジェクトディレクトリ (`app` ディレクトリを含んだ、`Dockerfile` のある場所) へ移動
* FastAPIイメージのビルド:
Nginx や Traefik のような TLS Termination Proxy (ロードバランサ) の後ろでコンテナを動かしている場合は、`--proxy-headers`オプションを追加します。
このオプションは、Uvicornにプロキシ経由でHTTPSで動作しているアプリケーションに対して、送信されるヘッダを信頼するよう指示します。
```Dockerfile
CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
```
#### Dockerキャッシュ
この`Dockerfile`には重要なトリックがあり、まず**依存関係だけのファイル**をコピーします。その理由を説明します。
```Dockerfile
COPY ./requirements.txt /code/requirements.txt
```
Dockerや他のツールは、これらのコンテナイメージを**段階的に**ビルドし、**1つのレイヤーを他のレイヤーの上に**追加します。`Dockerfile`の先頭から開始し、`Dockerfile`の各命令によって作成されたファイルを追加していきます。
Dockerや同様のツールは、イメージをビルドする際に**内部キャッシュ**も使用します。前回コンテナイメージを構築したときからファイルが変更されていない場合、ファイルを再度コピーしてゼロから新しいレイヤーを作成する代わりに、**前回作成した同じレイヤーを再利用**します。
ただファイルのコピーを避けるだけではあまり改善されませんが、そのステップでキャッシュを利用したため、**次のステップ**でキャッシュを使うことができます。
例えば、依存関係をインストールする命令のためにキャッシュを使うことができます:
```Dockerfile
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
```
パッケージ要件のファイルは**頻繁に変更されることはありません**。そのため、そのファイルだけをコピーすることで、Dockerはそのステップでは**キャッシュ**を使用することができます。
そして、Dockerは**次のステップのためにキャッシュ**を使用し、それらの依存関係をダウンロードしてインストールすることができます。そして、ここで**多くの時間を節約**します。✨ ...そして退屈な待ち時間を避けることができます。😪😆
パッケージの依存関係をダウンロードしてインストールするには**数分**かかりますが、**キャッシュ**を使えば**せいぜい数秒**です。
加えて、開発中にコンテナ・イメージを何度もビルドして、コードの変更が機能しているかどうかをチェックすることになるため、多くの時間を節約することができます。
そして`Dockerfile`の最終行の近くですべてのコードをコピーします。この理由は、**最も頻繁に**変更されるものなので、このステップの後にあるものはほとんどキャッシュを使用することができないのためです。
```Dockerfile
COPY ./app /code/app
```
### Dockerイメージをビルドする
すべてのファイルが揃ったので、コンテナ・イメージをビルドしましょう。
* プロジェクトディレクトリに移動します(`Dockerfile`がある場所で、`app`ディレクトリがあります)
* FastAPI イメージをビルドします:
<div class="termy">
@@ -106,9 +305,14 @@ $ docker build -t myimage .
</div>
## Dockerコンテナを起動
!!! tip
末尾の `.` に注目してほしいです。これは `./` と同じ意味です。 これはDockerにコンテナイメージのビルドに使用するディレクトリを指示します。
* 用意したイメージを基にしたコンテナの起動:
この場合、同じカレント・ディレクトリ(`.`)です。
### Dockerコンテナの起動する
* イメージに基づいてコンテナを実行します:
<div class="termy">
@@ -118,62 +322,394 @@ $ docker run -d --name mycontainer -p 80:80 myimage
</div>
これで、Dockerコンテナ内に最適化されたFastAPIサーバが動作しています。使用しているサーバ (そしてCPUコア数) に沿った自動チューニングが行われています。
## 確認する
## 確認
Dockerコンテナの<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> や <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> (またはそれに相当するDockerホストを使用したものといったURLで確認できるはずです。
DockerコンテナのURLで確認できるはずです。例えば: <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> や <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> (もしくはDockerホストを使用したこれらと同等のもの)。
以下の様なものが返されます:
アクセスすると以下のようなものが表示されます:
```JSON
{"item_id": 5, "q": "somequery"}
```
## 対話的APIドキュメント
## インタラクティブなAPIドキュメント
こで、<a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> や <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (もしくはDockerホストを使用したこれらと同等のもの) を開いて下さい。
れらのURLにもアクセスできます: <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> や <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (またはそれに相当するDockerホストを使用したもの)
自動生成された対話APIドキュメントが確認できます (<a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>によって提供されます):
アクセスすると、自動対話APIドキュメント<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)
## その他のAPIドキュメント
## 代替のAPIドキュメント
また同様に、<a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> や <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (もしくはDockerホストを使用したこれらと同等のもの) を開いて下さい
また、<a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> や <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (またはそれに相当するDockerホストを使用したもの)にもアクセスできます
の自動生成された対話的なAPIドキュメントが確認できます (<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>によって提供されます):
代替の自動ドキュメント(<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)
## Traefik
## 単一ファイルのFastAPIでDockerイメージをビルドする
<a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>は、高性能なリバースプロキシ/ロードバランサーです。「TLSターミネーションプロキシ」ジョブを実行できます他の機能と切り離して
FastAPI が単一のファイル、例えば `./app` ディレクトリのない `main.py` の場合、ファイル構造は次のようになります:
```
.
├── Dockerfile
├── main.py
└── requirements.txt
```
Let's Encryptと統合されています。そのため、証明書の取得と更新を含むHTTPSに関するすべての処理を実行できます。
そうすれば、`Dockerfile`の中にファイルをコピーするために、対応するパスを変更するだけでよいです:
また、Dockerとも統合されています。したがって、各アプリケーション構成でドメインを宣言し、それらの構成を読み取って、HTTPS証明書を生成し、構成に変更を加えることなく、アプリケーションにHTTPSを自動的に提供できます。
```{ .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. main.py`ファイルを `/code` ディレクトリに直接コピーします。
2. Uvicornを実行し、`main`から`app`オブジェクトをインポートするように指示します(`app.main`からインポートするのではなく)。
次にUvicornコマンドを調整して、`app.main` の代わりに新しいモジュール `main` を使用し、FastAPIオブジェクトである `app` をインポートします。
## デプロイメントのコンセプト
コンテナという観点から、[デプロイのコンセプト](./concepts.md){.internal-link target=_blank}に共通するいくつかについて、もう一度説明しましょう。
コンテナは主に、アプリケーションの**ビルドとデプロイ**のプロセスを簡素化するためのツールですが、これらの**デプロイのコンセプト**を扱うための特定のアプローチを強制するものではないです。
**良いニュース**は、それぞれの異なる戦略には、すべてのデプロイメントのコンセプトをカバーする方法があるということです。🎉
これらの**デプロイメントのコンセプト**をコンテナの観点から見直してみましょう:
* セキュリティ - HTTPS
* 起動時の実行
* 再起動
* **レプリケーション(実行中のプロセス数)**
* メモリ
* 開始前の事前ステップ
## HTTPS
FastAPI アプリケーションの **コンテナ・イメージ**(および後で実行中の **コンテナ**だけに焦点を当てると、通常、HTTPSは別のツールを用いて**外部で**処理されます。
例えば<a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>のように、**HTTPS**と**証明書**の**自動**取得を扱う別のコンテナである可能性もあります。
!!! tip
TraefikはDockerやKubernetesなどと統合されているので、コンテナ用のHTTPSの設定や構成はとても簡単です。
あるいは、コンテナ内でアプリケーションを実行しながらクラウド・プロバイダーがサービスの1つとしてHTTPSを処理することもできます。
## 起動時および再起動時の実行
通常、コンテナの**起動と実行**を担当する別のツールがあります。
それは直接**Docker**であったり、**Docker Compose**であったり、**Kubernetes**であったり、**クラウドサービス**であったりします。
ほとんどの場合またはすべての場合、起動時にコンテナを実行し、失敗時に再起動を有効にする簡単なオプションがあります。例えばDockerでは、コマンドラインオプションの`--restart`が該当します。
コンテナを使わなければ、アプリケーションを起動時や再起動時に実行させるのは面倒で難しいかもしれません。しかし、**コンテナ**で作業する場合、ほとんどのケースでその機能はデフォルトで含まれています。✨
## レプリケーション - プロセス数
**Kubernetes** や Docker Swarm モード、Nomad、あるいは複数のマシン上で分散コンテナを管理するための同様の複雑なシステムを使ってマシンの<abbr title="何らかの方法で接続され、一緒に動作するように構成されたマシンのグループ">クラスター</abbr>を構成している場合、 各コンテナでWorkerを持つGunicornのような**プロセスマネージャ**を使用する代わりに、**クラスター・レベル**で**レプリケーション**を処理したいと思うでしょう。
Kubernetesのような分散コンテナ管理システムの1つは通常、入ってくるリクエストの**ロードバランシング**をサポートしながら、**コンテナのレプリケーション**を処理する統合された方法を持っています。このことはすべて**クラスタレベル**にてです。
そのような場合、UvicornワーカーでGunicornのようなものを実行するのではなく、[上記の説明](#dockerfile)のように**Dockerイメージをゼロから**ビルドし、依存関係をインストールして、**単一のUvicornプロセス**を実行したいでしょう。
### ロードバランサー
コンテナを使用する場合、通常はメイン・ポート**でリスニング**しているコンポーネントがあるはずです。それはおそらく、**HTTPS**を処理するための**TLS Termination Proxy**でもある別のコンテナであったり、同様のツールであったりするでしょう。
このコンポーネントはリクエストの **負荷** を受け、 (うまくいけば) その負荷を**バランスよく** ワーカーに分配するので、一般に **ロードバランサ** とも呼ばれます。
!!! tip
  HTTPSに使われるものと同じ**TLS Termination Proxy**コンポーネントは、おそらく**ロードバランサー**にもなるでしょう。
そしてコンテナで作業する場合、コンテナの起動と管理に使用する同じシステムには、**ロードバランサー****TLS Termination Proxy**の可能性もある)から**ネットワーク通信**HTTPリクエストなどをアプリのあるコンテナ複数可に送信するための内部ツールが既にあるはずです。
### 1つのロードバランサー - 複数のワーカーコンテナー
**Kubernetes**や同様の分散コンテナ管理システムで作業する場合、その内部のネットワーキングのメカニズムを使用することで、メインの**ポート**でリッスンしている単一の**ロードバランサー**が、アプリを実行している可能性のある**複数のコンテナ**に通信(リクエスト)を送信できるようになります。
アプリを実行するこれらのコンテナには、通常**1つのプロセス**たとえば、FastAPIアプリケーションを実行するUvicornプロセスがあります。これらはすべて**同一のコンテナ**であり同じものを実行しますが、それぞれが独自のプロセスやメモリなどを持ちます。そうすることで、CPUの**異なるコア**、あるいは**異なるマシン**での**並列化**を利用できます。
そして、**ロードバランサー**を備えた分散コンテナシステムは、**順番に**あなたのアプリを含む各コンテナに**リクエストを分配**します。つまり、各リクエストは、あなたのアプリを実行している複数の**レプリケートされたコンテナ**の1つによって処理されます。
そして通常、この**ロードバランサー**は、クラスタ内の*他の*アプリケーション例えば、異なるドメインや異なるURLパスのプレフィックスの配下へのリクエストを処理することができ、その通信をクラスタ内で実行されている*他の*アプリケーションのための適切なコンテナに送信します。
### 1コンテナにつき1プロセス
この種のシナリオでは、すでにクラスタ・レベルでレプリケーションを処理しているため、おそらくコンテナごとに**単一のUvicornプロセス**を持ちたいでしょう。
この場合、Uvicornワーカーを持つGunicornのようなプロセスマネージャーや、Uvicornワーカーを使うUvicornは**避けたい**でしょう。**コンテナごとにUvicornのプロセスは1つだけ**にしたいでしょう(おそらく複数のコンテナが必要でしょう)。
GunicornやUvicornがUvicornワーカーを管理するようにコンテナ内に別のプロセスマネージャーを持つことは、クラスターシステムですでに対処しているであろう**不要な複雑さ**を追加するだけです。
### Containers with Multiple Processes and Special Cases
もちろん、**特殊なケース**として、**Gunicornプロセスマネージャ**を持つ**コンテナ**内で複数の**Uvicornワーカープロセス**を起動させたい場合があります。
このような場合、**公式のDockerイメージ**を使用することができます。このイメージには、複数の**Uvicornワーカープロセス**を実行するプロセスマネージャとして**Gunicorn**が含まれており、現在のCPUコアに基づいてワーカーの数を自動的に調整するためのデフォルト設定がいくつか含まれています。詳しくは後述の[Gunicornによる公式Dockerイメージ - Uvicorn](#gunicornによる公式dockerイメージ---Uvicorn)で説明します。
以下は、それが理にかなっている場合の例です:
#### シンプルなアプリケーション
アプリケーションを**シンプル**な形で実行する場合、プロセス数の細かい調整が必要ない場合、自動化されたデフォルトを使用するだけで、コンテナ内にプロセスマネージャが必要かもしれません。例えば、公式Dockerイメージでシンプルな設定が可能です。
#### Docker Compose
Docker Composeで**シングルサーバ**(クラスタではない)にデプロイすることもできますので、共有ネットワークと**ロードバランシング**を維持しながらDocker Composeでコンテナのレプリケーションを管理する簡単な方法はないでしょう。
その場合、**単一のコンテナ**で、**プロセスマネージャ**が内部で**複数のワーカープロセス**を起動するようにします。
#### Prometheusとその他の理由
また、**1つのコンテナ**に**1つのプロセス**を持たせるのではなく、**1つのコンテナ**に**複数のプロセス**を持たせる方が簡単だという**他の理由**もあるでしょう。
例えば、(セットアップにもよりますが)Prometheusエクスポーターのようなツールを同じコンテナ内に持つことができます。
この場合、**複数のコンテナ**があると、デフォルトでは、Prometheusが**メトリクスを**読みに来たとき、すべてのレプリケートされたコンテナの**蓄積されたメトリクス**を取得するのではなく、毎回**単一のコンテナ**(その特定のリクエストを処理したコンテナ)のものを取得することになります。
その場合、**複数のプロセス**を持つ**1つのコンテナ**を用意し、同じコンテナ上のローカルツール例えばPrometheusエクスポーターがすべての内部プロセスのPrometheusメトリクスを収集し、その1つのコンテナ上でそれらのメトリクスを公開する方がシンプルかもしれません。
---
次のセクションに進み、この情報とツールを使用して、すべてを組み合わせます。
重要なのは、盲目的に従わなければならない普遍のルールはないということです。
## TraefikとHTTPSを使用したDocker Swarmモードのクラスタ
これらのアイデアは、**あなた自身のユースケース**を評価し、あなたのシステムに最適なアプローチを決定するために使用することができます:
HTTPSを処理する証明書の取得と更新を含むTraefikを使用して、Docker Swarmモードのクラスタを数分20分程度でセットアップできます。
* セキュリティ - HTTPS
* 起動時の実行
* 再起動
* **レプリケーション(実行中のプロセス数)**
* メモリ
* 開始前の事前ステップ
Docker Swarmモードを使用することで、1台のマシンの「クラスタ」から開始でき1か月あたり5ドルのサーバーでもできます、後から必要なだけサーバーを拡張できます。
## メモリー
TraefikおよびHTTPS処理を備えたDocker Swarm Modeクラスターをセットアップするには、次のガイドに従います:
コンテナごとに**単一のプロセスを実行する**と、それらのコンテナレプリケートされている場合は1つ以上によって消費される多かれ少なかれ明確に定義された、安定し制限された量のメモリを持つことになります
### <a href="https://medium.com/@tiangolo/docker-swarm-mode-and-traefik-for-a-https-cluster-20328dba6232" class="external-link" target="_blank">Docker Swarm Mode and Traefik for an HTTPS cluster</a>
そして、コンテナ管理システム(**Kubernetes**など)の設定で、同じメモリ制限と要件を設定することができます。
### FastAPIアプリケーションのデプロイ
そうすれば、コンテナが必要とするメモリ量とクラスタ内のマシンで利用可能なメモリ量を考慮して、**利用可能なマシン**に**コンテナ**をレプリケートできるようになります。
すべてを設定するための最も簡単な方法は、[**FastAPI** Project Generators](../project-generation.md){.internal-link target=_blank}を使用することでしょう
アプリケーションが**シンプル**なものであれば、これはおそらく**問題にはならない**でしょうし、ハードなメモリ制限を指定する必要はないかもしれないです
上述したTraefikとHTTPSを備えたDocker Swarm クラスタが統合されるように設計されています。
しかし、**多くのメモリを使用**している場合(たとえば**機械学習**モデルなど)、どれだけのメモリを消費しているかを確認し、**各マシンで実行するコンテナの数**を調整する必要があります(そしておそらくクラスタにマシンを追加します
2分程度でプロジェクトが生成されます。
**コンテナごとに複数のプロセス**を実行する場合たとえば公式のDockerイメージで、起動するプロセスの数が**利用可能なメモリ以上に消費しない**ようにする必要があります。
生成されたプロジェクトはデプロイの指示がありますが、それを実行するとさらに2分かかります。
## 開始前の事前ステップとコンテナ
コンテナDockerやKubernetesなどを使っている場合、主に2つのアプローチがあります。
### 複数のコンテナ
複数の**コンテナ**があり、おそらくそれぞれが**単一のプロセス**を実行している場合(**Kubernetes**クラスタなど)、レプリケートされたワーカーコンテナを実行する**前に**、単一のコンテナで**事前のステップ**の作業を行う**別のコンテナ**を持ちたいと思うでしょう。
!!! info
もしKubernetesを使用している場合, これはおそらく<a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init コンテナ</a>でしょう。
ユースケースが事前のステップを**並列で複数回**実行するのに問題がない場合(例:データベースの準備チェック)、メインプロセスを開始する前に、それらのステップを各コンテナに入れることが可能です。
### 単一コンテナ
単純なセットアップで、**単一のコンテナ**で複数の**ワーカー・プロセス**または1つのプロセスのみを起動する場合、アプリでプロセスを開始する直前に、同じコンテナで事前のステップを実行できます。公式Dockerイメージは、内部的にこれをサポートしています。
## Gunicornによる公式Dockerイメージ - Uvicorn
前の章で詳しく説明したように、Uvicornワーカーで動作するGunicornを含む公式のDockerイメージがあります [Server Workers - Gunicorn と Uvicorn](./server-workers.md){.internal-link target=_blank}で詳しく説明しています。
このイメージは、主に上記で説明した状況で役に立つでしょう: [複数のプロセスと特殊なケースを持つコンテナContainers with Multiple Processes and Special Cases](#containers-with-multiple-processes-and-special-cases)
* <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
!!! warning
このベースイメージや類似のイメージは**必要ない**可能性が高いので、[上記の: FastAPI用のDockerイメージをビルドするBuild a Docker Image for FastAPI](#build-a-docker-image-for-fastapi)のようにゼロからイメージをビルドする方が良いでしょう。
このイメージには、利用可能なCPUコアに基づいて**ワーカー・プロセスの数**を設定する**オートチューニング**メカニズムが含まれています。
これは**賢明なデフォルト**を備えていますが、**環境変数**や設定ファイルを使ってすべての設定を変更したり更新したりすることができます。
また、スクリプトで<a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker#pre_start_path" class="external-link" target="_blank">**開始前の事前ステップ**</a>を実行することもサポートしている。
!!! tip
すべての設定とオプションを見るには、Dockerイメージのページをご覧ください: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>
### 公式Dockerイメージのプロセス数
このイメージの**プロセス数**は、利用可能なCPU**コア**から**自動的に計算**されます。
つまり、CPUから可能な限り**パフォーマンス**を**引き出そう**とします。
また、**環境変数**などを使った設定で調整することもできます。
しかし、プロセスの数はコンテナが実行しているCPUに依存するため、**消費されるメモリの量**もそれに依存することになります。
そのため、機械学習モデルなどで大量のメモリを消費するアプリケーションで、サーバーのCPUコアが多いが**メモリが少ない**場合、コンテナは利用可能なメモリよりも多くのメモリを使おうとすることになります。
その結果、パフォーマンスが大幅に低下する(あるいはクラッシュする)可能性があります。🚨
### Dockerfileを作成する
この画像に基づいて`Dockerfile`を作成する方法を以下に示します:
```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
```
### より大きなアプリケーション
[複数のファイルを持つ大きなアプリケーション](../tutorial/bigger-applications.md){.internal-link target=_blank}を作成するセクションに従った場合、`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
```
### いつ使うのか
おそらく、**Kubernetes**(または他のもの)を使用していて、すでにクラスタレベルで複数の**コンテナ**で**レプリケーション**を設定している場合は、この公式ベースイメージ(または他の類似のもの)は**使用すべきではありません**。
そのような場合は、上記のように**ゼロから**イメージを構築する方がよいでしょう: [FastAPI用のDockerイメージをビルドするBuild a Docker Image for FastAPI](#build-a-docker-image-for-fastapi) を参照してください。
このイメージは、主に上記の[複数のプロセスと特殊なケースを持つコンテナContainers with Multiple Processes and Special Cases](#containers-with-multiple-processes-and-special-cases)で説明したような特殊なケースで役に立ちます。
例えば、アプリケーションが**シンプル**で、CPUに応じたデフォルトのプロセス数を設定すればうまくいく場合や、クラスタレベルでレプリケーションを手動で設定する手間を省きたい場合、アプリで複数のコンテナを実行しない場合などです。
または、**Docker Compose**でデプロイし、単一のサーバで実行している場合などです。
## コンテナ・イメージのデプロイ
コンテナDockerイメージを手に入れた後、それをデプロイするにはいくつかの方法があります。
例えば以下のリストの方法です:
* 単一サーバーの**Docker Compose**
* **Kubernetes**クラスタ
* Docker Swarmモードのクラスター
* Nomadのような別のツール
* コンテナ・イメージをデプロイするクラウド・サービス
## Poetryを利用したDockerイメージ
もしプロジェクトの依存関係を管理するために<a href="https://python-poetry.org/" class="external-link" target="_blank">Poetry</a>を利用する場合、マルチステージビルドを使うと良いでしょう。
```{ .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. これは最初のステージで、`requirements-stage`と名付けられます
2. `/tmp` を現在の作業ディレクトリに設定します
ここで `requirements.txt` というファイルを生成します。
3. このDockerステージにPoetryをインストールします
4. pyproject.toml``poetry.lock`ファイルを`/tmp` ディレクトリにコピーします
`./poetry.lock*`(末尾に`*`)を使用するため、そのファイルがまだ利用できない場合でもクラッシュすることはないです。
5. requirements.txt`ファイルを生成します
6. これは最後のステージであり、ここにあるものはすべて最終的なコンテナ・イメージに保存されます
7. 現在の作業ディレクトリを `/code` に設定します
8. `requirements.txt`ファイルを `/code` ディレクトリにコピーします
このファイルは前のDockerステージにしか存在しないため、`--from-requirements-stage`を使ってコピーします。
9. 生成された `requirements.txt` ファイルにあるパッケージの依存関係をインストールします
10. app` ディレクトリを `/code` ディレクトリにコピーします
11. uvicorn` コマンドを実行して、`app.main` からインポートした `app` オブジェクトを使用するように指示します
!!! tip
"+"の吹き出しをクリックすると、それぞれの行が何をするのかを見ることができます
**Dockerステージ**は`Dockerfile`の一部で、**一時的なコンテナイメージ**として動作します。
最初のステージは **Poetryのインストール**と Poetry の `pyproject.toml` ファイルからプロジェクトの依存関係を含む**`requirements.txt`を生成**するためだけに使用されます。
この `requirements.txt` ファイルは後半の **次のステージ**で `pip` と共に使用されます。
最終的なコンテナイメージでは、**最終ステージ**のみが保存されます。前のステージは破棄されます。
Poetryを使用する場合、**Dockerマルチステージビルド**を使用することは理にかなっています。
なぜなら、最終的なコンテナイメージにPoetryとその依存関係がインストールされている必要はなく、**必要なのは**プロジェクトの依存関係をインストールするために生成された `requirements.txt` ファイルだけだからです。
そして次の(そして最終的な)ステージでは、前述とほぼ同じ方法でイメージをビルドします。
### TLS Termination Proxyの裏側 - Poetry
繰り返しになりますが、NginxやTraefikのようなTLS Termination Proxyロードバランサーの後ろでコンテナを動かしている場合は、`--proxy-headers`オプションをコマンドに追加します:
```Dockerfile
CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
```
## まとめ
コンテナ・システム(例えば**Docker**や**Kubernetes**など)を使えば、すべての**デプロイメントのコンセプト**を扱うのがかなり簡単になります:
* セキュリティ - HTTPS
* 起動時の実行
* 再起動
* **レプリケーション(実行中のプロセス数)**
* メモリ
* 開始前の事前ステップ
ほとんどの場合、ベースとなるイメージは使用せず、公式のPython Dockerイメージをベースにした**コンテナイメージをゼロからビルド**します。
`Dockerfile`と**Dockerキャッシュ**内の命令の**順番**に注意することで、**ビルド時間を最小化**することができ、生産性を最大化することができます(そして退屈を避けることができます)。😎
特別なケースでは、FastAPI用の公式Dockerイメージを使いたいかもしれません。🤓

View File

@@ -0,0 +1,182 @@
# Server Workers - Gunicorn と Uvicorn
前回のデプロイメントのコンセプトを振り返ってみましょう:
* セキュリティ - HTTPS
* 起動時の実行
* 再起動
* **レプリケーション(実行中のプロセス数)**
* メモリ
* 開始前の事前ステップ
ここまでのドキュメントのチュートリアルでは、おそらくUvicornのような**サーバープログラム**を**単一のプロセス**で実行しています。
アプリケーションをデプロイする際には、**複数のコア**を利用し、そしてより多くのリクエストを処理できるようにするために、プロセスの**レプリケーション**を持つことを望むでしょう。
前のチャプターである[デプロイメントのコンセプト](./concepts.md){.internal-link target=_blank}にて見てきたように、有効な戦略がいくつかあります。
ここでは<a href="https://gunicorn.org/" class="external-link" target="_blank">**Gunicorn**</a>が**Uvicornのワーカー・プロセス**を管理する場合の使い方について紹介していきます。
!!! info
<!-- NOTE: the current version of docker.md is outdated compared to English one. -->
DockerやKubernetesなどのコンテナを使用している場合は、次の章で詳しく説明します [コンテナ内のFastAPI - Docker](./docker.md){.internal-link target=_blank}
特に**Kubernetes**上で実行する場合は、おそらく**Gunicornを使用せず**、**コンテナごとに単一のUvicornプロセス**を実行することになりますが、それについてはこの章の後半で説明します。
## GunicornによるUvicornのワーカー・プロセスの管理
**Gunicorn**は**WSGI標準**のアプリケーションサーバーです。このことは、GunicornはFlaskやDjangoのようなアプリケーションにサービスを提供できることを意味します。Gunicornそれ自体は**FastAPI**と互換性がないですが、というのもFastAPIは最新の**<a href="https://asgi.readthedocs.io/en/latest/" class="external-link" target="_blank">ASGI 標準</a>**を使用しているためです。
しかし、Gunicornは**プロセスマネージャー**として動作し、ユーザーが特定の**ワーカー・プロセスクラス**を使用するように指示することができます。するとGunicornはそのクラスを使い1つ以上の**ワーカー・プロセス**を開始します。
そして**Uvicorn**には**Gunicorn互換のワーカークラス**があります。
この組み合わせで、Gunicornは**プロセスマネージャー**として動作し、**ポート**と**IP**をリッスンします。そして、**Uvicornクラス**を実行しているワーカー・プロセスに通信を**転送**します。
そして、Gunicorn互換の**Uvicornワーカー**クラスが、FastAPIが使えるように、Gunicornから送られてきたデータをASGI標準に変換する役割を担います。
## GunicornとUvicornをインストールする
<div class="termy">
```console
$ pip install "uvicorn[standard]" gunicorn
---> 100%
```
</div>
これによりUvicornと高性能を得るための標準`standard`の追加パッケージとGunicornの両方がインストールされます。
## UvicornのワーカーとともにGunicornを実行する
Gunicornを以下のように起動させることができます:
<div class="termy">
```console
$ gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:80
[19499] [INFO] Starting gunicorn 20.1.0
[19499] [INFO] Listening at: http://0.0.0.0:80 (19499)
[19499] [INFO] Using worker: uvicorn.workers.UvicornWorker
[19511] [INFO] Booting worker with pid: 19511
[19513] [INFO] Booting worker with pid: 19513
[19514] [INFO] Booting worker with pid: 19514
[19515] [INFO] Booting worker with pid: 19515
[19511] [INFO] Started server process [19511]
[19511] [INFO] Waiting for application startup.
[19511] [INFO] Application startup complete.
[19513] [INFO] Started server process [19513]
[19513] [INFO] Waiting for application startup.
[19513] [INFO] Application startup complete.
[19514] [INFO] Started server process [19514]
[19514] [INFO] Waiting for application startup.
[19514] [INFO] Application startup complete.
[19515] [INFO] Started server process [19515]
[19515] [INFO] Waiting for application startup.
[19515] [INFO] Application startup complete.
```
</div>
それぞれのオプションの意味を見てみましょう:
* `main:app` `main`は"`main`"という名前のPythonモジュール、つまりファイル`main.py`を意味します。そして `app`**FastAPI** アプリケーションの変数名です。
* main:app`はPythonの`import`文と同じようなものだと想像できます:
```Python
from main import app
```
* つまり、`main:app`のコロンは、`from main import app`のPythonの`import`の部分と同じになります。
* `--workers` 使用するワーカー・プロセスの数で、それぞれがUvicornのワーカーを実行します。
* `--worker-class` ワーカー・プロセスで使用するGunicorn互換のワーカークラスです。
* ここではGunicornがインポートして使用できるクラスを渡します
```Python
import uvicorn.workers.UvicornWorker
```
* `--bind` GunicornにリッスンするIPとポートを伝えます。コロン(`:`)でIPとポートを区切ります。
* Uvicornを直接実行している場合は、`--bind 0.0.0.0:80` Gunicornのオプションの代わりに、`--host 0.0.0.0`と `--port 80`を使います。
出力では、各プロセスの**PID**プロセスIDが表示されているのがわかります単なる数字です
以下の通りです:
* Gunicornの**プロセス・マネージャー**はPID `19499`(あなたの場合は違う番号でしょう)で始まります。
* 次に、`Listening at: http://0.0.0.0:80`を開始します。
* それから `uvicorn.workers.UvicornWorker` でワーカークラスを使用することを検出します。
* そして、**4つのワーカー**を起動します。それぞれのワーカーのPIDは、`19511`、`19513`、`19514`、`19515`です。
Gunicornはまた、ワーカーの数を維持するために必要であれば、**ダウンしたプロセス**を管理し、**新しいプロセスを**再起動**させます。そのため、上記のリストにある**再起動**の概念に一部役立ちます。
しかしながら、必要であればGunicornを**再起動**させ、**起動時に実行**させるなど、外部のコンポーネントを持たせることも必要かもしれません。
## Uvicornとワーカー
Uvicornには複数の**ワーカー・プロセス**を起動し実行するオプションもあります。
とはいうものの、今のところUvicornのワーカー・プロセスを扱う機能はGunicornよりも制限されています。そのため、このレベルPythonレベルでプロセスマネージャーを持ちたいのであれば、Gunicornをプロセスマネージャーとして使ってみた方が賢明かもしれないです。
どんな場合であれ、以下のように実行します:
<div class="termy">
```console
$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
<font color="#A6E22E">INFO</font>: Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)
<font color="#A6E22E">INFO</font>: Started parent process [<font color="#A1EFE4"><b>27365</b></font>]
<font color="#A6E22E">INFO</font>: Started server process [<font color="#A1EFE4">27368</font>]
<font color="#A6E22E">INFO</font>: Waiting for application startup.
<font color="#A6E22E">INFO</font>: Application startup complete.
<font color="#A6E22E">INFO</font>: Started server process [<font color="#A1EFE4">27369</font>]
<font color="#A6E22E">INFO</font>: Waiting for application startup.
<font color="#A6E22E">INFO</font>: Application startup complete.
<font color="#A6E22E">INFO</font>: Started server process [<font color="#A1EFE4">27370</font>]
<font color="#A6E22E">INFO</font>: Waiting for application startup.
<font color="#A6E22E">INFO</font>: Application startup complete.
<font color="#A6E22E">INFO</font>: Started server process [<font color="#A1EFE4">27367</font>]
<font color="#A6E22E">INFO</font>: Waiting for application startup.
<font color="#A6E22E">INFO</font>: Application startup complete.
```
</div>
ここで唯一の新しいオプションは `--workers` で、Uvicornに4つのワーカー・プロセスを起動するように指示しています。
各プロセスの **PID** が表示され、親プロセスの `27365` (これは **プロセスマネージャ**) と、各ワーカー・プロセスの **PID** が表示されます: `27368`、`27369`、`27370`、`27367`になります。
## デプロイメントのコンセプト
ここでは、アプリケーションの実行を**並列化**し、CPUの**マルチコア**を活用し、**より多くのリクエスト**に対応できるようにするために、**Gunicorn**またはUvicornを使用して**Uvicornワーカー・プロセス**を管理する方法を見ていきました。
上記のデプロイのコンセプトのリストから、ワーカーを使うことは主に**レプリケーション**の部分と、**再起動**を少し助けてくれます:
* セキュリティ - HTTPS
* 起動時の実行
* 再起動
* レプリケーション(実行中のプロセス数)
* メモリー
* 開始前の事前のステップ
## コンテナとDocker
<!-- NOTE: the current version of docker.md is outdated compared to English one. -->
次章の[コンテナ内のFastAPI - Docker](./docker.md){.internal-link target=_blank}では、その他の**デプロイのコンセプト**を扱うために実施するであろう戦略をいくつか紹介します。
また、**GunicornとUvicornワーカー**を含む**公式Dockerイメージ**と、簡単なケースに役立ついくつかのデフォルト設定も紹介します。
また、(Gunicornを使わずに)Uvicornプロセスを1つだけ実行するために、**ゼロから独自のイメージを**構築する方法も紹介します。これは簡単なプロセスで、おそらく**Kubernetes**のような分散コンテナ管理システムを使うときにやりたいことでしょう。
## まとめ
Uvicornワーカーを使ったプロセスマネージャとして**Gunicorn**またはUvicornを使えば、**マルチコアCPU**を活用して**複数のプロセスを並列実行**できます。
これらのツールやアイデアは、**あなた自身のデプロイシステム**をセットアップしながら、他のデプロイコンセプトを自分で行う場合にも使えます。
次の章では、コンテナDockerやKubernetesなどを使った**FastAPI**について学んでいきましょう。これらのツールには、他の**デプロイのコンセプト**も解決する簡単な方法があることがわかるでしょう。✨

404
docs/ko/docs/async.md Normal file
View File

@@ -0,0 +1,404 @@
# 동시성과 async / await
*경로 작동 함수*에서의 `async def` 문법에 대한 세부사항과 비동기 코드, 동시성 및 병렬성에 대한 배경
## <a name="in-a-hurry"></a>바쁘신 경우
<strong>요약</strong>
다음과 같이 `await`를 사용해 호출하는 제3의 라이브러리를 사용하는 경우:
```Python
results = await some_library()
```
다음처럼 *경로 작동 함수*를 `async def`를 사용해 선언하십시오:
```Python hl_lines="2"
@app.get('/')
async def read_results():
results = await some_library()
return results
```
!!! note "참고"
`async def`로 생성된 함수 내부에서만 `await`를 사용할 수 있습니다.
---
데이터베이스, API, 파일시스템 등과 의사소통하는 제3의 라이브러리를 사용하고, 그것이 `await`를 지원하지 않는 경우(현재 거의 모든 데이터베이스 라이브러리가 그러합니다), *경로 작동 함수*를 일반적인 `def`를 사용해 선언하십시오:
```Python hl_lines="2"
@app.get('/')
def results():
results = some_library()
return results
```
---
만약 당신의 응용프로그램이 (어째서인지) 다른 무엇과 의사소통하고 그것이 응답하기를 기다릴 필요가 없다면 `async def`를 사용하십시오.
---
모르겠다면, 그냥 `def`를 사용하십시오.
---
**참고**: *경로 작동 함수*에서 필요한만큼 `def`와 `async def`를 혼용할 수 있고, 가장 알맞은 것을 선택해서 정의할 수 있습니다. FastAPI가 자체적으로 알맞은 작업을 수행할 것입니다.
어찌되었든, 상기 어떠한 경우라도, FastAPI는 여전히 비동기적으로 작동하고 매우 빠릅니다.
그러나 상기 작업을 수행함으로써 어느 정도의 성능 최적화가 가능합니다.
## 기술적 세부사항
최신 파이썬 버전은 `async`와 `await` 문법과 함께 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 지원합니다.
아래 섹션들에서 해당 문장을 부분별로 살펴보겠습니다:
* **비동기 코드**
* **`async`와 `await`**
* **코루틴**
## 비동기 코드
비동기 코드란 언어 💬 가 코드의 어느 한 부분에서, 컴퓨터 / 프로그램🤖에게 *다른 무언가*가 어딘가에서 끝날 때까지 기다려야한다고 말하는 방식입니다. *다른 무언가*가 “느린-파일" 📝 이라고 불린다고 가정해봅시다.
따라서 “느린-파일” 📝이 끝날때까지 컴퓨터는 다른 작업을 수행할 수 있습니다.
그 다음 컴퓨터 / 프로그램 🤖 은 다시 기다리고 있기 때문에 기회가 있을 때마다 다시 돌아오거나, 혹은 당시에 수행해야하는 작업들이 완료될 때마다 다시 돌아옵니다. 그리고 그것 🤖 은 기다리고 있던 작업 중 어느 것이 이미 완료되었는지, 그것 🤖 이 해야하는 모든 작업을 수행하면서 확인합니다.
다음으로, 그것 🤖 은 완료할 첫번째 작업에 착수하고(우리의 "느린-파일" 📝 이라고 가정합시다) 그에 대해 수행해야하는 작업을 계속합니다.
"다른 무언가를 기다리는 것"은 일반적으로 비교적 "느린" (프로세서와 RAM 메모리 속도에 비해) <abbr title="Input and Output">I/O</abbr> 작업을 의미합니다. 예를 들면 다음의 것들을 기다리는 것입니다:
* 네트워크를 통해 클라이언트로부터 전송되는 데이터
* 네트워크를 통해 클라이언트가 수신할, 당신의 프로그램으로부터 전송되는 데이터
* 시스템이 읽고 프로그램에 전달할 디스크 내의 파일 내용
* 당신의 프로그램이 시스템에 전달하는, 디스크에 작성될 내용
* 원격 API 작업
* 완료될 데이터베이스 작업
* 결과를 반환하는 데이터베이스 쿼리
* 기타
수행 시간의 대부분이 <abbr title="Input and Output">I/O</abbr> 작업을 기다리는데에 소요되기 때문에, "I/O에 묶인" 작업이라고 불립니다.
이것은 "비동기"라고 불리는데 컴퓨터 / 프로그램이 작업 결과를 가지고 일을 수행할 수 있도록, 느린 작업에 "동기화"되어 아무것도 하지 않으면서 작업이 완료될 정확한 시점만을 기다릴 필요가 없기 때문입니다.
이 대신에, "비동기" 시스템에서는, 작업은 일단 완료되면, 컴퓨터 / 프로그램이 수행하고 있는 일을 완료하고 이후 다시 돌아와서 그것의 결과를 받아 이를 사용해 작업을 지속할 때까지 잠시 (몇 마이크로초) 대기할 수 있습니다.
"동기"("비동기"의 반대)는 컴퓨터 / 프로그램이 상이한 작업들간 전환을 하기 전에 그것이 대기를 동반하게 될지라도 모든 순서를 따르기 때문에 "순차"라는 용어로도 흔히 불립니다.
### 동시성과 버거
위에서 설명한 **비동기** 코드에 대한 개념은 종종 **"동시성"**이라고도 불립니다. 이것은 **"병렬성"**과는 다릅니다.
**동시성**과 **병렬성**은 모두 "동시에 일어나는 서로 다른 일들"과 관련이 있습니다.
하지만 *동시성*과 *병렬성*의 세부적인 개념에는 꽤 차이가 있습니다.
차이를 확인하기 위해, 다음의 버거에 대한 이야기를 상상해보십시오:
### 동시 버거
당신은 짝사랑 상대 😍 와 패스트푸드 🍔 를 먹으러 갔습니다. 당신은 점원 💁 이 당신 앞에 있는 사람들의 주문을 받을 동안 줄을 서서 기다리고 있습니다.
이제 당신의 순서가 되어서, 당신은 당신과 짝사랑 상대 😍 를 위한 두 개의 고급스러운 버거 🍔 를 주문합니다.
당신이 돈을 냅니다 💸.
점원 💁 은 주방 👨‍🍳 에 요리를 하라고 전달하고, 따라서 그들은 당신의 버거 🍔 를 준비해야한다는 사실을 알게됩니다(그들이 지금은 당신 앞 고객들의 주문을 준비하고 있을지라도 말입니다).
점원 💁 은 당신의 순서가 적힌 번호표를 줍니다.
기다리는 동안, 당신은 짝사랑 상대 😍 와 함께 테이블을 고르고, 자리에 앉아 오랫동안 (당신이 주문한 버거는 꽤나 고급스럽기 때문에 준비하는데 시간이 조금 걸립니다 ✨🍔✨) 대화를 나눕니다.
짝사랑 상대 😍 와 테이블에 앉아서 버거 🍔 를 기다리는 동안, 그 사람 😍 이 얼마나 멋지고, 사랑스럽고, 똑똑한지 감탄하며 시간을 보냅니다 ✨😍✨.
짝사랑 상대 😍 와 기다리면서 얘기하는 동안, 때때로, 당신은 당신의 차례가 되었는지 보기 위해 카운터의 번호를 확인합니다.
그러다 어느 순간, 당신의 차례가 됩니다. 카운터에 가서, 버거 🍔 를 받고, 테이블로 다시 돌아옵니다.
당신과 짝사랑 상대 😍 는 버거 🍔 를 먹으며 좋은 시간을 보냅니다 ✨.
---
당신이 이 이야기에서 컴퓨터 / 프로그램 🤖 이라고 상상해보십시오.
줄을 서서 기다리는 동안, 당신은 아무것도 하지 않고 😴 당신의 차례를 기다리며, 어떠한 "생산적인" 일도 하지 않습니다. 하지만 점원 💁 이 (음식을 준비하지는 않고) 주문을 받기만 하기 때문에 줄이 빨리 줄어들어서 괜찮습니다.
그다음, 당신이 차례가 오면, 당신은 실제로 "생산적인" 일 🤓 을 합니다. 당신은 메뉴를 보고, 무엇을 먹을지 결정하고, 짝사랑 상대 😍 의 선택을 묻고, 돈을 내고 💸 , 맞는 카드를 냈는지 확인하고, 비용이 제대로 지불되었는지 확인하고, 주문이 제대로 들어갔는지 확인을 하는 작업 등등을 수행합니다.
하지만 이후에는, 버거 🍔 를 아직 받지 못했음에도, 버거가 준비될 때까지 기다려야 🕙 하기 때문에 점원 💁 과의 작업은 "일시정지" ⏸ 상태입니다.
하지만 번호표를 받고 카운터에서 나와 테이블에 앉으면, 당신은 짝사랑 상대 😍 와 그 "작업" ⏯ 🤓 에 번갈아가며 🔀 집중합니다. 그러면 당신은 다시 짝사랑 상대 😍 에게 작업을 거는 매우 "생산적인" 일 🤓 을 합니다.
점원 💁 이 카운터 화면에 당신의 번호를 표시함으로써 "버거 🍔 가 준비되었습니다"라고 해도, 당신은 즉시 뛰쳐나가지는 않을 것입니다. 당신은 당신의 번호를 갖고있고, 다른 사람들은 그들의 번호를 갖고있기 때문에, 아무도 당신의 버거 🍔 를 훔쳐가지 않는다는 사실을 알기 때문입니다.
그래서 당신은 짝사랑 상대 😍 가 이야기를 끝낼 때까지 기다린 후 (현재 작업 완료 ⏯ / 진행 중인 작업 처리 🤓 ), 정중하게 미소짓고 버거를 가지러 가겠다고 말합니다 ⏸.
그다음 당신은 카운터에 가서 🔀 , 초기 작업을 이제 완료하고 ⏯ , 버거 🍔 를 받고, 감사하다고 말하고 테이블로 가져옵니다. 이로써 카운터와의 상호작용 단계 / 작업이 종료됩니다 ⏹.
이전 작업인 "버거 받기"가 종료되면 ⏹ "버거 먹기"라는 새로운 작업이 생성됩니다 🔀 ⏯.
### 병렬 버거
이제 "동시 버거"가 아닌 "병렬 버거"를 상상해보십시오.
당신은 짝사랑 상대 😍 와 함께 병렬 패스트푸드 🍔 를 먹으러 갔습니다.
당신은 여러명(8명이라고 가정합니다)의 점원이 당신 앞 사람들의 주문을 받으며 동시에 요리 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳 도 하는 동안 줄을 서서 기다립니다.
당신 앞 모든 사람들이 버거가 준비될 때까지 카운터에서 떠나지 않고 기다립니다 🕙 . 왜냐하면 8명의 직원들이 다음 주문을 받기 전에 버거를 준비하러 가기 때문입니다.
마침내 당신의 차례가 왔고, 당신은 당신과 짝사랑 상대 😍 를 위한 두 개의 고급스러운 버거 🍔 를 주문합니다.
당신이 비용을 지불합니다 💸 .
점원이 주방에 갑니다 👨‍🍳 .
당신은 번호표가 없기 때문에 누구도 당신의 버거 🍔 를 대신 가져갈 수 없도록 카운터에 서서 기다립니다 🕙 .
당신과 짝사랑 상대 😍 는 다른 사람이 새치기해서 버거를 가져가지 못하게 하느라 바쁘기 때문에 🕙 , 짝사랑 상대에게 주의를 기울일 수 없습니다 😞 .
이것은 "동기" 작업이고, 당신은 점원/요리사 👨‍🍳 와 "동기화" 되었습니다. 당신은 기다리고 🕙 , 점원/요리사 👨‍🍳 가 버거 🍔 준비를 완료한 후 당신에게 주거나, 누군가가 그것을 가져가는 그 순간에 그 곳에 있어야합니다.
카운터 앞에서 오랫동안 기다린 후에 🕙 , 점원/요리사 👨‍🍳 가 당신의 버거 🍔 를 가지고 돌아옵니다.
당신은 버거를 받고 짝사랑 상대와 함께 테이블로 돌아옵니다.
단지 먹기만 하다가, 다 먹었습니다 🍔 ⏹.
카운터 앞에서 기다리면서 🕙 너무 많은 시간을 허비했기 때문에 대화를 하거나 작업을 걸 시간이 거의 없었습니다 😞 .
---
이 병렬 버거 시나리오에서, 당신은 기다리고 🕙 , 오랜 시간동안 "카운터에서 기다리는" 🕙 데에 주의를 기울이는 ⏯ 두 개의 프로세서(당신과 짝사랑 상대😍)를 가진 컴퓨터 / 프로그램 🤖 입니다.
패스트푸드점에는 8개의 프로세서(점원/요리사) 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳 가 있습니다. 동시 버거는 단 두 개(한 명의 직원과 한 명의 요리사) 💁 👨‍🍳 만을 가지고 있었습니다.
하지만 여전히, 병렬 버거 예시가 최선은 아닙니다 😞 .
---
이 예시는 버거🍔 이야기와 결이 같습니다.
더 "현실적인" 예시로, 은행을 상상해보십시오.
최근까지, 대다수의 은행에는 다수의 은행원들 👨‍💼👨‍💼👨‍💼👨‍💼 과 긴 줄 🕙🕙🕙🕙🕙🕙🕙🕙 이 있습니다.
모든 은행원들은 한 명 한 명의 고객들을 차례로 상대합니다 👨‍💼⏯ .
그리고 당신은 오랫동안 줄에서 기다려야하고 🕙 , 그렇지 않으면 당신의 차례를 잃게 됩니다.
아마 당신은 은행 🏦 심부름에 짝사랑 상대 😍 를 데려가고 싶지는 않을 것입니다.
### 버거 예시의 결론
"짝사랑 상대와의 패스트푸드점 버거" 시나리오에서, 오랜 기다림 🕙 이 있기 때문에 동시 시스템 ⏸🔀⏯ 을 사용하는 것이 더 합리적입니다.
대다수의 웹 응용프로그램의 경우가 그러합니다.
매우 많은 수의 유저가 있지만, 서버는 그들의 요청을 전송하기 위해 그닥-좋지-않은 연결을 기다려야 합니다 🕙 .
그리고 응답이 돌아올 때까지 다시 기다려야 합니다 🕙 .
이 "기다림" 🕙 은 마이크로초 단위이지만, 모두 더해지면, 결국에는 매우 긴 대기시간이 됩니다.
따라서 웹 API를 위해 비동기 ⏸🔀⏯ 코드를 사용하는 것이 합리적입니다.
대부분의 존재하는 유명한 파이썬 프레임워크 (Flask와 Django 등)은 새로운 비동기 기능들이 파이썬에 존재하기 전에 만들어졌습니다. 그래서, 그들의 배포 방식은 병렬 실행과 새로운 기능만큼 강력하지는 않은 예전 버전의 비동기 실행을 지원합니다.
비동기 웹 파이썬(ASGI)에 대한 주요 명세가 웹소켓을 지원하기 위해 Django에서 개발 되었음에도 그렇습니다.
이러한 종류의 비동기성은 (NodeJS는 병렬적이지 않음에도) NodeJS가 사랑받는 이유이고, 프로그래밍 언어로서의 Go의 강점입니다.
그리고 **FastAPI**를 사용함으로써 동일한 성능을 낼 수 있습니다.
또한 병렬성과 비동기성을 동시에 사용할 수 있기 때문에, 대부분의 테스트가 완료된 NodeJS 프레임워크보다 더 높은 성능을 얻고 C에 더 가까운 컴파일 언어인 Go와 동등한 성능을 얻을 수 있습니다<a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(모두 Starlette 덕분입니다)</a>.
### 동시성이 병렬성보다 더 나은가?
그렇지 않습니다! 그것이 이야기의 교훈은 아닙니다.
동시성은 병렬성과 다릅니다. 그리고 그것은 많은 대기를 필요로하는 **특정한** 시나리오에서는 더 낫습니다. 이로 인해, 웹 응용프로그램 개발에서 동시성이 병렬성보다 일반적으로 훨씬 낫습니다. 하지만 모든 경우에 그런 것은 아닙니다.
따라서, 균형을 맞추기 위해, 다음의 짧은 이야기를 상상해보십시오:
> 당신은 크고, 더러운 집을 청소해야합니다.
*네, 이게 전부입니다*.
---
어디에도 대기 🕙 는 없고, 집안 곳곳에서 해야하는 많은 작업들만 있습니다.
버거 예시처럼 처음에는 거실, 그 다음은 부엌과 같은 식으로 순서를 정할 수도 있으나, 무엇도 기다리지 🕙 않고 계속해서 청소 작업만 수행하기 때문에, 순서는 아무런 영향을 미치지 않습니다.
순서가 있든 없든 동일한 시간이 소요될 것이고(동시성) 동일한 양의 작업을 하게 될 것입니다.
하지만 이 경우에서, 8명의 전(前)-점원/요리사이면서-현(現)-청소부 👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳👩‍🍳👨‍🍳 를 고용할 수 있고, 그들 각자(그리고 당신)가 집의 한 부분씩 맡아 청소를 한다면, 당신은 **병렬적**으로 작업을 수행할 수 있고, 조금의 도움이 있다면, 훨씬 더 빨리 끝낼 수 있습니다.
이 시나리오에서, (당신을 포함한) 각각의 청소부들은 프로세서가 될 것이고, 각자의 역할을 수행합니다.
실행 시간의 대부분이 대기가 아닌 실제 작업에 소요되고, 컴퓨터에서 작업은 <abbr title="Central Processing Unit">CPU</abbr>에서 이루어지므로, 이러한 문제를 "CPU에 묶였"다고 합니다.
---
CPU에 묶인 연산에 관한 흔한 예시는 복잡한 수학 처리를 필요로 하는 경우입니다.
예를 들어:
* **오디오** 또는 **이미지** 처리.
* **컴퓨터 비전**: 하나의 이미지는 수백개의 픽셀로 구성되어있고, 각 픽셀은 3개의 값 / 색을 갖고 있으며, 일반적으로 해당 픽셀들에 대해 동시에 무언가를 계산해야하는 처리.
* **머신러닝**: 일반적으로 많은 "행렬"과 "벡터" 곱셈이 필요합니다. 거대한 스프레드 시트에 수들이 있고 그 수들을 동시에 곱해야 한다고 생각해보십시오.
* **딥러닝**: 머신러닝의 하위영역으로, 동일한 예시가 적용됩니다. 단지 이 경우에는 하나의 스프레드 시트에 곱해야할 수들이 있는 것이 아니라, 거대한 세트의 스프레드 시트들이 있고, 많은 경우에, 이 모델들을 만들고 사용하기 위해 특수한 프로세서를 사용합니다.
### 동시성 + 병렬성: 웹 + 머신러닝
**FastAPI**를 사용하면 웹 개발에서는 매우 흔한 동시성의 이점을 (NodeJS의 주된 매력만큼) 얻을 수 있습니다.
뿐만 아니라 머신러닝 시스템과 같이 **CPU에 묶인** 작업을 위해 병렬성과 멀티프로세싱(다수의 프로세스를 병렬적으로 동작시키는 것)을 이용하는 것도 가능합니다.
파이썬이 **데이터 사이언스**, 머신러닝과 특히 딥러닝에 의 주된 언어라는 간단한 사실에 더해서, 이것은 FastAPI를 데이터 사이언스 / 머신러닝 웹 API와 응용프로그램에 (다른 것들보다) 좋은 선택지가 되게 합니다.
배포시 병렬을 어떻게 가능하게 하는지 알고싶다면, [배포](/ko/deployment){.internal-link target=_blank}문서를 참고하십시오.
## `async`와 `await`
최신 파이썬 버전에는 비동기 코드를 정의하는 매우 직관적인 방법이 있습니다. 이는 이것을 평범한 "순차적" 코드로 보이게 하고, 적절한 순간에 당신을 위해 "대기"합니다.
연산이 결과를 전달하기 전에 대기를 해야하고 새로운 파이썬 기능들을 지원한다면, 이렇게 코드를 작성할 수 있습니다:
```Python
burgers = await get_burgers(2)
```
여기서 핵심은 `await`입니다. 이것은 파이썬에게 `burgers` 결과를 저장하기 이전에 `get_burgers(2)`의 작업이 완료되기를 🕙 기다리라고 ⏸ 말합니다. 이로 인해, 파이썬은 그동안 (다른 요청을 받는 것과 같은) 다른 작업을 수행해도 된다는 것을 🔀 ⏯ 알게될 것입니다.
`await`가 동작하기 위해, 이것은 비동기를 지원하는 함수 내부에 있어야 합니다. 이를 위해서 함수를 `async def`를 사용해 정의하기만 하면 됩니다:
```Python hl_lines="1"
async def get_burgers(number: int):
# Do some asynchronous stuff to create the burgers
return burgers
```
...`def`를 사용하는 대신:
```Python hl_lines="2"
# This is not asynchronous
def get_sequential_burgers(number: int):
# Do some sequential stuff to create the burgers
return burgers
```
`async def`를 사용하면, 파이썬은 해당 함수 내에서 `await` 표현에 주의해야한다는 사실과, 해당 함수의 실행을 "일시정지"⏸하고 다시 돌아오기 전까지 다른 작업을 수행🔀할 수 있다는 것을 알게됩니다.
`async def`f 함수를 호출하고자 할 때, "대기"해야합니다. 따라서, 아래는 동작하지 않습니다.
```Python
# This won't work, because get_burgers was defined with: async def
burgers = get_burgers(2)
```
---
따라서, `await`f를 사용해서 호출할 수 있는 라이브러리를 사용한다면, 다음과 같이 `async def`를 사용하는 *경로 작동 함수*를 생성해야 합니다:
```Python hl_lines="2-3"
@app.get('/burgers')
async def read_burgers():
burgers = await get_burgers(2)
return burgers
```
### 더 세부적인 기술적 사항
`await`가 `async def`를 사용하는 함수 내부에서만 사용이 가능하다는 것을 눈치채셨을 것입니다.
하지만 동시에, `async def`로 정의된 함수들은 "대기"되어야만 합니다. 따라서, `async def`를 사용한 함수들은 역시 `async def`를 사용한 함수 내부에서만 호출될 수 있습니다.
그렇다면 닭이 먼저냐, 달걀이 먼저냐, 첫 `async` 함수를 어떻게 호출할 수 있겠습니까?
**FastAPI**를 사용해 작업한다면 이것을 걱정하지 않아도 됩니다. 왜냐하면 그 "첫" 함수는 당신의 *경로 작동 함수*가 될 것이고, FastAPI는 어떻게 올바르게 처리할지 알고있기 때문입니다.
하지만 FastAPI를 사용하지 않고 `async` / `await`를 사용하고 싶다면, 이 역시 가능합니다.
### 당신만의 비동기 코드 작성하기
Starlette(그리고 FastAPI)는 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 기반으로 하고있고, 따라서 파이썬 표준 라이브러리인 <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> 및 <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>와 호환됩니다.
특히, 코드에서 고급 패턴이 필요한 고급 동시성을 사용하는 경우 직접적으로 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 사용할 수 있습니다.
FastAPI를 사용하지 않더라도, 높은 호환성 및 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>의 이점(예: *구조화된 동시성*)을 취하기 위해 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>를 사용해 비동기 응용프로그램을 작성할 수 있습니다.
### 비동기 코드의 다른 형태
파이썬에서 `async`와 `await`를 사용하게 된 것은 비교적 최근의 일입니다.
하지만 이로 인해 비동기 코드 작업이 훨씬 간단해졌습니다.
같은 (또는 거의 유사한) 문법은 최신 버전의 자바스크립트(브라우저와 NodeJS)에도 추가되었습니다.
하지만 그 이전에, 비동기 코드를 처리하는 것은 꽤 복잡하고 어려운 일이었습니다.
파이썬의 예전 버전이라면, 스레드 또는 <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>를 사용할 수 있을 것입니다. 하지만 코드를 이해하고, 디버깅하고, 이에 대해 생각하는게 훨씬 복잡합니다.
예전 버전의 NodeJS / 브라우저 자바스크립트라면, "콜백 함수"를 사용했을 것입니다. 그리고 이로 인해 <a href="http://callbackhell.com/" class="external-link" target="_blank">콜백 지옥</a>에 빠지게 될 수 있습니다.
## 코루틴
**코루틴**은 `async def` 함수가 반환하는 것을 칭하는 매우 고급스러운 용어일 뿐입니다. 파이썬은 그것이 시작되고 어느 시점에서 완료되지만 내부에 `await`가 있을 때마다 내부적으로 일시정지⏸될 수도 있는 함수와 유사한 것이라는 사실을 알고있습니다.
그러나 `async` 및 `await`와 함께 비동기 코드를 사용하는 이 모든 기능들은 "코루틴"으로 간단히 요약됩니다. 이것은 Go의 주된 핵심 기능인 "고루틴"에 견줄 수 있습니다.
## 결론
상기 문장을 다시 한 번 봅시다:
> 최신 파이썬 버전은 **`async` 및 `await`** 문법과 함께 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 지원합니다.
이제 이 말을 조금 더 이해할 수 있을 것입니다. ✨
이것이 (Starlette을 통해) FastAPI를 강하게 하면서 그것이 인상적인 성능을 낼 수 있게 합니다.
## 매우 세부적인 기술적 사항
!!! warning "경고"
이 부분은 넘어가도 됩니다.
이것들은 **FastAPI**가 내부적으로 어떻게 동작하는지에 대한 매우 세부적인 기술사항입니다.
만약 기술적 지식(코루틴, 스레드, 블록킹 등)이 있고 FastAPI가 어떻게 `async def` vs `def`를 다루는지 궁금하다면, 계속하십시오.
### 경로 작동 함수
경로 작동 함수를 `async def` 대신 일반적인 `def`로 선언하는 경우, (서버를 차단하는 것처럼) 그것을 직접 호출하는 대신 대기중인 외부 스레드풀에서 실행됩니다.
만약 상기에 묘사된대로 동작하지 않는 비동기 프로그램을 사용해왔고 약간의 성능 향상 (약 100 나노초)을 위해 `def`를 사용해서 계산만을 위한 사소한 *경로 작동 함수*를 정의해왔다면, **FastAPI**는 이와는 반대라는 것에 주의하십시오. 이러한 경우에, *경로 작동 함수*가 블로킹 <abbr title="Input/Output: 디스크 읽기 또는 쓰기, 네트워크 통신.">I/O</abbr>를 수행하는 코드를 사용하지 않는 한 `async def`를 사용하는 편이 더 낫습니다.
하지만 두 경우 모두, FastAPI가 당신이 전에 사용하던 프레임워크보다 [더 빠를](/#performance){.internal-link target=_blank} (최소한 비견될) 확률이 높습니다.
### 의존성
의존성에도 동일하게 적용됩니다. 의존성이 `async def`가 아닌 표준 `def` 함수라면, 외부 스레드풀에서 실행됩니다.
### 하위-의존성
함수 정의시 매개변수로 서로를 필요로하는 다수의 의존성과 하위-의존성을 가질 수 있고, 그 중 일부는 `async def`로, 다른 일부는 일반적인 `def`로 생성되었을 수 있습니다. 이것은 여전히 잘 동작하고, 일반적인 `def`로 생성된 것들은 "대기"되는 대신에 (스레드풀로부터) 외부 스레드에서 호출됩니다.
### 다른 유틸리티 함수
직접 호출되는 다른 모든 유틸리티 함수는 일반적인 `def`나 `async def`로 생성될 수 있고 FastAPI는 이를 호출하는 방식에 영향을 미치지 않습니다.
이것은 FastAPI가 당신을 위해 호출하는 함수와는 반대입니다: *경로 작동 함수*와 의존성
만약 당신의 유틸리티 함수가 `def`를 사용한 일반적인 함수라면, 스레드풀에서가 아니라 직접 호출(당신이 코드에 작성한 대로)될 것이고, `async def`로 생성된 함수라면 코드에서 호출할 때 그 함수를 `await` 해야 합니다.
---
다시 말하지만, 이것은 당신이 이것에 대해 찾고있던 경우에 한해 유용할 매우 세부적인 기술사항입니다.
그렇지 않은 경우, 상기의 가이드라인만으로도 충분할 것입니다: [바쁘신 경우](#in-a-hurry).

View File

@@ -1,258 +0,0 @@
# Implantação FastAPI na Deta
Nessa seção você aprenderá sobre como realizar a implantação de uma aplicação **FastAPI** na <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> utilizando o plano gratuito. 🎁
Isso tudo levará aproximadamente **10 minutos**.
!!! info "Informação"
<a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> é uma patrocinadora do **FastAPI**. 🎉
## Uma aplicação **FastAPI** simples
* Crie e entre em um diretório para a sua aplicação, por exemplo, `./fastapideta/`.
### Código FastAPI
* Crie o arquivo `main.py` com:
```Python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}
```
### Requisitos
Agora, no mesmo diretório crie o arquivo `requirements.txt` com:
```text
fastapi
```
!!! tip "Dica"
Você não precisa instalar Uvicorn para realizar a implantação na Deta, embora provavelmente queira instalá-lo para testar seu aplicativo localmente.
### Estrutura de diretório
Agora você terá o diretório `./fastapideta/` com dois arquivos:
```
.
└── main.py
└── requirements.txt
```
## Crie uma conta gratuita na Deta
Agora crie <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">uma conta gratuita na Deta</a>, você precisará apenas de um email e senha.
Você nem precisa de um cartão de crédito.
## Instale a CLI
Depois de ter sua conta criada, instale Deta <abbr title="Interface de Linha de Comando">CLI</abbr>:
=== "Linux, macOS"
<div class="termy">
```console
$ curl -fsSL https://get.deta.dev/cli.sh | sh
```
</div>
=== "Windows PowerShell"
<div class="termy">
```console
$ iwr https://get.deta.dev/cli.ps1 -useb | iex
```
</div>
Após a instalação, abra um novo terminal para que a CLI seja detectada.
Em um novo terminal, confirme se foi instalado corretamente com:
<div class="termy">
```console
$ deta --help
Deta command line interface for managing deta micros.
Complete documentation available at https://docs.deta.sh
Usage:
deta [flags]
deta [command]
Available Commands:
auth Change auth settings for a deta micro
...
```
</div>
!!! tip "Dica"
Se você tiver problemas ao instalar a CLI, verifique a <a href="https://docs.deta.sh/docs/micros/getting_started?ref=fastapi" class="external-link" target="_blank">documentação oficial da Deta</a>.
## Login pela CLI
Agora faça login na Deta pela CLI com:
<div class="termy">
```console
$ deta login
Please, log in from the web page. Waiting..
Logged in successfully.
```
</div>
Isso abrirá um navegador da Web e autenticará automaticamente.
## Implantação com Deta
Em seguida, implante seu aplicativo com a Deta CLI:
<div class="termy">
```console
$ deta new
Successfully created a new micro
// Notice the "endpoint" 🔍
{
"name": "fastapideta",
"runtime": "python3.7",
"endpoint": "https://qltnci.deta.dev",
"visor": "enabled",
"http_auth": "enabled"
}
Adding dependencies...
---> 100%
Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6
```
</div>
Você verá uma mensagem JSON semelhante a:
```JSON hl_lines="4"
{
"name": "fastapideta",
"runtime": "python3.7",
"endpoint": "https://qltnci.deta.dev",
"visor": "enabled",
"http_auth": "enabled"
}
```
!!! tip "Dica"
Sua implantação terá um URL `"endpoint"` diferente.
## Confira
Agora, abra seu navegador na URL do `endpoint`. No exemplo acima foi `https://qltnci.deta.dev`, mas o seu será diferente.
Você verá a resposta JSON do seu aplicativo FastAPI:
```JSON
{
"Hello": "World"
}
```
Agora vá para o `/docs` da sua API, no exemplo acima seria `https://qltnci.deta.dev/docs`.
Ele mostrará sua documentação como:
<img src="/img/deployment/deta/image01.png">
## Permitir acesso público
Por padrão, a Deta lidará com a autenticação usando cookies para sua conta.
Mas quando estiver pronto, você pode torná-lo público com:
<div class="termy">
```console
$ deta auth disable
Successfully disabled http auth
```
</div>
Agora você pode compartilhar essa URL com qualquer pessoa e elas conseguirão acessar sua API. 🚀
## HTTPS
Parabéns! Você realizou a implantação do seu app FastAPI na Deta! 🎉 🍰
Além disso, observe que a Deta lida corretamente com HTTPS para você, para que você não precise cuidar disso e tenha a certeza de que seus clientes terão uma conexão criptografada segura. ✅ 🔒
## Verifique o Visor
Na UI da sua documentação (você estará em um URL como `https://qltnci.deta.dev/docs`) envie um request para *operação de rota* `/items/{item_id}`.
Por exemplo com ID `5`.
Agora vá para <a href="https://web.deta.sh/" class="external-link" target="_blank">https://web.deta.sh</a>.
Você verá que há uma seção à esquerda chamada <abbr title="it comes from Micro(server)">"Micros"</abbr> com cada um dos seus apps.
Você verá uma aba com "Detalhes", e também a aba "Visor", vá para "Visor".
Lá você pode inspecionar as solicitações recentes enviadas ao seu aplicativo.
Você também pode editá-los e reproduzi-los novamente.
<img src="/img/deployment/deta/image02.png">
## Saiba mais
Em algum momento, você provavelmente desejará armazenar alguns dados para seu aplicativo de uma forma que persista ao longo do tempo. Para isso você pode usar <a href="https://docs.deta.sh/docs/base/py_tutorial?ref=fastapi" class="external-link" target="_blank">Deta Base</a>, que também tem um generoso **nível gratuito**.
Você também pode ler mais na <a href="https://docs.deta.sh?ref=fastapi" class="external-link" target="_blank">documentação da Deta</a>.
## Conceitos de implantação
Voltando aos conceitos que discutimos em [Deployments Concepts](./concepts.md){.internal-link target=_blank}, veja como cada um deles seria tratado com a Deta:
* **HTTPS**: Realizado pela Deta, eles fornecerão um subdomínio e lidarão com HTTPS automaticamente.
* **Executando na inicialização**: Realizado pela Deta, como parte de seu serviço.
* **Reinicialização**: Realizado pela Deta, como parte de seu serviço.
* **Replicação**: Realizado pela Deta, como parte de seu serviço.
* **Memória**: Limite predefinido pela Deta, você pode contatá-los para aumentá-lo.
* **Etapas anteriores a inicialização**: Não suportado diretamente, você pode fazê-lo funcionar com o sistema Cron ou scripts adicionais.
!!! note "Nota"
O Deta foi projetado para facilitar (e gratuitamente) a implantação rápida de aplicativos simples.
Ele pode simplificar vários casos de uso, mas, ao mesmo tempo, não suporta outros, como o uso de bancos de dados externos (além do próprio sistema de banco de dados NoSQL da Deta), máquinas virtuais personalizadas, etc.
Você pode ler mais detalhes na <a href="https://docs.deta.sh/docs/micros/about/" class="external-link" target="_blank">documentação da Deta</a> para ver se é a escolha certa para você.

View File

@@ -0,0 +1,700 @@
# FastAPI и Docker-контейнеры
При развёртывании приложений FastAPI, часто начинают с создания **образа контейнера на основе Linux**. Обычно для этого используют <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>. Затем можно развернуть такой контейнер на сервере одним из нескольких способов.
Использование контейнеров на основе Linux имеет ряд преимуществ, включая **безопасность**, **воспроизводимость**, **простоту** и прочие.
!!! tip "Подсказка"
Торопитесь или уже знакомы с этой технологией? Перепрыгните на раздел [Создать Docker-образ для FastAPI 👇](#docker-fastapi)
<details>
<summary>Развернуть 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"]
# Если используете прокси-сервер, такой как Nginx или Traefik, добавьте --proxy-headers
# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers"]
```
</details>
## Что такое "контейнер"
Контейнеризация - это **легковесный** способ упаковать приложение, включая все его зависимости и необходимые файлы, чтобы изолировать его от других контейнеров (других приложений и компонентов) работающих на этой же системе.
Контейнеры, основанные на Linux, запускаются используя ядро Linux хоста (машины, виртуальной машины, облачного сервера и т.п.). Это значит, что они очень легковесные (по сравнению с полноценными виртуальными машинами, полностью эмулирующими работу операционной системы).
Благодаря этому, контейнеры потребляют **малое количество ресурсов**, сравнимое с процессом запущенным напрямую (виртуальная машина потребует гораздо больше ресурсов).
Контейнеры также имеют собственные запущенные **изолированные** процессы (но часто только один процесс), файловую систему и сеть, что упрощает развёртывание, разработку, управление доступом и т.п.
## Что такое "образ контейнера"
Для запуска **контейнера** нужен **образ контейнера**.
Образ контейнера - это **замороженная** версия всех файлов, переменных окружения, программ и команд по умолчанию, необходимых для работы приложения. **Замороженный** - означает, что **образ** не запущен и не выполняется, это всего лишь упакованные вместе файлы и метаданные.
В отличие от **образа контейнера**, хранящего неизменное содержимое, под термином **контейнер** подразумевают запущенный образ, то есть объёкт, который **исполняется**.
Когда **контейнер** запущен (на основании **образа**), он может создавать и изменять файлы, переменные окружения и т.д. Эти изменения будут существовать только внутри контейнера, но не будут сохраняться в образе контейнера (не будут сохранены на диск).
Образ контейнера можно сравнить с файлом, содержащем **программу**, например, как файл `main.py`.
И **контейнер** (в отличие от **образа**) - это на самом деле выполняемый экземпляр образа, примерно как **процесс**. По факту, контейнер запущен только когда запущены его процессы (чаще, всего один процесс) и остановлен, когда запущенных процессов нет.
## Образы контейнеров
Docker является одним оз основных инструментов для создания **образов** и **контейнеров** и управления ими.
Существует общедоступный <a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a> с подготовленными **официальными образами** многих инструментов, окружений, баз данных и приложений.
К примеру, есть официальный <a href="https://hub.docker.com/_/python" class="external-link" target="_blank">образ Python</a>.
Также там представлены и другие полезные образы, такие как базы данных:
* <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>
и т.п.
Использование подготовленных образов значительно упрощает **комбинирование** и использование разных инструментов. Например, Вы можете попытаться использовать новую базу данных. В большинстве случаев можно использовать **официальный образ** и всего лишь указать переменные окружения.
Таким образом, Вы можете изучить, что такое контейнеризация и Docker, и использовать полученные знания с разными инструментами и компонентами.
Так, Вы можете запустить одновременно **множество контейнеров** с базой данных, Python-приложением, веб-сервером, React-приложением и соединить их вместе через внутреннюю сеть.
Все системы управления контейнерами (такие, как Docker или Kubernetes) имеют встроенные возможности для организации такого сетевого взаимодействия.
## Контейнеры и процессы
Обычно **образ контейнера** содержит метаданные предустановленной программы или команду, которую следует выполнить при запуске **контейнера**. Также он может содержать параметры, передаваемые предустановленной программе. Похоже на то, как если бы Вы запускали такую программу через терминал.
Когда **контейнер** запущен, он будет выполнять прописанные в нём команды и программы. Но Вы можете изменить его так, чтоб он выполнял другие команды и программы.
Контейнер буде работать до тех пор, пока выполняется его **главный процесс** (команда или программа).
В контейнере обычно выполняется **только один процесс**, но от его имени можно запустить другие процессы, тогда в этом же в контейнере будет выполняться **множество процессов**.
Контейнер не считается запущенным, если в нём **не выполняется хотя бы один процесс**. Если главный процесс остановлен, значит и контейнер остановлен.
## Создать Docker-образ для FastAPI
Что ж, давайте ужё создадим что-нибудь! 🚀
Я покажу Вам, как собирать **Docker-образ** для FastAPI **с нуля**, основываясь на **официальном образе Python**.
Такой подход сгодится для **большинства случаев**, например:
* Использование с **Kubernetes** или аналогичным инструментом
* Запуск в **Raspberry Pi**
* Использование в облачных сервисах, запускающих образы контейнеров для Вас и т.п.
### Установить зависимости
Обычно Вашему приложению необходимы **дополнительные библиотеки**, список которых находится в отдельном файле.
На название и содержание такого файла влияет выбранный Вами инструмент **установки** этих библиотек (зависимостей).
Чаще всего это простой файл `requirements.txt` с построчным перечислением библиотек и их версий.
При этом Вы, для выбора версий, будете использовать те же идеи, что упомянуты на странице [О версиях FastAPI](./versions.md){.internal-link target=_blank}.
Ваш файл `requirements.txt` может выглядеть как-то так:
```
fastapi>=0.68.0,<0.69.0
pydantic>=1.8.0,<2.0.0
uvicorn>=0.15.0,<0.16.0
```
Устанавливать зависимости проще всего с помощью `pip`:
<div class="termy">
```console
$ pip install -r requirements.txt
---> 100%
Successfully installed fastapi pydantic uvicorn
```
</div>
!!! info "Информация"
Существуют и другие инструменты управления зависимостями.
В этом же разделе, но позже, я покажу Вам пример использования Poetry. 👇
### Создать приложение **FastAPI**
* Создайте директорию `app` и перейдите в неё.
* Создайте пустой файл `__init__.py`.
* Создайте файл `main.py` и заполните его:
```Python
from typing import Union
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
В этой же директории создайте файл `Dockerfile` и заполните его:
```{ .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. Начните с официального образа Python, который будет основой для образа приложения.
2. Укажите, что в дальнейшем команды запускаемые в контейнере, будут выполняться в директории `/code`.
Инструкция создаст эту директорию внутри контейнера и мы поместим в неё файл `requirements.txt` и директорию `app`.
3. Скопируете файл с зависимостями из текущей директории в `/code`.
Сначала копируйте **только** файл с зависимостями.
Этот файл **изменяется довольно редко**, Docker ищет изменения при постройке образа и если не находит, то использует **кэш**, в котором хранятся предыдущии версии сборки образа.
4. Установите библиотеки перечисленные в файле с зависимостями.
Опция `--no-cache-dir` указывает `pip` не сохранять загружаемые библиотеки на локальной машине для использования их в случае повторной загрузки. В контейнере, в случае пересборки этого шага, они всё равно будут удалены.
!!! note "Заметка"
Опция `--no-cache-dir` нужна только для `pip`, она никак не влияет на Docker или контейнеры.
Опция `--upgrade` указывает `pip` обновить библиотеки, емли они уже установлены.
Ка и в предыдущем шаге с копированием файла, этот шаг также будет использовать **кэш Docker** в случае отсутствия изменений.
Использрвание кэша, особенно на этом шаге, позволит Вам **сэкономить** кучу времени при повторной сборке образа, так как зависимости будут сохранены в кеше, а не **загружаться и устанавливаться каждый раз**.
5. Скопируйте директорию `./app` внутрь директории `/code` (в контейнере).
Так как в этой директории расположен код, который **часто изменяется**, то использование **кэша** на этом шаге будет наименее эффективно, а значит лучше поместить этот шаг **ближе к концу** `Dockerfile`, дабы не терять выгоду от оптимизации предыдущих шагов.
6. Укажите **команду**, запускающую сервер `uvicorn`.
`CMD` принимает список строк, разделённых запятыми, но при выполнении объединит их через пробел, собрав из них одну команду, которую Вы могли бы написать в терминале.
Эта команда будет выполнена в **текущей рабочей директории**, а именно в директории `/code`, котоая указана командой `WORKDIR /code`.
Так как команда выполняется внутрии директории `/code`, в которую мы поместили папку `./app` с приложением, то **Uvicorn** сможет найти и **импортировать** объект `app` из файла `app.main`.
!!! tip "Подсказка"
Если ткнёте на кружок с плюсом, то увидите пояснения. 👆
На данном этапе структура проекта должны выглядеть так:
```
.
├── app
│   ├── __init__.py
│ └── main.py
├── Dockerfile
└── requirements.txt
```
#### Использование прокси-сервера
Если Вы запускаете контейнер за прокси-сервером завершения TLS (балансирующего нагрузку), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`, которая укажет Uvicorn, что он работает позади прокси-сервера и может доверять заголовкам отправляемым им.
```Dockerfile
CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
```
#### Кэш Docker'а
В нашем `Dockerfile` использована полезная хитрость, когда сначала копируется **только файл с зависимостями**, а не вся папка с кодом приложения.
```Dockerfile
COPY ./requirements.txt /code/requirements.txt
```
Docker и подобные ему инструменты **создают** образы контейнеров **пошагово**, добавляя **один слой над другим**, начиная с первой строки `Dockerfile` и добавляя файлы, создаваемые при выполнении каждой инструкции из `Dockerfile`.
При создании образа используется **внутренний кэш** и если в файлах нет изменений с момента последней сборки образа, то будет **переиспользован** ранее созданный слой образа, а не повторное копирование файлов и создание слоя с нуля.
Заметьте, что так как слой следующего шага зависит от слоя предыдущего, то изменения внесённые в промежуточный слой, также повлияют на последующие.
Избегание копирования файлов не обязательно улучшит ситуацию, но использование кэша на одном шаге, позволит **использовать кэш и на следующих шагах**. Например, можно использовать кэш при установке зависимостей:
```Dockerfile
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
```
Файл со списком зависимостей **изменяется довольно редко**. Так что выполнив команду копирования только этого файла, Docker сможет **использовать кэш** на этом шаге.
А затем **использовать кэш и на следующем шаге**, загружающем и устанавливающем зависимости. И вот тут-то мы и **сэкономим много времени**. ✨ ...а не будем томиться в тягостном ожидании. 😪😆
Для загрузки и установки необходимых библиотек **может понадобиться несколько минут**, но использование **кэша** занимает несколько **секунд** максимум.
И так как во время разработки Вы будете часто пересобирать контейнер для проверки работоспособности внесённых изменений, то сэкономленные минуты сложатся в часы, а то и дни.
Так как папка с кодом приложения **изменяется чаще всего**, то мы расположили её в конце `Dockerfile`, ведь после внесённых в код изменений кэш не будет использован на этом и следующих шагах.
```Dockerfile
COPY ./app /code/app
```
### Создать Docker-образ
Теперь, когда все файлы на своих местах, давайте создадим образ контейнера.
* Перейдите в директорию проекта (в ту, где расположены `Dockerfile` и папка `app` с приложением).
* Создай образ приложения FastAPI:
<div class="termy">
```console
$ docker build -t myimage .
---> 100%
```
</div>
!!! tip "Подсказка"
Обратите внимание, что в конце написана точка - `.`, это то же самое что и `./`, тем самым мы указываем Docker директорию, из которой нужно выполнять сборку образа контейнера.
В данном случае это та же самая директория (`.`).
### Запуск Docker-контейнера
* Запустите контейнер, основанный на Вашем образе:
<div class="termy">
```console
$ docker run -d --name mycontainer -p 80:80 myimage
```
</div>
## Проверка
Вы можете проверить, что Ваш Docker-контейнер работает перейдя по ссылке: <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> или <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> (или похожей, которую использует Ваш Docker-хост).
Там Вы увидите:
```JSON
{"item_id": 5, "q": "somequery"}
```
## Интерактивная документация API
Теперь перейдите по ссылке <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> или <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (или похожей, которую использует Ваш Docker-хост).
Здесь Вы увидите автоматическую интерактивную документацию API (предоставляемую <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)
## Альтернативная документация API
Также Вы можете перейти по ссылке <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> or <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (или похожей, которую использует Ваш Docker-хост).
Здесь Вы увидите альтернативную автоматическую документацию API (предоставляемую <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)
## Создание Docker-образа на основе однофайлового приложения FastAPI
Если Ваше приложение FastAPI помещено в один файл, например, `main.py` и структура Ваших файлов похожа на эту:
```
.
├── Dockerfile
├── main.py
└── requirements.txt
```
Вам нужно изменить в `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. Скопируйте непосредственно файл `main.py` в директорию `/code` (не указывайте `./app`).
2. При запуске Uvicorn укажите ему, что объект `app` нужно импортировать из файла `main` (вместо импортирования из `app.main`).
Настройте Uvicorn на использование `main` вместо `app.main` для импорта объекта `app`.
## Концепции развёртывания
Давайте вспомним о [Концепциях развёртывания](./concepts.md){.internal-link target=_blank} и применим их к контейнерам.
Контейнеры - это, в основном, инструмент упрощающий **сборку и развёртывание** приложения и они не обязыают к применению какой-то определённой **концепции развёртывания**, а значит мы можем выбирать нужную стратегию.
**Хорошая новость** в том, что независимо от выбранной стратегии, мы всё равно можем покрыть все концепции развёртывания. 🎉
Рассмотрим эти **концепции развёртывания** применительно к контейнерам:
* Использование более безопасного протокола HTTPS
* Настройки запуска приложения
* Перезагрузка приложения
* Запуск нескольких экземпляров приложения
* Управление памятью
* Использование перечисленных функций перед запуском приложения
## Использование более безопасного протокола HTTPS
Если мы определимся, что **образ контейнера** будет содержать только приложение FastAPI, то работу с HTTPS можно организовать **снаружи** контейнера при помощи другого инструмента.
Это может быть другой контейнер, в котором есть, например, <a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>, работающий с **HTTPS** и **самостоятельно** обновляющий **сертификаты**.
!!! tip "Подсказка"
Traefik совместим с Docker, Kubernetes и им подобными инструментами. Он очень прост в установке и настройке использования HTTPS для Ваших контейнеров.
В качестве альтернативы, работу с HTTPS можно доверить облачному провайдеру, если он предоставляет такую услугу.
## Настройки запуска и перезагрузки приложения
Обычно **запуском контейнера с приложением** занимается какой-то отдельный инструмент.
Это может быть сам **Docker**, **Docker Compose**, **Kubernetes**, **облачный провайдер** и т.п.
В большинстве случаев это простейшие настройки запуска и перезагрузки приложения (при падении). Например, команде запуска Docker-контейнера можно добавить опцию `--restart`.
Управление запуском и перезагрузкой приложений без использования контейнеров - весьма затруднительно. Но при **работе с контейнерами** - это всего лишь функционал доступный по умолчанию. ✨
## Запуск нескольких экземпляров приложения - Указание количества процессов
Если у Вас есть <abbr title="Несколько серверов настроенных для совместной работы.">кластер</abbr> машин под управлением **Kubernetes**, Docker Swarm Mode, Nomad или аналогичной сложной системой оркестрации контейнеров, скорее всего, вместо использования менеджера процессов (типа Gunicorn и его воркеры) в каждом контейнере, Вы захотите **управлять количеством запущенных экземпляров приложения** на **уровне кластера**.
В любую из этих систем управления контейнерами обычно встроен способ управления **количеством запущенных контейнеров** для распределения **нагрузки** от входящих запросов на **уровне кластера**.
В такой ситуации Вы, вероятно, захотите создать **образ Docker**, как [описано выше](#dockerfile), с установленными зависимостями и запускающий **один процесс Uvicorn** вместо того, чтобы запускать Gunicorn управляющий несколькими воркерами Uvicorn.
### Балансировщик нагрузки
Обычно при использовании контейнеров один компонент **прослушивает главный порт**. Это может быть контейнер содержащий **прокси-сервер завершения работы TLS** для работы с **HTTPS** или что-то подобное.
Поскольку этот компонент **принимает запросы** и равномерно **распределяет** их между компонентами, его также называют **балансировщиком нагрузки**.
!!! tip "Подсказка"
**Прокси-сервер завершения работы TLS** одновременно может быть **балансировщиком нагрузки**.
Система оркестрации, которую Вы используете для запуска и управления контейнерами, имеет встроенный инструмент **сетевого взаимодействия** (например, для передачи HTTP-запросов) между контейнерами с Вашими приложениями и **балансировщиком нагрузки** (который также может быть **прокси-сервером**).
### Один балансировщик - Множество контейнеров
При работе с **Kubernetes** или аналогичными системами оркестрации использование их внутреннней сети позволяет иметь один **балансировщик нагрузки**, который прослушивает **главный** порт и передаёт запросы **множеству запущенных контейнеров** с Вашими приложениями.
В каждом из контейнеров обычно работает **только один процесс** (например, процесс Uvicorn управляющий Вашим приложением FastAPI). Контейнеры могут быть **идентичными**, запущенными на основе одного и того же образа, но у каждого будут свои отдельные процесс, память и т.п. Таким образом мы получаем преимущества **распараллеливания** работы по **разным ядрам** процессора или даже **разным машинам**.
Система управления контейнерами с **балансировщиком нагрузки** будет **распределять запросы** к контейнерам с приложениями **по очереди**. То есть каждый запрос будет обработан одним из множества **одинаковых контейнеров** с одним и тем же приложением.
**Балансировщик нагрузки** может обрабатывать запросы к *разным* приложениям, расположенным в Вашем кластере (например, если у них разные домены или префиксы пути) и передавать запросы нужному контейнеру с требуемым приложением.
### Один процесс на контейнер
В этом варианте **в одном контейнере будет запущен только один процесс (Uvicorn)**, а управление изменением количества запущенных копий приложения происходит на уровне кластера.
Здесь **не нужен** менеджер процессов типа Gunicorn, управляющий процессами Uvicorn, или же Uvicorn, управляющий другими процессами Uvicorn. Достаточно **только одного процесса Uvicorn** на контейнер (но запуск нескольких процессов не запрещён).
Использование менеджера процессов (Gunicorn или Uvicorn) внутри контейнера только добавляет **излишнее усложнение**, так как управление следует осуществлять системой оркестрации.
### <a name="special-cases"></a>Множество процессов внутри контейнера для особых случаев</a>
Безусловно, бывают **особые случаи**, когда может понадобится внутри контейнера запускать **менеджер процессов Gunicorn**, управляющий несколькими **процессами Uvicorn**.
Для таких случаев Вы можете использовать **официальный Docker-образ** (прим. пер: - *здесь и далее на этой странице, если Вы встретите сочетание "официальный Docker-образ" без уточнений, то автор имеет в виду именно предоставляемый им образ*), где в качестве менеджера процессов используется **Gunicorn**, запускающий несколько **процессов Uvicorn** и некоторые настройки по умолчанию, автоматически устанавливающие количество запущенных процессов в зависимости от количества ядер Вашего процессора. Я расскажу Вам об этом подробнее тут: [Официальный Docker-образ со встроенными Gunicorn и Uvicorn](#docker-gunicorn-uvicorn).
Некоторые примеры подобных случаев:
#### Простое приложение
Вы можете использовать менеджер процессов внутри контейнера, если Ваше приложение **настолько простое**, что у Вас нет необходимости (по крайней мере, пока нет) в тщательных настройках количества процессов и Вам достаточно имеющихся настроек по умолчанию (если используется официальный Docker-образ) для запуска приложения **только на одном сервере**, а не в кластере.
#### Docker Compose
С помощью **Docker Compose** можно разворачивать несколько контейнеров на **одном сервере** (не кластере), но при это у Вас не будет простого способа управления количеством запущенных контейнеров с одновременным сохранением общей сети и **балансировки нагрузки**.
В этом случае можно использовать **менеджер процессов**, управляющий **несколькими процессами**, внутри **одного контейнера**.
#### Prometheus и прочие причины
У Вас могут быть и **другие причины**, когда использование **множества процессов** внутри **одного контейнера** будет проще, нежели запуск **нескольких контейнеров** с **единственным процессом** в каждом из них.
Например (в зависимости от конфигурации), у Вас могут быть инструменты подобные экспортёру Prometheus, которые должны иметь доступ к **каждому запросу** приходящему в контейнер.
Если у Вас будет **несколько контейнеров**, то Prometheus, по умолчанию, **при сборе метрик** получит их **только с одного контейнера**, который обрабатывает конкретный запрос, вместо **сбора метрик** со всех работающих контейнеров.
В таком случае может быть проще иметь **один контейнер** со **множеством процессов**, с нужным инструментом (таким как экспортёр Prometheus) в этом же контейнере и собирающем метрики со всех внутренних процессов этого контейнера.
---
Самое главное - **ни одно** из перечисленных правил не является **высеченным в камне** и Вы не обязаны слепо их повторять. Вы можете использовать эти идеи при **рассмотрении Вашего конкретного случая** и самостоятельно решать, какая из концепции подходит лучше:
* Использование более безопасного протокола HTTPS
* Настройки запуска приложения
* Перезагрузка приложения
* Запуск нескольких экземпляров приложения
* Управление памятью
* Использование перечисленных функций перед запуском приложения
## Управление памятью
При **запуске одного процесса на контейнер** Вы получаете относительно понятный, стабильный и ограниченный объём памяти, потребляемый одним контейнером.
Вы можете установить аналогичные ограничения по памяти при конфигурировании своей системы управления контейнерами (например, **Kubernetes**). Таким образом система сможет **изменять количество контейнеров** на **доступных ей машинах** приводя в соответствие количество памяти нужной контейнерам с количеством памяти доступной в кластере (наборе доступных машин).
Если у Вас **простенькое** приложение, вероятно у Вас не будет **необходимости** устанавливать жёсткие ограничения на выделяемую ему память. Но если приложение **использует много памяти** (например, оно использует модели **машинного обучения**), Вам следует проверить, как много памяти ему требуется и отрегулировать **количество контейнеров** запущенных на **каждой машине** (может быть даже добавить машин в кластер).
Если Вы запускаете **несколько процессов в контейнере**, то должны быть уверены, что эти процессы не **займут памяти больше**, чем доступно для контейнера.
## Подготовительные шаги при запуске контейнеров
Есть два основных подхода, которые Вы можете использовать при запуске контейнеров (Docker, Kubernetes и т.п.).
### Множество контейнеров
Когда Вы запускаете **множество контейнеров**, в каждом из которых работает **только один процесс** (например, в кластере **Kubernetes**), может возникнуть необходимость иметь **отдельный контейнер**, который осуществит **предварительные шаги перед запуском** остальных контейнеров (например, применяет миграции к базе данных).
!!! info "Информация"
При использовании Kubernetes, это может быть <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Инициализирующий контейнер</a>.
При отсутствии такой необходимости (допустим, не нужно применять миграции к базе данных, а только проверить, что она готова принимать соединения), Вы можете проводить такую проверку в каждом контейнере перед запуском его основного процесса и запускать все контейнеры **одновременно**.
### Только один контейнер
Если у Вас несложное приложение для работы которого достаточно **одного контейнера**, но в котором работает **несколько процессов** (или один процесс), то прохождение предварительных шагов можно осуществить в этом же контейнере до запуска основного процесса. Официальный Docker-образ поддерживает такие действия.
## Официальный Docker-образ с Gunicorn и Uvicorn
Я подготовил для Вас Docker-образ, в который включён Gunicorn управляющий процессами (воркерами) Uvicorn, в соответствии с концепциями рассмотренными в предыдущей главе: [Рабочие процессы сервера (воркеры) - Gunicorn совместно с Uvicorn](./server-workers.md){.internal-link target=_blank}.
Этот образ может быть полезен для ситуаций описанных тут: [Множество процессов внутри контейнера для особых случаев](#special-cases).
* <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
!!! warning "Предупреждение"
Скорее всего у Вас **нет необходимости** в использовании этого образа или подобного ему и лучше создать свой образ с нуля как описано тут: [Создать Docker-образ для FastAPI](#docker-fastapi).
В этом образе есть **автоматический** механизм подстройки для запуска **необходимого количества процессов** в соответствии с доступным количеством ядер процессора.
В нём установлены **разумные значения по умолчанию**, но можно изменять и обновлять конфигурацию с помощью **переменных окружения** или конфигурационных файлов.
Он также поддерживает прохождение <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker#pre_start_path" class="external-link" target="_blank">**Подготовительных шагов при запуске контейнеров**</a> при помощи скрипта.
!!! tip "Подсказка"
Для просмотра всех возможных настроек перейдите на страницу этого Docker-образа: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
### Количество процессов в официальном Docker-образе
**Количество процессов** в этом образе **вычисляется автоматически** и зависит от доступного количества **ядер** центрального процессора.
Это означает, что он будет пытаться **выжать** из процессора как можно больше **производительности**.
Но Вы можете изменять и обновлять конфигурацию с помощью **переменных окружения** и т.п.
Поскольку количество процессов зависит от процессора, на котором работает контейнер, **объём потребляемой памяти** также будет зависеть от этого.
А значит, если Вашему приложению требуется много оперативной памяти (например, оно использует модели машинного обучения) и Ваш сервер имеет центральный процессор с большим количеством ядер, но **не слишком большим объёмом оперативной памяти**, то может дойти до того, что контейнер попытается занять памяти больше, чем доступно, из-за чего будет падение производительности (или сервер вовсе упадёт). 🚨
### Написание `Dockerfile`
Итак, теперь мы можем написать `Dockerfile` основанный на этом официальном Docker-образе:
```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
```
### Большие приложения
Если Вы успели ознакомиться с разделом [Приложения содержащие много файлов](../tutorial/bigger-applications.md){.internal-link target=_blank}, состоящие из множества файлов, Ваш 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
```
### Как им пользоваться
Если Вы используете **Kubernetes** (или что-то вроде того), скорее всего Вам **не нужно** использовать официальный Docker-образ (или другой похожий) в качестве основы, так как управление **количеством запущенных контейнеров** должно быть настроено на уровне кластера. В таком случае лучше **создать образ с нуля**, как описано в разделе Создать [Docker-образ для FastAPI](#docker-fastapi).
Официальный образ может быть полезен в отдельных случаях, описанных выше в разделе [Множество процессов внутри контейнера для особых случаев](#special-cases). Например, если Ваше приложение **достаточно простое**, не требует запуска в кластере и способно уместиться в один контейнер, то его настройки по умолчанию будут работать довольно хорошо. Или же Вы развертываете его с помощью **Docker Compose**, работаете на одном сервере и т. д
## Развёртывание образа контейнера
После создания образа контейнера существует несколько способов его развёртывания.
Например:
* С использованием **Docker Compose** при развёртывании на одном сервере
* С использованием **Kubernetes** в кластере
* С использованием режима Docker Swarm в кластере
* С использованием других инструментов, таких как Nomad
* С использованием облачного сервиса, который будет управлять разворачиванием Вашего контейнера
## Docker-образ и Poetry
Если Вы пользуетесь <a href="https://python-poetry.org/" class="external-link" target="_blank">Poetry</a> для управления зависимостями Вашего проекта, то можете использовать многоэтапную сборку образа:
```{ .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. Это первый этап, которому мы дадим имя `requirements-stage`.
2. Установите директорию `/tmp` в качестве рабочей директории.
В ней будет создан файл `requirements.txt`
3. На этом шаге установите Poetry.
4. Скопируйте файлы `pyproject.toml` и `poetry.lock` в директорию `/tmp`.
Поскольку название файла написано как `./poetry.lock*` (с `*` в конце), то ничего не сломается, если такой файл не будет найден.
5. Создайте файл `requirements.txt`.
6. Это второй (и последний) этап сборки, который и создаст окончательный образ контейнера.
7. Установите директорию `/code` в качестве рабочей.
8. Скопируйте файл `requirements.txt` в директорию `/code`.
Этот файл находится в образе, созданном на предыдущем этапе, которому мы дали имя requirements-stage, потому при копировании нужно написать `--from-requirements-stage`.
9. Установите зависимости, указанные в файле `requirements.txt`.
10. Скопируйте папку `app` в папку `/code`.
11. Запустите `uvicorn`, указав ему использовать объект `app`, расположенный в `app.main`.
!!! tip "Подсказка"
Если ткнёте на кружок с плюсом, то увидите объяснения, что происходит в этой строке.
**Этапы сборки Docker-образа** являются частью `Dockerfile` и работают как **временные образы контейнеров**. Они нужны только для создания файлов, используемых в дальнейших этапах.
Первый этап был нужен только для **установки Poetry** и **создания файла `requirements.txt`**, в которым прописаны зависимости Вашего проекта, взятые из файла `pyproject.toml`.
На **следующем этапе** `pip` будет использовать файл `requirements.txt`.
В итоговом образе будет содержаться **только последний этап сборки**, предыдущие этапы будут отброшены.
При использовании Poetry, имеет смысл использовать **многоэтапную сборку Docker-образа**, потому что на самом деле Вам не нужен Poetry и его зависимости в окончательном образе контейнера, Вам **нужен только** сгенерированный файл `requirements.txt` для установки зависимостей Вашего проекта.
А на последнем этапе, придерживаясь описанных ранее правил, создаётся итоговый образ
### Использование прокси-сервера завершения TLS и Poetry
И снова повторюсь, если используете прокси-сервер (балансировщик нагрузки), такой, как Nginx или Traefik, добавьте в команду запуска опцию `--proxy-headers`:
```Dockerfile
CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
```
## Резюме
При помощи систем контейнеризации (таких, как **Docker** и **Kubernetes**), становится довольно просто обрабатывать все **концепции развертывания**:
* Использование более безопасного протокола HTTPS
* Настройки запуска приложения
* Перезагрузка приложения
* Запуск нескольких экземпляров приложения
* Управление памятью
* Использование перечисленных функций перед запуском приложения
В большинстве случаев Вам, вероятно, не нужно использовать какой-либо базовый образ, **лучше создать образ контейнера с нуля** на основе официального Docker-образа Python.
Позаботившись о **порядке написания** инструкций в `Dockerfile`, Вы сможете использовать **кэш Docker'а**, **минимизировав время сборки**, максимально повысив свою производительность (и избежать скуки). 😎
В некоторых особых случаях вы можете использовать официальный образ Docker для FastAPI. 🤓

View File

@@ -0,0 +1,34 @@
# Глобальные зависимости
Для некоторых типов приложений может потребоваться добавить зависимости ко всему приложению.
Подобно тому, как вы можете [добавлять зависимости через параметр `dependencies` в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, вы можете добавлять зависимости сразу ко всему `FastAPI` приложению.
В этом случае они будут применяться ко всем *операциям пути* в приложении:
=== "Python 3.9+"
```Python hl_lines="16"
{!> ../../../docs_src/dependencies/tutorial012_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="16"
{!> ../../../docs_src/dependencies/tutorial012_an.py!}
```
=== "Python 3.6 non-Annotated"
!!! tip "Подсказка"
Рекомендуется использовать 'Annotated' версию, если это возможно.
```Python hl_lines="15"
{!> ../../../docs_src/dependencies/tutorial012.py!}
```
Все способы [добавления зависимостей в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} по-прежнему применимы, но в данном случае зависимости применяются ко всем *операциям пути* приложения.
## Зависимости для групп *операций пути*
Позднее, читая о том, как структурировать более крупные [приложения, содержащие много файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}, вы узнаете, как объявить один параметр dependencies для целой группы *операций пути*.

View File

@@ -0,0 +1,92 @@
# Данные формы
Когда вам нужно получить поля формы вместо JSON, вы можете использовать `Form`.
!!! info "Дополнительная информация"
Чтобы использовать формы, сначала установите <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>.
Например, выполните команду `pip install python-multipart`.
## Импорт `Form`
Импортируйте `Form` из `fastapi`:
=== "Python 3.9+"
```Python hl_lines="3"
{!> ../../../docs_src/request_forms/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="1"
{!> ../../../docs_src/request_forms/tutorial001_an.py!}
```
=== "Python 3.6+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать 'Annotated' версию, если это возможно.
```Python hl_lines="1"
{!> ../../../docs_src/request_forms/tutorial001.py!}
```
## Определение параметров `Form`
Создайте параметры формы так же, как это делается для `Body` или `Query`:
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/request_forms/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="8"
{!> ../../../docs_src/request_forms/tutorial001_an.py!}
```
=== "Python 3.6+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать 'Annotated' версию, если это возможно.
```Python hl_lines="7"
{!> ../../../docs_src/request_forms/tutorial001.py!}
```
Например, в одном из способов использования спецификации OAuth2 (называемом "потоком пароля") требуется отправить `username` и `password` в виде полей формы.
Данный способ требует отправку данных для авторизации посредством формы (а не JSON) и обязательного наличия в форме строго именованных полей `username` и `password`.
Вы можете настроить `Form` точно так же, как настраиваете и `Body` ( `Query`, `Path`, `Cookie`), включая валидации, примеры, псевдонимы (например, `user-name` вместо `username`) и т.д.
!!! info "Дополнительная информация"
`Form` - это класс, который наследуется непосредственно от `Body`.
!!! tip "Подсказка"
Вам необходимо явно указывать параметр `Form` при объявлении каждого поля, иначе поля будут интерпретироваться как параметры запроса или параметры тела (JSON).
## О "полях формы"
Обычно способ, которым HTML-формы (`<form></form>`) отправляют данные на сервер, использует "специальное" кодирование для этих данных, отличное от JSON.
**FastAPI** гарантирует правильное чтение этих данных из соответствующего места, а не из JSON.
!!! note "Технические детали"
Данные из форм обычно кодируются с использованием "типа медиа" `application/x-www-form-urlencoded`.
Но когда форма содержит файлы, она кодируется как `multipart/form-data`. Вы узнаете о работе с файлами в следующей главе.
Если вы хотите узнать больше про кодировки и поля формы, ознакомьтесь с <a href="https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank">документацией <abbr title="Mozilla Developer Network">MDN</abbr> для `POST` на веб-сайте</a>.
!!! warning "Предупреждение"
Вы можете объявлять несколько параметров `Form` в *операции пути*, но вы не можете одновременно с этим объявлять поля `Body`, которые вы ожидаете получить в виде JSON, так как запрос будет иметь тело, закодированное с использованием `application/x-www-form-urlencoded`, а не `application/json`.
Это не ограничение **FastAPI**, это часть протокола HTTP.
## Резюме
Используйте `Form` для объявления входных параметров данных формы.

View File

@@ -0,0 +1,101 @@
# Настройка авторизации
Существует множество способов обеспечения безопасности, аутентификации и авторизации.
Обычно эта тема является достаточно сложной и трудной.
Во многих фреймворках и системах только работа с определением доступов к приложению и аутентификацией требует значительных затрат усилий и написания множества кода (во многих случаях его объём может составлять более 50% от всего написанного кода).
**FastAPI** предоставляет несколько инструментов, которые помогут вам настроить **Авторизацию** легко, быстро, стандартным способом, без необходимости изучать все её тонкости.
Но сначала давайте рассмотрим некоторые небольшие концепции.
## Куда-то торопишься?
Если вам не нужна информация о каких-либо из следующих терминов и вам просто нужно добавить защиту с аутентификацией на основе логина и пароля *прямо сейчас*, переходите к следующим главам.
## OAuth2
OAuth2 - это протокол, который определяет несколько способов обработки аутентификации и авторизации.
Он довольно обширен и охватывает несколько сложных вариантов использования.
OAuth2 включает в себя способы аутентификации с использованием "третьей стороны".
Это то, что используют под собой все кнопки "вход с помощью Facebook, Google, Twitter, GitHub" на страницах авторизации.
### OAuth 1
Ранее использовался протокол OAuth 1, который сильно отличается от OAuth2 и является более сложным, поскольку он включал прямые описания того, как шифровать сообщение.
В настоящее время он не очень популярен и не используется.
OAuth2 не указывает, как шифровать сообщение, он ожидает, что ваше приложение будет обслуживаться по протоколу HTTPS.
!!! tip "Подсказка"
В разделе **Развертывание** вы увидите [как настроить протокол HTTPS бесплатно, используя Traefik и Let's Encrypt.](https://fastapi.tiangolo.com/ru/deployment/https/)
## OpenID Connect
OpenID Connect - это еще один протокол, основанный на **OAuth2**.
Он просто расширяет OAuth2, уточняя некоторые вещи, не имеющие однозначного определения в OAuth2, в попытке сделать его более совместимым.
Например, для входа в Google используется OpenID Connect (который под собой использует OAuth2).
Но вход в Facebook не поддерживает OpenID Connect. У него есть собственная вариация OAuth2.
### OpenID (не "OpenID Connect")
Также ранее использовался стандарт "OpenID", который пытался решить ту же проблему, что и **OpenID Connect**, но не был основан на OAuth2.
Таким образом, это была полноценная дополнительная система.
В настоящее время не очень популярен и не используется.
## OpenAPI
OpenAPI (ранее известный как Swagger) - это открытая спецификация для создания API (в настоящее время является частью Linux Foundation).
**FastAPI** основан на **OpenAPI**.
Это то, что делает возможным наличие множества автоматических интерактивных интерфейсов документирования, сгенерированного кода и т.д.
В OpenAPI есть способ использовать несколько "схем" безопасности.
Таким образом, вы можете воспользоваться преимуществами Всех этих стандартных инструментов, включая интерактивные системы документирования.
OpenAPI может использовать следующие схемы авторизации:
* `apiKey`: уникальный идентификатор для приложения, который может быть получен из:
* Параметров запроса.
* Заголовка.
* Cookies.
* `http`: стандартные системы аутентификации по протоколу HTTP, включая:
* `bearer`: заголовок `Authorization` со значением `Bearer {уникальный токен}`. Это унаследовано от OAuth2.
* Базовая аутентификация по протоколу HTTP.
* HTTP Digest и т.д.
* `oauth2`: все способы обеспечения безопасности OAuth2 называемые "потоки" (англ. "flows").
* Некоторые из этих "потоков" подходят для реализации аутентификации через сторонний сервис использующий OAuth 2.0 (например, Google, Facebook, Twitter, GitHub и т.д.):
* `implicit`
* `clientCredentials`
* `authorizationCode`
* Но есть один конкретный "поток", который может быть идеально использован для обработки аутентификации непосредственно в том же приложении:
* `password`: в некоторых следующих главах будут рассмотрены примеры этого.
* `openIdConnect`: способ определить, как автоматически обнаруживать данные аутентификации OAuth2.
* Это автоматическое обнаружение определено в спецификации OpenID Connect.
!!! tip "Подсказка"
Интеграция сторонних сервисов для аутентификации/авторизации таких как Google, Facebook, Twitter, GitHub и т.д. осуществляется достаточно легко.
Самой сложной проблемой является создание такого провайдера аутентификации/авторизации, но **FastAPI** предоставляет вам инструменты, позволяющие легко это сделать, выполняя при этом всю тяжелую работу за вас.
## Преимущества **FastAPI**
Fast API предоставляет несколько инструментов для каждой из этих схем безопасности в модуле `fastapi.security`, которые упрощают использование этих механизмов безопасности.
В следующих главах вы увидите, как обезопасить свой API, используя инструменты, предоставляемые **FastAPI**.
И вы также увидите, как он автоматически интегрируется в систему интерактивной документации.

View File

@@ -0,0 +1,178 @@
# Люди 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</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

@@ -0,0 +1,213 @@
# Тіло запиту
Коли вам потрібно надіслати дані з клієнта (скажімо, браузера) до вашого API, ви надсилаєте їх як **тіло запиту**.
Тіло **запиту** — це дані, надіслані клієнтом до вашого API. Тіло **відповіді** — це дані, які ваш API надсилає клієнту.
Ваш API майже завжди має надсилати тіло **відповіді**. Але клієнтам не обов’язково потрібно постійно надсилати тіла **запитів**.
Щоб оголосити тіло **запиту**, ви використовуєте <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> моделі з усією їх потужністю та перевагами.
!!! info
Щоб надіслати дані, ви повинні використовувати один із: `POST` (більш поширений), `PUT`, `DELETE` або `PATCH`.
Надсилання тіла із запитом `GET` має невизначену поведінку в специфікаціях, проте воно підтримується FastAPI лише для дуже складних/екстремальних випадків використання.
Оскільки це не рекомендується, інтерактивна документація з Swagger UI не відображатиме документацію для тіла запиту під час використання `GET`, і проксі-сервери в середині можуть не підтримувати її.
## Імпортуйте `BaseModel` від Pydantic
Спочатку вам потрібно імпортувати `BaseModel` з `pydantic`:
=== "Python 3.6 і вище"
```Python hl_lines="4"
{!> ../../../docs_src/body/tutorial001.py!}
```
=== "Python 3.10 і вище"
```Python hl_lines="2"
{!> ../../../docs_src/body/tutorial001_py310.py!}
```
## Створіть свою модель даних
Потім ви оголошуєте свою модель даних як клас, який успадковується від `BaseModel`.
Використовуйте стандартні типи Python для всіх атрибутів:
=== "Python 3.6 і вище"
```Python hl_lines="7-11"
{!> ../../../docs_src/body/tutorial001.py!}
```
=== "Python 3.10 і вище"
```Python hl_lines="5-9"
{!> ../../../docs_src/body/tutorial001_py310.py!}
```
Так само, як і при оголошенні параметрів запиту, коли атрибут моделі має значення за замовчуванням, він не є обов’язковим. В іншому випадку це потрібно. Використовуйте `None`, щоб зробити його необов'язковим.
Наприклад, ця модель вище оголошує JSON "`об'єкт`" (або Python `dict`), як:
```JSON
{
"name": "Foo",
"description": "An optional description",
"price": 45.2,
"tax": 3.5
}
```
...оскільки `description` і `tax` є необов'язковими (зі значенням за замовчуванням `None`), цей JSON "`об'єкт`" також буде дійсним:
```JSON
{
"name": "Foo",
"price": 45.2
}
```
## Оголоси її як параметр
Щоб додати модель даних до вашої *операції шляху*, оголосіть її так само, як ви оголосили параметри шляху та запиту:
=== "Python 3.6 і вище"
```Python hl_lines="18"
{!> ../../../docs_src/body/tutorial001.py!}
```
=== "Python 3.10 і вище"
```Python hl_lines="16"
{!> ../../../docs_src/body/tutorial001_py310.py!}
```
...і вкажіть її тип як модель, яку ви створили, `Item`.
## Результати
Лише з цим оголошенням типу Python **FastAPI** буде:
* Читати тіло запиту як JSON.
* Перетворювати відповідні типи (якщо потрібно).
* Валідувати дані.
* Якщо дані недійсні, він поверне гарну та чітку помилку, вказуючи, де саме і які дані були неправильними.
* Надавати отримані дані у параметрі `item`.
* Оскільки ви оголосили його у функції як тип `Item`, ви також матимете всю підтримку редактора (автозаповнення, тощо) для всіх атрибутів та їх типів.
* Генерувати <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> визначення для вашої моделі, ви також можете використовувати їх де завгодно, якщо це має сенс для вашого проекту.
* Ці схеми будуть частиною згенерованої схеми OpenAPI і використовуватимуться автоматичною документацією інтерфейсу користувача.
## Автоматична документація
Схеми JSON ваших моделей будуть частиною вашої схеми, згенерованої OpenAPI, і будуть показані в інтерактивній API документації:
<img src="/img/tutorial/body/image01.png">
А також використовуватимуться в API документації всередині кожної *операції шляху*, якій вони потрібні:
<img src="/img/tutorial/body/image02.png">
## Підтримка редактора
У вашому редакторі, всередині вашої функції, ви будете отримувати підказки типу та завершення скрізь (це б не сталося, якби ви отримали `dict` замість моделі Pydantic):
<img src="/img/tutorial/body/image03.png">
Ви також отримуєте перевірку помилок на наявність операцій з неправильним типом:
<img src="/img/tutorial/body/image04.png">
Це не випадково, весь каркас був побудований навколо цього дизайну.
І він був ретельно перевірений на етапі проектування, перед будь-яким впровадженням, щоб переконатися, що він працюватиме з усіма редакторами.
Були навіть деякі зміни в самому Pydantic, щоб підтримати це.
Попередні скріншоти були зроблені у <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>.
Але ви отримаєте ту саму підтримку редактора у <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> та більшість інших редакторів Python:
<img src="/img/tutorial/body/image05.png">
!!! tip
Якщо ви використовуєте <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> як ваш редактор, ви можете використати <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a>.
Він покращує підтримку редакторів для моделей Pydantic за допомогою:
* автозаповнення
* перевірки типу
* рефакторингу
* пошуку
* інспекції
## Використовуйте модель
Усередині функції ви можете отримати прямий доступ до всіх атрибутів об’єкта моделі:
=== "Python 3.6 і вище"
```Python hl_lines="21"
{!> ../../../docs_src/body/tutorial002.py!}
```
=== "Python 3.10 і вище"
```Python hl_lines="19"
{!> ../../../docs_src/body/tutorial002_py310.py!}
```
## Тіло запиту + параметри шляху
Ви можете одночасно оголошувати параметри шляху та тіло запиту.
**FastAPI** розпізнає, що параметри функції, які відповідають параметрам шляху, мають бути **взяті з шляху**, а параметри функції, які оголошуються як моделі Pydantic, **взяті з тіла запиту**.
=== "Python 3.6 і вище"
```Python hl_lines="17-18"
{!> ../../../docs_src/body/tutorial003.py!}
```
=== "Python 3.10 і вище"
```Python hl_lines="15-16"
{!> ../../../docs_src/body/tutorial003_py310.py!}
```
## Тіло запиту + шлях + параметри запиту
Ви також можете оголосити параметри **тіло**, **шлях** і **запит** одночасно.
**FastAPI** розпізнає кожен з них і візьме дані з потрібного місця.
=== "Python 3.6 і вище"
```Python hl_lines="18"
{!> ../../../docs_src/body/tutorial004.py!}
```
=== "Python 3.10 і вище"
```Python hl_lines="16"
{!> ../../../docs_src/body/tutorial004_py310.py!}
```
Параметри функції будуть розпізнаватися наступним чином:
* Якщо параметр також оголошено в **шляху**, він використовуватиметься як параметр шляху.
* Якщо параметр має **сингулярний тип** (наприклад, `int`, `float`, `str`, `bool` тощо), він буде інтерпретуватися як параметр **запиту**.
* Якщо параметр оголошується як тип **Pydantic моделі**, він інтерпретується як **тіло** запиту.
!!! note
FastAPI буде знати, що значення "q" не є обов'язковим через значення за замовчуванням "= None".
`Optional` у `Optional[str]` не використовується FastAPI, але дозволить вашому редактору надати вам кращу підтримку та виявляти помилки.
## Без Pydantic
Якщо ви не хочете використовувати моделі Pydantic, ви також можете використовувати параметри **Body**. Перегляньте документацію для [Тіло Кілька параметрів: сингулярні значення в тілі](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.

View File

@@ -0,0 +1,96 @@
# Параметри Cookie
Ви можете визначити параметри Cookie таким же чином, як визначаються параметри `Query` і `Path`.
## Імпорт `Cookie`
Спочатку імпортуйте `Cookie`:
=== "Python 3.10+"
```Python hl_lines="3"
{!> ../../../docs_src/cookie_params/tutorial001_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="3"
{!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="3"
{!> ../../../docs_src/cookie_params/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Бажано використовувати `Annotated` версію, якщо це можливо.
```Python hl_lines="1"
{!> ../../../docs_src/cookie_params/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Бажано використовувати `Annotated` версію, якщо це можливо.
```Python hl_lines="3"
{!> ../../../docs_src/cookie_params/tutorial001.py!}
```
## Визначення параметрів `Cookie`
Потім визначте параметри cookie, використовуючи таку ж конструкцію як для `Path` і `Query`.
Перше значення це значення за замовчуванням, ви можете також передати всі додаткові параметри валідації чи анотації:
=== "Python 3.10+"
```Python hl_lines="9"
{!> ../../../docs_src/cookie_params/tutorial001_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="10"
{!> ../../../docs_src/cookie_params/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Бажано використовувати `Annotated` версію, якщо це можливо.
```Python hl_lines="7"
{!> ../../../docs_src/cookie_params/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Бажано використовувати `Annotated` версію, якщо це можливо.
```Python hl_lines="9"
{!> ../../../docs_src/cookie_params/tutorial001.py!}
```
!!! note "Технічні Деталі"
`Cookie` це "сестра" класів `Path` і `Query`. Вони наслідуються від одного батьківського класу `Param`.
Але пам'ятайте, що коли ви імпортуєте `Query`, `Path`, `Cookie` та інше з `fastapi`, це фактично функції, що повертають спеціальні класи.
!!! info
Для визначення cookies ви маєте використовувати `Cookie`, тому що в іншому випадку параметри будуть інтерпритовані, як параметри запиту.
## Підсумки
Визначайте cookies за допомогою `Cookie`, використовуючи той же спільний шаблон, що і `Query` та `Path`.

1
docs/uk/mkdocs.yml Normal file
View File

@@ -0,0 +1 @@
INHERIT: ../en/mkdocs.yml

View File

@@ -0,0 +1,52 @@
# بینچ مارکس
انڈیپنڈنٹ ٹیک امپور بینچ مارک **FASTAPI** Uvicorn کے تحت چلنے والی ایپلی کیشنز کو <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 کے ذریعہ اندرونی طور پر استعمال کیا جاتا ہے ) (*)
لیکن جب بینچ مارک اور موازنہ کی جانچ پڑتال کرتے ہو تو آپ کو مندرجہ ذیل بات ذہن میں رکھنی چاہئے.
## بینچ مارک اور رفتار
جب آپ بینچ مارک کی جانچ کرتے ہیں تو ، مساوی کے مقابلے میں مختلف اقسام کے متعدد اوزار دیکھنا عام ہے.
خاص طور پر ، Uvicorn, Starlette اور FastAPI کو دیکھنے کے لئے ( بہت سے دوسرے ٹولز ) کے ساتھ موازنہ کیا گیا.
ٹول کے ذریعہ حل ہونے والا آسان مسئلہ ، اس کی بہتر کارکردگی ہوگی. اور زیادہ تر بینچ مارک ٹول کے ذریعہ فراہم کردہ اضافی خصوصیات کی جانچ نہیں کرتے ہیں.
درجہ بندی کی طرح ہے:
<ul style="direction: rtl;">
<li><div style="text-align: right;">ASGI :<b>Uvicorn</b> سرور</div></li>
<ul>
<li><div style="text-align: right;"><b>Starlette</b>: (Uvicorn استعمال کرتا ہے) ایک ویب مائیکرو فریم ورک </div></li>
<ul>
<li><div style="text-align: right;"><b>FastAPI</b>: (Starlette کا استعمال کرتا ہے) ایک API مائکرو فریم ورک جس میں APIs بنانے کے لیے کئی اضافی خصوصیات ہیں، ڈیٹا کی توثیق وغیرہ کے ساتھ۔</div></li>
</ul>
</ul>
</ul>
<ul style="direction: rtl;">
<li><div style="text-align: right;"><b>Uvicorn</b>:</div></li>
<ul>
<li><div style="text-align: right;">بہترین کارکردگی ہوگی، کیونکہ اس میں سرور کے علاوہ زیادہ اضافی کوڈ نہیں ہے۔</div></li>
<li><div style="text-align: right;">آپ براہ راست Uvicorn میں درخواست نہیں لکھیں گے۔ اس کا مطلب یہ ہوگا کہ آپ کے کوڈ میں کم و بیش، کم از کم، Starlette (یا <b>FastAPI</b>) کی طرف سے فراہم کردہ تمام کوڈ شامل کرنا ہوں گے۔ اور اگر آپ نے ایسا کیا تو، آپ کی حتمی ایپلیکیشن کا وہی اوور ہیڈ ہوگا جیسا کہ ایک فریم ورک استعمال کرنے اور آپ کے ایپ کوڈ اور کیڑے کو کم سے کم کرنا۔</div></li>
<li><div style="text-align: right;">اگر آپ Uvicorn کا موازنہ کر رہے ہیں تو اس کا موازنہ Daphne، Hypercorn، uWSGI وغیرہ ایپلیکیشن سرورز سے کریں۔</div></li>
</ul>
</ul>
<ul style="direction: rtl;">
<li><div style="text-align: right;"><b>Starlette</b>:</div></li>
<ul>
<li><div style="text-align: right;">Uvicorn کے بعد اگلی بہترین کارکردگی ہوگی۔ درحقیقت، Starlette چلانے کے لیے Uvicorn کا استعمال کرتی ہے۔ لہذا، یہ شاید زیادہ کوڈ پر عمل درآمد کرکے Uvicorn سے "سست" ہوسکتا ہے۔</div></li>
<li><div style="text-align: right;">لیکن یہ آپ کو آسان ویب ایپلیکیشنز بنانے کے لیے ٹولز فراہم کرتا ہے، راستوں پر مبنی روٹنگ کے ساتھ، وغیرہ۔</div></li>
<li><div style="text-align: right;">اگر آپ سٹارلیٹ کا موازنہ کر رہے ہیں تو اس کا موازنہ Sanic، Flask، Django وغیرہ سے کریں۔ ویب فریم ورکس (یا مائیکرو فریم ورکس)</div></li>
</ul>
</ul>
<ul style="direction: rtl;">
<li><div style="text-align: right;"><b>FastAPI</b>:</div></li>
<ul>
<li><div style="text-align: right;">جس طرح سے Uvicorn Starlette کا استعمال کرتا ہے اور اس سے تیز نہیں ہو سکتا، Starlette <b>FastAPI</b> کا استعمال کرتا ہے، اس لیے یہ اس سے تیز نہیں ہو سکتا۔</div></li>
<li><div style="text-align: right;">Starlette FastAPI کے اوپری حصے میں مزید خصوصیات فراہم کرتا ہے۔ وہ خصوصیات جن کی آپ کو APIs بناتے وقت تقریباً ہمیشہ ضرورت ہوتی ہے، جیسے ڈیٹا کی توثیق اور سیریلائزیشن۔ اور اسے استعمال کرنے سے، آپ کو خودکار دستاویزات مفت میں مل جاتی ہیں (خودکار دستاویزات چلنے والی ایپلی کیشنز میں اوور ہیڈ کو بھی شامل نہیں کرتی ہیں، یہ اسٹارٹ اپ پر تیار ہوتی ہیں)۔</div></li>
<li><div style="text-align: right;">اگر آپ نے FastAPI کا استعمال نہیں کیا ہے اور Starlette کو براہ راست استعمال کیا ہے (یا کوئی دوسرا ٹول، جیسے Sanic، Flask، Responder، وغیرہ) آپ کو تمام ڈیٹا کی توثیق اور سیریلائزیشن کو خود نافذ کرنا ہوگا۔ لہذا، آپ کی حتمی ایپلیکیشن اب بھی وہی اوور ہیڈ ہوگی جیسا کہ اسے FastAPI کا استعمال کرتے ہوئے بنایا گیا تھا۔ اور بہت سے معاملات میں، یہ ڈیٹا کی توثیق اور سیریلائزیشن ایپلی کیشنز میں لکھے گئے کوڈ کی سب سے بڑی مقدار ہے۔</div></li>
<li><div style="text-align: right;">لہذا، FastAPI کا استعمال کرکے آپ ترقیاتی وقت، Bugs، کوڈ کی لائنوں کی بچت کر رہے ہیں، اور شاید آپ کو وہی کارکردگی (یا بہتر) ملے گی اگر آپ اسے استعمال نہیں کرتے (جیسا کہ آپ کو یہ سب اپنے کوڈ میں لاگو کرنا ہوگا۔ )</div></li>
<li><div style="text-align: right;">اگر آپ FastAPI کا موازنہ کر رہے ہیں، تو اس کا موازنہ ویب ایپلیکیشن فریم ورک (یا ٹولز کے سیٹ) سے کریں جو ڈیٹا کی توثیق، سیریلائزیشن اور دستاویزات فراہم کرتا ہے، جیسے Flask-apispec، NestJS، Molten، وغیرہ۔ مربوط خودکار ڈیٹا کی توثیق، سیریلائزیشن اور دستاویزات کے ساتھ فریم ورک۔</div></li>
</ul>
</ul>

1
docs/ur/mkdocs.yml Normal file
View File

@@ -0,0 +1 @@
INHERIT: ../en/mkdocs.yml

197
docs/vi/docs/features.md Normal file
View File

@@ -0,0 +1,197 @@
# Tính năng
## Tính năng của FastAPI
**FastAPI** cho bạn những tính năng sau:
### Dựa trên những tiêu chuẩn mở
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> cho việc tạo API, bao gồm những khai báo về <abbr title="cũng được biết đến như: endpoints, routes">đường dẫn</abbr> <abbr title="cũng được biết đến như các phương thức HTTP, như POST, GET, PUT, DELETE"> các toán tử</abbr>, tham số, body requests, cơ chế bảo mật, etc.
* Tự động tài liệu hóa data model theo <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (OpenAPI bản thân nó được dựa trên JSON Schema).
* Được thiết kế xung quanh các tiêu chuẩn này sau khi nghiên cứu tỉ mỉ thay vì chỉ suy nghĩ đơn giản và sơ xài.
* Điều này cho phép tự động hóa **trình sinh code client** cho nhiều ngôn ngữ lập trình khác nhau.
### Tự động hóa tài liệu
Tài liệu tương tác API và web giao diện người dùng. Là một framework được dựa trên OpenAPI do đó có nhiều tùy chọn giao diện cho tài liệu API, 2 giao diện bên dưới là mặc định.
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>, với giao diện khám phá, gọi và kiểm thử API trực tiếp từ trình duyệt.
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
* Thay thế với tài liệu API với <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a>.
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### Chỉ cần phiên bản Python hiện đại
Tất cả được dựa trên khai báo kiểu dữ liệu chuẩn của **Python 3.6** (cảm ơn Pydantic). Bạn không cần học cú pháp mới, chỉ cần biết chuẩn Python hiện đại.
Nếu bạn cần 2 phút để làm mới lại cách sử dụng các kiểu dữ liệu mới của Python (thậm chí nếu bạn không sử dụng FastAPI), xem hướng dẫn ngắn: [Kiểu dữ liệu Python](python-types.md){.internal-link target=_blank}.
Bạn viết chuẩn Python với kiểu dữ liệu như sau:
```Python
from datetime import date
from pydantic import BaseModel
# Declare a variable as a str
# and get editor support inside the function
def main(user_id: str):
return user_id
# A Pydantic model
class User(BaseModel):
id: int
name: str
joined: date
```
Sau đó có thể được sử dụng:
```Python
my_user: User = User(id=3, name="John Doe", joined="2018-07-19")
second_user_data = {
"id": 4,
"name": "Mary",
"joined": "2018-11-30",
}
my_second_user: User = User(**second_user_data)
```
!!! info
`**second_user_data` nghĩa là:
Truyền các khóa và giá trị của dict `second_user_data` trực tiếp như các tham số kiểu key-value, tương đương với: `User(id=4, name="Mary", joined="2018-11-30")`
### Được hỗ trợ từ các trình soạn thảo
Toàn bộ framework được thiết kế để sử dụng dễ dàng và trực quan, toàn bộ quyết định đã được kiểm thử trên nhiều trình soạn thảo thậm chí trước khi bắt đầu quá trình phát triển, để chắc chắn trải nghiệm phát triển là tốt nhất.
Trong lần khảo sát cuối cùng dành cho các lập trình viên Python, đã rõ ràng <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">rằng đa số các lập trình viên sử dụng tính năng "autocompletion"</a>.
Toàn bộ framework "FastAPI" phải đảm bảo rằng: autocompletion hoạt động ở mọi nơi. Bạn sẽ hiếm khi cần quay lại để đọc tài liệu.
Đây là các trình soạn thảo có thể giúp bạn:
* trong <a href="https://code.visualstudio.com/" class="external-link" target="_blank">Visual Studio Code</a>:
![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
* trong <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>:
![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)
Bạn sẽ có được auto-completion trong code, thậm chí trước đó là không thể. Như trong ví dụ, khóa `price` bên trong một JSON (đó có thể được lồng nhau) đến từ một request.
Không còn nhập sai tên khóa, quay đi quay lại giữa các tài liệu hoặc cuộn lên cuộn xuống để tìm xem cuối cùng bạn đã sử dụng `username` hay `user_name`.
### Ngắn gọn
FastAPI có các giá trị mặc định hợp lý cho mọi thứ, với các cấu hình tùy chọn ở mọi nơi. Tất cả các tham số có thể được tinh chỉnh để thực hiện những gì bạn cần và để định nghĩa API bạn cần.
Nhưng mặc định, tất cả **đều hoạt động**.
### Validation
* Validation cho đa số (hoặc tất cả?) **các kiểu dữ liệu** Python, bao gồm:
* JSON objects (`dict`).
* Mảng JSON (`list`) định nghĩa kiểu dữ liệu từng phần tử.
* Xâu (`str`), định nghĩa độ dài lớn nhất, nhỏ nhất.
* Số (`int`, `float`) với các giá trị lớn nhất, nhỏ nhất, etc.
* Validation cho nhiều kiểu dữ liệu bên ngoài như:
* URL.
* Email.
* UUID.
* ...và nhiều cái khác.
Tất cả validation được xử lí bằng những thiết lập tốt và mạnh mẽ của **Pydantic**.
### Bảo mật và xác thực
Bảo mật và xác thực đã tích hợp mà không làm tổn hại tới cơ sở dữ liệu hoặc data models.
Tất cả cơ chế bảo mật định nghĩa trong OpenAPI, bao gồm:
* HTTP Basic.
* **OAuth2** (với **JWT tokens**). Xem hướng dẫn [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
* API keys in:
* Headers.
* Các tham số trong query string.
* Cookies, etc.
Cộng với tất cả các tính năng bảo mật từ Starlette (bao gồm **session cookies**).
Tất cả được xây dựng dưới dạng các công cụ và thành phần có thể tái sử dụng, dễ dàng tích hợp với hệ thống, kho lưu trữ dữ liệu, cơ sở dữ liệu quan hệ và NoSQL của bạn,...
### Dependency Injection
FastAPI bao gồm một hệ thống <abbr title='cũng biết đến như là "components", "resources", "services", "providers"'><strong>Dependency Injection</strong></abbr> vô cùng dễ sử dụng nhưng vô cùng mạnh mẽ.
* Thậm chí, các dependency có thể có các dependency khác, tạo thành một phân cấp hoặc **"một đồ thị" của các dependency**.
* Tất cả **được xử lí tự động** bởi framework.
* Tất cả các dependency có thể yêu cầu dữ liệu từ request và **tăng cường các ràng buộc từ đường dẫn** và tự động tài liệu hóa.
* **Tự động hóa validation**, thậm chí với các tham số *đường dẫn* định nghĩa trong các dependency.
* Hỗ trợ hệ thống xác thực người dùng phức tạp, **các kết nối cơ sở dữ liệu**,...
* **Không làm tổn hại** cơ sở dữ liệu, frontends,... Nhưng dễ dàng tích hợp với tất cả chúng.
### Không giới hạn "plug-ins"
Hoặc theo một cách nào khác, không cần chúng, import và sử dụng code bạn cần.
Bất kì tích hợp nào được thiết kế để sử dụng đơn giản (với các dependency), đến nỗi bạn có thể tạo một "plug-in" cho ứng dụng của mình trong 2 dòng code bằng cách sử dụng cùng một cấu trúc và cú pháp được sử dụng cho *path operations* của bạn.
### Đã được kiểm thử
* 100% <abbr title=" Lượng code đã được kiểm thử tự động">test coverage</abbr>.
* 100% <abbr title="Python type annotations, với điều này trình soạn thảo của bạn và các công cụ bên ngoài có thể hỗ trợ bạn tốt hơn">type annotated</abbr> code base.
* Được sử dụng cho các ứng dụng sản phẩm.
## Tính năng của Starlette
`FastAPI` is thực sự là một sub-class của `Starlette`. Do đó, nếu bạn đã biết hoặc đã sử dụng Starlette, đa số các chức năng sẽ làm việc giống như vậy.
Với **FastAPI**, bạn có được tất cả những tính năng của **Starlette**:
* Hiệu năng thực sự ấn tượng. Nó là <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">một trong nhưng framework Python nhanh nhất, khi so sánh với **NodeJS****Go**</a>.
* Hỗ trợ **WebSocket**.
* In-process background tasks.
* Startup and shutdown events.
* Client cho kiểm thử xây dựng trên HTTPX.
* **CORS**, GZip, Static Files, Streaming responses.
* Hỗ trợ **Session and Cookie**.
* 100% test coverage.
* 100% type annotated codebase.
## Tính năng của Pydantic
**FastAPI** tương thích đầy đủ với (và dựa trên) <a href="https://pydantic-docs.helpmanual.io" class="external-link" target="_blank"><strong>Pydantic</strong></a>. Do đó, bất kì code Pydantic nào bạn thêm vào cũng sẽ hoạt động.
Bao gồm các thư viện bên ngoài cũng dựa trên Pydantic, như <abbr title="Object-Relational Mapper">ORM</abbr>s, <abbr title="Object-Document Mapper">ODM</abbr>s cho cơ sở dữ liệu.
Nó cũng có nghĩa là trong nhiều trường hợp, bạn có thể truyền cùng object bạn có từ một request **trực tiếp cho cơ sở dữ liệu**, vì mọi thứ được validate tự động.
Điều tương tự áp dụng cho các cách khác nhau, trong nhiều trường hợp, bạn có thể chỉ truyền object từ cơ sở dữ liêu **trực tiếp tới client**.
Với **FastAPI**, bạn có tất cả những tính năng của **Pydantic** (FastAPI dựa trên Pydantic cho tất cả những xử lí về dữ liệu):
* **Không gây rối não**:
* Không cần học ngôn ngữ mô tả cấu trúc mới.
* Nếu bạn biết kiểu dữ liệu Python, bạn biết cách sử dụng Pydantic.
* Sử dụng tốt với **<abbr title="Môi trường phát triển tích hợp, tương tự như một trình soạn thảo code">IDE</abbr>/<abbr title="Một chương trình kiểm tra code lỗi">linter</abbr>/não của bạn**:
* Bởi vì các cấu trúc dữ liệu của Pydantic chỉ là các instances của class bạn định nghĩa; auto-completion, linting, mypy và trực giác của bạn nên làm việc riêng biệt với những dữ liệu mà bạn đã validate.
* Validate **các cấu trúc phức tạp**:
* Sử dụng các models Pydantic phân tầng, `List``Dict` của Python `typing`,...
* Và các validators cho phép các cấu trúc dữ liệu phức tạp trở nên rõ ràng và dễ dàng để định nghĩa, kiểm tra và tài liệu hóa thành JSON Schema.
* Bạn có thể có các object **JSON lồng nhau** và tất cả chúng đã validate và annotated.
* **Có khả năng mở rộng**:
* Pydantic cho phép bạn tùy chỉnh kiểu dữ liệu bằng việc định nghĩa hoặc bạn có thể mở rộng validation với các decorator trong model.
* 100% test coverage.

472
docs/vi/docs/index.md Normal file
View File

@@ -0,0 +1,472 @@
<p align="center">
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
</p>
<p align="center">
<em>FastAPI framework, hiệu năng cao, dễ học, dễ code, sẵn sàng để tạo ra sản phẩm</em>
</p>
<p align="center">
<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://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">
</a>
<a href="https://pypi.org/project/fastapi" target="_blank">
<img src="https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058" alt="Supported Python versions">
</a>
</p>
---
**Tài liệu**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
**Mã nguồn**: <a href="https://github.com/tiangolo/fastapi" target="_blank">https://github.com/tiangolo/fastapi</a>
---
FastAPI là một web framework hiện đại, hiệu năng cao để xây dựng web APIs với Python 3.7+ dựa trên tiêu chuẩn Python type hints.
Những tính năng như:
* **Nhanh**: Hiệu năng rất cao khi so sánh với **NodeJS****Go** (cảm ơn Starlette và Pydantic). [Một trong những Python framework nhanh nhất](#performance).
* **Code nhanh**: Tăng tốc độ phát triển tính năng từ 200% tới 300%. *
* **Ít lỗi hơn**: Giảm khoảng 40% những lỗi phát sinh bởi con người (nhà phát triển). *
* **Trực giác tốt hơn**: Được các trình soạn thảo hỗ tuyệt vời. <abbr title="như auto-complete, autocompletion, IntelliSense">Completion</abbr> mọi nơi. Ít thời gian gỡ lỗi.
* **Dễ dàng**: Được thiết kế để dễ dàng học và sử dụng. Ít thời gian đọc tài liệu.
* **Ngắn**: Tối thiểu code bị trùng lặp. Nhiều tính năng được tích hợp khi định nghĩa tham số. Ít lỗi hơn.
* **Tăng tốc**: Có được sản phẩm cùng với tài liệu (được tự động tạo) có thể tương tác.
* **Được dựa trên các tiêu chuẩn**: Dựa trên (và hoàn toàn tương thích với) các tiêu chuẩn mở cho APIs : <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (trước đó được biết đến là Swagger) và <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
<small>* ước tính được dựa trên những kiểm chứng trong nhóm phát triển nội bộ, xây dựng các ứng dụng sản phẩm.</small>
## Nhà tài trợ
<!-- sponsors -->
{% if sponsors %}
{% for sponsor in sponsors.gold -%}
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
{% endfor -%}
{%- 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 %}
<!-- /sponsors -->
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">Những nhà tài trợ khác</a>
## Ý kiến đánh giá
"_[...] Tôi đang sử dụng **FastAPI** vô cùng nhiều vào những ngày này. [...] Tôi thực sự đang lên kế hoạch sử dụng nó cho tất cả các nhóm **dịch vụ ML tại Microsoft**. Một vài trong số đó đang tích hợp vào sản phẩm lõi của **Window** và một vài sản phẩm cho **Office**._"
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/tiangolo/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
---
"_Chúng tôi tích hợp thư viện **FastAPI** để sinh ra một **REST** server, nó có thể được truy vấn để thu được những **dự đoán**._ [bởi Ludwid] "
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, và Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
---
"_**Netflix** vui mừng thông báo việc phát hành framework mã nguồn mở của chúng tôi cho *quản lí khủng hoảng* tập trung: **Dispatch**! [xây dựng với **FastAPI**]_"
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
---
"_Tôi vô cùng hào hứng về **FastAPI**. Nó rất thú vị_"
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://twitter.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
---
"_Thành thật, những gì bạn đã xây dựng nhìn siêu chắc chắn và bóng bẩy. Theo nhiều cách, nó là những gì tôi đã muốn Hug trở thành - thật sự truyền cảm hứng để thấy ai đó xây dựng nó._"
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - người tạo ra <strong><a href="https://www.hug.rest/" target="_blank">Hug</a></strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
---
"_Nếu bạn đang tìm kiếm một **framework hiện đại** để xây dựng một REST APIs, thử xem xét **FastAPI** [...] Nó nhanh, dễ dùng và dễ học [...]_"
"_Chúng tôi đã chuyển qua **FastAPI cho **APIs** của chúng tôi [...] Tôi nghĩ bạn sẽ thích nó [...]_"
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> founders - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://twitter.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://twitter.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong>nhà sáng lập <a href="https://explosion.ai" target="_blank">Explosion AI</a> - người tạo ra <a href="https://spacy.io" target="_blank">spaCy</a></strong> <a href="https://twitter.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://twitter.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
---
"_Nếu ai đó đang tìm cách xây dựng sản phẩm API bằng Python, tôi sẽ đề xuất **FastAPI**. Nó **được thiết kế đẹp đẽ**, **sử dụng đơn giản****có khả năng mở rộng cao**, nó đã trở thành một **thành phần quan trọng** trong chiến lược phát triển API của chúng tôi và đang thúc đẩy nhiều dịch vụ và mảng tự động hóa như Kỹ sư TAC ảo của chúng tôi._"
<div style="text-align: right; margin-right: 10%;">Deon Pillsbury - <strong>Cisco</strong> <a href="https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/" target="_blank"><small>(ref)</small></a></div>
---
## **Typer**, giao diện dòng lệnh của FastAPI
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
Nếu bạn đang xây dựng một <abbr title="Giao diện dòng lệnh">CLI</abbr> - ứng dụng được sử dụng trong giao diện dòng lệnh, xem về <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
**Typer** là một người anh em của FastAPI. Và nó được dự định trở thành **giao diện dòng lệnh cho FastAPI**. ⌨️ 🚀
## Yêu cầu
Python 3.7+
FastAPI đứng trên vai những người khổng lồ:
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> cho phần web.
* <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> cho phần data.
## Cài đặt
<div class="termy">
```console
$ pip install fastapi
---> 100%
```
</div>
Bạn cũng sẽ cần một ASGI server cho production như <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> hoặc <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
<div class="termy">
```console
$ pip install "uvicorn[standard]"
---> 100%
```
</div>
## Ví dụ
### Khởi tạo
* Tạo một tệp tin `main.py` như sau:
```Python
from typing import Union
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}
```
<details markdown="1">
<summary>Hoặc sử dụng <code>async def</code>...</summary>
Nếu code của bạn sử dụng `async` / `await`, hãy sử dụng `async def`:
```Python hl_lines="9 14"
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
**Lưu ý**:
Nếu bạn không biết, xem phần _"In a hurry?"_ về <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` và `await` trong tài liệu này</a>.
</details>
### Chạy ứng dụng
Chạy server như sau:
<div class="termy">
```console
$ uvicorn main:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
</div>
<details markdown="1">
<summary>Về lệnh <code>uvicorn main:app --reload</code>...</summary>
Lệnh `uvicorn main:app` tham chiếu tới những thành phần sau:
* `main`: tệp tin `main.py` (một Python "module").
* `app`: object được tạo trong tệp tin `main.py` tại dòng `app = FastAPI()`.
* `--reload`: chạy lại server sau khi code thay đổi. Chỉ sử dụng trong quá trình phát triển.
</details>
### Kiểm tra
Mở trình duyệt của bạn tại <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
Bạn sẽ thấy một JSON response:
```JSON
{"item_id": 5, "q": "somequery"}
```
Bạn đã sẵn sàng để tạo một API như sau:
* Nhận HTTP request với _đường dẫn_ `/` và `/items/{item_id}`.
* Cả hai _đường dẫn_ sử dụng <em>toán tử</em> `GET` (cũng đươc biết đến là _phương thức_ HTTP).
* _Đường dẫn_ `/items/{item_id}` có một _tham số đường dẫn_ `item_id`, nó là một tham số kiểu `int`.
* _Đường dẫn_ `/items/{item_id}` có một _tham số query string_ `q`, nó là một tham số tùy chọn kiểu `str`.
### Tài liệu tương tác API
Truy cập <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Bạn sẽ thấy tài liệu tương tác API được tạo tự động (cung cấp bởi <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)
### Tài liệu API thay thế
Và bây giờ, hãy truy cập tới <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
Bạn sẽ thấy tài liệu được thay thế (cung cấp bởi <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)
## Nâng cấp ví dụ
Bây giờ sửa tệp tin `main.py` để nhận body từ một request `PUT`.
Định nghĩa của body sử dụng kiểu dữ liệu chuẩn của Python, cảm ơn Pydantic.
```Python hl_lines="4 9-12 25-27"
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: Union[bool, None] = None
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
```
Server nên tự động chạy lại (bởi vì bạn đã thêm `--reload` trong lệnh `uvicorn` ở trên).
### Nâng cấp tài liệu API
Bây giờ truy cập tới <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
* Tài liệu API sẽ được tự động cập nhật, bao gồm body mới:
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
* Click vào nút "Try it out", nó cho phép bạn điền những tham số và tương tác trực tiếp với API:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)
* Sau khi click vào nút "Execute", giao diện người dùng sẽ giao tiếp với API của bạn bao gồm: gửi các tham số, lấy kết quả và hiển thị chúng trên màn hình:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)
### Nâng cấp tài liệu API thay thế
Và bây giờ truy cập tới <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
* Tài liệu thay thế cũng sẽ phản ánh tham số và body mới:
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### Tóm lại
Bạn khai báo **một lần** kiểu dữ liệu của các tham số, body, etc là các tham số của hàm số.
Bạn định nghĩa bằng cách sử dụng các kiểu dữ liệu chuẩn của Python.
Bạn không phải học một cú pháp mới, các phương thức và class của một thư viện cụ thể nào.
Chỉ cần sử dụng các chuẩn của **Python 3.7+**.
Ví dụ, với một tham số kiểu `int`:
```Python
item_id: int
```
hoặc với một model `Item` phức tạp hơn:
```Python
item: Item
```
...và với định nghĩa đơn giản đó, bạn có được:
* Sự hỗ trợ từ các trình soạn thảo, bao gồm:
* Completion.
* Kiểm tra kiểu dữ liệu.
* Kiểm tra kiểu dữ liệu:
* Tự động sinh lỗi rõ ràng khi dữ liệu không hợp lệ .
* Kiểm tra JSON lồng nhau .
* <abbr title="cũng được biết tới như: serialization, parsing, marshalling">Chuyển đổi</abbr> dữ liệu đầu vào: tới từ network sang dữ liệu kiểu Python. Đọc từ:
* JSON.
* Các tham số trong đường dẫn.
* Các tham số trong query string.
* Cookies.
* Headers.
* Forms.
* Files.
* <abbr title="cũng được biết tới như: serialization, parsing, marshalling">Chuyển đổi</abbr> dữ liệu đầu ra: chuyển đổi từ kiểu dữ liệu Python sang dữ liệu network (như JSON):
* Chuyển đổi kiểu dữ liệu Python (`str`, `int`, `float`, `bool`, `list`,...).
* `datetime` objects.
* `UUID` objects.
* Database models.
* ...và nhiều hơn thế.
* Tự động tạo tài liệu tương tác API, bao gồm 2 giao diện người dùng:
* Swagger UI.
* ReDoc.
---
Quay trở lại ví dụ trước, **FastAPI** sẽ thực hiện:
* Kiểm tra xem có một `item_id` trong đường dẫn với các request `GET` và `PUT` không?
* Kiểm tra xem `item_id` có phải là kiểu `int` trong các request `GET` và `PUT` không?
* Nếu không, client sẽ thấy một lỗi rõ ràng và hữu ích.
* Kiểm tra xem nếu có một tham số `q` trong query string (ví dụ như `http://127.0.0.1:8000/items/foo?q=somequery`) cho request `GET`.
* Tham số `q` được định nghĩa `= None`, nó là tùy chọn.
* Nếu không phải `None`, nó là bắt buộc (như body trong trường hợp của `PUT`).
* Với request `PUT` tới `/items/{item_id}`, đọc body như JSON:
* Kiểm tra xem nó có một thuộc tính bắt buộc kiểu `str` là `name` không?
* Kiểm tra xem nó có một thuộc tính bắt buộc kiểu `float` là `price` không?
* Kiểm tra xem nó có một thuộc tính tùy chọn là `is_offer` không? Nếu có, nó phải có kiểu `bool`.
* Tất cả những kiểm tra này cũng được áp dụng với các JSON lồng nhau.
* Chuyển đổi tự động các JSON object đến và JSON object đi.
* Tài liệu hóa mọi thứ với OpenAPI, tài liệu đó có thể được sử dụng bởi:
* Các hệ thống tài liệu có thể tương tác.
* Hệ thống sinh code tự động, cho nhiều ngôn ngữ lập trình.
* Cung cấp trực tiếp 2 giao diện web cho tài liệu tương tác
---
Chúng tôi chỉ trình bày những thứ cơ bản bên ngoài, nhưng bạn đã hiểu cách thức hoạt động của nó.
Thử thay đổi dòng này:
```Python
return {"item_name": item.name, "item_id": item_id}
```
...từ:
```Python
... "item_name": item.name ...
```
...sang:
```Python
... "item_price": item.price ...
```
...và thấy trình soạn thảo của bạn nhận biết kiểu dữ liệu và gợi ý hoàn thiện các thuộc tính.
![trình soạn thảo hỗ trợ](https://fastapi.tiangolo.com/img/vscode-completion.png)
Ví dụ hoàn chỉnh bao gồm nhiều tính năng hơn, xem <a href="https://fastapi.tiangolo.com/tutorial/">Tutorial - User Guide</a>.
**Cảnh báo tiết lỗ**: Tutorial - User Guide:
* Định nghĩa **tham số** từ các nguồn khác nhau như: **headers**, **cookies**, **form fields** và **files**.
* Cách thiết lập **các ràng buộc cho validation** như `maximum_length` hoặc `regex`.
* Một hệ thống **<abbr title="cũng được biết đến như components, resources, providers, services, injectables">Dependency Injection</abbr> vô cùng mạnh mẽ và dễ dàng sử dụng.
* Bảo mật và xác thực, hỗ trợ **OAuth2**(với **JWT tokens**) và **HTTP Basic**.
* Những kĩ thuật nâng cao hơn (nhưng tương đối dễ) để định nghĩa **JSON models lồng nhau** (cảm ơn Pydantic).
* Tích hợp **GraphQL** với <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> và các thư viện khác.
* Nhiều tính năng mở rộng (cảm ơn Starlette) như:
* **WebSockets**
* kiểm thử vô cùng dễ dàng dựa trên HTTPX và `pytest`
* **CORS**
* **Cookie Sessions**
* ...và nhiều hơn thế.
## Hiệu năng
Independent TechEmpower benchmarks cho thấy các ứng dụng **FastAPI** chạy dưới Uvicorn là <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">một trong những Python framework nhanh nhất</a>, chỉ đứng sau Starlette và Uvicorn (được sử dụng bên trong FastAPI). (*)
Để hiểu rõ hơn, xem phần <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
## Các dependency tùy chọn
Sử dụng bởi Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - <abbr title="chuyển dổi string từ HTTP request sang dữ liệu Python">"Parse"</abbr> JSON nhanh hơn.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - cho email validation.
Sử dụng Starlette:
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Bắt buộc nếu bạn muốn sử dụng `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Bắt buộc nếu bạn muốn sử dụng cấu hình template engine mặc định.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Bắt buộc nếu bạn muốn hỗ trợ <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, form với `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Bắt buộc để hỗ trợ `SessionMiddleware`.
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Bắt buộc để hỗ trợ `SchemaGenerator` cho Starlette (bạn có thể không cần nó trong FastAPI).
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Bắt buộc nếu bạn muốn sử dụng `UJSONResponse`.
Sử dụng bởi FastAPI / Starlette:
* <a href="https://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - Server để chạy ứng dụng của bạn.
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Bắt buộc nếu bạn muốn sử dụng `ORJSONResponse`.
Bạn có thể cài đặt tất cả những dependency trên với `pip install "fastapi[all]"`.
## Giấy phép
Dự án này được cấp phép dưới những điều lệ của giấy phép MIT.

View File

@@ -0,0 +1,545 @@
# Giới thiệu kiểu dữ liệu Python
Python hỗ trợ tùy chọn "type hints" (còn được gọi là "type annotations").
Những **"type hints"** hay chú thích là một cú pháp đặc biệt cho phép khai báo <abbr title="ví dụ: str, int, float, bool"> kiểu dữ liệu</abbr> của một biến.
Bằng việc khai báo kiểu dữ liệu cho các biến của bạn, các trình soạn thảo và các công cụ có thể hỗ trợ bạn tốt hơn.
Đây chỉ là một **hướng dẫn nhanh** về gợi ý kiểu dữ liệu trong Python. Nó chỉ bao gồm những điều cần thiết tối thiểu để sử dụng chúng với **FastAPI**... đó thực sự là rất ít.
**FastAPI** hoàn toàn được dựa trên những gợi ý kiểu dữ liệu, chúng mang đến nhiều ưu điểm và lợi ích.
Nhưng thậm chí nếu bạn không bao giờ sử dụng **FastAPI**, bạn sẽ được lợi từ việc học một ít về chúng.
!!! note
Nếu bạn là một chuyên gia về Python, và bạn đã biết mọi thứ về gợi ý kiểu dữ liệu, bỏ qua và đi tới chương tiếp theo.
## Động lực
Hãy bắt đầu với một ví dụ đơn giản:
```Python
{!../../../docs_src/python_types/tutorial001.py!}
```
Kết quả khi gọi chương trình này:
```
John Doe
```
Hàm thực hiện như sau:
* Lấy một `first_name``last_name`.
* Chuyển đổi kí tự đầu tiên của mỗi biến sang kiểu chữ hoa với `title()`.
* <abbr title="Đặt chúng lại với nhau thành một. Với các nội dung lần lượt.">Nối</abbr> chúng lại với nhau bằng một kí tự trắng ở giữa.
```Python hl_lines="2"
{!../../../docs_src/python_types/tutorial001.py!}
```
### Sửa đổi
Nó là một chương trình rất đơn giản.
Nhưng bây giờ hình dung rằng bạn đang viết nó từ đầu.
Tại một vài thời điểm, bạn sẽ bắt đầu định nghĩa hàm, bạn có các tham số...
Nhưng sau đó bạn phải gọi "phương thức chuyển đổi kí tự đầu tiên sang kiểu chữ hoa".
Có phải là `upper`? Có phải là `uppercase`? `first_uppercase`? `capitalize`?
Sau đó, bạn thử hỏi người bạn cũ của mình, autocompletion của trình soạn thảo.
Bạn gõ tham số đầu tiên của hàm, `first_name`, sau đó một dấu chấm (`.`) và sau đó ấn `Ctrl+Space` để kích hoạt bộ hoàn thành.
Nhưng đáng buồn, bạn không nhận được điều gì hữu ích cả:
<img src="/img/python-types/image01.png">
### Thêm kiểu dữ liệu
Hãy sửa một dòng từ phiên bản trước.
Chúng ta sẽ thay đổi chính xác đoạn này, tham số của hàm, từ:
```Python
first_name, last_name
```
sang:
```Python
first_name: str, last_name: str
```
Chính là nó.
Những thứ đó là "type hints":
```Python hl_lines="1"
{!../../../docs_src/python_types/tutorial002.py!}
```
Đó không giống như khai báo những giá trị mặc định giống như:
```Python
first_name="john", last_name="doe"
```
Nó là một thứ khác.
Chúng ta sử dụng dấu hai chấm (`:`), không phải dấu bằng (`=`).
Và việc thêm gợi ý kiểu dữ liệu không làm thay đổi những gì xảy ra so với khi chưa thêm chúng.
But now, imagine you are again in the middle of creating that function, but with type hints.
Tại cùng một điểm, bạn thử kích hoạt autocomplete với `Ctrl+Space` và bạn thấy:
<img src="/img/python-types/image02.png">
Với cái đó, bạn có thể cuộn, nhìn thấy các lựa chọn, cho đến khi bạn tìm thấy một "tiếng chuông":
<img src="/img/python-types/image03.png">
## Động lực nhiều hơn
Kiểm tra hàm này, nó đã có gợi ý kiểu dữ liệu:
```Python hl_lines="1"
{!../../../docs_src/python_types/tutorial003.py!}
```
Bởi vì trình soạn thảo biết kiểu dữ liệu của các biến, bạn không chỉ có được completion, bạn cũng được kiểm tra lỗi:
<img src="/img/python-types/image04.png">
Bây giờ bạn biết rằng bạn phải sửa nó, chuyển `age` sang một xâu với `str(age)`:
```Python hl_lines="2"
{!../../../docs_src/python_types/tutorial004.py!}
```
## Khai báo các kiểu dữ liệu
Bạn mới chỉ nhìn thấy những nơi chủ yếu để đặt khai báo kiểu dữ liệu. Như là các tham số của hàm.
Đây cũng là nơi chủ yếu để bạn sử dụng chúng với **FastAPI**.
### Kiểu dữ liệu đơn giản
Bạn có thể khai báo tất cả các kiểu dữ liệu chuẩn của Python, không chỉ là `str`.
Bạn có thể sử dụng, ví dụ:
* `int`
* `float`
* `bool`
* `bytes`
```Python hl_lines="1"
{!../../../docs_src/python_types/tutorial005.py!}
```
### Các kiểu dữ liệu tổng quát với tham số kiểu dữ liệu
Có một vài cấu trúc dữ liệu có thể chứa các giá trị khác nhau như `dict`, `list`, `set` và `tuple`. Và những giá trị nội tại cũng có thể có kiểu dữ liệu của chúng.
Những kiểu dữ liệu nội bộ này được gọi là những kiểu dữ liệu "**tổng quát**". Và có khả năng khai báo chúng, thậm chí với các kiểu dữ liệu nội bộ của chúng.
Để khai báo những kiểu dữ liệu và những kiểu dữ liệu nội bộ đó, bạn có thể sử dụng mô đun chuẩn của Python là `typing`. Nó có hỗ trợ những gợi ý kiểu dữ liệu này.
#### Những phiên bản mới hơn của Python
Cú pháp sử dụng `typing` **tương thích** với tất cả các phiên bản, từ Python 3.6 tới những phiên bản cuối cùng, bao gồm Python 3.9, Python 3.10,...
As Python advances, **những phiên bản mới** mang tới sự hỗ trợ được cải tiến cho những chú thích kiểu dữ liệu và trong nhiều trường hợp bạn thậm chí sẽ không cần import và sử dụng mô đun `typing` để khai báo chú thích kiểu dữ liệu.
Nếu bạn có thể chọn một phiên bản Python gần đây hơn cho dự án của bạn, ban sẽ có được những ưu điểm của những cải tiến đơn giản đó.
Trong tất cả các tài liệu tồn tại những ví dụ tương thích với mỗi phiên bản Python (khi có một sự khác nhau).
Cho ví dụ "**Python 3.6+**" có nghĩa là nó tương thích với Python 3.7 hoặc lớn hơn (bao gồm 3.7, 3.8, 3.9, 3.10,...). và "**Python 3.9+**" nghĩa là nó tương thích với Python 3.9 trở lên (bao gồm 3.10,...).
Nếu bạn có thể sử dụng **phiên bản cuối cùng của Python**, sử dụng những ví dụ cho phiên bản cuối, những cái đó sẽ có **cú pháp đơn giản và tốt nhât**, ví dụ, "**Python 3.10+**".
#### List
Ví dụ, hãy định nghĩa một biến là `list` các `str`.
=== "Python 3.9+"
Khai báo biến với cùng dấu hai chấm (`:`).
Tương tự kiểu dữ liệu `list`.
Như danh sách là một kiểu dữ liệu chứa một vài kiểu dữ liệu có sẵn, bạn đặt chúng trong các dấu ngoặc vuông:
```Python hl_lines="1"
{!> ../../../docs_src/python_types/tutorial006_py39.py!}
```
=== "Python 3.6+"
Từ `typing`, import `List` (với chữ cái `L` viết hoa):
``` Python hl_lines="1"
{!> ../../../docs_src/python_types/tutorial006.py!}
```
Khai báo biến với cùng dấu hai chấm (`:`).
Tương tự như kiểu dữ liệu, `List` bạn import từ `typing`.
Như danh sách là một kiểu dữ liệu chứa các kiểu dữ liệu có sẵn, bạn đặt chúng bên trong dấu ngoặc vuông:
```Python hl_lines="4"
{!> ../../../docs_src/python_types/tutorial006.py!}
```
!!! info
Các kiểu dữ liệu có sẵn bên trong dấu ngoặc vuông được gọi là "tham số kiểu dữ liệu".
Trong trường hợp này, `str` là tham số kiểu dữ liệu được truyền tới `List` (hoặc `list` trong Python 3.9 trở lên).
Có nghĩa là: "biến `items` là một `list`, và mỗi phần tử trong danh sách này là một `str`".
!!! tip
Nếu bạn sử dụng Python 3.9 hoặc lớn hơn, bạn không phải import `List` từ `typing`, bạn có thể sử dụng `list` để thay thế.
Bằng cách này, trình soạn thảo của bạn có thể hỗ trợ trong khi xử lí các phần tử trong danh sách:
<img src="/img/python-types/image05.png">
Đa phần đều không thể đạt được nếu không có các kiểu dữ liệu.
Chú ý rằng, biến `item` là một trong các phần tử trong danh sách `items`.
Và do vậy, trình soạn thảo biết nó là một `str`, và cung cấp sự hỗ trợ cho nó.
#### Tuple and Set
Bạn sẽ làm điều tương tự để khai báo các `tuple` và các `set`:
=== "Python 3.9+"
```Python hl_lines="1"
{!> ../../../docs_src/python_types/tutorial007_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 4"
{!> ../../../docs_src/python_types/tutorial007.py!}
```
Điều này có nghĩa là:
* Biến `items_t` là một `tuple` với 3 phần tử, một `int`, một `int` nữa, và một `str`.
* Biến `items_s` là một `set`, và mỗi phần tử của nó có kiểu `bytes`.
#### Dict
Để định nghĩa một `dict`, bạn truyền 2 tham số kiểu dữ liệu, phân cách bởi dấu phẩy.
Tham số kiểu dữ liệu đầu tiên dành cho khóa của `dict`.
Tham số kiểu dữ liệu thứ hai dành cho giá trị của `dict`.
=== "Python 3.9+"
```Python hl_lines="1"
{!> ../../../docs_src/python_types/tutorial008_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 4"
{!> ../../../docs_src/python_types/tutorial008.py!}
```
Điều này có nghĩa là:
* Biến `prices` là một `dict`:
* Khóa của `dict` này là kiểu `str` (đó là tên của mỗi vật phẩm).
* Giá trị của `dict` này là kiểu `float` (đó là giá của mỗi vật phẩm).
#### Union
Bạn có thể khai báo rằng một biến có thể là **một vài kiểu dữ liệu" bất kì, ví dụ, một `int` hoặc một `str`.
Trong Python 3.6 hoặc lớn hơn (bao gồm Python 3.10) bạn có thể sử dụng kiểu `Union` từ `typing` và đặt trong dấu ngoặc vuông những giá trị được chấp nhận.
In Python 3.10 there's also a **new syntax** where you can put the possible types separated by a <abbr title='also called "bitwise or operator", but that meaning is not relevant here'>vertical bar (`|`)</abbr>.
Trong Python 3.10 cũng có một **cú pháp mới** mà bạn có thể đặt những kiểu giá trị khả thi phân cách bởi một dấu <abbr title='cũng được gọi là "toán tử nhị phân"'>sổ dọc (`|`)</abbr>.
=== "Python 3.10+"
```Python hl_lines="1"
{!> ../../../docs_src/python_types/tutorial008b_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 4"
{!> ../../../docs_src/python_types/tutorial008b.py!}
```
Trong cả hai trường hợp có nghĩa là `item` có thể là một `int` hoặc `str`.
#### Khả năng `None`
Bạn có thể khai báo một giá trị có thể có một kiểu dữ liệu, giống như `str`, nhưng nó cũng có thể là `None`.
Trong Python 3.6 hoặc lớn hơn (bao gồm Python 3.10) bạn có thể khai báo nó bằng các import và sử dụng `Optional` từ mô đun `typing`.
```Python hl_lines="1 4"
{!../../../docs_src/python_types/tutorial009.py!}
```
Sử dụng `Optional[str]` thay cho `str` sẽ cho phép trình soạn thảo giúp bạn phát hiện các lỗi mà bạn có thể gặp như một giá trị luôn là một `str`, trong khi thực tế nó rất có thể là `None`.
`Optional[Something]` là một cách viết ngắn gọn của `Union[Something, None]`, chúng là tương đương nhau.
Điều này cũng có nghĩa là trong Python 3.10, bạn có thể sử dụng `Something | None`:
=== "Python 3.10+"
```Python hl_lines="1"
{!> ../../../docs_src/python_types/tutorial009_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 4"
{!> ../../../docs_src/python_types/tutorial009.py!}
```
=== "Python 3.6+ alternative"
```Python hl_lines="1 4"
{!> ../../../docs_src/python_types/tutorial009b.py!}
```
#### Sử dụng `Union` hay `Optional`
If you are using a Python version below 3.10, here's a tip from my very **subjective** point of view:
Nếu bạn đang sử dụng phiên bản Python dưới 3.10, đây là một mẹo từ ý kiến rất "chủ quan" của tôi:
* 🚨 Tránh sử dụng `Optional[SomeType]`
* Thay vào đó ✨ **sử dụng `Union[SomeType, None]`** ✨.
Cả hai là tương đương và bên dưới chúng giống nhau, nhưng tôi sẽ đễ xuất `Union` thay cho `Optional` vì từ "**tùy chọn**" có vẻ ngầm định giá trị là tùy chọn, và nó thực sự có nghĩa rằng "nó có thể là `None`", do đó nó không phải là tùy chọn và nó vẫn được yêu cầu.
Tôi nghĩ `Union[SomeType, None]` là rõ ràng hơn về ý nghĩa của nó.
Nó chỉ là về các từ và tên. Nhưng những từ đó có thể ảnh hưởng cách bạn và những đồng đội của bạn suy nghĩ về code.
Cho một ví dụ, hãy để ý hàm này:
```Python hl_lines="1 4"
{!../../../docs_src/python_types/tutorial009c.py!}
```
Tham số `name` được định nghĩa là `Optional[str]`, nhưng nó **không phải là tùy chọn**, bạn không thể gọi hàm mà không có tham số:
```Python
say_hi() # Oh, no, this throws an error! 😱
```
Tham số `name` **vẫn được yêu cầu** (không phải là *tùy chọn*) vì nó không có giá trị mặc định. Trong khi đó, `name` chấp nhận `None` như là giá trị:
```Python
say_hi(name=None) # This works, None is valid 🎉
```
Tin tốt là, khi bạn sử dụng Python 3.10, bạn sẽ không phải lo lắng về điều đó, bạn sẽ có thể sử dụng `|` để định nghĩa hợp của các kiểu dữ liệu một cách đơn giản:
```Python hl_lines="1 4"
{!../../../docs_src/python_types/tutorial009c_py310.py!}
```
Và sau đó, bạn sẽ không phải lo rằng những cái tên như `Optional` và `Union`. 😎
#### Những kiểu dữ liệu tổng quát
Những kiểu dữ liệu này lấy tham số kiểu dữ liệu trong dấu ngoặc vuông được gọi là **Kiểu dữ liệu tổng quát**, cho ví dụ:
=== "Python 3.10+"
Bạn có thể sử dụng các kiểu dữ liệu có sẵn như là kiểu dữ liệu tổng quát (với ngoặc vuông và kiểu dữ liệu bên trong):
* `list`
* `tuple`
* `set`
* `dict`
Và tương tự với Python 3.6, từ mô đun `typing`:
* `Union`
* `Optional` (tương tự như Python 3.6)
* ...và các kiểu dữ liệu khác.
Trong Python 3.10, thay vì sử dụng `Union` và `Optional`, bạn có thể sử dụng <abbr title='cũng gọi là "toán tử nhị phân", nhưng ý nghĩa không liên quan ở đây'>sổ dọc ('|')</abbr> để khai báo hợp của các kiểu dữ liệu, điều đó tốt hơn và đơn giản hơn nhiều.
=== "Python 3.9+"
Bạn có thể sử dụng các kiểu dữ liệu có sẵn tương tự như (với ngoặc vuông và kiểu dữ liệu bên trong):
* `list`
* `tuple`
* `set`
* `dict`
Và tương tự với Python 3.6, từ mô đun `typing`:
* `Union`
* `Optional`
* ...and others.
=== "Python 3.6+"
* `List`
* `Tuple`
* `Set`
* `Dict`
* `Union`
* `Optional`
* ...và các kiểu khác.
### Lớp như kiểu dữ liệu
Bạn cũng có thể khai báo một lớp như là kiểu dữ liệu của một biến.
Hãy nói rằng bạn muốn có một lớp `Person` với một tên:
```Python hl_lines="1-3"
{!../../../docs_src/python_types/tutorial010.py!}
```
Sau đó bạn có thể khai báo một biến có kiểu là `Person`:
```Python hl_lines="6"
{!../../../docs_src/python_types/tutorial010.py!}
```
Và lại một lần nữa, bạn có được tất cả sự hỗ trợ từ trình soạn thảo:
<img src="/img/python-types/image06.png">
Lưu ý rằng, điều này có nghĩa rằng "`one_person`" là một **thực thể** của lớp `Person`.
Nó không có nghĩa "`one_person`" là một **lớp** gọi là `Person`.
## Pydantic models
<a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> là một thư viện Python để validate dữ liệu hiệu năng cao.
Bạn có thể khai báo "hình dạng" của dữa liệu như là các lớp với các thuộc tính.
Và mỗi thuộc tính có một kiểu dữ liệu.
Sau đó bạn tạo một thực thể của lớp đó với một vài giá trị và nó sẽ validate các giá trị, chuyển đổi chúng sang kiểu dữ liệu phù hợp (nếu đó là trường hợp) và cho bạn một object với toàn bộ dữ liệu.
Và bạn nhận được tất cả sự hỗ trợ của trình soạn thảo với object kết quả đó.
Một ví dụ từ tài liệu chính thức của Pydantic:
=== "Python 3.10+"
```Python
{!> ../../../docs_src/python_types/tutorial011_py310.py!}
```
=== "Python 3.9+"
```Python
{!> ../../../docs_src/python_types/tutorial011_py39.py!}
```
=== "Python 3.6+"
```Python
{!> ../../../docs_src/python_types/tutorial011.py!}
```
!!! info
Để học nhiều hơn về <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic, tham khảo tài liệu của nó</a>.
**FastAPI** được dựa hoàn toàn trên Pydantic.
Bạn sẽ thấy nhiều ví dụ thực tế hơn trong [Hướng dẫn sử dụng](tutorial/index.md){.internal-link target=_blank}.
!!! tip
Pydantic có một hành vi đặc biệt khi bạn sử dụng `Optional` hoặc `Union[Something, None]` mà không có giá trị mặc dịnh, bạn có thể đọc nhiều hơn về nó trong tài liệu của Pydantic về <a href="https://pydantic-docs.helpmanual.io/usage/models/#required-optional-fields" class="external-link" target="_blank">Required Optional fields</a>.
## Type Hints với Metadata Annotations
Python cũng có một tính năng cho phép đặt **metadata bổ sung** trong những gợi ý kiểu dữ liệu này bằng cách sử dụng `Annotated`.
=== "Python 3.9+"
Trong Python 3.9, `Annotated` là một phần của thư viện chuẩn, do đó bạn có thể import nó từ `typing`.
```Python hl_lines="1 4"
{!> ../../../docs_src/python_types/tutorial013_py39.py!}
```
=== "Python 3.6+"
Ở phiên bản dưới Python 3.9, bạn import `Annotated` từ `typing_extensions`.
Nó đã được cài đặt sẵng cùng với **FastAPI**.
```Python hl_lines="1 4"
{!> ../../../docs_src/python_types/tutorial013.py!}
```
Python bản thân nó không làm bất kì điều gì với `Annotated`. Với các trình soạn thảo và các công cụ khác, kiểu dữ liệu vẫn là `str`.
Nhưng bạn có thể sử dụng `Annotated` để cung cấp cho **FastAPI** metadata bổ sung về cách mà bạn muốn ứng dụng của bạn xử lí.
Điều quan trọng cần nhớ là ***tham số kiểu dữ liệu* đầu tiên** bạn truyền tới `Annotated` là **kiểu giá trị thực sự**. Phần còn lại chỉ là metadata cho các công cụ khác.
Bây giờ, bạn chỉ cần biết rằng `Annotated` tồn tại, và nó là tiêu chuẩn của Python. 😎
Sau đó, bạn sẽ thấy sự **mạnh mẽ** mà nó có thể làm.
!!! tip
Thực tế, cái này là **tiêu chuẩn của Python**, nghĩa là bạn vẫn sẽ có được **trải nghiệm phát triển tốt nhất có thể** với trình soạn thảo của bạn, với các công cụ bạn sử dụng để phân tích và tái cấu trúc code của bạn, etc. ✨
Và code của bạn sẽ tương thích với nhiều công cụ và thư viện khác của Python. 🚀
## Các gợi ý kiểu dữ liệu trong **FastAPI**
**FastAPI** lấy các ưu điểm của các gợi ý kiểu dữ liệu để thực hiện một số thứ.
Với **FastAPI**, bạn khai báo các tham số với gợi ý kiểu và bạn có được:
* **Sự hỗ trợ từ các trình soạn thảo**.
* **Kiểm tra kiểu dữ liệu (type checking)**.
...và **FastAPI** sử dụng các khia báo để:
* **Định nghĩa các yêu cầu**: từ tham số đường dẫn của request, tham số query, headers, bodies, các phụ thuộc (dependencies),...
* **Chuyển dổi dữ liệu*: từ request sang kiểu dữ liệu được yêu cầu.
* **Kiểm tra tính đúng đắn của dữ liệu**: tới từ mỗi request:
* Sinh **lỗi tự động** để trả về máy khác khi dữ liệu không hợp lệ.
* **Tài liệu hóa** API sử dụng OpenAPI:
* cái mà sau được được sử dụng bởi tài liệu tương tác người dùng.
Điều này có thể nghe trừu tượng. Đừng lo lắng. Bạn sẽ thấy tất cả chúng trong [Hướng dẫn sử dụng](tutorial/index.md){.internal-link target=_blank}.
Điều quan trọng là bằng việc sử dụng các kiểu dữ liệu chuẩn của Python (thay vì thêm các lớp, decorators,...), **FastAPI** sẽ thực hiện nhiều công việc cho bạn.
!!! info
Nếu bạn đã đi qua toàn bộ các hướng dẫn và quay trở lại để tìm hiểu nhiều hơn về các kiểu dữ liệu, một tài nguyên tốt như <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">"cheat sheet" từ `mypy`</a>.

1
docs/vi/mkdocs.yml Normal file
View File

@@ -0,0 +1 @@
INHERIT: ../en/mkdocs.yml

View File

@@ -0,0 +1,126 @@
# 后台任务
你可以定义在返回响应后运行的后台任务。
这对需要在请求之后执行的操作很有用,但客户端不必在接收响应之前等待操作完成。
包括这些例子:
* 执行操作后发送的电子邮件通知:
* 由于连接到电子邮件服务器并发送电子邮件往往很“慢”(几秒钟),您可以立即返回响应并在后台发送电子邮件通知。
* 处理数据:
* 例如,假设您收到的文件必须经过一个缓慢的过程,您可以返回一个"Accepted"(HTTP 202)响应并在后台处理它。
## 使用 `BackgroundTasks`
首先导入 `BackgroundTasks` 并在 *路径操作函数* 中使用类型声明 `BackgroundTasks` 定义一个参数:
```Python hl_lines="1 13"
{!../../../docs_src/background_tasks/tutorial001.py!}
```
**FastAPI** 会创建一个 `BackgroundTasks` 类型的对象并作为该参数传入。
## 创建一个任务函数
创建要作为后台任务运行的函数。
它只是一个可以接收参数的标准函数。
它可以是 `async def` 或普通的 `def` 函数,**FastAPI** 知道如何正确处理。
在这种情况下,任务函数将写入一个文件(模拟发送电子邮件)。
由于写操作不使用 `async` 和 `await`,我们用普通的 `def` 定义函数:
```Python hl_lines="6-9"
{!../../../docs_src/background_tasks/tutorial001.py!}
```
## 添加后台任务
在你的 *路径操作函数* 里,用 `.add_task()` 方法将任务函数传到 *后台任务* 对象中:
```Python hl_lines="14"
{!../../../docs_src/background_tasks/tutorial001.py!}
```
`.add_task()` 接收以下参数:
* 在后台运行的任务函数(`write_notification`)。
* 应按顺序传递给任务函数的任意参数序列(`email`)。
* 应传递给任务函数的任意关键字参数(`message="some notification"`)。
## 依赖注入
使用 `BackgroundTasks` 也适用于依赖注入系统,你可以在多个级别声明 `BackgroundTasks` 类型的参数:在 *路径操作函数* 里,在依赖中(可依赖),在子依赖中,等等。
**FastAPI** 知道在每种情况下该做什么以及如何复用同一对象,因此所有后台任务被合并在一起并且随后在后台运行:
=== "Python 3.10+"
```Python hl_lines="13 15 22 25"
{!> ../../../docs_src/background_tasks/tutorial002_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="13 15 22 25"
{!> ../../../docs_src/background_tasks/tutorial002_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="14 16 23 26"
{!> ../../../docs_src/background_tasks/tutorial002_an.py!}
```
=== "Python 3.10+ 没Annotated"
!!! tip
尽可能选择使用 `Annotated` 的版本。
```Python hl_lines="11 13 20 23"
{!> ../../../docs_src/background_tasks/tutorial002_py310.py!}
```
=== "Python 3.6+ 没Annotated"
!!! tip
尽可能选择使用 `Annotated` 的版本。
```Python hl_lines="13 15 22 25"
{!> ../../../docs_src/background_tasks/tutorial002.py!}
```
该示例中,信息会在响应发出 *之后* 被写到 `log.txt` 文件。
如果请求中有查询,它将在后台任务中写入日志。
然后另一个在 *路径操作函数* 生成的后台任务会使用路径参数 `email` 写入一条信息。
## 技术细节
`BackgroundTasks` 类直接来自 <a href="https://www.starlette.io/background/" class="external-link" target="_blank">`starlette.background`</a>。
它被直接导入/包含到FastAPI以便你可以从 `fastapi` 导入,并避免意外从 `starlette.background` 导入备用的 `BackgroundTask` (后面没有 `s`)。
通过仅使用 `BackgroundTasks` (而不是 `BackgroundTask`),使得能将它作为 *路径操作函数* 的参数 ,并让**FastAPI**为您处理其余部分, 就像直接使用 `Request` 对象。
在FastAPI中仍然可以单独使用 `BackgroundTask`但您必须在代码中创建对象并返回包含它的Starlette `Response`。
更多细节查看 <a href="https://www.starlette.io/background/" class="external-link" target="_blank">Starlette's official docs for Background Tasks</a>.
## 告诫
如果您需要执行繁重的后台计算,并且不一定需要由同一进程运行(例如,您不需要共享内存、变量等),那么使用其他更大的工具(如 <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>)可能更好。
它们往往需要更复杂的配置,即消息/作业队列管理器如RabbitMQ或Redis但它们允许您在多个进程中运行后台任务甚至是在多个服务器中。
要查看示例,查阅 [Project Generators](../project-generation.md){.internal-link target=_blank}它们都包括已经配置的Celery。
但是,如果您需要从同一个**FastAPI**应用程序访问变量和对象,或者您需要执行小型后台任务(如发送电子邮件通知),您只需使用 `BackgroundTasks` 即可。
## 回顾
导入并使用 `BackgroundTasks` 通过 *路径操作函数* 中的参数和依赖项来添加后台任务。

View File

@@ -6,9 +6,41 @@
首先,你必须导入它:
```Python hl_lines="2"
{!../../../docs_src/body_fields/tutorial001.py!}
```
=== "Python 3.10+"
```Python hl_lines="4"
{!> ../../../docs_src/body_fields/tutorial001_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="4"
{!> ../../../docs_src/body_fields/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="4"
{!> ../../../docs_src/body_fields/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
尽可能选择使用 `Annotated` 的版本。
```Python hl_lines="2"
{!> ../../../docs_src/body_fields/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
尽可能选择使用 `Annotated` 的版本。
```Python hl_lines="4"
{!> ../../../docs_src/body_fields/tutorial001.py!}
```
!!! warning
注意,`Field` 是直接从 `pydantic` 导入的,而不是像其他的(`Query``Path``Body` 等)都从 `fastapi` 导入。
@@ -17,9 +49,41 @@
然后,你可以对模型属性使用 `Field`
```Python hl_lines="9-10"
{!../../../docs_src/body_fields/tutorial001.py!}
```
=== "Python 3.10+"
```Python hl_lines="11-14"
{!> ../../../docs_src/body_fields/tutorial001_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="11-14"
{!> ../../../docs_src/body_fields/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="12-15"
{!> ../../../docs_src/body_fields/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9-12"
{!> ../../../docs_src/body_fields/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="11-14"
{!> ../../../docs_src/body_fields/tutorial001.py!}
```
`Field` 的工作方式和 `Query`、`Path` 和 `Body` 相同,包括它们的参数等等也完全相同。

View File

@@ -8,9 +8,41 @@
你还可以通过将默认值设置为 `None` 来将请求体参数声明为可选参数:
```Python hl_lines="17-19"
{!../../../docs_src/body_multiple_params/tutorial001.py!}
```
=== "Python 3.10+"
```Python hl_lines="18-20"
{!> ../../../docs_src/body_multiple_params/tutorial001_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="18-20"
{!> ../../../docs_src/body_multiple_params/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="19-21"
{!> ../../../docs_src/body_multiple_params/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
尽可能选择使用 `Annotated` 的版本。
```Python hl_lines="17-19"
{!> ../../../docs_src/body_multiple_params/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
尽可能选择使用 `Annotated` 的版本。
```Python hl_lines="19-21"
{!> ../../../docs_src/body_multiple_params/tutorial001.py!}
```
!!! note
请注意,在这种情况下,将从请求体获取的 `item` 是可选的。因为它的默认值为 `None`。
@@ -30,9 +62,17 @@
但是你也可以声明多个请求体参数,例如 `item` 和 `user`
```Python hl_lines="20"
{!../../../docs_src/body_multiple_params/tutorial002.py!}
```
=== "Python 3.10+"
```Python hl_lines="20"
{!> ../../../docs_src/body_multiple_params/tutorial002_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="22"
{!> ../../../docs_src/body_multiple_params/tutorial002.py!}
```
在这种情况下,**FastAPI** 将注意到该函数中有多个请求体参数(两个 Pydantic 模型参数)。
@@ -72,9 +112,41 @@
但是你可以使用 `Body` 指示 **FastAPI** 将其作为请求体的另一个键进行处理。
```Python hl_lines="22"
{!../../../docs_src/body_multiple_params/tutorial003.py!}
```
=== "Python 3.10+"
```Python hl_lines="23"
{!> ../../../docs_src/body_multiple_params/tutorial003_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="23"
{!> ../../../docs_src/body_multiple_params/tutorial003_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="24"
{!> ../../../docs_src/body_multiple_params/tutorial003_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
尽可能选择使用 `Annotated` 的版本。
```Python hl_lines="20"
{!> ../../../docs_src/body_multiple_params/tutorial003_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
尽可能选择使用 `Annotated` 的版本。
```Python hl_lines="22"
{!> ../../../docs_src/body_multiple_params/tutorial003.py!}
```
在这种情况下,**FastAPI** 将期望像这样的请求体:
@@ -109,9 +181,41 @@ q: str = None
比如:
```Python hl_lines="25"
{!../../../docs_src/body_multiple_params/tutorial004.py!}
```
=== "Python 3.10+"
```Python hl_lines="27"
{!> ../../../docs_src/body_multiple_params/tutorial004_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="27"
{!> ../../../docs_src/body_multiple_params/tutorial004_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="28"
{!> ../../../docs_src/body_multiple_params/tutorial004_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
尽可能选择使用 `Annotated` 的版本。
```Python hl_lines="25"
{!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
尽可能选择使用 `Annotated` 的版本。
```Python hl_lines="27"
{!> ../../../docs_src/body_multiple_params/tutorial004.py!}
```
!!! info
`Body` 同样具有与 `Query`、`Path` 以及其他后面将看到的类完全相同的额外校验和元数据参数。
@@ -131,9 +235,41 @@ item: Item = Body(embed=True)
比如:
```Python hl_lines="15"
{!../../../docs_src/body_multiple_params/tutorial005.py!}
```
=== "Python 3.10+"
```Python hl_lines="17"
{!> ../../../docs_src/body_multiple_params/tutorial005_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="17"
{!> ../../../docs_src/body_multiple_params/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="18"
{!> ../../../docs_src/body_multiple_params/tutorial005_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
尽可能选择使用 `Annotated` 的版本。
```Python hl_lines="15"
{!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
尽可能选择使用 `Annotated` 的版本。
```Python hl_lines="17"
{!> ../../../docs_src/body_multiple_params/tutorial005.py!}
```
在这种情况下,**FastAPI** 将期望像这样的请求体:

View File

@@ -6,9 +6,17 @@
你可以将一个属性定义为拥有子元素的类型。例如 Python `list`
```Python hl_lines="12"
{!../../../docs_src/body_nested_models/tutorial001.py!}
```
=== "Python 3.10+"
```Python hl_lines="12"
{!> ../../../docs_src/body_nested_models/tutorial001_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial001.py!}
```
这将使 `tags` 成为一个由元素组成的列表。不过它没有声明每个元素的类型。
@@ -21,7 +29,7 @@
首先,从 Python 的标准库 `typing` 模块中导入 `List`
```Python hl_lines="1"
{!../../../docs_src/body_nested_models/tutorial002.py!}
{!> ../../../docs_src/body_nested_models/tutorial002.py!}
```
### 声明具有子类型的 List
@@ -43,9 +51,23 @@ my_list: List[str]
因此,在我们的示例中,我们可以将 `tags` 明确地指定为一个「字符串列表」:
```Python hl_lines="14"
{!../../../docs_src/body_nested_models/tutorial002.py!}
```
=== "Python 3.10+"
```Python hl_lines="12"
{!> ../../../docs_src/body_nested_models/tutorial002_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial002_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial002.py!}
```
## Set 类型
@@ -55,9 +77,23 @@ Python 具有一种特殊的数据类型来保存一组唯一的元素,即 `se
然后我们可以导入 `Set` 并将 `tag` 声明为一个由 `str` 组成的 `set`
```Python hl_lines="1 14"
{!../../../docs_src/body_nested_models/tutorial003.py!}
```
=== "Python 3.10+"
```Python hl_lines="12"
{!> ../../../docs_src/body_nested_models/tutorial003_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial003_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 14"
{!> ../../../docs_src/body_nested_models/tutorial003.py!}
```
这样,即使你收到带有重复数据的请求,这些数据也会被转换为一组唯一项。
@@ -79,17 +115,45 @@ Pydantic 模型的每个属性都具有类型。
例如,我们可以定义一个 `Image` 模型:
```Python hl_lines="9 10 11"
{!../../../docs_src/body_nested_models/tutorial004.py!}
```
=== "Python 3.10+"
```Python hl_lines="7-9"
{!> ../../../docs_src/body_nested_models/tutorial004_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="9-11"
{!> ../../../docs_src/body_nested_models/tutorial004_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9-11"
{!> ../../../docs_src/body_nested_models/tutorial004.py!}
```
### 将子模型用作类型
然后我们可以将其用作一个属性的类型:
```Python hl_lines="20"
{!../../../docs_src/body_nested_models/tutorial004.py!}
```
=== "Python 3.10+"
```Python hl_lines="18"
{!> ../../../docs_src/body_nested_models/tutorial004_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial004_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial004.py!}
```
这意味着 **FastAPI** 将期望类似于以下内容的请求体:
@@ -122,9 +186,23 @@ Pydantic 模型的每个属性都具有类型。
例如,在 `Image` 模型中我们有一个 `url` 字段,我们可以把它声明为 Pydantic 的 `HttpUrl`,而不是 `str`
```Python hl_lines="4 10"
{!../../../docs_src/body_nested_models/tutorial005.py!}
```
=== "Python 3.10+"
```Python hl_lines="2 8"
{!> ../../../docs_src/body_nested_models/tutorial005_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="4 10"
{!> ../../../docs_src/body_nested_models/tutorial005_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="4 10"
{!> ../../../docs_src/body_nested_models/tutorial005.py!}
```
该字符串将被检查是否为有效的 URL并在 JSON Schema / OpenAPI 文档中进行记录。
@@ -132,9 +210,23 @@ Pydantic 模型的每个属性都具有类型。
你还可以将 Pydantic 模型用作 `list`、`set` 等的子类型:
```Python hl_lines="20"
{!../../../docs_src/body_nested_models/tutorial006.py!}
```
=== "Python 3.10+"
```Python hl_lines="18"
{!> ../../../docs_src/body_nested_models/tutorial006_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial006_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial006.py!}
```
这将期望(转换,校验,记录文档等)下面这样的 JSON 请求体:
@@ -169,9 +261,23 @@ Pydantic 模型的每个属性都具有类型。
你可以定义任意深度的嵌套模型:
```Python hl_lines="9 14 20 23 27"
{!../../../docs_src/body_nested_models/tutorial007.py!}
```
=== "Python 3.10+"
```Python hl_lines="7 12 18 21 25"
{!> ../../../docs_src/body_nested_models/tutorial007_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="9 14 20 23 27"
{!> ../../../docs_src/body_nested_models/tutorial007_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9 14 20 23 27"
{!> ../../../docs_src/body_nested_models/tutorial007.py!}
```
!!! info
请注意 `Offer` 拥有一组 `Item` 而反过来 `Item` 又是一个可选的 `Image` 列表是如何发生的。
@@ -186,9 +292,17 @@ images: List[Image]
例如:
```Python hl_lines="15"
{!../../../docs_src/body_nested_models/tutorial008.py!}
```
=== "Python 3.9+"
```Python hl_lines="13"
{!> ../../../docs_src/body_nested_models/tutorial008_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="15"
{!> ../../../docs_src/body_nested_models/tutorial008.py!}
```
## 无处不在的编辑器支持
@@ -218,9 +332,17 @@ images: List[Image]
在下面的例子中,你将接受任意键为 `int` 类型并且值为 `float` 类型的 `dict`
```Python hl_lines="15"
{!../../../docs_src/body_nested_models/tutorial009.py!}
```
=== "Python 3.9+"
```Python hl_lines="7"
{!> ../../../docs_src/body_nested_models/tutorial009_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9"
{!> ../../../docs_src/body_nested_models/tutorial009.py!}
```
!!! tip
请记住 JSON 仅支持将 `str` 作为键。

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