Compare commits

..

247 Commits

Author SHA1 Message Date
Sebastián Ramírez
d666ccb622 🔖 Release version 0.95.0 2023-03-18 20:37:42 +01:00
Sebastián Ramírez
38f0cad517 📝 Tweak release notes 2023-03-18 20:37:20 +01:00
Sebastián Ramírez
bd90bed02a 📝 Update release notes 2023-03-18 20:24:12 +01:00
github-actions
546392db98 📝 Update release notes 2023-03-18 19:08:30 +00:00
Sebastián Ramírez
0bc87ec77c 📝 Tweak tip recommending Annotated in docs (#9270)
📝 Tweak tip recommending Annotated
2023-03-18 19:07:53 +00:00
Sebastián Ramírez
fbfd53542e 📝 Update release notes 2023-03-18 19:46:47 +01:00
github-actions
994ea1ad33 📝 Update release notes 2023-03-18 16:16:37 +00:00
Sebastián Ramírez
69673548bc 📝 Update order of examples, latest Python version first, and simplify version tab names (#9269)
* 📝 Simplify names in Python versions in tabs in docs

* 📝 Update docs for Types Intro, explain Python 3.6+, Python 3.9+, Python 3.10+

* 📝 Re-order all Python examples, show latest Python versions first
2023-03-18 17:16:02 +01:00
github-actions
166d348ea6 📝 Update release notes 2023-03-18 12:30:38 +00:00
Sebastián Ramírez
9eaed2eb37 📝 Update all docs to use Annotated as the main recommendation, with new examples and tests (#9268)
* 🍱 Add new source examples with Annotated for Query Params and String Validations

* 📝 Add new docs with Annotated for Query Params and String Validations

* 🚚 Rename incorrectly named tests for Query Params and str validations

*  Add new tests with Annotated for Query Params and Sring Validations examples

* 🍱 Add new examples with Annotated for Intro to Python Types

* 📝 Update Python Types Intro, include Annotated

* 🎨 Fix formatting in Query params and string validation, and highlight

* 🍱 Add new Annotated source examples for Path Params and Numeric Validations

* 📝 Update docs for Path Params and Numeric Validations with Annotated

* 🍱 Add new source examples with Annotated for Body - Multiple Params

* 📝 Update docs with Annotated for Body - Multiple Parameters

*  Add test for new Annotated examples in Body - Multiple Parameters

* 🍱 Add new Annotated source examples for Body Fields

* 📝 Update docs for Body Fields with new Annotated examples

*  Add new tests for new Annotated examples for Body Fields

* 🍱 Add new Annotated source examples for Schema Extra (Example Data)

* 📝 Update docs for Schema Extra with Annotated

*  Add tests for new Annotated examples for Schema Extra

* 🍱 Add new Annnotated source examples for Extra Data Types

* 📝 Update docs with Annotated for Extra Data Types

*  Add tests for new Annotated examples for Extra Data Types

* 🍱 Add new Annotated source examples for Cookie Parameters

* 📝 Update docs for Cookie Parameters with Annotated examples

*  Add tests for new Annotated source examples in Cookie Parameters

* 🍱 Add new Annotated examples for Header Params

* 📝 Update docs with Annotated examples for Header Parameters

*  Add tests for new Annotated examples for Header Params

* 🍱 Add new Annotated examples for Form Data

* 📝 Update Annotated docs for Form Data

*  Add tests for new Annotated examples in Form Data

* 🍱 Add new Annotated source examples for Request Files

* 📝 Update Annotated docs for Request Files

*  Test new Annotated examples for Request Files

* 🍱 Add new Annotated source examples for Request Forms and Files

*  Add tests for new Anotated examples for Request Forms and Files

* 🍱 Add new Annotated source examples for Dependencies and Advanced Dependencies

*  Add tests for new Annotated dependencies

* 📝 Add new docs for using Annotated with dependencies including type aliases

* 📝 Update docs for Classes as Dependencies with Annotated

* 📝 Update docs for Sub-dependencies with Annotated

* 📝 Update docs for Dependencies in path operation decorators with Annotated

* 📝 Update docs for Global Dependencies with Annotated

* 📝 Update docs for Dependencies with yield with Annotated

* 🎨 Update format in example for dependencies with Annotated

* 🍱 Add source examples with Annotated for Security

*  Add tests for new Annotated examples for security

* 📝 Update docs for Security - First Steps with Annotated

* 📝 Update docs for Security: Get Current User with Annotated

* 📝 Update docs for Simple OAuth2 with Password and Bearer with Annotated

* 📝 Update docs for OAuth2 with Password (and hashing), Bearer with JWT tokens with Annotated

* 📝 Update docs for Request Forms and Files with Annotated

* 🍱 Add new source examples for Bigger Applications with Annotated

*  Add new tests for Bigger Applications with Annotated

* 📝 Update docs for Bigger Applications - Multiple Files with Annotated

* 🍱 Add source examples for background tasks with Annotated

* 📝 Update docs for Background Tasks with Annotated

*  Add test for Background Tasks with Anotated

* 🍱 Add new source examples for docs for Testing with Annotated

* 📝 Update docs for Testing with Annotated

*  Add tests for Annotated examples for Testing

* 🍱 Add new source examples for Additional Status Codes with Annotated

*  Add tests for new Annotated examples for Additional Status Codes

* 📝 Update docs for Additional Status Codes with Annotated

* 📝 Update docs for Advanced Dependencies with Annotated

* 📝 Update docs for OAuth2 scopes with Annotated

* 📝 Update docs for HTTP Basic Auth with Annotated

* 🍱 Add source examples with Annotated for WebSockets

*  Add tests for new Annotated examples for WebSockets

* 📝 Update docs for WebSockets with new Annotated examples

* 🍱 Add source examples with Annotated for Settings and Environment Variables

* 📝 Update docs for Settings and Environment Variables with Annotated

* 🍱 Add new source examples for testing dependencies with Annotated

*  Add tests for new examples for testing dependencies

* 📝 Update docs for testing dependencies with new Annotated examples

*  Update and fix marker for Python 3.9 test

* 🔧 Update Ruff ignores for source examples in docs

*  Fix some tests in the grid for Python 3.9 (incorrectly testing 3.10)

* 🔥 Remove source examples and tests for (non existent) docs section about Annotated, as it's covered in all the rest of the docs
2023-03-18 13:29:59 +01:00
github-actions
f63b3ad53e 📝 Update release notes 2023-03-17 20:36:26 +00:00
Nadav Zingerman
375513f114 Add support for PEP-593 Annotated for specifying dependencies and parameters (#4871)
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-03-17 21:35:45 +01:00
Sebastián Ramírez
ef176c6631 🔖 Release version 0.94.1 2023-03-14 03:27:11 +01:00
github-actions
7b7e86a307 📝 Update release notes 2023-03-14 02:19:50 +00:00
Sebastián Ramírez
25aabe05ce 🎨 Fix types for lifespan, upgrade Starlette to 0.26.1 (#9245) 2023-03-14 03:19:04 +01:00
Sebastián Ramírez
392ffaae43 🔖 Release version 0.94.0 2023-03-10 20:00:49 +01:00
Sebastián Ramírez
202ee0497a 📝 Update release notes 2023-03-10 20:00:09 +01:00
github-actions
321e873c95 📝 Update release notes 2023-03-10 18:57:58 +00:00
github-actions
4860631468 📝 Update release notes 2023-03-10 18:57:42 +00:00
dependabot[bot]
8e4c96c703 ⬆ Bump black from 22.10.0 to 23.1.0 (#5953)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-03-10 19:57:21 +01:00
dependabot[bot]
39813aa9b0 ⬆ Bump types-ujson from 5.6.0.0 to 5.7.0.1 (#6027)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-03-10 19:57:07 +01:00
github-actions
3e3278ed3f 📝 Update release notes 2023-03-10 18:51:19 +00:00
dependabot[bot]
c8a07078cf ⬆ Bump dawidd6/action-download-artifact from 2.24.3 to 2.26.0 (#6034)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-03-10 19:50:08 +01:00
github-actions
59f91db1d2 📝 Update release notes 2023-03-10 18:49:54 +00:00
pre-commit-ci[bot]
f04b61bd16 ⬆ [pre-commit.ci] pre-commit autoupdate (#5709)
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-03-10 19:49:18 +01:00
github-actions
253d58bc5c 📝 Update release notes 2023-03-10 18:48:20 +00:00
Yasser Tahiri
78b8a9b6ec Add pydantic to PyPI classifiers (#5914) 2023-03-10 19:47:38 +01:00
github-actions
c26db94a90 📝 Update release notes 2023-03-10 18:43:10 +00:00
Vladislav Kramorenko
d1f3753e5e 🌐 Add Russian translation for docs/ru/docs/history-design-future.md (#5986) 2023-03-10 19:42:25 +01:00
github-actions
d5b0cc9f58 📝 Update release notes 2023-03-10 18:32:12 +00:00
Ben Beasley
42daed222e ⬆ Upgrade python-multipart to support 0.0.6 (#9212) 2023-03-10 19:31:36 +01:00
github-actions
fd3bfe9f50 📝 Update release notes 2023-03-10 18:27:50 +00:00
Steven Eubank
1fea9c5626 📝 Update Sentry link in docs (#9218) 2023-03-10 19:27:10 +01:00
github-actions
d783463ebd 📝 Update release notes 2023-03-10 18:24:42 +00:00
Sebastián Ramírez
8a4cfa52af ⬆️ Upgrade Starlette version, support new lifespan with state (#9239) 2023-03-10 19:24:04 +01:00
Sebastián Ramírez
25382d2d19 🔖 Release version 0.93.0 2023-03-07 17:06:47 +01:00
Sebastián Ramírez
b9bb441b23 📝 Update release notes 2023-03-07 17:04:40 +01:00
github-actions
e33f30a607 📝 Update release notes 2023-03-07 15:46:37 +00:00
Jordan Speicher
cc9a73c3f8 Add support for lifespan async context managers (superseding startup and shutdown events) (#2944)
Co-authored-by: Mike Shantz <mshantz@coldstorage.com>
Co-authored-by: Jonathan Plasse <13716151+JonathanPlasse@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-03-07 16:46:00 +01:00
github-actions
66e03c816b 📝 Update release notes 2023-03-06 19:32:19 +00:00
gusty1g
639cf3440a 🌐 Tamil translations - initial setup (#5564)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-03-06 20:31:37 +01:00
github-actions
2f1b856fe6 📝 Update release notes 2023-03-06 16:29:17 +00:00
Axel
31e148ba8e 🌐 Add French translation for docs/fr/docs/advanced/path-operation-advanced-configuration.md (#9221)
Co-authored-by: Julian Maurin <julian.maurin.perso@pm.me>
Co-authored-by: Cedric Fraboulet <62244267+frabc@users.noreply.github.com>
2023-03-06 17:28:40 +01:00
github-actions
40c2c44ff9 📝 Update release notes 2023-03-06 16:27:29 +00:00
Cedric Fraboulet
c5f72f02cd 🌐 Add French translation for docs/tutorial/debugging.md (#9175) 2023-03-06 17:26:49 +01:00
github-actions
9b83a00c40 📝 Update release notes 2023-03-04 12:52:10 +00:00
har8
83012a9cf6 🌐 Initiate Armenian translation setup (#5844)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-03-04 12:51:37 +00:00
github-actions
8625189351 📝 Update release notes 2023-03-04 12:43:32 +00:00
eykamp
e570371003 ✏ Fix formatting in docs/en/docs/tutorial/metadata.md for ReDoc (#6005) 2023-03-04 13:42:55 +01:00
Aayush Chhabra
4d099250f6 ✏ Fix typo in docs/en/docs/tutorial/bigger-applications.md, "codes" to "code" (#5990)
Typo in docs: it should be code instead of codes
2023-03-04 13:17:21 +01:00
github-actions
9ef46a2299 📝 Update release notes 2023-03-04 12:02:42 +00:00
Ruidy
30a9d68232 🌐 Add French translation for deployment/manually.md (#3693)
Co-authored-by: Sam Courtemanche <smlep.pro@gmail.com>
Co-authored-by: Ruidy <r.nemausat@empfohlen.de>
Co-authored-by: Ruidy <rnemausat@newstore.com>
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-03-04 12:02:09 +00:00
github-actions
03bb7c166c 📝 Update release notes 2023-03-04 11:45:13 +00:00
Sebastián Ramírez
c5f343a4fd 👷 Update translation bot messages (#9206) 2023-03-04 11:44:30 +00:00
github-actions
83050bead6 📝 Update release notes 2023-03-04 10:40:08 +00:00
Sebastián Ramírez
bd219c2bbf 👷 Update translations bot to use Discussions, and notify when a PR is done (#9183) 2023-03-04 11:39:28 +01:00
github-actions
4b95025d44 📝 Update release notes 2023-03-04 07:35:11 +00:00
Sebastián Ramírez
ff64772dd1 🔧 Update sponsors-badges (#9182) 2023-03-04 07:34:39 +00:00
github-actions
e8fd74e737 📝 Update release notes 2023-03-04 07:30:07 +00:00
github-actions[bot]
87842ac0db 👥 Update FastAPI People (#9181)
Co-authored-by: github-actions <github-actions@github.com>
2023-03-04 08:29:30 +01:00
github-actions
7674da89d3 📝 Update release notes 2023-03-02 15:11:54 +00:00
Sebastián Ramírez
e9326de161 🔊 Log GraphQL errors in FastAPI People, because it returns 200, with a payload with an error (#9171) 2023-03-02 15:11:17 +00:00
github-actions
97effae92d 📝 Update release notes 2023-03-02 13:07:40 +00:00
Sebastián Ramírez
a8bde44029 💚 Fix/workaround GitHub Actions in Docker with git for FastAPI People (#9169) 2023-03-02 13:06:57 +00:00
github-actions
be54d44b0c 📝 Update release notes 2023-03-01 13:22:41 +00:00
Sebastián Ramírez
35d93d59d8 ♻️ Refactor FastAPI Experts to use only discussions now that questions are migrated (#9165) 2023-03-01 13:22:00 +00:00
github-actions
7b3727e03e 📝 Update release notes 2023-02-21 10:24:13 +00:00
Sebastián Ramírez
a270ab0c3f ⬆️ Upgrade analytics (#6025) 2023-02-21 11:23:37 +01:00
github-actions
f6f39d8714 📝 Update release notes 2023-02-16 18:51:02 +00:00
Sebastián Ramírez
4f4035262c ⬆️ Upgrade and re-enable installing Typer-CLI (#6008) 2023-02-16 18:50:21 +00:00
Sebastián Ramírez
6879082b36 🔖 Release version 0.92.0 2023-02-14 10:17:53 +01:00
Sebastián Ramírez
52ca6cb95b 📝 Update release notes 2023-02-14 10:17:08 +01:00
github-actions
9e283ef66b 📝 Update release notes 2023-02-14 09:13:56 +00:00
Sebastián Ramírez
75e7e9e0a2 ⬆️ Upgrade Starlette to 0.25.0 (#5996) 2023-02-14 09:13:22 +00:00
Sebastián Ramírez
2ca77f9a4d 🔖 Release version 0.91.0 2023-02-10 15:33:25 +01:00
Sebastián Ramírez
3c05189b06 📝 Update release notes 2023-02-10 15:32:23 +01:00
github-actions
a04acf6900 📝 Update release notes 2023-02-10 14:13:57 +00:00
Sebastián Ramírez
d566c6cbca ⬆️ Upgrade Starlette version to 0.24.0 and refactor internals for compatibility (#5985) 2023-02-10 15:13:04 +01:00
Sebastián Ramírez
6e94ec2bf0 🔖 Release version 0.90.1 2023-02-09 20:41:40 +01:00
Sebastián Ramírez
e85c109bcd 📝 Update release notes 2023-02-09 20:40:53 +01:00
github-actions
445e611a29 📝 Update release notes 2023-02-09 19:37:21 +00:00
Jakepys
392766bcfa ✏ Update zip-docs.sh internal script, remove extra space (#5931) 2023-02-09 20:36:46 +01:00
github-actions
5ed70f285b 📝 Update release notes 2023-02-09 19:35:40 +00:00
Chandra Deb
d6fb9429d2 ✏ Tweak wording to clarify docs/en/docs/project-generation.md (#5930) 2023-02-09 20:35:01 +01:00
github-actions
9a5147382e 📝 Update release notes 2023-02-09 19:29:30 +00:00
Yasser Tahiri
99deead7fc ✏ Update Pydantic GitHub URLs (#5952) 2023-02-09 20:28:54 +01:00
github-actions
18e6c3ff6a 📝 Update release notes 2023-02-09 19:27:57 +00:00
Igor Shevchenko
3c5536a780 🌐 Add Russian translation for docs/ru/docs/tutorial/cookie-params.md (#5890) 2023-02-09 20:27:16 +01:00
github-actions
79eed9d7d9 📝 Update release notes 2023-02-09 18:58:23 +00:00
Sebastián Ramírez
e37d504e27 📝 Add opinion from Cisco (#5981) 2023-02-09 18:57:49 +00:00
github-actions
70688eb7b2 📝 Update release notes 2023-02-09 18:47:16 +00:00
Sebastián Ramírez
16599b7356 ⬆️ Upgrade Starlette range to allow 0.23.1 (#5980) 2023-02-09 18:46:38 +00:00
Sebastián Ramírez
148bcf5ce4 🔖 Release version 0.90.0 2023-02-08 11:30:01 +01:00
Sebastián Ramírez
e4c8df062b 📝 Update release notes 2023-02-08 11:28:55 +01:00
github-actions
b313f86338 📝 Update release notes 2023-02-08 10:23:46 +00:00
Marcelo Trylesinski
9293795e99 ⬆️ Bump Starlette from 0.22.0 to 0.23.0 (#5739)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-02-08 11:23:07 +01:00
github-actions
58757f63af 📝 Update release notes 2023-02-07 16:51:06 +00:00
Leon
88dc4ce3d7 📝 Add article "Tortoise ORM / FastAPI 整合快速筆記" to External Links (#5496)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-02-07 16:50:02 +00:00
github-actions
c9d3656a6e 📝 Update release notes 2023-02-07 16:46:40 +00:00
Sebastián Ramírez
3e4840f21b ⬆️ Upgrade Ubuntu version for docs workflow (#5971) 2023-02-07 16:46:03 +00:00
github-actions
9cb2586499 📝 Update release notes 2023-02-07 13:33:51 +00:00
Alexander Sviridov
8b62319d6c 🌐 Add Russian translation for docs/ru/docs/tutorial/body-fields.md (#5898) 2023-02-07 14:33:16 +01:00
github-actions
6e3c707c60 📝 Update release notes 2023-02-07 13:28:45 +00:00
Sebastián Ramírez
94fa151881 🌐 Add Russian translation for docs/ru/docs/help-fastapi.md (#5970)
Co-authored-by: Xewus <xewuss@yandex.ru>
Co-authored-by: Vladislav Kramorenko <85196001+Xewus@users.noreply.github.com>
2023-02-07 13:28:10 +00:00
github-actions
a4f3bc5a69 📝 Update release notes 2023-02-07 13:10:13 +00:00
github-actions
05342cc264 📝 Update release notes 2023-02-07 13:09:45 +00:00
Bruno Artur Torres Lopes Pereira
8115282ed3 🌐 Add Portuguese translation for docs/pt/docs/tutorial/static-files.md (#5858)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-02-07 14:09:32 +01:00
felipebpl
9ad2cb29f9 🌐 Add Portuguese translation for docs/pt/docs/tutorial/encoder.md (#5525)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-02-07 13:09:00 +00:00
github-actions
23d0efa894 📝 Update release notes 2023-02-07 13:05:18 +00:00
Vladislav Kramorenko
e1129af819 🌐 Add Russian translation for docs/ru/docs/contributing.md (#5870)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-02-07 14:04:38 +01:00
github-actions
c59539913d 📝 Update release notes 2023-02-03 17:56:25 +00:00
github-actions[bot]
7a64587d7f 👥 Update FastAPI People (#5954)
Co-authored-by: github-actions <github-actions@github.com>
2023-02-03 18:55:25 +01:00
github-actions
62fc0b4923 📝 Update release notes 2023-02-03 17:55:03 +00:00
Sebastián Ramírez
fc7da62005 📝 Micro-tweak help docs (#5960) 2023-02-03 17:54:22 +00:00
github-actions
40df42f5c7 📝 Update release notes 2023-01-31 14:03:27 +00:00
Sebastián Ramírez
0b0af37b0e 🔧 Update new issue chooser to direct to GitHub Discussions (#5948) 2023-01-31 14:02:52 +00:00
github-actions
73920366e5 📝 Update release notes 2023-01-30 16:50:10 +00:00
Sebastián Ramírez
682067cab2 📝 Recommend GitHub Discussions for questions (#5944) 2023-01-30 16:49:32 +00:00
github-actions
ca30b92dd7 📝 Update release notes 2023-01-30 16:24:22 +00:00
Sebastián Ramírez
72b542d90a 🔧 Update sponsors badges (#5943) 2023-01-30 16:23:43 +00:00
github-actions
9012ab8bcd 📝 Update release notes 2023-01-30 15:16:30 +00:00
Sebastián Ramírez
9530defba8 Compute FastAPI Experts including GitHub Discussions (#5941) 2023-01-30 15:15:56 +00:00
github-actions
7c23bbd96f 📝 Update release notes 2023-01-30 15:10:29 +00:00
Sebastián Ramírez
11b6c0146d ⬆️ Upgrade isort and update pre-commit (#5940) 2023-01-30 16:09:51 +01:00
github-actions
4e29835609 📝 Update release notes 2023-01-24 14:30:38 +00:00
Sebastián Ramírez
9858577cd6 🔧 Add template for questions in Discussions (#5920) 2023-01-24 18:30:03 +04:00
github-actions
cd1ee83435 📝 Update release notes 2023-01-23 14:24:31 +00:00
Sebastián Ramírez
fe74890b4b 🔧 Update Sponsor Budget Insight to Powens (#5916) 2023-01-23 14:23:53 +00:00
github-actions
97a2ebc219 📝 Update release notes 2023-01-23 14:13:39 +00:00
Sebastián Ramírez
805226c2b0 🔧 Update GitHub Sponsors badge data (#5915) 2023-01-23 14:13:03 +00:00
Sebastián Ramírez
5905c3f740 🔖 Release version 0.89.1 2023-01-10 20:31:23 +04:00
Sebastián Ramírez
00f3c831f3 📝 Update release notes 2023-01-10 20:30:10 +04:00
github-actions
e84cb6663e 📝 Update release notes 2023-01-10 16:23:24 +00:00
Sebastián Ramírez
fb8e9083f4 📝 Update docs and examples for Response Model with Return Type Annotations, and update runtime error (#5873) 2023-01-10 16:22:47 +00:00
github-actions
6b83525ff4 📝 Update release notes 2023-01-10 12:46:04 +00:00
Marcelo Trylesinski
fba7493042 🐛 Ignore Response classes on return annotation (#5855)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-01-10 12:45:18 +00:00
github-actions
53973f7f94 📝 Update release notes 2023-01-10 12:38:39 +00:00
Kader M
1562592bde 🌐 Add Turkish translation for docs/tr/docs/tutorial/first_steps.md (#5691)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-10 12:38:01 +00:00
github-actions
52a84175c1 📝 Update release notes 2023-01-10 12:34:24 +00:00
Raf Rasenberg
929289b630 📝 Add External Link: FastAPI lambda container: serverless simplified (#5784)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-10 16:33:36 +04:00
Sebastián Ramírez
69bd7d8501 🔖 Release version 0.89.0 2023-01-07 21:17:10 +04:00
Sebastián Ramírez
a6af7c27f8 📝 Update release notes 2023-01-07 21:15:11 +04:00
github-actions
aa6a8e5d49 📝 Update release notes 2023-01-07 17:05:20 +00:00
dependabot[bot]
c482dd3d42 ⬆ Update coverage[toml] requirement from <7.0,>=6.5.0 to >=6.5.0,<8.0 (#5801)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 17:04:43 +00:00
github-actions
681e5c0199 📝 Update release notes 2023-01-07 17:02:15 +00:00
github-actions
eb39b0f8f8 📝 Update release notes 2023-01-07 17:01:58 +00:00
Xhy-5000
27ce2e2108 📝 Add External Link: Authorization on FastAPI with Casbin (#5712)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 21:01:38 +04:00
dependabot[bot]
f56b0d571d ⬆ Update uvicorn[standard] requirement from <0.19.0,>=0.12.0 to >=0.12.0,<0.21.0 for development (#5795)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 17:01:21 +00:00
github-actions
5c6d7b2ff3 📝 Update release notes 2023-01-07 16:57:45 +00:00
Nonso Mgbechi
78813a543d ✏ Fix typo in docs/en/docs/async.md (#5785)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 20:56:58 +04:00
github-actions
903e3be3b8 📝 Update release notes 2023-01-07 16:56:07 +00:00
dependabot[bot]
a17da3d0f4 ⬆ Bump dawidd6/action-download-artifact from 2.24.2 to 2.24.3 (#5842)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 20:55:29 +04:00
github-actions
d202598c71 📝 Update release notes 2023-01-07 15:35:51 +00:00
github-actions[bot]
2dfdcea69a 👥 Update FastAPI People (#5825)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 15:35:14 +00:00
github-actions
789d649fba 📝 Update release notes 2023-01-07 15:31:38 +00:00
Kelby Faessler
bea1fdd2eb ✏ Fix typo in docs/en/docs/deployment/concepts.md (#5824) 2023-01-07 19:31:03 +04:00
github-actions
929c700117 📝 Update release notes 2023-01-07 15:13:27 +00:00
dependabot[bot]
f4e895bc8a ⬆ Bump types-ujson from 5.5.0 to 5.6.0.0 (#5735)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 15:12:49 +00:00
github-actions
adef9f4c02 📝 Update release notes 2023-01-07 15:08:57 +00:00
dependabot[bot]
6e1152d31f ⬆ Bump pypa/gh-action-pypi-publish from 1.5.2 to 1.6.4 (#5750)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 15:08:12 +00:00
github-actions
9812116dc7 📝 Update release notes 2023-01-07 14:55:35 +00:00
Sviatoslav Sydorenko
2583a83f9d 👷 Add GitHub Action gate/check (#5492) 2023-01-07 18:54:59 +04:00
github-actions
59d654672f 📝 Update release notes 2023-01-07 14:46:09 +00:00
Vladislav Kramorenko
d0027de64f 🌐 Add Russian translation for docs/ru/docs/fastapi-people.md (#5577)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 18:45:32 +04:00
github-actions
3c20b6e42b 📝 Update release notes 2023-01-07 14:34:13 +00:00
Ben Ho
3178c17776 🌐 Fix typo in Chinese translation for docs/zh/docs/benchmarks.md (#4269)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 14:33:29 +00:00
github-actions
1be95ba02d 📝 Update release notes 2023-01-07 14:21:59 +00:00
Nina Hwang
2a3a786dd7 🌐 Add Korean translation for docs/tutorial/cors.md (#3764)
Co-authored-by: weekwith.me <63915557+0417taehyun@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-01-07 18:21:23 +04:00
github-actions
a3edc76051 📝 Update release notes 2023-01-07 14:14:07 +00:00
Sebastián Ramírez
d70eef825e 🔧 Update sponsors, add Svix (#5848) 2023-01-07 14:13:34 +00:00
github-actions
679aee85ce 📝 Update release notes 2023-01-07 13:59:26 +00:00
Sebastián Ramírez
cb35e275e3 🔧 Remove Doist sponsor (#5847) 2023-01-07 13:58:46 +00:00
github-actions
18d087f9c6 📝 Update release notes 2023-01-07 13:46:24 +00:00
Yurii Karabas
d0573f5713 Add support for function return type annotations to declare the response_model (#1436)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2023-01-07 17:45:48 +04:00
github-actions
efc12c5cdb 📝 Update release notes 2022-12-16 20:25:51 +00:00
dependabot[bot]
4d5cbc71ac ⬆ Update sqlalchemy requirement from <=1.4.41,>=1.3.18 to >=1.3.18,<1.4.43 (#5540)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2022-12-16 23:41:48 +04:00
github-actions
10500dbc03 📝 Update release notes 2022-12-16 19:11:14 +00:00
dependabot[bot]
63ad0ed4a6 ⬆ Bump nwtgck/actions-netlify from 1.2.4 to 2.0.0 (#5757)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-16 23:10:29 +04:00
github-actions
dc9fb1305a 📝 Update release notes 2022-12-16 18:11:45 +00:00
Sebastián Ramírez
9efab1bd96 👷 Refactor CI artifact upload/download for docs previews (#5793) 2022-12-16 22:11:03 +04:00
github-actions
97f04ab58c 📝 Update release notes 2022-12-03 22:26:17 +00:00
dependabot[bot]
1ba515a18d ⬆ Bump pypa/gh-action-pypi-publish from 1.5.1 to 1.5.2 (#5714)
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.5.1 to 1.5.2.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/v1.5.1...v1.5.2)

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

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

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

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

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

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

A full-stop was missing in `TrustedHostMiddleware` section

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

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

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

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

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

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

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

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-09 12:46:14 +01:00
github-actions
5f0e095689 📝 Update release notes 2022-11-04 19:20:29 +00:00
568 changed files with 32482 additions and 2446 deletions

View File

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

View File

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

View File

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

View File

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

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

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

View File

@@ -1,10 +1,11 @@
import logging
import random
import sys
import time
from pathlib import Path
from typing import Dict, Union
from typing import Any, Dict, List, Union, cast
import yaml
import httpx
from github import Github
from pydantic import BaseModel, BaseSettings, SecretStr
@@ -13,12 +14,172 @@ lang_all_label = "lang-all"
approved_label = "approved-2"
translations_path = Path(__file__).parent / "translations.yml"
github_graphql_url = "https://api.github.com/graphql"
questions_translations_category_id = "DIC_kwDOCZduT84CT5P9"
all_discussions_query = """
query Q($category_id: ID) {
repository(name: "fastapi", owner: "tiangolo") {
discussions(categoryId: $category_id, first: 100) {
nodes {
title
id
number
labels(first: 10) {
edges {
node {
id
name
}
}
}
}
}
}
}
"""
translation_discussion_query = """
query Q($after: String, $discussion_number: Int!) {
repository(name: "fastapi", owner: "tiangolo") {
discussion(number: $discussion_number) {
comments(first: 100, after: $after) {
edges {
cursor
node {
id
url
body
}
}
}
}
}
}
"""
add_comment_mutation = """
mutation Q($discussion_id: ID!, $body: String!) {
addDiscussionComment(input: {discussionId: $discussion_id, body: $body}) {
comment {
id
url
body
}
}
}
"""
update_comment_mutation = """
mutation Q($comment_id: ID!, $body: String!) {
updateDiscussionComment(input: {commentId: $comment_id, body: $body}) {
comment {
id
url
body
}
}
}
"""
class Comment(BaseModel):
id: str
url: str
body: str
class UpdateDiscussionComment(BaseModel):
comment: Comment
class UpdateCommentData(BaseModel):
updateDiscussionComment: UpdateDiscussionComment
class UpdateCommentResponse(BaseModel):
data: UpdateCommentData
class AddDiscussionComment(BaseModel):
comment: Comment
class AddCommentData(BaseModel):
addDiscussionComment: AddDiscussionComment
class AddCommentResponse(BaseModel):
data: AddCommentData
class CommentsEdge(BaseModel):
node: Comment
cursor: str
class Comments(BaseModel):
edges: List[CommentsEdge]
class CommentsDiscussion(BaseModel):
comments: Comments
class CommentsRepository(BaseModel):
discussion: CommentsDiscussion
class CommentsData(BaseModel):
repository: CommentsRepository
class CommentsResponse(BaseModel):
data: CommentsData
class AllDiscussionsLabelNode(BaseModel):
id: str
name: str
class AllDiscussionsLabelsEdge(BaseModel):
node: AllDiscussionsLabelNode
class AllDiscussionsDiscussionLabels(BaseModel):
edges: List[AllDiscussionsLabelsEdge]
class AllDiscussionsDiscussionNode(BaseModel):
title: str
id: str
number: int
labels: AllDiscussionsDiscussionLabels
class AllDiscussionsDiscussions(BaseModel):
nodes: List[AllDiscussionsDiscussionNode]
class AllDiscussionsRepository(BaseModel):
discussions: AllDiscussionsDiscussions
class AllDiscussionsData(BaseModel):
repository: AllDiscussionsRepository
class AllDiscussionsResponse(BaseModel):
data: AllDiscussionsData
class Settings(BaseSettings):
github_repository: str
input_token: SecretStr
github_event_path: Path
github_event_name: Union[str, None] = None
httpx_timeout: int = 30
input_debug: Union[bool, None] = False
@@ -30,6 +191,113 @@ class PartialGitHubEvent(BaseModel):
pull_request: PartialGitHubEventIssue
def get_graphql_response(
*,
settings: Settings,
query: str,
after: Union[str, None] = None,
category_id: Union[str, None] = None,
discussion_number: Union[int, None] = None,
discussion_id: Union[str, None] = None,
comment_id: Union[str, None] = None,
body: Union[str, None] = None,
) -> Dict[str, Any]:
headers = {"Authorization": f"token {settings.input_token.get_secret_value()}"}
# some fields are only used by one query, but GraphQL allows unused variables, so
# keep them here for simplicity
variables = {
"after": after,
"category_id": category_id,
"discussion_number": discussion_number,
"discussion_id": discussion_id,
"comment_id": comment_id,
"body": body,
}
response = httpx.post(
github_graphql_url,
headers=headers,
timeout=settings.httpx_timeout,
json={"query": query, "variables": variables, "operationName": "Q"},
)
if response.status_code != 200:
logging.error(
f"Response was not 200, after: {after}, category_id: {category_id}"
)
logging.error(response.text)
raise RuntimeError(response.text)
data = response.json()
if "errors" in data:
logging.error(f"Errors in response, after: {after}, category_id: {category_id}")
logging.error(response.text)
raise RuntimeError(response.text)
return cast(Dict[str, Any], data)
def get_graphql_translation_discussions(*, settings: Settings):
data = get_graphql_response(
settings=settings,
query=all_discussions_query,
category_id=questions_translations_category_id,
)
graphql_response = AllDiscussionsResponse.parse_obj(data)
return graphql_response.data.repository.discussions.nodes
def get_graphql_translation_discussion_comments_edges(
*, settings: Settings, discussion_number: int, after: Union[str, None] = None
):
data = get_graphql_response(
settings=settings,
query=translation_discussion_query,
discussion_number=discussion_number,
after=after,
)
graphql_response = CommentsResponse.parse_obj(data)
return graphql_response.data.repository.discussion.comments.edges
def get_graphql_translation_discussion_comments(
*, settings: Settings, discussion_number: int
):
comment_nodes: List[Comment] = []
discussion_edges = get_graphql_translation_discussion_comments_edges(
settings=settings, discussion_number=discussion_number
)
while discussion_edges:
for discussion_edge in discussion_edges:
comment_nodes.append(discussion_edge.node)
last_edge = discussion_edges[-1]
discussion_edges = get_graphql_translation_discussion_comments_edges(
settings=settings,
discussion_number=discussion_number,
after=last_edge.cursor,
)
return comment_nodes
def create_comment(*, settings: Settings, discussion_id: str, body: str):
data = get_graphql_response(
settings=settings,
query=add_comment_mutation,
discussion_id=discussion_id,
body=body,
)
response = AddCommentResponse.parse_obj(data)
return response.data.addDiscussionComment.comment
def update_comment(*, settings: Settings, comment_id: str, body: str):
data = get_graphql_response(
settings=settings,
query=update_comment_mutation,
comment_id=comment_id,
body=body,
)
response = UpdateCommentResponse.parse_obj(data)
return response.data.updateDiscussionComment.comment
if __name__ == "__main__":
settings = Settings()
if settings.input_debug:
@@ -45,60 +313,105 @@ if __name__ == "__main__":
)
contents = settings.github_event_path.read_text()
github_event = PartialGitHubEvent.parse_raw(contents)
translations_map: Dict[str, int] = yaml.safe_load(translations_path.read_text())
logging.debug(f"Using translations map: {translations_map}")
# Avoid race conditions with multiple labels
sleep_time = random.random() * 10 # random number between 0 and 10 seconds
pr = repo.get_pull(github_event.pull_request.number)
logging.debug(
f"Processing PR: {pr.number}, with anti-race condition sleep time: {sleep_time}"
logging.info(
f"Sleeping for {sleep_time} seconds to avoid "
"race conditions and multiple comments"
)
if pr.state == "open":
logging.debug(f"PR is open: {pr.number}")
label_strs = {label.name for label in pr.get_labels()}
if lang_all_label in label_strs and awaiting_label in label_strs:
logging.info(
f"This PR seems to be a language translation and awaiting reviews: {pr.number}"
)
if approved_label in label_strs:
message = (
f"It seems this PR already has the approved label: {pr.number}"
)
logging.error(message)
raise RuntimeError(message)
langs = []
for label in label_strs:
if label.startswith("lang-") and not label == lang_all_label:
langs.append(label[5:])
for lang in langs:
if lang in translations_map:
num = translations_map[lang]
logging.info(
f"Found a translation issue for language: {lang} in issue: {num}"
)
issue = repo.get_issue(num)
message = f"Good news everyone! 😉 There's a new translation PR to be reviewed: #{pr.number} 🎉"
already_notified = False
time.sleep(sleep_time)
logging.info(
f"Sleeping for {sleep_time} seconds to avoid race conditions and multiple comments"
)
logging.info(
f"Checking current comments in issue: {num} to see if already notified about this PR: {pr.number}"
)
for comment in issue.get_comments():
if message in comment.body:
already_notified = True
if not already_notified:
logging.info(
f"Writing comment in issue: {num} about PR: {pr.number}"
)
issue.create_comment(message)
else:
logging.info(
f"Issue: {num} was already notified of PR: {pr.number}"
)
else:
time.sleep(sleep_time)
# Get PR
logging.debug(f"Processing PR: #{github_event.pull_request.number}")
pr = repo.get_pull(github_event.pull_request.number)
label_strs = {label.name for label in pr.get_labels()}
langs = []
for label in label_strs:
if label.startswith("lang-") and not label == lang_all_label:
langs.append(label[5:])
logging.info(f"PR #{pr.number} has labels: {label_strs}")
if not langs or lang_all_label not in label_strs:
logging.info(f"PR #{pr.number} doesn't seem to be a translation PR, skipping")
sys.exit(0)
# Generate translation map, lang ID to discussion
discussions = get_graphql_translation_discussions(settings=settings)
lang_to_discussion_map: Dict[str, AllDiscussionsDiscussionNode] = {}
for discussion in discussions:
for edge in discussion.labels.edges:
label = edge.node.name
if label.startswith("lang-") and not label == lang_all_label:
lang = label[5:]
lang_to_discussion_map[lang] = discussion
logging.debug(f"Using translations map: {lang_to_discussion_map}")
# Messages to create or check
new_translation_message = f"Good news everyone! 😉 There's a new translation PR to be reviewed: #{pr.number} by @{pr.user.login}. 🎉 This requires 2 approvals from native speakers to be merged. 🤓"
done_translation_message = f"~There's a new translation PR to be reviewed: #{pr.number} by @{pr.user.login}~ Good job! This is done. 🍰☕"
# Normally only one language, but still
for lang in langs:
if lang not in lang_to_discussion_map:
log_message = f"Could not find discussion for language: {lang}"
logging.error(log_message)
raise RuntimeError(log_message)
discussion = lang_to_discussion_map[lang]
logging.info(
f"Changing labels in a closed PR doesn't trigger comments, PR: {pr.number}"
f"Found a translation discussion for language: {lang} in discussion: #{discussion.number}"
)
already_notified_comment: Union[Comment, None] = None
already_done_comment: Union[Comment, None] = None
logging.info(
f"Checking current comments in discussion: #{discussion.number} to see if already notified about this PR: #{pr.number}"
)
comments = get_graphql_translation_discussion_comments(
settings=settings, discussion_number=discussion.number
)
for comment in comments:
if new_translation_message in comment.body:
already_notified_comment = comment
elif done_translation_message in comment.body:
already_done_comment = comment
logging.info(
f"Already notified comment: {already_notified_comment}, already done comment: {already_done_comment}"
)
if pr.state == "open" and awaiting_label in label_strs:
logging.info(
f"This PR seems to be a language translation and awaiting reviews: #{pr.number}"
)
if already_notified_comment:
logging.info(
f"This PR #{pr.number} was already notified in comment: {already_notified_comment.url}"
)
else:
logging.info(
f"Writing notification comment about PR #{pr.number} in Discussion: #{discussion.number}"
)
comment = create_comment(
settings=settings,
discussion_id=discussion.id,
body=new_translation_message,
)
logging.info(f"Notified in comment: {comment.url}")
elif pr.state == "closed" or approved_label in label_strs:
logging.info(f"Already approved or closed PR #{pr.number}")
if already_done_comment:
logging.info(
f"This PR #{pr.number} was already marked as done in comment: {already_done_comment.url}"
)
elif already_notified_comment:
updated_comment = update_comment(
settings=settings,
comment_id=already_notified_comment.id,
body=done_translation_message,
)
logging.info(f"Marked as done in comment: {updated_comment.url}")
else:
logging.info(
f"There doesn't seem to be anything to be done about PR #{pr.number}"
)
logging.info("Finished")

View File

@@ -1,20 +0,0 @@
pt: 1211
es: 1218
zh: 1228
ru: 1362
it: 1556
ja: 1572
uk: 1748
tr: 1892
fr: 1972
ko: 2017
fa: 2041
pl: 3169
de: 3716
id: 3717
az: 3994
nl: 4701
uz: 4883
sv: 5146
he: 5157
ta: 5434

View File

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

View File

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

View File

@@ -4,6 +4,7 @@ on:
pull_request_target:
types:
- labeled
- closed
jobs:
notify-translations:

View File

@@ -15,6 +15,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# Ref: https://github.com/actions/runner/issues/2033
- name: Fix git safe.directory in container
run: mkdir -p /home/runner/work/_temp/_github_home && printf "[safe]\n\tdirectory = /github/workspace" > /home/runner/work/_temp/_github_home/.gitconfig
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3

View File

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

View File

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

View File

@@ -20,7 +20,7 @@ jobs:
- run: pip install smokeshow
- uses: dawidd6/action-download-artifact@v2
- uses: dawidd6/action-download-artifact@v2.26.0
with:
workflow: test.yml
commit: ${{ github.event.workflow_run.head_sha }}

View File

@@ -21,11 +21,13 @@ jobs:
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
cache-dependency-path: pyproject.toml
- uses: actions/cache@v3
id: cache
with:
path: ${{ env.pythonLocation }}
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test-v02
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test-v03
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -e .[all,dev,doc,test]
@@ -52,6 +54,8 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: '3.8'
cache: "pip"
cache-dependency-path: pyproject.toml
- name: Get coverage files
uses: actions/download-artifact@v3
@@ -71,3 +75,19 @@ jobs:
with:
name: coverage-html
path: htmlcov
# https://github.com/marketplace/actions/alls-green#why
check: # This job does nothing and is only used for the branch protection
if: always()
needs:
- coverage-combine
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1
with:
jobs: ${{ toJSON(needs) }}

View File

@@ -1,8 +1,10 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
default_language_version:
python: python3.10
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
rev: v4.4.0
hooks:
- id: check-added-large-files
- id: check-toml
@@ -12,27 +14,20 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/asottile/pyupgrade
rev: v3.1.0
rev: v3.3.1
hooks:
- id: pyupgrade
args:
- --py3-plus
- --keep-runtime-typing
- repo: https://github.com/PyCQA/autoflake
rev: v1.7.7
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.254
hooks:
- id: autoflake
- id: ruff
args:
- --recursive
- --in-place
- --remove-all-unused-imports
- --remove-unused-variables
- --expand-star-imports
- --exclude
- __init__.py
- --remove-duplicate-keys
- --fix
- repo: https://github.com/pycqa/isort
rev: 5.10.1
rev: 5.12.0
hooks:
- id: isort
name: isort (python)
@@ -43,7 +38,7 @@ repos:
name: isort (pyi)
types: [pyi]
- repo: https://github.com/psf/black
rev: 22.10.0
rev: 23.1.0
hooks:
- id: black
ci:

View File

@@ -49,14 +49,14 @@ The key features are:
<a href="https://bit.ly/3dmXC5S" target="_blank" title="The data structure for unstructured multimodal data"><img src="https://fastapi.tiangolo.com/img/sponsors/docarray.svg"></a>
<a href="https://bit.ly/3JJ7y5C" target="_blank" title="Build cross-modal and multimodal applications on the cloud"><img src="https://fastapi.tiangolo.com/img/sponsors/jina2.svg"></a>
<a href="https://cryptapi.io/" target="_blank" title="CryptAPI: Your easy to use, secure and privacy oriented payment gateway."><img src="https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg"></a>
<a href="https://doist.com/careers/9B437B1615-wa-senior-backend-engineer-python" target="_blank" title="Help us migrate doist to FastAPI"><img src="https://fastapi.tiangolo.com/img/sponsors/doist.svg"></a>
<a href="https://www.deta.sh/?ref=fastapi" target="_blank" title="The launchpad for all your (team's) ideas"><img src="https://fastapi.tiangolo.com/img/sponsors/deta.svg"></a>
<a href="https://www.investsuite.com/jobs" target="_blank" title="Wealthtech jobs with FastAPI"><img src="https://fastapi.tiangolo.com/img/sponsors/investsuite.svg"></a>
<a href="https://training.talkpython.fm/fastapi-courses" target="_blank" title="FastAPI video courses on demand from people you trust"><img src="https://fastapi.tiangolo.com/img/sponsors/talkpython.png"></a>
<a href="https://testdriven.io/courses/tdd-fastapi/" target="_blank" title="Learn to build high-quality web apps with best practices"><img src="https://fastapi.tiangolo.com/img/sponsors/testdriven.svg"></a>
<a href="https://github.com/deepset-ai/haystack/" target="_blank" title="Build powerful search from composable, open source building blocks"><img src="https://fastapi.tiangolo.com/img/sponsors/haystack-fastapi.svg"></a>
<a href="https://www.udemy.com/course/fastapi-rest/" target="_blank" title="Learn FastAPI by building a complete project. Extend your knowledge on advanced web development-AWS, Payments, Emails."><img src="https://fastapi.tiangolo.com/img/sponsors/ines-course.jpg"></a>
<a href="https://careers.budget-insight.com/" target="_blank" title="Budget Insight is hiring!"><img src="https://fastapi.tiangolo.com/img/sponsors/budget-insight.svg"></a>
<a href="https://careers.powens.com/" target="_blank" title="Powens is hiring!"><img src="https://fastapi.tiangolo.com/img/sponsors/powens.png"></a>
<a href="https://www.svix.com/" target="_blank" title="Svix - Webhooks as a service"><img src="https://fastapi.tiangolo.com/img/sponsors/svix.svg"></a>
<!-- /sponsors -->
@@ -102,6 +102,12 @@ The key features are:
---
"_If anyone is looking to build a production Python API, I would highly recommend **FastAPI**. It is **beautifully designed**, **simple to use** and **highly scalable**, it has become a **key component** in our API first development strategy and is driving many automations and services such as our Virtual TAC Engineer._"
<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**, the FastAPI of CLIs
<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>
@@ -427,7 +433,7 @@ For a more complete example including more features, see the <a href="https://fa
* **GraphQL** integration with <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> and other libraries.
* Many extra features (thanks to Starlette) as:
* **WebSockets**
* extremely easy tests based on `requests` and `pytest`
* extremely easy tests based on HTTPX and `pytest`
* **CORS**
* **Cookie Sessions**
* ...and more.
@@ -447,7 +453,7 @@ Used by Pydantic:
Used by Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.

View File

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

View File

@@ -45,6 +45,7 @@ nav:
- fa: /fa/
- fr: /fr/
- he: /he/
- hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
@@ -55,6 +56,7 @@ nav:
- ru: /ru/
- sq: /sq/
- sv: /sv/
- ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -80,7 +82,7 @@ markdown_extensions:
extra:
analytics:
provider: google
property: UA-133183413-1
property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -111,6 +113,8 @@ extra:
name: fr - français
- link: /he/
name: he
- link: /hy/
name: hy
- link: /id/
name: id
- link: /it/
@@ -131,6 +135,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
- link: /ta/
name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/

View File

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

View File

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

View File

@@ -45,6 +45,7 @@ nav:
- fa: /fa/
- fr: /fr/
- he: /he/
- hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
@@ -55,6 +56,7 @@ nav:
- ru: /ru/
- sq: /sq/
- sv: /sv/
- ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -81,7 +83,7 @@ markdown_extensions:
extra:
analytics:
provider: google
property: UA-133183413-1
property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -112,6 +114,8 @@ extra:
name: fr - français
- link: /he/
name: he
- link: /hy/
name: hy
- link: /id/
name: id
- link: /it/
@@ -132,6 +136,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
- link: /ta/
name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/

View File

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

View File

@@ -2,18 +2,18 @@ sponsors:
- - login: jina-ai
avatarUrl: https://avatars.githubusercontent.com/u/60539444?v=4
url: https://github.com/jina-ai
- - login: Doist
avatarUrl: https://avatars.githubusercontent.com/u/2565372?v=4
url: https://github.com/Doist
- login: cryptapi
- - login: armand-sauzay
avatarUrl: https://avatars.githubusercontent.com/u/35524799?u=56e3e944bfe62770d1709c09552d2efc6d285ca6&v=4
url: https://github.com/armand-sauzay
- - login: cryptapi
avatarUrl: https://avatars.githubusercontent.com/u/44925437?u=61369138589bc7fee6c417f3fbd50fbd38286cc4&v=4
url: https://github.com/cryptapi
- - login: ObliviousAI
- - login: nihpo
avatarUrl: https://avatars.githubusercontent.com/u/1841030?u=0264956d7580f7e46687a762a7baa629f84cf97c&v=4
url: https://github.com/nihpo
- login: ObliviousAI
avatarUrl: https://avatars.githubusercontent.com/u/65656077?v=4
url: https://github.com/ObliviousAI
- login: Lovage-Labs
avatarUrl: https://avatars.githubusercontent.com/u/71685552?v=4
url: https://github.com/Lovage-Labs
- login: chaserowbotham
avatarUrl: https://avatars.githubusercontent.com/u/97751084?v=4
url: https://github.com/chaserowbotham
@@ -29,6 +29,9 @@ sponsors:
- login: investsuite
avatarUrl: https://avatars.githubusercontent.com/u/73833632?v=4
url: https://github.com/investsuite
- login: svix
avatarUrl: https://avatars.githubusercontent.com/u/80175132?v=4
url: https://github.com/svix
- login: VincentParedes
avatarUrl: https://avatars.githubusercontent.com/u/103889729?v=4
url: https://github.com/VincentParedes
@@ -38,18 +41,15 @@ sponsors:
- - login: InesIvanova
avatarUrl: https://avatars.githubusercontent.com/u/22920417?u=409882ec1df6dbd77455788bb383a8de223dbf6f&v=4
url: https://github.com/InesIvanova
- - login: SendCloud
avatarUrl: https://avatars.githubusercontent.com/u/7831959?v=4
url: https://github.com/SendCloud
- login: mercedes-benz
avatarUrl: https://avatars.githubusercontent.com/u/34240465?v=4
url: https://github.com/mercedes-benz
- - login: vyos
avatarUrl: https://avatars.githubusercontent.com/u/5647000?v=4
url: https://github.com/vyos
- login: takashi-yoneya
avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4
url: https://github.com/takashi-yoneya
- login: xoflare
avatarUrl: https://avatars.githubusercontent.com/u/74335107?v=4
url: https://github.com/xoflare
- login: Striveworks
avatarUrl: https://avatars.githubusercontent.com/u/45523576?v=4
url: https://github.com/Striveworks
- login: BoostryJP
avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4
url: https://github.com/BoostryJP
@@ -59,12 +59,21 @@ sponsors:
- login: HiredScore
avatarUrl: https://avatars.githubusercontent.com/u/3908850?v=4
url: https://github.com/HiredScore
- login: ianshan0915
avatarUrl: https://avatars.githubusercontent.com/u/5893101?u=a178d247d882578b1d1ef214b2494e52eb28634c&v=4
url: https://github.com/ianshan0915
- login: Trivie
avatarUrl: https://avatars.githubusercontent.com/u/8161763?v=4
url: https://github.com/Trivie
- login: Lovage-Labs
avatarUrl: https://avatars.githubusercontent.com/u/71685552?v=4
url: https://github.com/Lovage-Labs
- - login: moellenbeck
avatarUrl: https://avatars.githubusercontent.com/u/169372?v=4
url: https://github.com/moellenbeck
- login: birkjernstrom
avatarUrl: https://avatars.githubusercontent.com/u/281715?u=4be14b43f76b4bd497b1941309bb390250b405e6&v=4
url: https://github.com/birkjernstrom
- login: AccentDesign
avatarUrl: https://avatars.githubusercontent.com/u/2429332?v=4
url: https://github.com/AccentDesign
@@ -80,30 +89,18 @@ sponsors:
- login: jmaralc
avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4
url: https://github.com/jmaralc
- login: takashi-yoneya
avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4
url: https://github.com/takashi-yoneya
- login: mainframeindustries
avatarUrl: https://avatars.githubusercontent.com/u/55092103?v=4
url: https://github.com/mainframeindustries
- login: DelfinaCare
avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4
url: https://github.com/DelfinaCare
- - login: karelhusa
avatarUrl: https://avatars.githubusercontent.com/u/11407706?u=4f787cffc30ea198b15935c751940f0b48a26a17&v=4
url: https://github.com/karelhusa
- - login: povilasb
avatarUrl: https://avatars.githubusercontent.com/u/1213442?u=b11f58ed6ceea6e8297c9b310030478ebdac894d&v=4
url: https://github.com/povilasb
- login: primer-io
avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4
url: https://github.com/primer-io
- - login: DucNgn
avatarUrl: https://avatars.githubusercontent.com/u/43587865?u=a9f9f61569aebdc0ce74df85b8cc1a219a7ab570&v=4
url: https://github.com/DucNgn
- login: A-Edge
avatarUrl: https://avatars.githubusercontent.com/u/59514131?v=4
url: https://github.com/A-Edge
- - login: indeedeng
avatarUrl: https://avatars.githubusercontent.com/u/2905043?v=4
url: https://github.com/indeedeng
- - login: Kludex
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
@@ -119,18 +116,12 @@ sponsors:
- login: kamalgill
avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4
url: https://github.com/kamalgill
- login: gazpachoking
avatarUrl: https://avatars.githubusercontent.com/u/187133?v=4
url: https://github.com/gazpachoking
- login: dekoza
avatarUrl: https://avatars.githubusercontent.com/u/210980?u=c03c78a8ae1039b500dfe343665536ebc51979b2&v=4
url: https://github.com/dekoza
- login: pamelafox
avatarUrl: https://avatars.githubusercontent.com/u/297042?v=4
url: https://github.com/pamelafox
- login: deserat
avatarUrl: https://avatars.githubusercontent.com/u/299332?v=4
url: https://github.com/deserat
- login: ericof
avatarUrl: https://avatars.githubusercontent.com/u/306014?u=cf7c8733620397e6584a451505581c01c5d842d7&v=4
url: https://github.com/ericof
@@ -146,72 +137,63 @@ sponsors:
- login: jqueguiner
avatarUrl: https://avatars.githubusercontent.com/u/690878?u=bd65cc1f228ce6455e56dfaca3ef47c33bc7c3b0&v=4
url: https://github.com/jqueguiner
- login: alexsantos
avatarUrl: https://avatars.githubusercontent.com/u/932219?v=4
url: https://github.com/alexsantos
- login: 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
- login: ltieman
avatarUrl: https://avatars.githubusercontent.com/u/1084689?u=e69b17de17cb3ca141a17daa7ccbe173ceb1eb17&v=4
url: https://github.com/ltieman
- login: mrkmcknz
avatarUrl: https://avatars.githubusercontent.com/u/1089376?u=2b9b8a8c25c33a4f6c220095638bd821cdfd13a3&v=4
url: https://github.com/mrkmcknz
- login: coffeewasmyidea
avatarUrl: https://avatars.githubusercontent.com/u/1636488?u=8e32a4f200eff54dd79cd79d55d254bfce5e946d&v=4
url: https://github.com/coffeewasmyidea
- login: jonakoudijs
avatarUrl: https://avatars.githubusercontent.com/u/1906344?u=5ca0c9a1a89b6a2ba31abe35c66bdc07af60a632&v=4
url: https://github.com/jonakoudijs
- login: corleyma
avatarUrl: https://avatars.githubusercontent.com/u/2080732?u=aed2ff652294a87d666b1c3f6dbe98104db76d26&v=4
avatarUrl: https://avatars.githubusercontent.com/u/2080732?u=c61f9a4bbc45a45f5d855f93e5f6e0fc8b32c468&v=4
url: https://github.com/corleyma
- login: madisonmay
avatarUrl: https://avatars.githubusercontent.com/u/2645393?u=f22b93c6ea345a4d26a90a3834dfc7f0789fcb63&v=4
url: https://github.com/madisonmay
- login: saivarunk
avatarUrl: https://avatars.githubusercontent.com/u/2976867?u=71f4385e781e9a9e871a52f2d4686f9a8d69ba2f&v=4
url: https://github.com/saivarunk
- login: andre1sk
avatarUrl: https://avatars.githubusercontent.com/u/3148093?v=4
url: https://github.com/andre1sk
- login: Shark009
avatarUrl: https://avatars.githubusercontent.com/u/3163309?u=0c6f4091b0eda05c44c390466199826e6dc6e431&v=4
url: https://github.com/Shark009
- login: grillazz
avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=0b32b7073ae1ab8b7f6d2db0188c2e1e357ff451&v=4
url: https://github.com/grillazz
- login: ColliotL
avatarUrl: https://avatars.githubusercontent.com/u/3412402?u=ca64b07ecbef2f9da1cc2cac3f37522aa4814902&v=4
url: https://github.com/ColliotL
- login: dblackrun
avatarUrl: https://avatars.githubusercontent.com/u/3528486?v=4
url: https://github.com/dblackrun
- login: zsinx6
avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4
url: https://github.com/zsinx6
- login: bauyrzhanospan
avatarUrl: https://avatars.githubusercontent.com/u/3536037?u=25c86201d0212497aefcc1688cccf509057a1dc4&v=4
url: https://github.com/bauyrzhanospan
- login: MarekBleschke
avatarUrl: https://avatars.githubusercontent.com/u/3616870?v=4
url: https://github.com/MarekBleschke
- login: aacayaco
avatarUrl: https://avatars.githubusercontent.com/u/3634801?u=eaadda178c964178fcb64886f6c732172c8f8219&v=4
url: https://github.com/aacayaco
- login: peterHoburg
avatarUrl: https://avatars.githubusercontent.com/u/3860655?u=f55f47eb2d6a9b495e806ac5a044e3ae01ccc1fa&v=4
url: https://github.com/peterHoburg
- login: anomaly
avatarUrl: https://avatars.githubusercontent.com/u/3654837?v=4
url: https://github.com/anomaly
- login: jgreys
avatarUrl: https://avatars.githubusercontent.com/u/4136890?u=b579fd97033269a5e703ab509c7d5478b146cc2d&v=4
avatarUrl: https://avatars.githubusercontent.com/u/4136890?u=c66ae617d614f6c886f1f1c1799d22100b3c848d&v=4
url: https://github.com/jgreys
- login: gorhack
avatarUrl: https://avatars.githubusercontent.com/u/4141690?u=ec119ebc4bdf00a7bc84657a71aa17834f4f27f3&v=4
url: https://github.com/gorhack
- login: jaredtrog
avatarUrl: https://avatars.githubusercontent.com/u/4381365?v=4
url: https://github.com/jaredtrog
- login: oliverxchen
avatarUrl: https://avatars.githubusercontent.com/u/4471774?u=534191f25e32eeaadda22dfab4b0a428733d5489&v=4
url: https://github.com/oliverxchen
- login: ScrimForever
avatarUrl: https://avatars.githubusercontent.com/u/5040124?u=091ec38bfe16d6e762099e91309b59f248616a65&v=4
url: https://github.com/ScrimForever
- login: ennui93
avatarUrl: https://avatars.githubusercontent.com/u/5300907?u=5b5452725ddb391b2caaebf34e05aba873591c3a&v=4
url: https://github.com/ennui93
- login: ternaus
avatarUrl: https://avatars.githubusercontent.com/u/5481618?u=fabc8d75c921b3380126adb5a931c5da6e7db04f&v=4
url: https://github.com/ternaus
- login: eseglem
avatarUrl: https://avatars.githubusercontent.com/u/5920492?u=208d419cf667b8ac594c82a8db01932c7e50d057&v=4
url: https://github.com/eseglem
- login: Yaleesa
avatarUrl: https://avatars.githubusercontent.com/u/6135475?v=4
url: https://github.com/Yaleesa
@@ -230,6 +212,9 @@ sponsors:
- login: Rehket
avatarUrl: https://avatars.githubusercontent.com/u/7015688?u=3afb0ba200feebbc7f958950e92db34df2a3c172&v=4
url: https://github.com/Rehket
- login: ValentinCalomme
avatarUrl: https://avatars.githubusercontent.com/u/7288672?u=e09758c7a36c49f0fb3574abe919cbd344fdc2d6&v=4
url: https://github.com/ValentinCalomme
- login: hiancdtrsnm
avatarUrl: https://avatars.githubusercontent.com/u/7343177?v=4
url: https://github.com/hiancdtrsnm
@@ -239,15 +224,9 @@ sponsors:
- login: wdwinslow
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4
url: https://github.com/wdwinslow
- login: Ge0f3
avatarUrl: https://avatars.githubusercontent.com/u/11887760?u=ccd80f1ac36dcb8517ef5c4e702e8cc5a80cad2f&v=4
url: https://github.com/Ge0f3
- login: svats2k
avatarUrl: https://avatars.githubusercontent.com/u/12378398?u=ecf28c19f61052e664bdfeb2391f8107d137915c&v=4
url: https://github.com/svats2k
- login: gokulyc
avatarUrl: https://avatars.githubusercontent.com/u/13468848?u=269f269d3e70407b5fb80138c52daba7af783997&v=4
url: https://github.com/gokulyc
- login: dannywade
avatarUrl: https://avatars.githubusercontent.com/u/13680237?u=418ee985bd41577b20fde81417fb2d901e875e8a&v=4
url: https://github.com/dannywade
@@ -255,23 +234,26 @@ sponsors:
avatarUrl: https://avatars.githubusercontent.com/u/13686061?u=59f25ef42ecf04c22657aac4238ce0e2d3d30304&v=4
url: https://github.com/khadrawy
- login: pablonnaoji
avatarUrl: https://avatars.githubusercontent.com/u/15187159?u=afc15bd5a4ba9c5c7206bbb1bcaeef606a0932e0&v=4
avatarUrl: https://avatars.githubusercontent.com/u/15187159?u=7480e0eaf959e9c5dfe3a05286f2ea4588c0a3c6&v=4
url: https://github.com/pablonnaoji
- login: robintully
avatarUrl: https://avatars.githubusercontent.com/u/17059673?u=862b9bb01513f5acd30df97433cb97a24dbfb772&v=4
url: https://github.com/robintully
- login: mjohnsey
avatarUrl: https://avatars.githubusercontent.com/u/16784016?u=38fad2e6b411244560b3af99c5f5a4751bc81865&v=4
url: https://github.com/mjohnsey
- login: abdalla19977
avatarUrl: https://avatars.githubusercontent.com/u/17257234?v=4
url: https://github.com/abdalla19977
- login: wedwardbeck
avatarUrl: https://avatars.githubusercontent.com/u/19333237?u=1de4ae2bf8d59eb4c013f21d863cbe0f2010575f&v=4
url: https://github.com/wedwardbeck
- login: RedCarpetUp
avatarUrl: https://avatars.githubusercontent.com/u/20360440?v=4
url: https://github.com/RedCarpetUp
- login: Filimoa
avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=75e02d102d2ee3e3d793e555fa5c63045913ccb0&v=4
avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=0be845711495bbd7b756e13fcaeb8efc1ebd78ba&v=4
url: https://github.com/Filimoa
- login: shuheng-liu
avatarUrl: https://avatars.githubusercontent.com/u/22414322?u=813c45f30786c6b511b21a661def025d8f7b609e&v=4
url: https://github.com/shuheng-liu
- login: Pablongo24
avatarUrl: https://avatars.githubusercontent.com/u/24843427?u=78a6798469889d7a0690449fc667c39e13d5c6a9&v=4
url: https://github.com/Pablongo24
- login: Joeriksson
avatarUrl: https://avatars.githubusercontent.com/u/25037079?v=4
url: https://github.com/Joeriksson
@@ -302,6 +284,12 @@ sponsors:
- login: ProteinQure
avatarUrl: https://avatars.githubusercontent.com/u/33707203?v=4
url: https://github.com/ProteinQure
- login: askurihin
avatarUrl: https://avatars.githubusercontent.com/u/37978981?v=4
url: https://github.com/askurihin
- login: arleybri18
avatarUrl: https://avatars.githubusercontent.com/u/39681546?u=5c028f81324b0e8c73b3c15bc4e7b0218d2ba0c3&v=4
url: https://github.com/arleybri18
- login: ybressler
avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=41e2c00f1eebe3c402635f0325e41b4e6511462c&v=4
url: https://github.com/ybressler
@@ -311,18 +299,21 @@ sponsors:
- login: VictorCalderon
avatarUrl: https://avatars.githubusercontent.com/u/44529243?u=cea69884f826a29aff1415493405209e0706d07a&v=4
url: https://github.com/VictorCalderon
- login: arthuRHD
avatarUrl: https://avatars.githubusercontent.com/u/48015496?u=05a0d5b8b9320eeb7990d35c9337b823f269d2ff&v=4
url: https://github.com/arthuRHD
- login: rafsaf
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
url: https://github.com/rafsaf
- login: dudikbender
avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=494f85229115076121b3639a3806bbac1c6ae7f6&v=4
avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=3a57542938ebfd57579a0111db2b297e606d9681&v=4
url: https://github.com/dudikbender
- login: dazeddd
avatarUrl: https://avatars.githubusercontent.com/u/59472056?u=7a1b668449bf8b448db13e4c575576d24d7d658b&v=4
url: https://github.com/dazeddd
- login: thisistheplace
avatarUrl: https://avatars.githubusercontent.com/u/57633545?u=a3f3a7f8ace8511c6c067753f6eb6aee0db11ac6&v=4
url: https://github.com/thisistheplace
- login: kyjoconn
avatarUrl: https://avatars.githubusercontent.com/u/58443406?u=a3e9c2acfb7ba62edda9334aba61cf027f41f789&v=4
url: https://github.com/kyjoconn
- 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
@@ -332,29 +323,29 @@ sponsors:
- login: predictionmachine
avatarUrl: https://avatars.githubusercontent.com/u/63719559?v=4
url: https://github.com/predictionmachine
- login: minsau
avatarUrl: https://avatars.githubusercontent.com/u/64386242?u=7e45f24b2958caf946fa3546ea33bacf5cd886f8&v=4
url: https://github.com/minsau
- login: daverin
avatarUrl: https://avatars.githubusercontent.com/u/70378377?u=6d1814195c0de7162820eaad95a25b423a3869c0&v=4
url: https://github.com/daverin
- login: anthonycepeda
avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=4252c6b6dc5024af502a823a3ac5e7a03a69963f&v=4
url: https://github.com/anthonycepeda
- login: dotlas
avatarUrl: https://avatars.githubusercontent.com/u/88832003?v=4
url: https://github.com/dotlas
- login: programvx
avatarUrl: https://avatars.githubusercontent.com/u/96057906?v=4
url: https://github.com/programvx
- login: DelfinaCare
avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4
url: https://github.com/DelfinaCare
- login: osawa-koki
avatarUrl: https://avatars.githubusercontent.com/u/94336223?u=59c6fe6945bcbbaff87b2a794238671b060620d2&v=4
url: https://github.com/osawa-koki
- login: pyt3h
avatarUrl: https://avatars.githubusercontent.com/u/99658549?v=4
url: https://github.com/pyt3h
- login: Dagmaara
avatarUrl: https://avatars.githubusercontent.com/u/115501964?v=4
url: https://github.com/Dagmaara
- - login: linux-china
avatarUrl: https://avatars.githubusercontent.com/u/46711?v=4
- - login: pawamoy
avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4
url: https://github.com/pawamoy
- login: linux-china
avatarUrl: https://avatars.githubusercontent.com/u/46711?u=cd77c65338b158750eb84dc7ff1acf3209ccfc4f&v=4
url: https://github.com/linux-china
- login: ddanier
avatarUrl: https://avatars.githubusercontent.com/u/113563?u=ed1dc79de72f93bd78581f88ebc6952b62f472da&v=4
@@ -368,18 +359,6 @@ sponsors:
- login: bryanculbertson
avatarUrl: https://avatars.githubusercontent.com/u/144028?u=defda4f90e93429221cc667500944abde60ebe4a&v=4
url: https://github.com/bryanculbertson
- login: hhatto
avatarUrl: https://avatars.githubusercontent.com/u/150309?u=3e8f63c27bf996bfc68464b0ce3f7a3e40e6ea7f&v=4
url: https://github.com/hhatto
- login: yourkin
avatarUrl: https://avatars.githubusercontent.com/u/178984?u=b43a7e5f8818f7d9083d3b110118d9c27d48a794&v=4
url: https://github.com/yourkin
- login: slafs
avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4
url: https://github.com/slafs
- login: assem-ch
avatarUrl: https://avatars.githubusercontent.com/u/315228?u=e0c5ab30726d3243a40974bb9bae327866e42d9b&v=4
url: https://github.com/assem-ch
- login: adamghill
avatarUrl: https://avatars.githubusercontent.com/u/317045?u=f1349d5ffe84a19f324e204777859fbf69ddf633&v=4
url: https://github.com/adamghill
@@ -389,9 +368,6 @@ sponsors:
- login: dmig
avatarUrl: https://avatars.githubusercontent.com/u/388564?v=4
url: https://github.com/dmig
- login: rinckd
avatarUrl: https://avatars.githubusercontent.com/u/546002?u=8ec88ab721a5636346f19dcd677a6f323058be8b&v=4
url: https://github.com/rinckd
- login: securancy
avatarUrl: https://avatars.githubusercontent.com/u/606673?v=4
url: https://github.com/securancy
@@ -404,39 +380,27 @@ sponsors:
- login: janfilips
avatarUrl: https://avatars.githubusercontent.com/u/870699?u=50de77b93d3a0b06887e672d4e8c7b9d643085aa&v=4
url: https://github.com/janfilips
- login: woodrad
avatarUrl: https://avatars.githubusercontent.com/u/1410765?u=86707076bb03d143b3b11afc1743d2aa496bd8bf&v=4
url: https://github.com/woodrad
- login: Pytlicek
avatarUrl: https://avatars.githubusercontent.com/u/1430522?u=01b1f2f7671ce3131e0877d08e2e3f8bdbb0a38a&v=4
url: https://github.com/Pytlicek
- login: allen0125
avatarUrl: https://avatars.githubusercontent.com/u/1448456?u=dc2ad819497eef494b88688a1796e0adb87e7cae&v=4
url: https://github.com/allen0125
- login: WillHogan
avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=7036c064cf29781470573865264ec8e60b6b809f&v=4
url: https://github.com/WillHogan
- login: my3
avatarUrl: https://avatars.githubusercontent.com/u/1825270?v=4
url: https://github.com/my3
- login: cbonoz
avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4
url: https://github.com/cbonoz
- login: Debakel
avatarUrl: https://avatars.githubusercontent.com/u/2857237?u=07df6d11c8feef9306d071cb1c1005a2dd596585&v=4
url: https://github.com/Debakel
- login: paul121
avatarUrl: https://avatars.githubusercontent.com/u/3116995?u=6e2d8691cc345e63ee02e4eb4d7cef82b1fcbedc&v=4
url: https://github.com/paul121
- login: igorcorrea
avatarUrl: https://avatars.githubusercontent.com/u/3438238?u=c57605077c31a8f7b2341fc4912507f91b4a5621&v=4
url: https://github.com/igorcorrea
- login: larsvik
avatarUrl: https://avatars.githubusercontent.com/u/3442226?v=4
url: https://github.com/larsvik
- login: anthonycorletti
avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4
url: https://github.com/anthonycorletti
- login: jonathanhle
avatarUrl: https://avatars.githubusercontent.com/u/3851599?u=76b9c5d2fecd6c3a16e7645231878c4507380d4d&v=4
url: https://github.com/jonathanhle
- login: pawamoy
avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4
url: https://github.com/pawamoy
- login: nikeee
avatarUrl: https://avatars.githubusercontent.com/u/4068864?u=63f8eee593f25138e0f1032ef442e9ad24907d4c&v=4
url: https://github.com/nikeee
@@ -452,11 +416,14 @@ sponsors:
- login: Baghdady92
avatarUrl: https://avatars.githubusercontent.com/u/5708590?v=4
url: https://github.com/Baghdady92
- login: KentShikama
avatarUrl: https://avatars.githubusercontent.com/u/6329898?u=8b236810db9b96333230430837e1f021f9246da1&v=4
url: https://github.com/KentShikama
- login: holec
avatarUrl: https://avatars.githubusercontent.com/u/6438041?u=f5af71ec85b3a9d7b8139cb5af0512b02fa9ab1e&v=4
url: https://github.com/holec
- login: mattwelke
avatarUrl: https://avatars.githubusercontent.com/u/7719209?u=5d963ead289969257190b133250653bd99df06ba&v=4
avatarUrl: https://avatars.githubusercontent.com/u/7719209?v=4
url: https://github.com/mattwelke
- login: hcristea
avatarUrl: https://avatars.githubusercontent.com/u/7814406?u=61d7a4fcf846983a4606788eac25e1c6c1209ba8&v=4
@@ -464,9 +431,6 @@ sponsors:
- login: moonape1226
avatarUrl: https://avatars.githubusercontent.com/u/8532038?u=d9f8b855a429fff9397c3833c2ff83849ebf989d&v=4
url: https://github.com/moonape1226
- login: yenchenLiu
avatarUrl: https://avatars.githubusercontent.com/u/9199638?u=8cdf5ae507448430d90f6f3518d1665a23afe99b&v=4
url: https://github.com/yenchenLiu
- login: xncbf
avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=866a1311e4bd3ec5ae84185c4fcc99f397c883d7&v=4
url: https://github.com/xncbf
@@ -491,12 +455,9 @@ sponsors:
- login: giuliano-oliveira
avatarUrl: https://avatars.githubusercontent.com/u/13181797?u=0ef2dfbf7fc9a9726d45c21d32b5d1038a174870&v=4
url: https://github.com/giuliano-oliveira
- login: logan-connolly
avatarUrl: https://avatars.githubusercontent.com/u/16244943?u=8ae66dfbba936463cc8aa0dd7a6d2b4c0cc757eb&v=4
url: https://github.com/logan-connolly
- login: stevenayers
avatarUrl: https://avatars.githubusercontent.com/u/16361214?u=098b797d8d48afb8cd964b717847943b61d24a6d&v=4
url: https://github.com/stevenayers
- login: TheR1D
avatarUrl: https://avatars.githubusercontent.com/u/16740832?u=b2923ac17fe6e2a7c9ea14800351ddb92f79b100&v=4
url: https://github.com/TheR1D
- login: cdsre
avatarUrl: https://avatars.githubusercontent.com/u/16945936?v=4
url: https://github.com/cdsre
@@ -506,21 +467,21 @@ sponsors:
- login: paulowiz
avatarUrl: https://avatars.githubusercontent.com/u/18649504?u=d8a6ac40321f2bded0eba78b637751c7f86c6823&v=4
url: https://github.com/paulowiz
- login: yannicschroeer
avatarUrl: https://avatars.githubusercontent.com/u/22749683?u=4df05a7296c207b91c5d7c7a11c29df5ab313e2b&v=4
url: https://github.com/yannicschroeer
- login: ghandic
avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
url: https://github.com/ghandic
- login: fstau
avatarUrl: https://avatars.githubusercontent.com/u/24669867?u=60e7c8c09f8dafabee8fc3edcd6f9e19abbff918&v=4
url: https://github.com/fstau
- login: pers0n4
avatarUrl: https://avatars.githubusercontent.com/u/24864600?u=444441027bc2c9f9db68e8047d65ff23d25699cf&v=4
avatarUrl: https://avatars.githubusercontent.com/u/24864600?u=f211a13a7b572cbbd7779b9c8d8cb428cc7ba07e&v=4
url: https://github.com/pers0n4
- login: SebTota
avatarUrl: https://avatars.githubusercontent.com/u/25122511?v=4
url: https://github.com/SebTota
- login: hoenie-ams
avatarUrl: https://avatars.githubusercontent.com/u/25708487?u=cda07434f0509ac728d9edf5e681117c0f6b818b&v=4
url: https://github.com/hoenie-ams
- login: joerambo
avatarUrl: https://avatars.githubusercontent.com/u/26282974?v=4
url: https://github.com/joerambo
- login: mertguvencli
avatarUrl: https://avatars.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4
url: https://github.com/mertguvencli
@@ -533,6 +494,9 @@ sponsors:
- login: engineerjoe440
avatarUrl: https://avatars.githubusercontent.com/u/33275230?u=eb223cad27017bb1e936ee9b429b450d092d0236&v=4
url: https://github.com/engineerjoe440
- login: bnkc
avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=76cdc0a8b4e88c7d3e58dccb4b2670839e1247b4&v=4
url: https://github.com/bnkc
- login: declon
avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4
url: https://github.com/declon
@@ -546,26 +510,14 @@ sponsors:
avatarUrl: https://avatars.githubusercontent.com/u/38921751?u=ae14bc1e40f2dd5a9c5741fc0b0dffbd416a5fa9&v=4
url: https://github.com/ww-daniel-mora
- login: rwxd
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=9ddf8023ca3326381ba8fb77285ae36598a15de3&v=4
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=cd04a39e3655923be4f25c2ba8a5a07b3da3230a&v=4
url: https://github.com/rwxd
- login: ilias-ant
avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4
url: https://github.com/ilias-ant
- login: arrrrrmin
avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=2a812c1a2ec58227ed01778837f255143de9df97&v=4
avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=5265858add14a6822bd145f7547323cf078563e6&v=4
url: https://github.com/arrrrrmin
- login: MauriceKuenicke
avatarUrl: https://avatars.githubusercontent.com/u/47433175?u=37455bc95c7851db296ac42626f0cacb77ca2443&v=4
url: https://github.com/MauriceKuenicke
- login: hgalytoby
avatarUrl: https://avatars.githubusercontent.com/u/50397689?u=f4888c2c54929bd86eed0d3971d09fcb306e5088&v=4
url: https://github.com/hgalytoby
- login: akanz1
avatarUrl: https://avatars.githubusercontent.com/u/51492342?u=2280f57134118714645e16b535c1a37adf6b369b&v=4
url: https://github.com/akanz1
- login: shidenko97
avatarUrl: https://avatars.githubusercontent.com/u/54946990?u=3fdc0caea36af9217dacf1cc7760c7ed9d67dcfe&v=4
url: https://github.com/shidenko97
- login: data-djinn
avatarUrl: https://avatars.githubusercontent.com/u/56449985?u=42146e140806908d49bd59ccc96f222abf587886&v=4
url: https://github.com/data-djinn
@@ -584,27 +536,12 @@ sponsors:
- login: realabja
avatarUrl: https://avatars.githubusercontent.com/u/66185192?u=001e2dd9297784f4218997981b4e6fa8357bb70b&v=4
url: https://github.com/realabja
- login: alessio-proietti
avatarUrl: https://avatars.githubusercontent.com/u/67370599?u=8ac73db1e18e946a7681f173abdb640516f88515&v=4
url: https://github.com/alessio-proietti
- login: pondDevThai
avatarUrl: https://avatars.githubusercontent.com/u/71592181?u=08af9a59bccfd8f6b101de1005aa9822007d0a44&v=4
url: https://github.com/pondDevThai
- login: marlonmartins2
avatarUrl: https://avatars.githubusercontent.com/u/87719558?u=d07ffecfdabf4fd9aca987f8b5cd9128c65e598e&v=4
url: https://github.com/marlonmartins2
- - login: 2niuhe
avatarUrl: https://avatars.githubusercontent.com/u/13382324?u=ac918d72e0329c87ba29b3bf85e03e98a4ee9427&v=4
url: https://github.com/2niuhe
- login: gabrielmbmb
avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=6d1e00b5d558e96718312ff910a2318f47cc3145&v=4
url: https://github.com/gabrielmbmb
- login: garydsong
avatarUrl: https://avatars.githubusercontent.com/u/105745865?u=03cc1aa9c978be0020e5a1ce1ecca323dd6c8d65&v=4
url: https://github.com/garydsong
- - login: Leon0824
avatarUrl: https://avatars.githubusercontent.com/u/1922026?v=4
url: https://github.com/Leon0824
- login: danburonline
avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4
url: https://github.com/danburonline
- login: Moises6669
avatarUrl: https://avatars.githubusercontent.com/u/66188523?u=96af25b8d5be9f983cb96e9dd7c605c716caf1f5&v=4
url: https://github.com/Moises6669
- login: su-shubham
avatarUrl: https://avatars.githubusercontent.com/u/75021117?v=4
url: https://github.com/su-shubham

View File

@@ -1,154 +1,158 @@
maintainers:
- login: tiangolo
answers: 1315
prs: 342
answers: 1827
prs: 384
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4
url: https://github.com/tiangolo
experts:
- login: Kludex
count: 367
count: 376
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: dmontagu
count: 262
count: 237
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
url: https://github.com/dmontagu
- login: ycd
count: 221
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=fa40e037060d62bf82e16b505d870a2866725f38&v=4
url: https://github.com/ycd
- login: Mause
count: 207
count: 220
avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4
url: https://github.com/Mause
- login: ycd
count: 217
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
url: https://github.com/ycd
- login: JarroVGIT
count: 187
count: 192
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
url: https://github.com/JarroVGIT
- login: euri10
count: 166
count: 151
avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
url: https://github.com/euri10
- login: phy25
count: 130
count: 126
avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4
url: https://github.com/phy25
- login: raphaelauv
count: 77
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
url: https://github.com/raphaelauv
- login: iudeen
count: 76
count: 116
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: jgould22
count: 101
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
url: https://github.com/jgould22
- login: raphaelauv
count: 83
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
url: https://github.com/raphaelauv
- login: ArcLightSlavik
count: 71
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=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: 58
count: 57
avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4
url: https://github.com/falkben
- login: sm-Fifteen
count: 50
count: 49
avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4
url: https://github.com/sm-Fifteen
- login: insomnes
count: 46
avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4
url: https://github.com/insomnes
- login: jgould22
count: 46
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
url: https://github.com/jgould22
- login: Dustyposa
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4
url: https://github.com/Dustyposa
- login: insomnes
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4
url: https://github.com/insomnes
- login: frankie567
count: 43
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
url: https://github.com/frankie567
- login: acidjunk
count: 43
avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
url: https://github.com/acidjunk
- login: odiseo0
count: 42
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
url: https://github.com/odiseo0
- login: adriangb
count: 40
avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=75087f0cf0e9f725f3cd18a899218b6c63ae60d3&v=4
avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=1e2c2c9b39f5c9b780fb933d8995cf08ec235a47&v=4
url: https://github.com/adriangb
- login: includeamin
count: 39
count: 40
avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4
url: https://github.com/includeamin
- login: STeveShary
count: 37
avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4
url: https://github.com/STeveShary
- login: chbndrhnns
count: 35
avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4
url: https://github.com/chbndrhnns
- login: prostomarkeloff
count: 33
avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4
url: https://github.com/prostomarkeloff
- login: frankie567
count: 31
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
url: https://github.com/frankie567
- login: acidjunk
count: 31
avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
url: https://github.com/acidjunk
- login: krishnardt
count: 31
count: 35
avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4
url: https://github.com/krishnardt
- login: wshayes
count: 29
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
url: https://github.com/wshayes
- login: yinziyan1206
count: 34
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
url: https://github.com/yinziyan1206
- login: chbndrhnns
count: 34
avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4
url: https://github.com/chbndrhnns
- login: panla
count: 29
count: 32
avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4
url: https://github.com/panla
- login: ghandic
count: 25
avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
url: https://github.com/ghandic
- login: prostomarkeloff
count: 28
avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4
url: https://github.com/prostomarkeloff
- login: dbanty
count: 25
count: 26
avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4
url: https://github.com/dbanty
- login: wshayes
count: 25
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
url: https://github.com/wshayes
- login: SirTelemak
count: 24
count: 23
avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4
url: https://github.com/SirTelemak
- login: odiseo0
count: 23
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
url: https://github.com/odiseo0
- login: acnebs
count: 22
avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=c27e50269f1ef8ea950cc6f0268c8ec5cebbe9c9&v=4
url: https://github.com/acnebs
- login: caeser1996
count: 21
avatarUrl: https://avatars.githubusercontent.com/u/16540232?u=05d2beb8e034d584d0a374b99d8826327bd7f614&v=4
url: https://github.com/caeser1996
- login: rafsaf
count: 21
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
url: https://github.com/rafsaf
- login: nsidnev
count: 22
count: 20
avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4
url: https://github.com/nsidnev
- login: acnebs
count: 20
avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=c27e50269f1ef8ea950cc6f0268c8ec5cebbe9c9&v=4
url: https://github.com/acnebs
- login: chris-allnutt
count: 21
count: 20
avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4
url: https://github.com/chris-allnutt
- login: retnikt
count: 19
count: 18
avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4
url: https://github.com/retnikt
- login: Hultner
- login: zoliknemet
count: 18
avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4
url: https://github.com/Hultner
- login: rafsaf
count: 18
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
url: https://github.com/rafsaf
- login: jorgerpo
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4
url: https://github.com/jorgerpo
avatarUrl: https://avatars.githubusercontent.com/u/22326718?u=31ba446ac290e23e56eea8e4f0c558aaf0b40779&v=4
url: https://github.com/zoliknemet
- login: nkhitrov
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/28262306?u=66ee21316275ef356081c2efc4ed7a4572e690dc&v=4
@@ -157,63 +161,79 @@ experts:
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4
url: https://github.com/harunyasar
- login: waynerv
- login: Hultner
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4
url: https://github.com/Hultner
- login: jonatasoli
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
url: https://github.com/waynerv
- login: yinziyan1206
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4
url: https://github.com/yinziyan1206
avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4
url: https://github.com/jonatasoli
- login: dstlny
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4
url: https://github.com/dstlny
- login: jonatasoli
- login: jorgerpo
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4
url: https://github.com/jonatasoli
avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4
url: https://github.com/jorgerpo
- login: ghost
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/10137?u=b1951d34a583cf12ec0d3b0781ba19be97726318&v=4
url: https://github.com/ghost
- login: simondale00
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/33907262?v=4
url: https://github.com/simondale00
- login: hellocoldworld
count: 14
avatarUrl: https://avatars.githubusercontent.com/u/47581948?u=3d2186796434c507a6cb6de35189ab0ad27c356f&v=4
url: https://github.com/hellocoldworld
- login: haizaar
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/58201?u=dd40d99a3e1935d0b768f122bfe2258d6ea53b2b&v=4
url: https://github.com/haizaar
- login: valentin994
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/42819267?u=fdeeaa9242a59b243f8603496b00994f6951d5a2&v=4
url: https://github.com/valentin994
- login: David-Lor
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/17401854?u=474680c02b94cba810cb9032fb7eb787d9cc9d22&v=4
url: https://github.com/David-Lor
- login: n8sty
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4
url: https://github.com/n8sty
- login: waynerv
count: 14
avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
url: https://github.com/waynerv
- login: mbroton
count: 12
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/50829834?u=a48610bf1bffaa9c75d03228926e2eb08a2e24ee&v=4
url: https://github.com/mbroton
last_month_active:
- login: JarroVGIT
count: 18
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
url: https://github.com/JarroVGIT
- login: iudeen
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: mbroton
- login: mr-st0rm
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/48455163?u=6b83550e4e70bea57cd2fdb41e717aeab7f64a91&v=4
url: https://github.com/mr-st0rm
- login: caeser1996
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/16540232?u=05d2beb8e034d584d0a374b99d8826327bd7f614&v=4
url: https://github.com/caeser1996
- login: ebottos94
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/100039558?u=e2c672da5a7977fd24d87ce6ab35f8bf5b1ed9fa&v=4
url: https://github.com/ebottos94
- login: jgould22
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
url: https://github.com/jgould22
- login: Kludex
count: 5
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: clemens-tolboom
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/50829834?u=a48610bf1bffaa9c75d03228926e2eb08a2e24ee&v=4
url: https://github.com/mbroton
- login: yinziyan1206
avatarUrl: https://avatars.githubusercontent.com/u/371014?v=4
url: https://github.com/clemens-tolboom
- login: williamjamir
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/5083518?u=b76ca8e08b906a86fa195fb817dd94e8d9d3d8f6&v=4
url: https://github.com/williamjamir
- login: nymous
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4
url: https://github.com/yinziyan1206
avatarUrl: https://avatars.githubusercontent.com/u/4216559?u=360a36fb602cded27273cbfc0afc296eece90662&v=4
url: https://github.com/nymous
- login: frankie567
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
url: https://github.com/frankie567
top_contributors:
- login: waynerv
count: 25
@@ -223,22 +243,18 @@ top_contributors:
count: 22
avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
url: https://github.com/tokusumi
- login: Kludex
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: jaystone776
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4
url: https://github.com/jaystone776
- login: dmontagu
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
url: https://github.com/dmontagu
- login: jaystone776
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4
url: https://github.com/jaystone776
- login: Kludex
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: dependabot
count: 14
avatarUrl: https://avatars.githubusercontent.com/in/29110?v=4
url: https://github.com/apps/dependabot
- login: euri10
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
@@ -257,7 +273,7 @@ top_contributors:
url: https://github.com/Serrones
- login: RunningIkkyu
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=efb5b45b55584450507834f279ce48d4d64dea2f&v=4
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=494ecc298e3f26197495bb357ad0f57cfd5f7a32&v=4
url: https://github.com/RunningIkkyu
- login: hard-coders
count: 7
@@ -267,10 +283,10 @@ top_contributors:
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
url: https://github.com/rjNemo
- login: pre-commit-ci
- login: batlopes
count: 6
avatarUrl: https://avatars.githubusercontent.com/in/68672?v=4
url: https://github.com/apps/pre-commit-ci
avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4
url: https://github.com/batlopes
- login: wshayes
count: 5
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
@@ -287,6 +303,14 @@ 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: Xewus
count: 5
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4
url: https://github.com/Xewus
- login: jekirl
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4
@@ -301,7 +325,7 @@ top_contributors:
url: https://github.com/jfunez
- login: ycd
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=fa40e037060d62bf82e16b505d870a2866725f38&v=4
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
url: https://github.com/ycd
- login: komtaki
count: 4
@@ -315,29 +339,21 @@ top_contributors:
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
url: https://github.com/lsglucas
- login: NinaHwang
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4
url: https://github.com/NinaHwang
- login: batlopes
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4
url: https://github.com/batlopes
top_reviewers:
- login: Kludex
count: 108
count: 111
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
url: https://github.com/Kludex
- login: BilalAlpaslan
count: 65
count: 75
avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4
url: https://github.com/BilalAlpaslan
- login: yezz123
count: 56
count: 71
avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4
url: https://github.com/yezz123
- login: tokusumi
count: 50
count: 51
avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
url: https://github.com/tokusumi
- login: waynerv
@@ -350,8 +366,12 @@ top_reviewers:
url: https://github.com/Laineyzhang55
- login: ycd
count: 45
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=fa40e037060d62bf82e16b505d870a2866725f38&v=4
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
url: https://github.com/ycd
- login: iudeen
count: 44
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: cikay
count: 41
avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4
@@ -368,26 +388,30 @@ top_reviewers:
count: 31
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4
url: https://github.com/ArcLightSlavik
- login: iudeen
count: 26
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
url: https://github.com/iudeen
- login: cassiobotaro
count: 25
count: 28
avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4
url: https://github.com/cassiobotaro
- login: komtaki
count: 27
avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4
url: https://github.com/komtaki
- login: lsglucas
count: 25
count: 26
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
url: https://github.com/lsglucas
- login: dmontagu
count: 23
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
url: https://github.com/dmontagu
- login: komtaki
count: 21
avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4
url: https://github.com/komtaki
- login: LorhanSohaky
count: 22
avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4
url: https://github.com/LorhanSohaky
- login: rjNemo
count: 20
avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
url: https://github.com/rjNemo
- login: hard-coders
count: 20
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4
@@ -396,10 +420,10 @@ top_reviewers:
count: 19
avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4
url: https://github.com/0417taehyun
- login: rjNemo
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
url: https://github.com/rjNemo
- login: odiseo0
count: 19
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
url: https://github.com/odiseo0
- login: Smlep
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4
@@ -428,22 +452,26 @@ top_reviewers:
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4
url: https://github.com/delhi09
- login: odiseo0
- login: Ryandaydev
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=809f3d1074d04bbc28012a7f17f06ea56f5bd71a&v=4
url: https://github.com/Ryandaydev
- login: Xewus
count: 14
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
url: https://github.com/odiseo0
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4
url: https://github.com/Xewus
- login: sh0nk
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4
url: https://github.com/sh0nk
- login: peidrao
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=5401640e0b961cc199dee39ec79e162c7833cd6b&v=4
url: https://github.com/peidrao
- login: RunningIkkyu
count: 12
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=efb5b45b55584450507834f279ce48d4d64dea2f&v=4
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=494ecc298e3f26197495bb357ad0f57cfd5f7a32&v=4
url: https://github.com/RunningIkkyu
- login: LorhanSohaky
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4
url: https://github.com/LorhanSohaky
- login: solomein-sv
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4
@@ -464,6 +492,14 @@ top_reviewers:
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=f440bc9062afb3c43b9b9c6cdfdcfe31d58699ef&v=4
url: https://github.com/ComicShrimp
- login: r0b2g1t
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/5357541?u=6428442d875d5d71aaa1bb38bb11c4be1a526bc2&v=4
url: https://github.com/r0b2g1t
- login: izaguerreiro
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4
url: https://github.com/izaguerreiro
- login: graingert
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/413772?u=64b77b6aa405c68a9c6bcf45f84257c66eea5f32&v=4
@@ -480,14 +516,18 @@ top_reviewers:
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4
url: https://github.com/bezaca
- login: izaguerreiro
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4
url: https://github.com/izaguerreiro
- login: dimaqq
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/662249?v=4
url: https://github.com/dimaqq
- login: raphaelauv
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
url: https://github.com/raphaelauv
- login: axel584
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/1334088?v=4
url: https://github.com/axel584
- login: blt232018
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/43393471?u=172b0e0391db1aa6c1706498d6dfcb003c8a4857&v=4
@@ -496,27 +536,3 @@ top_reviewers:
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/5690226?v=4
url: https://github.com/rogerbrinkmann
- login: NinaHwang
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4
url: https://github.com/NinaHwang
- login: dimaqq
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/662249?v=4
url: https://github.com/dimaqq
- login: Serrones
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4
url: https://github.com/Serrones
- login: jovicon
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4
url: https://github.com/jovicon
- login: ryuckel
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/36391432?u=094eec0cfddd5013f76f31e55e56147d78b19553&v=4
url: https://github.com/ryuckel
- login: NastasiaSaby
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/8245071?u=b3afd005f9e4bf080c219ef61a592b3a8004b764&v=4
url: https://github.com/NastasiaSaby

View File

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

View File

@@ -13,3 +13,6 @@ logins:
- BLUE-DEVIL1134
- ObliviousAI
- Doist
- nihpo
- svix
- armand-sauzay

View File

@@ -14,9 +14,41 @@ But you also want it to accept new items. And when the items didn't exist before
To achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want:
```Python hl_lines="4 25"
{!../../../docs_src/additional_status_codes/tutorial001.py!}
```
=== "Python 3.10+"
```Python hl_lines="4 25"
{!> ../../../docs_src/additional_status_codes/tutorial001_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="4 25"
{!> ../../../docs_src/additional_status_codes/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="4 26"
{!> ../../../docs_src/additional_status_codes/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="2 23"
{!> ../../../docs_src/additional_status_codes/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="4 25"
{!> ../../../docs_src/additional_status_codes/tutorial001.py!}
```
!!! warning
When you return a `Response` directly, like in the example above, it will be returned directly.

View File

@@ -18,9 +18,26 @@ Not the class itself (which is already a callable), but an instance of that clas
To do that, we declare a method `__call__`:
```Python hl_lines="10"
{!../../../docs_src/dependencies/tutorial011.py!}
```
=== "Python 3.9+"
```Python hl_lines="12"
{!> ../../../docs_src/dependencies/tutorial011_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="11"
{!> ../../../docs_src/dependencies/tutorial011_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="10"
{!> ../../../docs_src/dependencies/tutorial011.py!}
```
In this case, this `__call__` is what **FastAPI** will use to check for additional parameters and sub-dependencies, and this is what will be called to pass a value to the parameter in your *path operation function* later.
@@ -28,9 +45,26 @@ In this case, this `__call__` is what **FastAPI** will use to check for addition
And now, we can use `__init__` to declare the parameters of the instance that we can use to "parameterize" the dependency:
```Python hl_lines="7"
{!../../../docs_src/dependencies/tutorial011.py!}
```
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/dependencies/tutorial011_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="8"
{!> ../../../docs_src/dependencies/tutorial011_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/dependencies/tutorial011.py!}
```
In this case, **FastAPI** won't ever touch or care about `__init__`, we will use it directly in our code.
@@ -38,9 +72,26 @@ In this case, **FastAPI** won't ever touch or care about `__init__`, we will use
We could create an instance of this class with:
```Python hl_lines="16"
{!../../../docs_src/dependencies/tutorial011.py!}
```
=== "Python 3.9+"
```Python hl_lines="18"
{!> ../../../docs_src/dependencies/tutorial011_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="17"
{!> ../../../docs_src/dependencies/tutorial011_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="16"
{!> ../../../docs_src/dependencies/tutorial011.py!}
```
And that way we are able to "parameterize" our dependency, that now has `"bar"` inside of it, as the attribute `checker.fixed_content`.
@@ -56,9 +107,26 @@ checker(q="somequery")
...and pass whatever that returns as the value of the dependency in our *path operation function* as the parameter `fixed_content_included`:
```Python hl_lines="20"
{!../../../docs_src/dependencies/tutorial011.py!}
```
=== "Python 3.9+"
```Python hl_lines="22"
{!> ../../../docs_src/dependencies/tutorial011_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="21"
{!> ../../../docs_src/dependencies/tutorial011_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="20"
{!> ../../../docs_src/dependencies/tutorial011.py!}
```
!!! tip
All this might seem contrived. And it might not be very clear how is it useful yet.

View File

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

View File

@@ -1,13 +1,108 @@
# Events: startup - shutdown
# Lifespan Events
You can define logic (code) that should be executed before the application **starts up**. This means that this code will be executed **once**, **before** the application **starts receiving requests**.
The same way, you can define logic (code) that should be executed when the application is **shutting down**. In this case, this code will be executed **once**, **after** having handled possibly **many requests**.
Because this code is executed before the application **starts** taking requests, and right after it **finishes** handling requests, it covers the whole application **lifespan** (the word "lifespan" will be important in a second 😉).
This can be very useful for setting up **resources** that you need to use for the whole app, and that are **shared** among requests, and/or that you need to **clean up** afterwards. For example, a database connection pool, or loading a shared machine learning model.
## Use Case
Let's start with an example **use case** and then see how to solve it with this.
Let's imagine that you have some **machine learning models** that you want to use to handle requests. 🤖
The same models are shared among requests, so, it's not one model per request, or one per user or something similar.
Let's imagine that loading the model can **take quite some time**, because it has to read a lot of **data from disk**. So you don't want to do it for every request.
You could load it at the top level of the module/file, but that would also mean that it would **load the model** even if you are just running a simple automated test, then that test would be **slow** because it would have to wait for the model to load before being able to run an independent part of the code.
That's what we'll solve, let's load the model before the requests are handled, but only right before the application starts receiving requests, not while the code is being loaded.
## Lifespan
You can define this *startup* and *shutdown* logic using the `lifespan` parameter of the `FastAPI` app, and a "context manager" (I'll show you what that is in a second).
Let's start with an example and then see it in detail.
We create an async function `lifespan()` with `yield` like this:
```Python hl_lines="16 19"
{!../../../docs_src/events/tutorial003.py!}
```
Here we are simulating the expensive *startup* operation of loading the model by putting the (fake) model function in the dictionary with machine learning models before the `yield`. This code will be executed **before** the application **starts taking requests**, during the *startup*.
And then, right after the `yield`, we unload the model. This code will be executed **after** the application **finishes handling requests**, right before the *shutdown*. This could, for example, release resources like memory or a GPU.
!!! tip
The `shutdown` would happen when you are **stopping** the application.
Maybe you need to start a new version, or you just got tired of running it. 🤷
### Lifespan function
The first thing to notice, is that we are defining an async function with `yield`. This is very similar to Dependencies with `yield`.
```Python hl_lines="14-19"
{!../../../docs_src/events/tutorial003.py!}
```
The first part of the function, before the `yield`, will be executed **before** the application starts.
And the part after the `yield` will be executed **after** the application has finished.
### Async Context Manager
If you check, the function is decorated with an `@asynccontextmanager`.
That converts the function into something called an "**async context manager**".
```Python hl_lines="1 13"
{!../../../docs_src/events/tutorial003.py!}
```
A **context manager** in Python is something that you can use in a `with` statement, for example, `open()` can be used as a context manager:
```Python
with open("file.txt") as file:
file.read()
```
In recent versions of Python, there's also an **async context manager**. You would use it with `async with`:
```Python
async with lifespan(app):
await do_stuff()
```
When you create a context manager or an async context manager like above, what it does is that, before entering the `with` block, it will execute the code before the `yield`, and after exiting the `with` block, it will execute the code after the `yield`.
In our code example above, we don't use it directly, but we pass it to FastAPI for it to use it.
The `lifespan` parameter of the `FastAPI` app takes an **async context manager**, so we can pass our new `lifespan` async context manager to it.
```Python hl_lines="22"
{!../../../docs_src/events/tutorial003.py!}
```
## Alternative Events (deprecated)
!!! warning
The recommended way to handle the *startup* and *shutdown* is using the `lifespan` parameter of the `FastAPI` app as described above.
You can probably skip this part.
There's an alternative way to define this logic to be executed during *startup* and during *shutdown*.
You can define event handlers (functions) that need to be executed before the application starts up, or when the application is shutting down.
These functions can be declared with `async def` or normal `def`.
!!! warning
Only event handlers for the main application will be executed, not for [Sub Applications - Mounts](./sub-applications.md){.internal-link target=_blank}.
## `startup` event
### `startup` event
To add a function that should be run before the application starts, declare it with the event `"startup"`:
@@ -21,7 +116,7 @@ You can add more than one event handler function.
And your application won't start receiving requests until all the `startup` event handlers have completed.
## `shutdown` event
### `shutdown` event
To add a function that should be run when the application is shutting down, declare it with the event `"shutdown"`:
@@ -43,5 +138,25 @@ Here, the `shutdown` event handler function will write a text line `"Application
So, we declare the event handler function with standard `def` instead of `async def`.
### `startup` and `shutdown` together
There's a high chance that the logic for your *startup* and *shutdown* is connected, you might want to start something and then finish it, acquire a resource and then release it, etc.
Doing that in separated functions that don't share logic or variables together is more difficult as you would need to store values in global variables or similar tricks.
Because of that, it's now recommended to instead use the `lifespan` as explained above.
## Technical Details
Just a technical detail for the curious nerds. 🤓
Underneath, in the ASGI technical specification, this is part of the <a href="https://asgi.readthedocs.io/en/latest/specs/lifespan.html" class="external-link" target="_blank">Lifespan Protocol</a>, and it defines events called `startup` and `shutdown`.
!!! info
You can read more about these event handlers in <a href="https://www.starlette.io/events/" class="external-link" target="_blank">Starlette's Events' docs</a>.
You can read more about the Starlette `lifespan` handlers in <a href="https://www.starlette.io/lifespan/" class="external-link" target="_blank">Starlette's Lifespan' docs</a>.
Including how to handle lifespan state that can be used in other areas of your code.
## Sub Applications
🚨 Have in mind that these lifespan events (startup and shutdown) will only be executed for the main application, not for [Sub Applications - Mounts](./sub-applications.md){.internal-link target=_blank}.

View File

@@ -16,18 +16,18 @@ If you are building a **frontend**, a very interesting alternative is <a href="h
Let's start with a simple FastAPI application:
=== "Python 3.6 and above"
```Python hl_lines="9-11 14-15 18 19 23"
{!> ../../../docs_src/generate_clients/tutorial001.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="7-9 12-13 16-17 21"
{!> ../../../docs_src/generate_clients/tutorial001_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9-11 14-15 18 19 23"
{!> ../../../docs_src/generate_clients/tutorial001.py!}
```
Notice that the *path operations* define the models they use for request payload and response payload, using the models `Item` and `ResponseMessage`.
### API Docs
@@ -128,19 +128,18 @@ In many cases your FastAPI app will be bigger, and you will probably use tags to
For example, you could have a section for **items** and another section for **users**, and they could be separated by tags:
=== "Python 3.6 and above"
```Python hl_lines="23 28 36"
{!> ../../../docs_src/generate_clients/tutorial002.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="21 26 34"
{!> ../../../docs_src/generate_clients/tutorial002_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="23 28 36"
{!> ../../../docs_src/generate_clients/tutorial002.py!}
```
### Generate a TypeScript Client with Tags
If you generate a client for a FastAPI app using tags, it will normally also separate the client code based on the tags.
@@ -186,18 +185,18 @@ For example, here it is using the first tag (you will probably have only one tag
You can then pass that custom function to **FastAPI** as the `generate_unique_id_function` parameter:
=== "Python 3.6 and above"
```Python hl_lines="8-9 12"
{!> ../../../docs_src/generate_clients/tutorial003.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="6-7 10"
{!> ../../../docs_src/generate_clients/tutorial003_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="8-9 12"
{!> ../../../docs_src/generate_clients/tutorial003.py!}
```
### Generate a TypeScript Client with Custom Operation IDs
Now if you generate the client again, you will see that it has the improved method names:

View File

@@ -68,7 +68,7 @@ Enforces that all incoming requests have a correctly set `Host` header, in order
The following arguments are supported:
* `allowed_hosts` - A list of domain names that should be allowed as hostnames. Wildcard domains such as `*.example.com` are supported for matching subdomains to allow any hostname either use `allowed_hosts=["*"]` or omit the middleware.
* `allowed_hosts` - A list of domain names that should be allowed as hostnames. Wildcard domains such as `*.example.com` are supported for matching subdomains. To allow any hostname either use `allowed_hosts=["*"]` or omit the middleware.
If an incoming request does not validate correctly then a `400` response will be sent.
@@ -92,7 +92,7 @@ There are many other ASGI middlewares.
For example:
* <a href="https://docs.sentry.io/platforms/python/asgi/" class="external-link" target="_blank">Sentry</a>
* <a href="https://docs.sentry.io/platforms/python/guides/fastapi/" class="external-link" target="_blank">Sentry</a>
* <a href="https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py" class="external-link" target="_blank">Uvicorn's `ProxyHeadersMiddleware`</a>
* <a href="https://github.com/florimondmanca/msgpack-asgi" class="external-link" target="_blank">MessagePack</a>

View File

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

View File

@@ -20,9 +20,26 @@ Then, when you type that username and password, the browser sends them in the he
* It returns an object of type `HTTPBasicCredentials`:
* It contains the `username` and `password` sent.
```Python hl_lines="2 6 10"
{!../../../docs_src/security/tutorial006.py!}
```
=== "Python 3.9+"
```Python hl_lines="4 8 12"
{!> ../../../docs_src/security/tutorial006_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="2 7 11"
{!> ../../../docs_src/security/tutorial006_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="2 6 10"
{!> ../../../docs_src/security/tutorial006.py!}
```
When you try to open the URL for the first time (or click the "Execute" button in the docs) the browser will ask you for your username and password:
@@ -42,9 +59,26 @@ To handle that, we first convert the `username` and `password` to `bytes` encodi
Then we can use `secrets.compare_digest()` to ensure that `credentials.username` is `"stanleyjobson"`, and that `credentials.password` is `"swordfish"`.
```Python hl_lines="1 11-21"
{!../../../docs_src/security/tutorial007.py!}
```
=== "Python 3.9+"
```Python hl_lines="1 12-24"
{!> ../../../docs_src/security/tutorial007_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 12-24"
{!> ../../../docs_src/security/tutorial007_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="1 11-21"
{!> ../../../docs_src/security/tutorial007.py!}
```
This would be similar to:
@@ -108,6 +142,23 @@ That way, using `secrets.compare_digest()` in your application code, it will be
After detecting that the credentials are incorrect, return an `HTTPException` with a status code 401 (the same returned when no credentials are provided) and add the header `WWW-Authenticate` to make the browser show the login prompt again:
```Python hl_lines="23-27"
{!../../../docs_src/security/tutorial007.py!}
```
=== "Python 3.9+"
```Python hl_lines="26-30"
{!> ../../../docs_src/security/tutorial007_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="26-30"
{!> ../../../docs_src/security/tutorial007_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="23-27"
{!> ../../../docs_src/security/tutorial007.py!}
```

View File

@@ -56,9 +56,50 @@ They are normally used to declare specific security permissions, for example:
First, let's quickly see the parts that change from the examples in the main **Tutorial - User Guide** for [OAuth2 with Password (and hashing), Bearer with JWT tokens](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. Now using OAuth2 scopes:
```Python hl_lines="2 4 8 12 46 64 105 107-115 121-124 128-134 139 153"
{!../../../docs_src/security/tutorial005.py!}
```
=== "Python 3.10+"
```Python hl_lines="4 8 12 46 64 105 107-115 121-124 128-134 139 155"
{!> ../../../docs_src/security/tutorial005_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="2 4 8 12 46 64 105 107-115 121-124 128-134 139 155"
{!> ../../../docs_src/security/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="2 4 8 12 47 65 106 108-116 122-125 129-135 140 156"
{!> ../../../docs_src/security/tutorial005_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="3 7 11 45 63 104 106-114 120-123 127-133 138 152"
{!> ../../../docs_src/security/tutorial005_py310.py!}
```
=== "Python 3.9+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="2 4 8 12 46 64 105 107-115 121-124 128-134 139 153"
{!> ../../../docs_src/security/tutorial005_py39.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="2 4 8 12 46 64 105 107-115 121-124 128-134 139 153"
{!> ../../../docs_src/security/tutorial005.py!}
```
Now let's review those changes step by step.
@@ -68,9 +109,51 @@ The first change is that now we are declaring the OAuth2 security scheme with tw
The `scopes` parameter receives a `dict` with each scope as a key and the description as the value:
```Python hl_lines="62-65"
{!../../../docs_src/security/tutorial005.py!}
```
=== "Python 3.10+"
```Python hl_lines="62-65"
{!> ../../../docs_src/security/tutorial005_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="62-65"
{!> ../../../docs_src/security/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="63-66"
{!> ../../../docs_src/security/tutorial005_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="61-64"
{!> ../../../docs_src/security/tutorial005_py310.py!}
```
=== "Python 3.9+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="62-65"
{!> ../../../docs_src/security/tutorial005_py39.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="62-65"
{!> ../../../docs_src/security/tutorial005.py!}
```
Because we are now declaring those scopes, they will show up in the API docs when you log-in/authorize.
@@ -93,9 +176,50 @@ And we return the scopes as part of the JWT token.
But in your application, for security, you should make sure you only add the scopes that the user is actually able to have, or the ones you have predefined.
```Python hl_lines="153"
{!../../../docs_src/security/tutorial005.py!}
```
=== "Python 3.10+"
```Python hl_lines="155"
{!> ../../../docs_src/security/tutorial005_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="155"
{!> ../../../docs_src/security/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="156"
{!> ../../../docs_src/security/tutorial005_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="152"
{!> ../../../docs_src/security/tutorial005_py310.py!}
```
=== "Python 3.9+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="153"
{!> ../../../docs_src/security/tutorial005_py39.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="153"
{!> ../../../docs_src/security/tutorial005.py!}
```
## Declare scopes in *path operations* and dependencies
@@ -118,9 +242,50 @@ In this case, it requires the scope `me` (it could require more than one scope).
We are doing it here to demonstrate how **FastAPI** handles scopes declared at different levels.
```Python hl_lines="4 139 166"
{!../../../docs_src/security/tutorial005.py!}
```
=== "Python 3.10+"
```Python hl_lines="4 139 170"
{!> ../../../docs_src/security/tutorial005_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="4 139 170"
{!> ../../../docs_src/security/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="4 140 171"
{!> ../../../docs_src/security/tutorial005_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="3 138 165"
{!> ../../../docs_src/security/tutorial005_py310.py!}
```
=== "Python 3.9+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="4 139 166"
{!> ../../../docs_src/security/tutorial005_py39.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="4 139 166"
{!> ../../../docs_src/security/tutorial005.py!}
```
!!! info "Technical Details"
`Security` is actually a subclass of `Depends`, and it has just one extra parameter that we'll see later.
@@ -143,9 +308,50 @@ We also declare a special parameter of type `SecurityScopes`, imported from `fas
This `SecurityScopes` class is similar to `Request` (`Request` was used to get the request object directly).
```Python hl_lines="8 105"
{!../../../docs_src/security/tutorial005.py!}
```
=== "Python 3.10+"
```Python hl_lines="8 105"
{!> ../../../docs_src/security/tutorial005_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="8 105"
{!> ../../../docs_src/security/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="8 106"
{!> ../../../docs_src/security/tutorial005_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7 104"
{!> ../../../docs_src/security/tutorial005_py310.py!}
```
=== "Python 3.9+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="8 105"
{!> ../../../docs_src/security/tutorial005_py39.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="8 105"
{!> ../../../docs_src/security/tutorial005.py!}
```
## Use the `scopes`
@@ -159,9 +365,50 @@ We create an `HTTPException` that we can re-use (`raise`) later at several point
In this exception, we include the scopes required (if any) as a string separated by spaces (using `scope_str`). We put that string containing the scopes in the `WWW-Authenticate` header (this is part of the spec).
```Python hl_lines="105 107-115"
{!../../../docs_src/security/tutorial005.py!}
```
=== "Python 3.10+"
```Python hl_lines="105 107-115"
{!> ../../../docs_src/security/tutorial005_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="105 107-115"
{!> ../../../docs_src/security/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="106 108-116"
{!> ../../../docs_src/security/tutorial005_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="104 106-114"
{!> ../../../docs_src/security/tutorial005_py310.py!}
```
=== "Python 3.9+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="105 107-115"
{!> ../../../docs_src/security/tutorial005_py39.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="105 107-115"
{!> ../../../docs_src/security/tutorial005.py!}
```
## Verify the `username` and data shape
@@ -177,9 +424,50 @@ Instead of, for example, a `dict`, or something else, as it could break the appl
We also verify that we have a user with that username, and if not, we raise that same exception we created before.
```Python hl_lines="46 116-127"
{!../../../docs_src/security/tutorial005.py!}
```
=== "Python 3.10+"
```Python hl_lines="46 116-127"
{!> ../../../docs_src/security/tutorial005_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="46 116-127"
{!> ../../../docs_src/security/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="47 117-128"
{!> ../../../docs_src/security/tutorial005_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="45 115-126"
{!> ../../../docs_src/security/tutorial005_py310.py!}
```
=== "Python 3.9+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="46 116-127"
{!> ../../../docs_src/security/tutorial005_py39.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="46 116-127"
{!> ../../../docs_src/security/tutorial005.py!}
```
## Verify the `scopes`
@@ -187,9 +475,50 @@ We now verify that all the scopes required, by this dependency and all the depen
For this, we use `security_scopes.scopes`, that contains a `list` with all these scopes as `str`.
```Python hl_lines="128-134"
{!../../../docs_src/security/tutorial005.py!}
```
=== "Python 3.10+"
```Python hl_lines="128-134"
{!> ../../../docs_src/security/tutorial005_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="128-134"
{!> ../../../docs_src/security/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="129-135"
{!> ../../../docs_src/security/tutorial005_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="127-133"
{!> ../../../docs_src/security/tutorial005_py310.py!}
```
=== "Python 3.9+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="128-134"
{!> ../../../docs_src/security/tutorial005_py39.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="128-134"
{!> ../../../docs_src/security/tutorial005.py!}
```
## Dependency tree and scopes

View File

@@ -216,9 +216,26 @@ Notice that now we don't create a default instance `settings = Settings()`.
Now we create a dependency that returns a new `config.Settings()`.
```Python hl_lines="5 11-12"
{!../../../docs_src/settings/app02/main.py!}
```
=== "Python 3.9+"
```Python hl_lines="6 12-13"
{!> ../../../docs_src/settings/app02_an_py39/main.py!}
```
=== "Python 3.6+"
```Python hl_lines="6 12-13"
{!> ../../../docs_src/settings/app02_an/main.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="5 11-12"
{!> ../../../docs_src/settings/app02/main.py!}
```
!!! tip
We'll discuss the `@lru_cache()` in a bit.
@@ -227,9 +244,26 @@ Now we create a dependency that returns a new `config.Settings()`.
And then we can require it from the *path operation function* as a dependency and use it anywhere we need it.
```Python hl_lines="16 18-20"
{!../../../docs_src/settings/app02/main.py!}
```
=== "Python 3.9+"
```Python hl_lines="17 19-21"
{!> ../../../docs_src/settings/app02_an_py39/main.py!}
```
=== "Python 3.6+"
```Python hl_lines="17 19-21"
{!> ../../../docs_src/settings/app02_an/main.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="16 18-20"
{!> ../../../docs_src/settings/app02/main.py!}
```
### Settings and testing
@@ -304,9 +338,26 @@ we would create that object for each request, and we would be reading the `.env`
But as we are using the `@lru_cache()` decorator on top, the `Settings` object will be created only once, the first time it's called. ✔️
```Python hl_lines="1 10"
{!../../../docs_src/settings/app03/main.py!}
```
=== "Python 3.9+"
```Python hl_lines="1 11"
{!> ../../../docs_src/settings/app03_an_py39/main.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 11"
{!> ../../../docs_src/settings/app03_an/main.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="1 10"
{!> ../../../docs_src/settings/app03/main.py!}
```
Then for any subsequent calls of `get_settings()` in the dependencies for the next requests, instead of executing the internal code of `get_settings()` and creating a new `Settings` object, it will return the same object that was returned on the first call, again and again.

View File

@@ -28,9 +28,41 @@ To override a dependency for testing, you put as a key the original dependency (
And then **FastAPI** will call that override instead of the original dependency.
```Python hl_lines="28-29 32"
{!../../../docs_src/dependency_testing/tutorial001.py!}
```
=== "Python 3.10+"
```Python hl_lines="26-27 30"
{!> ../../../docs_src/dependency_testing/tutorial001_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="28-29 32"
{!> ../../../docs_src/dependency_testing/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="29-30 33"
{!> ../../../docs_src/dependency_testing/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="24-25 28"
{!> ../../../docs_src/dependency_testing/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="28-29 32"
{!> ../../../docs_src/dependency_testing/tutorial001.py!}
```
!!! tip
You can set a dependency override for a dependency used anywhere in your **FastAPI** application.

View File

@@ -112,17 +112,47 @@ In WebSocket endpoints you can import from `fastapi` and use:
They work the same way as for other FastAPI endpoints/*path operations*:
```Python hl_lines="58-65 68-83"
{!../../../docs_src/websockets/tutorial002.py!}
```
=== "Python 3.10+"
```Python hl_lines="68-69 82"
{!> ../../../docs_src/websockets/tutorial002_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="68-69 82"
{!> ../../../docs_src/websockets/tutorial002_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="69-70 83"
{!> ../../../docs_src/websockets/tutorial002_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="66-67 79"
{!> ../../../docs_src/websockets/tutorial002_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="68-69 81"
{!> ../../../docs_src/websockets/tutorial002.py!}
```
!!! info
In a WebSocket it doesn't really make sense to raise an `HTTPException`. So it's better to close the WebSocket connection directly.
As this is a WebSocket it doesn't really make sense to raise an `HTTPException`, instead we raise a `WebSocketException`.
You can use a closing code from the <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">valid codes defined in the specification</a>.
In the future, there will be a `WebSocketException` that you will be able to `raise` from anywhere, and add exception handlers for it. It depends on the <a href="https://github.com/encode/starlette/pull/527" class="external-link" target="_blank">PR #527</a> in Starlette.
### Try the WebSockets with dependencies
If your file is named `main.py`, run your application with:
@@ -155,9 +185,17 @@ With that you can connect the WebSocket and then send and receive messages:
When a WebSocket connection is closed, the `await websocket.receive_text()` will raise a `WebSocketDisconnect` exception, which you can then catch and handle like in this example.
```Python hl_lines="81-83"
{!../../../docs_src/websockets/tutorial003.py!}
```
=== "Python 3.9+"
```Python hl_lines="79-81"
{!> ../../../docs_src/websockets/tutorial003_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="81-83"
{!> ../../../docs_src/websockets/tutorial003.py!}
```
To try it out:

View File

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

View File

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

View File

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

View File

@@ -56,6 +56,15 @@ Here's an incomplete list of some of them.
{% endfor %}
{% endif %}
### Taiwanese
{% if external_links %}
{% for article in external_links.articles.taiwanese %}
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
{% endfor %}
{% endif %}
## Podcasts
{% if external_links %}

View File

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

View File

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

View File

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

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

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

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -99,6 +99,12 @@ The key features are:
---
"_If anyone is looking to build a production Python API, I would highly recommend **FastAPI**. It is **beautifully designed**, **simple to use** and **highly scalable**, it has become a **key component** in our API first development strategy and is driving many automations and services such as our Virtual TAC Engineer._"
<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**, the FastAPI of CLIs
<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>
@@ -424,7 +430,7 @@ For a more complete example including more features, see the <a href="https://fa
* **GraphQL** integration with <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> and other libraries.
* Many extra features (thanks to Starlette) as:
* **WebSockets**
* extremely easy tests based on `requests` and `pytest`
* extremely easy tests based on HTTPX and `pytest`
* **CORS**
* **Cookie Sessions**
* ...and more.
@@ -444,7 +450,7 @@ Used by Pydantic:
Used by Starlette:
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Required if you want to use the `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.

View File

@@ -1,6 +1,6 @@
# Project Generation - Template
You can use a project generator to get started, as it includes a lot of the initial set up, security, database and first API endpoints already done for you.
You can use a project generator to get started, as it includes a lot of the initial set up, security, database and some API endpoints already done for you.
A project generator will always have a very opinionated setup that you should update and adapt for your own needs, but it might be a good starting point for your project.

View File

@@ -1,8 +1,8 @@
# Python Types Intro
Python has support for optional "type hints".
Python has support for optional "type hints" (also called "type annotations").
These **"type hints"** are a special syntax that allow declaring the <abbr title="for example: str, int, float, bool">type</abbr> of a variable.
These **"type hints"** or annotations are a special syntax that allow declaring the <abbr title="for example: str, int, float, bool">type</abbr> of a variable.
By declaring types for your variables, editors and tools can give you better support.
@@ -158,13 +158,31 @@ The syntax using `typing` is **compatible** with all versions, from Python 3.6 t
As Python advances, **newer versions** come with improved support for these type annotations and in many cases you won't even need to import and use the `typing` module to declare the type annotations.
If you can choose a more recent version of Python for your project, you will be able to take advantage of that extra simplicity. See some examples below.
If you can choose a more recent version of Python for your project, you will be able to take advantage of that extra simplicity.
In all the docs there are examples compatible with each version of Python (when there's a difference).
For example "**Python 3.6+**" means it's compatible with Python 3.6 or above (including 3.7, 3.8, 3.9, 3.10, etc). And "**Python 3.9+**" means it's compatible with Python 3.9 or above (including 3.10, etc).
If you can use the **latest versions of Python**, use the examples for the latest version, those will have the **best and simplest syntax**, for example, "**Python 3.10+**".
#### List
For example, let's define a variable to be a `list` of `str`.
=== "Python 3.6 and above"
=== "Python 3.9+"
Declare the variable, with the same colon (`:`) syntax.
As the type, put `list`.
As the list is a type that contains some internal types, you put them in square brackets:
```Python hl_lines="1"
{!> ../../../docs_src/python_types/tutorial006_py39.py!}
```
=== "Python 3.6+"
From `typing`, import `List` (with a capital `L`):
@@ -182,18 +200,6 @@ For example, let's define a variable to be a `list` of `str`.
{!> ../../../docs_src/python_types/tutorial006.py!}
```
=== "Python 3.9 and above"
Declare the variable, with the same colon (`:`) syntax.
As the type, put `list`.
As the list is a type that contains some internal types, you put them in square brackets:
```Python hl_lines="1"
{!> ../../../docs_src/python_types/tutorial006_py39.py!}
```
!!! info
Those internal types in the square brackets are called "type parameters".
@@ -218,18 +224,18 @@ And still, the editor knows it is a `str`, and provides support for that.
You would do the same to declare `tuple`s and `set`s:
=== "Python 3.6 and above"
```Python hl_lines="1 4"
{!> ../../../docs_src/python_types/tutorial007.py!}
```
=== "Python 3.9 and above"
=== "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!}
```
This means:
* The variable `items_t` is a `tuple` with 3 items, an `int`, another `int`, and a `str`.
@@ -243,18 +249,18 @@ The first type parameter is for the keys of the `dict`.
The second type parameter is for the values of the `dict`:
=== "Python 3.6 and above"
```Python hl_lines="1 4"
{!> ../../../docs_src/python_types/tutorial008.py!}
```
=== "Python 3.9 and above"
=== "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!}
```
This means:
* The variable `prices` is a `dict`:
@@ -267,20 +273,20 @@ You can declare that a variable can be any of **several types**, for example, an
In Python 3.6 and above (including Python 3.10) you can use the `Union` type from `typing` and put inside the square brackets the possible types to accept.
In Python 3.10 there's also an **alternative 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>.
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>.
=== "Python 3.6 and above"
```Python hl_lines="1 4"
{!> ../../../docs_src/python_types/tutorial008b.py!}
```
=== "Python 3.10 and above"
=== "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!}
```
In both cases this means that `item` could be an `int` or a `str`.
#### Possibly `None`
@@ -299,24 +305,24 @@ Using `Optional[str]` instead of just `str` will let the editor help you detecti
This also means that in Python 3.10, you can use `Something | None`:
=== "Python 3.6 and above"
=== "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 and above - alternative"
=== "Python 3.6+ alternative"
```Python hl_lines="1 4"
{!> ../../../docs_src/python_types/tutorial009b.py!}
```
=== "Python 3.10 and above"
```Python hl_lines="1"
{!> ../../../docs_src/python_types/tutorial009_py310.py!}
```
#### Using `Union` or `Optional`
If you are using a Python version below 3.10, here's a tip from my very **subjective** point of view:
@@ -360,32 +366,7 @@ And then you won't have to worry about names like `Optional` and `Union`. 😎
These types that take type parameters in square brackets are called **Generic types** or **Generics**, for example:
=== "Python 3.6 and above"
* `List`
* `Tuple`
* `Set`
* `Dict`
* `Union`
* `Optional`
* ...and others.
=== "Python 3.9 and above"
You can use the same builtin types as generics (with square brackets and types inside):
* `list`
* `tuple`
* `set`
* `dict`
And the same as with Python 3.6, from the `typing` module:
* `Union`
* `Optional`
* ...and others.
=== "Python 3.10 and above"
=== "Python 3.10+"
You can use the same builtin types as generics (with square brackets and types inside):
@@ -400,7 +381,32 @@ These types that take type parameters in square brackets are called **Generic ty
* `Optional` (the same as with Python 3.6)
* ...and others.
In Python 3.10, as an alternative to using the generics `Union` and `Optional`, you can use the <abbr title='also called "bitwise or operator", but that meaning is not relevant here'>vertical bar (`|`)</abbr> to declare unions of types.
In Python 3.10, as an alternative to using the generics `Union` and `Optional`, you can use the <abbr title='also called "bitwise or operator", but that meaning is not relevant here'>vertical bar (`|`)</abbr> to declare unions of types, that's a lot better and simpler.
=== "Python 3.9+"
You can use the same builtin types as generics (with square brackets and types inside):
* `list`
* `tuple`
* `set`
* `dict`
And the same as with Python 3.6, from the `typing` module:
* `Union`
* `Optional`
* ...and others.
=== "Python 3.6+"
* `List`
* `Tuple`
* `Set`
* `Dict`
* `Union`
* `Optional`
* ...and others.
### Classes as types
@@ -422,6 +428,10 @@ And then, again, you get all the editor support:
<img src="/img/python-types/image06.png">
Notice that this means "`one_person` is an **instance** of the class `Person`".
It doesn't mean "`one_person` is the **class** called `Person`".
## Pydantic models
<a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> is a Python library to perform data validation.
@@ -436,22 +446,22 @@ And you get all the editor support with that resulting object.
An example from the official Pydantic docs:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python
{!> ../../../docs_src/python_types/tutorial011.py!}
{!> ../../../docs_src/python_types/tutorial011_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python
{!> ../../../docs_src/python_types/tutorial011_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python
{!> ../../../docs_src/python_types/tutorial011_py310.py!}
{!> ../../../docs_src/python_types/tutorial011.py!}
```
!!! info
@@ -464,6 +474,43 @@ You will see a lot more of all this in practice in the [Tutorial - User Guide](t
!!! tip
Pydantic has a special behavior when you use `Optional` or `Union[Something, None]` without a default value, you can read more about it in the Pydantic docs about <a href="https://pydantic-docs.helpmanual.io/usage/models/#required-optional-fields" class="external-link" target="_blank">Required Optional fields</a>.
## Type Hints with Metadata Annotations
Python also has a feature that allows putting **additional metadata** in these type hints using `Annotated`.
=== "Python 3.9+"
In Python 3.9, `Annotated` is part of the standard library, so you can import it from `typing`.
```Python hl_lines="1 4"
{!> ../../../docs_src/python_types/tutorial013_py39.py!}
```
=== "Python 3.6+"
In versions below Python 3.9, you import `Annotated` from `typing_extensions`.
It will already be installed with **FastAPI**.
```Python hl_lines="1 4"
{!> ../../../docs_src/python_types/tutorial013.py!}
```
Python itself doesn't do anything with this `Annotated`. And for editors and other tools, the type is still `str`.
But you can use this space in `Annotated` to provide **FastAPI** with additional metadata about how you want your application to behave.
The important thing to remember is that **the first *type parameter*** you pass to `Annotated` is the **actual type**. The rest, is just metadata for other tools.
For now, you just need to know that `Annotated` exists, and that it's standard Python. 😎
Later you will see how **powerful** it can be.
!!! tip
The fact that this is **standard Python** means that you will still get the **best possible developer experience** in your editor, with the tools you use to analyze and refactor your code, etc. ✨
And also that your code will be very compatible with many other Python tools and libraries. 🚀
## Type hints in **FastAPI**
**FastAPI** takes advantage of these type hints to do several things.

View File

@@ -3,6 +3,433 @@
## Latest Changes
## 0.95.0
### Highlights
This release adds support for dependencies and parameters using `Annotated` and recommends its usage. ✨
This has **several benefits**, one of the main ones is that now the parameters of your functions with `Annotated` would **not be affected** at all.
If you call those functions in **other places in your code**, the actual **default values** will be kept, your editor will help you notice missing **required arguments**, Python will require you to pass required arguments at **runtime**, you will be able to **use the same functions** for different things and with different libraries (e.g. **Typer** will soon support `Annotated` too, then you could use the same function for an API and a CLI), etc.
Because `Annotated` is **standard Python**, you still get all the **benefits** from editors and tools, like **autocompletion**, **inline errors**, etc.
One of the **biggest benefits** is that now you can create `Annotated` dependencies that are then shared by multiple *path operation functions*, this will allow you to **reduce** a lot of **code duplication** in your codebase, while keeping all the support from editors and tools.
For example, you could have code like this:
```Python
def get_current_user(token: str):
# authenticate user
return User()
@app.get("/items/")
def read_items(user: User = Depends(get_current_user)):
...
@app.post("/items/")
def create_item(*, user: User = Depends(get_current_user), item: Item):
...
@app.get("/items/{item_id}")
def read_item(*, user: User = Depends(get_current_user), item_id: int):
...
@app.delete("/items/{item_id}")
def delete_item(*, user: User = Depends(get_current_user), item_id: int):
...
```
There's a bit of code duplication for the dependency:
```Python
user: User = Depends(get_current_user)
```
...the bigger the codebase, the more noticeable it is.
Now you can create an annotated dependency once, like this:
```Python
CurrentUser = Annotated[User, Depends(get_current_user)]
```
And then you can reuse this `Annotated` dependency:
```Python
CurrentUser = Annotated[User, Depends(get_current_user)]
@app.get("/items/")
def read_items(user: CurrentUser):
...
@app.post("/items/")
def create_item(user: CurrentUser, item: Item):
...
@app.get("/items/{item_id}")
def read_item(user: CurrentUser, item_id: int):
...
@app.delete("/items/{item_id}")
def delete_item(user: CurrentUser, item_id: int):
...
```
...and `CurrentUser` has all the typing information as `User`, so your editor will work as expected (autocompletion and everything), and **FastAPI** will be able to understand the dependency defined in `Annotated`. 😎
Roughly **all the docs** have been rewritten to use `Annotated` as the main way to declare **parameters** and **dependencies**. All the **examples** in the docs now include a version with `Annotated` and a version without it, for each of the specific Python versions (when there are small differences/improvements in more recent versions). There were around 23K new lines added between docs, examples, and tests. 🚀
The key updated docs are:
* Python Types Intro:
* [Type Hints with Metadata Annotations](https://fastapi.tiangolo.com/python-types/#type-hints-with-metadata-annotations).
* Tutorial:
* [Query Parameters and String Validations - Additional validation](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#additional-validation)
* [Advantages of `Annotated`](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#advantages-of-annotated)
* [Path Parameters and Numeric Validations - Order the parameters as you need, tricks](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#order-the-parameters-as-you-need-tricks)
* [Better with `Annotated`](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#better-with-annotated)
* [Dependencies - First Steps - Share `Annotated` dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/#share-annotated-dependencies)
Special thanks to [@nzig](https://github.com/nzig) for the core implementation and to [@adriangb](https://github.com/adriangb) for the inspiration and idea with [Xpresso](https://github.com/adriangb/xpresso)! 🚀
### Features
* ✨Add support for PEP-593 `Annotated` for specifying dependencies and parameters. PR [#4871](https://github.com/tiangolo/fastapi/pull/4871) by [@nzig](https://github.com/nzig).
### Docs
* 📝 Tweak tip recommending `Annotated` in docs. PR [#9270](https://github.com/tiangolo/fastapi/pull/9270) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update order of examples, latest Python version first, and simplify version tab names. PR [#9269](https://github.com/tiangolo/fastapi/pull/9269) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update all docs to use `Annotated` as the main recommendation, with new examples and tests. PR [#9268](https://github.com/tiangolo/fastapi/pull/9268) by [@tiangolo](https://github.com/tiangolo).
## 0.94.1
### Fixes
* 🎨 Fix types for lifespan, upgrade Starlette to 0.26.1. PR [#9245](https://github.com/tiangolo/fastapi/pull/9245) by [@tiangolo](https://github.com/tiangolo).
## 0.94.0
### Upgrades
* ⬆ Upgrade python-multipart to support 0.0.6. PR [#9212](https://github.com/tiangolo/fastapi/pull/9212) by [@musicinmybrain](https://github.com/musicinmybrain).
* ⬆️ Upgrade Starlette version, support new `lifespan` with state. PR [#9239](https://github.com/tiangolo/fastapi/pull/9239) by [@tiangolo](https://github.com/tiangolo).
### Docs
* 📝 Update Sentry link in docs. PR [#9218](https://github.com/tiangolo/fastapi/pull/9218) by [@smeubank](https://github.com/smeubank).
### Translations
* 🌐 Add Russian translation for `docs/ru/docs/history-design-future.md`. PR [#5986](https://github.com/tiangolo/fastapi/pull/5986) by [@Xewus](https://github.com/Xewus).
### Internal
* Add `pydantic` to PyPI classifiers. PR [#5914](https://github.com/tiangolo/fastapi/pull/5914) by [@yezz123](https://github.com/yezz123).
* ⬆ Bump black from 22.10.0 to 23.1.0. PR [#5953](https://github.com/tiangolo/fastapi/pull/5953) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump types-ujson from 5.6.0.0 to 5.7.0.1. PR [#6027](https://github.com/tiangolo/fastapi/pull/6027) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump dawidd6/action-download-artifact from 2.24.3 to 2.26.0. PR [#6034](https://github.com/tiangolo/fastapi/pull/6034) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5709](https://github.com/tiangolo/fastapi/pull/5709) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
## 0.93.0
### Features
* ✨ Add support for `lifespan` async context managers (superseding `startup` and `shutdown` events). Initial PR [#2944](https://github.com/tiangolo/fastapi/pull/2944) by [@uSpike](https://github.com/uSpike).
Now, instead of using independent `startup` and `shutdown` events, you can define that logic in a single function with `yield` decorated with `@asynccontextmanager` (an async context manager).
For example:
```Python
from contextlib import asynccontextmanager
from fastapi import FastAPI
def fake_answer_to_everything_ml_model(x: float):
return x * 42
ml_models = {}
@asynccontextmanager
async def lifespan(app: FastAPI):
# Load the ML model
ml_models["answer_to_everything"] = fake_answer_to_everything_ml_model
yield
# Clean up the ML models and release the resources
ml_models.clear()
app = FastAPI(lifespan=lifespan)
@app.get("/predict")
async def predict(x: float):
result = ml_models["answer_to_everything"](x)
return {"result": result}
```
**Note**: This is the recommended way going forward, instead of using `startup` and `shutdown` events.
Read more about it in the new docs: [Advanced User Guide: Lifespan Events](https://fastapi.tiangolo.com/advanced/events/).
### Docs
* ✏ Fix formatting in `docs/en/docs/tutorial/metadata.md` for `ReDoc`. PR [#6005](https://github.com/tiangolo/fastapi/pull/6005) by [@eykamp](https://github.com/eykamp).
### Translations
* 🌐 Tamil translations - initial setup. PR [#5564](https://github.com/tiangolo/fastapi/pull/5564) by [@gusty1g](https://github.com/gusty1g).
* 🌐 Add French translation for `docs/fr/docs/advanced/path-operation-advanced-configuration.md`. PR [#9221](https://github.com/tiangolo/fastapi/pull/9221) by [@axel584](https://github.com/axel584).
* 🌐 Add French translation for `docs/tutorial/debugging.md`. PR [#9175](https://github.com/tiangolo/fastapi/pull/9175) by [@frabc](https://github.com/frabc).
* 🌐 Initiate Armenian translation setup. PR [#5844](https://github.com/tiangolo/fastapi/pull/5844) by [@har8](https://github.com/har8).
* 🌐 Add French translation for `deployment/manually.md`. PR [#3693](https://github.com/tiangolo/fastapi/pull/3693) by [@rjNemo](https://github.com/rjNemo).
### Internal
* 👷 Update translation bot messages. PR [#9206](https://github.com/tiangolo/fastapi/pull/9206) by [@tiangolo](https://github.com/tiangolo).
* 👷 Update translations bot to use Discussions, and notify when a PR is done. PR [#9183](https://github.com/tiangolo/fastapi/pull/9183) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update sponsors-badges. PR [#9182](https://github.com/tiangolo/fastapi/pull/9182) by [@tiangolo](https://github.com/tiangolo).
* 👥 Update FastAPI People. PR [#9181](https://github.com/tiangolo/fastapi/pull/9181) by [@github-actions[bot]](https://github.com/apps/github-actions).
* 🔊 Log GraphQL errors in FastAPI People, because it returns 200, with a payload with an error. PR [#9171](https://github.com/tiangolo/fastapi/pull/9171) by [@tiangolo](https://github.com/tiangolo).
* 💚 Fix/workaround GitHub Actions in Docker with git for FastAPI People. PR [#9169](https://github.com/tiangolo/fastapi/pull/9169) by [@tiangolo](https://github.com/tiangolo).
* ♻️ Refactor FastAPI Experts to use only discussions now that questions are migrated. PR [#9165](https://github.com/tiangolo/fastapi/pull/9165) by [@tiangolo](https://github.com/tiangolo).
* ⬆️ Upgrade analytics. PR [#6025](https://github.com/tiangolo/fastapi/pull/6025) by [@tiangolo](https://github.com/tiangolo).
* ⬆️ Upgrade and re-enable installing Typer-CLI. PR [#6008](https://github.com/tiangolo/fastapi/pull/6008) by [@tiangolo](https://github.com/tiangolo).
## 0.92.0
🚨 This is a security fix. Please upgrade as soon as possible.
### Upgrades
* ⬆️ Upgrade Starlette to 0.25.0. PR [#5996](https://github.com/tiangolo/fastapi/pull/5996) by [@tiangolo](https://github.com/tiangolo).
* This solves a vulnerability that could allow denial of service attacks by using many small multipart fields/files (parts), consuming high CPU and memory.
* Only applications using forms (e.g. file uploads) could be affected.
* For most cases, upgrading won't have any breaking changes.
## 0.91.0
### Upgrades
* ⬆️ Upgrade Starlette version to `0.24.0` and refactor internals for compatibility. PR [#5985](https://github.com/tiangolo/fastapi/pull/5985) by [@tiangolo](https://github.com/tiangolo).
* This can solve nuanced errors when using middlewares. Before Starlette `0.24.0`, a new instance of each middleware class would be created when a new middleware was added. That normally was not a problem, unless the middleware class expected to be created only once, with only one instance, that happened in some cases. This upgrade would solve those cases (thanks [@adriangb](https://github.com/adriangb)! Starlette PR [#2017](https://github.com/encode/starlette/pull/2017)). Now the middleware class instances are created once, right before the first request (the first time the app is called).
* If you depended on that previous behavior, you might need to update your code. As always, make sure your tests pass before merging the upgrade.
## 0.90.1
### Upgrades
* ⬆️ Upgrade Starlette range to allow 0.23.1. PR [#5980](https://github.com/tiangolo/fastapi/pull/5980) by [@tiangolo](https://github.com/tiangolo).
### Docs
* ✏ Tweak wording to clarify `docs/en/docs/project-generation.md`. PR [#5930](https://github.com/tiangolo/fastapi/pull/5930) by [@chandra-deb](https://github.com/chandra-deb).
* ✏ Update Pydantic GitHub URLs. PR [#5952](https://github.com/tiangolo/fastapi/pull/5952) by [@yezz123](https://github.com/yezz123).
* 📝 Add opinion from Cisco. PR [#5981](https://github.com/tiangolo/fastapi/pull/5981) by [@tiangolo](https://github.com/tiangolo).
### Translations
* 🌐 Add Russian translation for `docs/ru/docs/tutorial/cookie-params.md`. PR [#5890](https://github.com/tiangolo/fastapi/pull/5890) by [@bnzone](https://github.com/bnzone).
### Internal
* ✏ Update `zip-docs.sh` internal script, remove extra space. PR [#5931](https://github.com/tiangolo/fastapi/pull/5931) by [@JuanPerdomo00](https://github.com/JuanPerdomo00).
## 0.90.0
### Upgrades
* ⬆️ Bump Starlette from 0.22.0 to 0.23.0. Initial PR [#5739](https://github.com/tiangolo/fastapi/pull/5739) by [@Kludex](https://github.com/Kludex).
### Docs
* 📝 Add article "Tortoise ORM / FastAPI 整合快速筆記" to External Links. PR [#5496](https://github.com/tiangolo/fastapi/pull/5496) by [@Leon0824](https://github.com/Leon0824).
* 👥 Update FastAPI People. PR [#5954](https://github.com/tiangolo/fastapi/pull/5954) by [@github-actions[bot]](https://github.com/apps/github-actions).
* 📝 Micro-tweak help docs. PR [#5960](https://github.com/tiangolo/fastapi/pull/5960) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update new issue chooser to direct to GitHub Discussions. PR [#5948](https://github.com/tiangolo/fastapi/pull/5948) by [@tiangolo](https://github.com/tiangolo).
* 📝 Recommend GitHub Discussions for questions. PR [#5944](https://github.com/tiangolo/fastapi/pull/5944) by [@tiangolo](https://github.com/tiangolo).
### Translations
* 🌐 Add Russian translation for `docs/ru/docs/tutorial/body-fields.md`. PR [#5898](https://github.com/tiangolo/fastapi/pull/5898) by [@simatheone](https://github.com/simatheone).
* 🌐 Add Russian translation for `docs/ru/docs/help-fastapi.md`. PR [#5970](https://github.com/tiangolo/fastapi/pull/5970) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/static-files.md`. PR [#5858](https://github.com/tiangolo/fastapi/pull/5858) by [@batlopes](https://github.com/batlopes).
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/encoder.md`. PR [#5525](https://github.com/tiangolo/fastapi/pull/5525) by [@felipebpl](https://github.com/felipebpl).
* 🌐 Add Russian translation for `docs/ru/docs/contributing.md`. PR [#5870](https://github.com/tiangolo/fastapi/pull/5870) by [@Xewus](https://github.com/Xewus).
### Internal
* ⬆️ Upgrade Ubuntu version for docs workflow. PR [#5971](https://github.com/tiangolo/fastapi/pull/5971) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update sponsors badges. PR [#5943](https://github.com/tiangolo/fastapi/pull/5943) by [@tiangolo](https://github.com/tiangolo).
* ✨ Compute FastAPI Experts including GitHub Discussions. PR [#5941](https://github.com/tiangolo/fastapi/pull/5941) by [@tiangolo](https://github.com/tiangolo).
* ⬆️ Upgrade isort and update pre-commit. PR [#5940](https://github.com/tiangolo/fastapi/pull/5940) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Add template for questions in Discussions. PR [#5920](https://github.com/tiangolo/fastapi/pull/5920) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update Sponsor Budget Insight to Powens. PR [#5916](https://github.com/tiangolo/fastapi/pull/5916) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Update GitHub Sponsors badge data. PR [#5915](https://github.com/tiangolo/fastapi/pull/5915) by [@tiangolo](https://github.com/tiangolo).
## 0.89.1
### Fixes
* 🐛 Ignore Response classes on return annotation. PR [#5855](https://github.com/tiangolo/fastapi/pull/5855) by [@Kludex](https://github.com/Kludex). See the new docs in the PR below.
### Docs
* 📝 Update docs and examples for Response Model with Return Type Annotations, and update runtime error. PR [#5873](https://github.com/tiangolo/fastapi/pull/5873) by [@tiangolo](https://github.com/tiangolo). New docs at [Response Model - Return Type: Other Return Type Annotations](https://fastapi.tiangolo.com/tutorial/response-model/#other-return-type-annotations).
* 📝 Add External Link: FastAPI lambda container: serverless simplified. PR [#5784](https://github.com/tiangolo/fastapi/pull/5784) by [@rafrasenberg](https://github.com/rafrasenberg).
### Translations
* 🌐 Add Turkish translation for `docs/tr/docs/tutorial/first_steps.md`. PR [#5691](https://github.com/tiangolo/fastapi/pull/5691) by [@Kadermiyanyedi](https://github.com/Kadermiyanyedi).
## 0.89.0
### Features
* ✨ Add support for function return type annotations to declare the `response_model`. Initial PR [#1436](https://github.com/tiangolo/fastapi/pull/1436) by [@uriyyo](https://github.com/uriyyo).
Now you can declare the return type / `response_model` in the function return type annotation:
```python
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
@app.get("/items/")
async def read_items() -> list[Item]:
return [
Item(name="Portal Gun", price=42.0),
Item(name="Plumbus", price=32.0),
]
```
FastAPI will use the return type annotation to perform:
* Data validation
* Automatic documentation
* It could power automatic client generators
* **Data filtering**
Before this version it was only supported via the `response_model` parameter.
Read more about it in the new docs: [Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/).
### Docs
* 📝 Add External Link: Authorization on FastAPI with Casbin. PR [#5712](https://github.com/tiangolo/fastapi/pull/5712) by [@Xhy-5000](https://github.com/Xhy-5000).
* ✏ Fix typo in `docs/en/docs/async.md`. PR [#5785](https://github.com/tiangolo/fastapi/pull/5785) by [@Kingdageek](https://github.com/Kingdageek).
* ✏ Fix typo in `docs/en/docs/deployment/concepts.md`. PR [#5824](https://github.com/tiangolo/fastapi/pull/5824) by [@kelbyfaessler](https://github.com/kelbyfaessler).
### Translations
* 🌐 Add Russian translation for `docs/ru/docs/fastapi-people.md`. PR [#5577](https://github.com/tiangolo/fastapi/pull/5577) by [@Xewus](https://github.com/Xewus).
* 🌐 Fix typo in Chinese translation for `docs/zh/docs/benchmarks.md`. PR [#4269](https://github.com/tiangolo/fastapi/pull/4269) by [@15027668g](https://github.com/15027668g).
* 🌐 Add Korean translation for `docs/tutorial/cors.md`. PR [#3764](https://github.com/tiangolo/fastapi/pull/3764) by [@NinaHwang](https://github.com/NinaHwang).
### Internal
* ⬆ Update coverage[toml] requirement from <7.0,>=6.5.0 to >=6.5.0,<8.0. PR [#5801](https://github.com/tiangolo/fastapi/pull/5801) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Update uvicorn[standard] requirement from <0.19.0,>=0.12.0 to >=0.12.0,<0.21.0 for development. PR [#5795](https://github.com/tiangolo/fastapi/pull/5795) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump dawidd6/action-download-artifact from 2.24.2 to 2.24.3. PR [#5842](https://github.com/tiangolo/fastapi/pull/5842) by [@dependabot[bot]](https://github.com/apps/dependabot).
* 👥 Update FastAPI People. PR [#5825](https://github.com/tiangolo/fastapi/pull/5825) by [@github-actions[bot]](https://github.com/apps/github-actions).
* ⬆ Bump types-ujson from 5.5.0 to 5.6.0.0. PR [#5735](https://github.com/tiangolo/fastapi/pull/5735) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump pypa/gh-action-pypi-publish from 1.5.2 to 1.6.4. PR [#5750](https://github.com/tiangolo/fastapi/pull/5750) by [@dependabot[bot]](https://github.com/apps/dependabot).
* 👷 Add GitHub Action gate/check. PR [#5492](https://github.com/tiangolo/fastapi/pull/5492) by [@webknjaz](https://github.com/webknjaz).
* 🔧 Update sponsors, add Svix. PR [#5848](https://github.com/tiangolo/fastapi/pull/5848) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Remove Doist sponsor. PR [#5847](https://github.com/tiangolo/fastapi/pull/5847) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Update sqlalchemy requirement from <=1.4.41,>=1.3.18 to >=1.3.18,<1.4.43. PR [#5540](https://github.com/tiangolo/fastapi/pull/5540) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump nwtgck/actions-netlify from 1.2.4 to 2.0.0. PR [#5757](https://github.com/tiangolo/fastapi/pull/5757) by [@dependabot[bot]](https://github.com/apps/dependabot).
* 👷 Refactor CI artifact upload/download for docs previews. PR [#5793](https://github.com/tiangolo/fastapi/pull/5793) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Bump pypa/gh-action-pypi-publish from 1.5.1 to 1.5.2. PR [#5714](https://github.com/tiangolo/fastapi/pull/5714) by [@dependabot[bot]](https://github.com/apps/dependabot).
* 👥 Update FastAPI People. PR [#5722](https://github.com/tiangolo/fastapi/pull/5722) by [@github-actions[bot]](https://github.com/apps/github-actions).
* 🔧 Update sponsors, disable course bundle. PR [#5713](https://github.com/tiangolo/fastapi/pull/5713) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Update typer[all] requirement from <0.7.0,>=0.6.1 to >=0.6.1,<0.8.0. PR [#5639](https://github.com/tiangolo/fastapi/pull/5639) by [@dependabot[bot]](https://github.com/apps/dependabot).
## 0.88.0
### Upgrades
* ⬆ Bump Starlette to version `0.22.0` to fix bad encoding for query parameters in new `TestClient`. PR [#5659](https://github.com/tiangolo/fastapi/pull/5659) by [@azogue](https://github.com/azogue).
### Docs
* ✏️ Fix typo in docs for `docs/en/docs/advanced/middleware.md`. PR [#5376](https://github.com/tiangolo/fastapi/pull/5376) by [@rifatrakib](https://github.com/rifatrakib).
### Translations
* 🌐 Add Portuguese translation for `docs/pt/docs/deployment/docker.md`. PR [#5663](https://github.com/tiangolo/fastapi/pull/5663) by [@ayr-ton](https://github.com/ayr-ton).
### Internal
* 👷 Tweak build-docs to improve CI performance. PR [#5699](https://github.com/tiangolo/fastapi/pull/5699) by [@tiangolo](https://github.com/tiangolo).
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5566](https://github.com/tiangolo/fastapi/pull/5566) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
* ⬆️ Upgrade Ruff. PR [#5698](https://github.com/tiangolo/fastapi/pull/5698) by [@tiangolo](https://github.com/tiangolo).
* 👷 Remove pip cache for Smokeshow as it depends on a requirements.txt. PR [#5700](https://github.com/tiangolo/fastapi/pull/5700) by [@tiangolo](https://github.com/tiangolo).
* 💚 Fix pip cache for Smokeshow. PR [#5697](https://github.com/tiangolo/fastapi/pull/5697) by [@tiangolo](https://github.com/tiangolo).
* 👷 Fix and tweak CI cache handling. PR [#5696](https://github.com/tiangolo/fastapi/pull/5696) by [@tiangolo](https://github.com/tiangolo).
* 👷 Update `setup-python` action in tests to use new caching feature. PR [#5680](https://github.com/tiangolo/fastapi/pull/5680) by [@madkinsz](https://github.com/madkinsz).
* ⬆ Bump black from 22.8.0 to 22.10.0. PR [#5569](https://github.com/tiangolo/fastapi/pull/5569) by [@dependabot[bot]](https://github.com/apps/dependabot).
## 0.87.0
Highlights of this release:
* [Upgraded Starlette](https://github.com/encode/starlette/releases/tag/0.21.0)
* Now the `TestClient` is based on HTTPX instead of Requests. 🚀
* There are some possible **breaking changes** in the `TestClient` usage, but [@Kludex](https://github.com/Kludex) built [bump-testclient](https://github.com/Kludex/bump-testclient) to help you automatize migrating your tests. Make sure you are using Git and that you can undo any unnecessary changes (false positive changes, etc) before using `bump-testclient`.
* New [WebSocketException (and docs)](https://fastapi.tiangolo.com/advanced/websockets/#using-depends-and-others), re-exported from Starlette.
* Upgraded and relaxed dependencies for package extras `all` (including new Uvicorn version), when you install `"fastapi[all]"`.
* New docs about how to [**Help Maintain FastAPI**](https://fastapi.tiangolo.com/help-fastapi/#help-maintain-fastapi).
### Features
* ⬆️ Upgrade and relax dependencies for extras "all". PR [#5634](https://github.com/tiangolo/fastapi/pull/5634) by [@tiangolo](https://github.com/tiangolo).
* ✨ Re-export Starlette's `WebSocketException` and add it to docs. PR [#5629](https://github.com/tiangolo/fastapi/pull/5629) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update references to Requests for tests to HTTPX, and add HTTPX to extras. PR [#5628](https://github.com/tiangolo/fastapi/pull/5628) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Upgrade Starlette to `0.21.0`, including the new [`TestClient` based on HTTPX](https://github.com/encode/starlette/releases/tag/0.21.0). PR [#5471](https://github.com/tiangolo/fastapi/pull/5471) by [@pawelrubin](https://github.com/pawelrubin).
### Docs
* ✏️ Tweak Help FastAPI from PR review after merging. PR [#5633](https://github.com/tiangolo/fastapi/pull/5633) by [@tiangolo](https://github.com/tiangolo).
* ✏️ Clarify docs on CORS. PR [#5627](https://github.com/tiangolo/fastapi/pull/5627) by [@paxcodes](https://github.com/paxcodes).
* 📝 Update Help FastAPI: Help Maintain FastAPI. PR [#5632](https://github.com/tiangolo/fastapi/pull/5632) by [@tiangolo](https://github.com/tiangolo).
### Translations
* 🌐 Fix highlight lines for Japanese translation for `docs/tutorial/query-params.md`. PR [#2969](https://github.com/tiangolo/fastapi/pull/2969) by [@ftnext](https://github.com/ftnext).
* 🌐 Add French translation for `docs/fr/docs/advanced/additional-status-code.md`. PR [#5477](https://github.com/tiangolo/fastapi/pull/5477) by [@axel584](https://github.com/axel584).
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/request-forms-and-files.md`. PR [#5579](https://github.com/tiangolo/fastapi/pull/5579) by [@batlopes](https://github.com/batlopes).
* 🌐 Add Japanese translation for `docs/ja/docs/advanced/websockets.md`. PR [#4983](https://github.com/tiangolo/fastapi/pull/4983) by [@xryuseix](https://github.com/xryuseix).
### Internal
* ✨ Use Ruff for linting. PR [#5630](https://github.com/tiangolo/fastapi/pull/5630) by [@tiangolo](https://github.com/tiangolo).
* 🛠 Add Arabic issue number to Notify Translations GitHub Action. PR [#5610](https://github.com/tiangolo/fastapi/pull/5610) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Bump dawidd6/action-download-artifact from 2.24.1 to 2.24.2. PR [#5609](https://github.com/tiangolo/fastapi/pull/5609) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump dawidd6/action-download-artifact from 2.24.0 to 2.24.1. PR [#5603](https://github.com/tiangolo/fastapi/pull/5603) by [@dependabot[bot]](https://github.com/apps/dependabot).
* 📝 Update coverage badge to use Samuel Colvin's Smokeshow. PR [#5585](https://github.com/tiangolo/fastapi/pull/5585) by [@tiangolo](https://github.com/tiangolo).
## 0.86.0
### Features
@@ -1060,7 +1487,7 @@ Thanks to [Dima Boger](https://twitter.com/b0g3r) for the security report! 🙇
### Security fixes
* 📌 Upgrade pydantic pin, to handle security vulnerability [CVE-2021-29510](https://github.com/samuelcolvin/pydantic/security/advisories/GHSA-5jqp-qgf6-3pvh). PR [#3213](https://github.com/tiangolo/fastapi/pull/3213) by [@tiangolo](https://github.com/tiangolo).
* 📌 Upgrade pydantic pin, to handle security vulnerability [CVE-2021-29510](https://github.com/pydantic/pydantic/security/advisories/GHSA-5jqp-qgf6-3pvh). PR [#3213](https://github.com/tiangolo/fastapi/pull/3213) by [@tiangolo](https://github.com/tiangolo).
## 0.65.0
@@ -1615,11 +2042,11 @@ Note: all the previous parameters are still there, so it's still possible to dec
## 0.55.1
* Fix handling of enums with their own schema in path parameters. To support [samuelcolvin/pydantic#1432](https://github.com/samuelcolvin/pydantic/pull/1432) in FastAPI. PR [#1463](https://github.com/tiangolo/fastapi/pull/1463).
* Fix handling of enums with their own schema in path parameters. To support [pydantic/pydantic#1432](https://github.com/pydantic/pydantic/pull/1432) in FastAPI. PR [#1463](https://github.com/tiangolo/fastapi/pull/1463).
## 0.55.0
* Allow enums to allow them to have their own schemas in OpenAPI. To support [samuelcolvin/pydantic#1432](https://github.com/samuelcolvin/pydantic/pull/1432) in FastAPI. PR [#1461](https://github.com/tiangolo/fastapi/pull/1461).
* Allow enums to allow them to have their own schemas in OpenAPI. To support [pydantic/pydantic#1432](https://github.com/pydantic/pydantic/pull/1432) in FastAPI. PR [#1461](https://github.com/tiangolo/fastapi/pull/1461).
* Add links for funding through [GitHub sponsors](https://github.com/sponsors/tiangolo). PR [#1425](https://github.com/tiangolo/fastapi/pull/1425).
* Update issue template for for questions. PR [#1344](https://github.com/tiangolo/fastapi/pull/1344) by [@retnikt](https://github.com/retnikt).
* Update warning about storing passwords in docs. PR [#1336](https://github.com/tiangolo/fastapi/pull/1336) by [@skorokithakis](https://github.com/skorokithakis).

View File

@@ -57,18 +57,42 @@ Using `BackgroundTasks` also works with the dependency injection system, you can
**FastAPI** knows what to do in each case and how to re-use the same object, so that all the background tasks are merged together and are run in the background afterwards:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="13 15 22 25"
{!> ../../../docs_src/background_tasks/tutorial002.py!}
{!> ../../../docs_src/background_tasks/tutorial002_an_py310.py!}
```
=== "Python 3.10 and above"
=== "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+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="11 13 20 23"
{!> ../../../docs_src/background_tasks/tutorial002_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="13 15 22 25"
{!> ../../../docs_src/background_tasks/tutorial002.py!}
```
In this example, the messages will be written to the `log.txt` file *after* the response is sent.
If there was a query in the request, it will be written to the log in a background task.

View File

@@ -112,9 +112,26 @@ So we put them in their own `dependencies` module (`app/dependencies.py`).
We will now use a simple dependency to read a custom `X-Token` header:
```Python hl_lines="1 4-6"
{!../../../docs_src/bigger_applications/app/dependencies.py!}
```
=== "Python 3.9+"
```Python hl_lines="3 6-8"
{!> ../../../docs_src/bigger_applications/app_an_py39/dependencies.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 5-7"
{!> ../../../docs_src/bigger_applications/app_an/dependencies.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="1 4-6"
{!> ../../../docs_src/bigger_applications/app/dependencies.py!}
```
!!! tip
We are using an invented header to simplify this example.
@@ -189,7 +206,7 @@ The end result is that the item paths are now:
### Import the dependencies
This codes lives in the module `app.routers.items`, the file `app/routers/items.py`.
This code lives in the module `app.routers.items`, the file `app/routers/items.py`.
And we need to get the dependency function from the module `app.dependencies`, the file `app/dependencies.py`.

View File

@@ -6,18 +6,42 @@ The same way you can declare additional validation and metadata in *path operati
First, you have to import it:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="4"
{!> ../../../docs_src/body_fields/tutorial001.py!}
{!> ../../../docs_src/body_fields/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "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
Prefer to use the `Annotated` version if possible.
```Python hl_lines="2"
{!> ../../../docs_src/body_fields/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="4"
{!> ../../../docs_src/body_fields/tutorial001.py!}
```
!!! warning
Notice that `Field` is imported directly from `pydantic`, not from `fastapi` as are all the rest (`Query`, `Path`, `Body`, etc).
@@ -25,18 +49,42 @@ First, you have to import it:
You can then use `Field` with model attributes:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="11-14"
{!> ../../../docs_src/body_fields/tutorial001.py!}
{!> ../../../docs_src/body_fields/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "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` works the same way as `Query`, `Path` and `Body`, it has all the same parameters, etc.
!!! note "Technical Details"

View File

@@ -8,18 +8,42 @@ First, of course, you can mix `Path`, `Query` and request body parameter declara
And you can also declare body parameters as optional, by setting the default to `None`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="19-21"
{!> ../../../docs_src/body_multiple_params/tutorial001.py!}
```Python hl_lines="18-20"
{!> ../../../docs_src/body_multiple_params/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "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
Prefer to use the `Annotated` version if possible.
```Python hl_lines="17-19"
{!> ../../../docs_src/body_multiple_params/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="19-21"
{!> ../../../docs_src/body_multiple_params/tutorial001.py!}
```
!!! note
Notice that, in this case, the `item` that would be taken from the body is optional. As it has a `None` default value.
@@ -38,18 +62,18 @@ In the previous example, the *path operations* would expect a JSON body with the
But you can also declare multiple body parameters, e.g. `item` and `user`:
=== "Python 3.6 and above"
```Python hl_lines="22"
{!> ../../../docs_src/body_multiple_params/tutorial002.py!}
```
=== "Python 3.10 and above"
=== "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!}
```
In this case, **FastAPI** will notice that there are more than one body parameters in the function (two parameters that are Pydantic models).
So, it will then use the parameter names as keys (field names) in the body, and expect a body like:
@@ -87,18 +111,42 @@ If you declare it as is, because it is a singular value, **FastAPI** will assume
But you can instruct **FastAPI** to treat it as another body key using `Body`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="22"
{!> ../../../docs_src/body_multiple_params/tutorial003.py!}
```Python hl_lines="23"
{!> ../../../docs_src/body_multiple_params/tutorial003_an_py310.py!}
```
=== "Python 3.10 and above"
=== "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
Prefer to use the `Annotated` version if possible.
```Python hl_lines="20"
{!> ../../../docs_src/body_multiple_params/tutorial003_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="22"
{!> ../../../docs_src/body_multiple_params/tutorial003.py!}
```
In this case, **FastAPI** will expect a body like:
```JSON
@@ -137,18 +185,42 @@ q: str | None = None
For example:
=== "Python 3.6 and above"
=== "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
Prefer to use the `Annotated` version if possible.
```Python hl_lines="25"
{!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="27"
{!> ../../../docs_src/body_multiple_params/tutorial004.py!}
```
=== "Python 3.10 and above"
```Python hl_lines="26"
{!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!}
```
!!! info
`Body` also has all the same extra validation and metadata parameters as `Query`,`Path` and others you will see later.
@@ -166,18 +238,42 @@ item: Item = Body(embed=True)
as in:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="17"
{!> ../../../docs_src/body_multiple_params/tutorial005.py!}
{!> ../../../docs_src/body_multiple_params/tutorial005_an_py310.py!}
```
=== "Python 3.10 and above"
=== "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
Prefer to use the `Annotated` version if possible.
```Python hl_lines="15"
{!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="17"
{!> ../../../docs_src/body_multiple_params/tutorial005.py!}
```
In this case **FastAPI** will expect a body like:
```JSON hl_lines="2"

View File

@@ -6,18 +6,18 @@ With **FastAPI**, you can define, validate, document, and use arbitrarily deeply
You can define an attribute to be a subtype. For example, a Python `list`:
=== "Python 3.6 and above"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial001.py!}
```
=== "Python 3.10 and above"
=== "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!}
```
This will make `tags` be a list, although it doesn't declare the type of the elements of the list.
## List fields with type parameter
@@ -61,22 +61,22 @@ Use that same standard syntax for model attributes with internal types.
So, in our example, we can make `tags` be specifically a "list of strings":
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial002.py!}
```Python hl_lines="12"
{!> ../../../docs_src/body_nested_models/tutorial002_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial002_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="12"
{!> ../../../docs_src/body_nested_models/tutorial002_py310.py!}
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial002.py!}
```
## Set types
@@ -87,22 +87,22 @@ And Python has a special data type for sets of unique items, the `set`.
Then we can declare `tags` as a set of strings:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="1 14"
{!> ../../../docs_src/body_nested_models/tutorial003.py!}
```Python hl_lines="12"
{!> ../../../docs_src/body_nested_models/tutorial003_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial003_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="12"
{!> ../../../docs_src/body_nested_models/tutorial003_py310.py!}
```Python hl_lines="1 14"
{!> ../../../docs_src/body_nested_models/tutorial003.py!}
```
With this, even if you receive a request with duplicate data, it will be converted to a set of unique items.
@@ -125,44 +125,44 @@ All that, arbitrarily nested.
For example, we can define an `Image` model:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="9-11"
{!> ../../../docs_src/body_nested_models/tutorial004.py!}
```Python hl_lines="7-9"
{!> ../../../docs_src/body_nested_models/tutorial004_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="9-11"
{!> ../../../docs_src/body_nested_models/tutorial004_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="7-9"
{!> ../../../docs_src/body_nested_models/tutorial004_py310.py!}
```Python hl_lines="9-11"
{!> ../../../docs_src/body_nested_models/tutorial004.py!}
```
### Use the submodel as a type
And then we can use it as the type of an attribute:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial004.py!}
```Python hl_lines="18"
{!> ../../../docs_src/body_nested_models/tutorial004_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial004_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="18"
{!> ../../../docs_src/body_nested_models/tutorial004_py310.py!}
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial004.py!}
```
This would mean that **FastAPI** would expect a body similar to:
@@ -196,22 +196,22 @@ To see all the options you have, checkout the docs for <a href="https://pydantic
For example, as in the `Image` model we have a `url` field, we can declare it to be instead of a `str`, a Pydantic's `HttpUrl`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="4 10"
{!> ../../../docs_src/body_nested_models/tutorial005.py!}
```Python hl_lines="2 8"
{!> ../../../docs_src/body_nested_models/tutorial005_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="4 10"
{!> ../../../docs_src/body_nested_models/tutorial005_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="2 8"
{!> ../../../docs_src/body_nested_models/tutorial005_py310.py!}
```Python hl_lines="4 10"
{!> ../../../docs_src/body_nested_models/tutorial005.py!}
```
The string will be checked to be a valid URL, and documented in JSON Schema / OpenAPI as such.
@@ -220,22 +220,22 @@ The string will be checked to be a valid URL, and documented in JSON Schema / Op
You can also use Pydantic models as subtypes of `list`, `set`, etc:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial006.py!}
```Python hl_lines="18"
{!> ../../../docs_src/body_nested_models/tutorial006_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial006_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="18"
{!> ../../../docs_src/body_nested_models/tutorial006_py310.py!}
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial006.py!}
```
This will expect (convert, validate, document, etc) a JSON body like:
@@ -271,22 +271,22 @@ This will expect (convert, validate, document, etc) a JSON body like:
You can define arbitrarily deeply nested models:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="9 14 20 23 27"
{!> ../../../docs_src/body_nested_models/tutorial007.py!}
```Python hl_lines="7 12 18 21 25"
{!> ../../../docs_src/body_nested_models/tutorial007_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="9 14 20 23 27"
{!> ../../../docs_src/body_nested_models/tutorial007_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="7 12 18 21 25"
{!> ../../../docs_src/body_nested_models/tutorial007_py310.py!}
```Python hl_lines="9 14 20 23 27"
{!> ../../../docs_src/body_nested_models/tutorial007.py!}
```
!!! info
@@ -308,18 +308,18 @@ images: list[Image]
as in:
=== "Python 3.6 and above"
```Python hl_lines="15"
{!> ../../../docs_src/body_nested_models/tutorial008.py!}
```
=== "Python 3.9 and above"
=== "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!}
```
## Editor support everywhere
And you get editor support everywhere.
@@ -348,18 +348,18 @@ That's what we are going to see here.
In this case, you would accept any `dict` as long as it has `int` keys with `float` values:
=== "Python 3.6 and above"
```Python hl_lines="9"
{!> ../../../docs_src/body_nested_models/tutorial009.py!}
```
=== "Python 3.9 and above"
=== "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
Have in mind that JSON only supports `str` as keys.

View File

@@ -6,22 +6,22 @@ To update an item you can use the <a href="https://developer.mozilla.org/en-US/d
You can use the `jsonable_encoder` to convert the input data to data that can be stored as JSON (e.g. with a NoSQL database). For example, converting `datetime` to `str`.
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="30-35"
{!> ../../../docs_src/body_updates/tutorial001.py!}
```Python hl_lines="28-33"
{!> ../../../docs_src/body_updates/tutorial001_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="30-35"
{!> ../../../docs_src/body_updates/tutorial001_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="28-33"
{!> ../../../docs_src/body_updates/tutorial001_py310.py!}
```Python hl_lines="30-35"
{!> ../../../docs_src/body_updates/tutorial001.py!}
```
`PUT` is used to receive data that should replace the existing data.
@@ -67,22 +67,22 @@ That would generate a `dict` with only the data that was set when creating the `
Then you can use this to generate a `dict` with only the data that was set (sent in the request), omitting default values:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="34"
{!> ../../../docs_src/body_updates/tutorial002.py!}
```Python hl_lines="32"
{!> ../../../docs_src/body_updates/tutorial002_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="34"
{!> ../../../docs_src/body_updates/tutorial002_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="32"
{!> ../../../docs_src/body_updates/tutorial002_py310.py!}
```Python hl_lines="34"
{!> ../../../docs_src/body_updates/tutorial002.py!}
```
### Using Pydantic's `update` parameter
@@ -91,22 +91,22 @@ Now, you can create a copy of the existing model using `.copy()`, and pass the `
Like `stored_item_model.copy(update=update_data)`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="35"
{!> ../../../docs_src/body_updates/tutorial002.py!}
```Python hl_lines="33"
{!> ../../../docs_src/body_updates/tutorial002_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="35"
{!> ../../../docs_src/body_updates/tutorial002_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="33"
{!> ../../../docs_src/body_updates/tutorial002_py310.py!}
```Python hl_lines="35"
{!> ../../../docs_src/body_updates/tutorial002.py!}
```
### Partial updates recap
@@ -124,22 +124,22 @@ In summary, to apply partial updates you would:
* Save the data to your DB.
* Return the updated model.
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="30-37"
{!> ../../../docs_src/body_updates/tutorial002.py!}
```Python hl_lines="28-35"
{!> ../../../docs_src/body_updates/tutorial002_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="30-37"
{!> ../../../docs_src/body_updates/tutorial002_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="28-35"
{!> ../../../docs_src/body_updates/tutorial002_py310.py!}
```Python hl_lines="30-37"
{!> ../../../docs_src/body_updates/tutorial002.py!}
```
!!! tip

View File

@@ -19,36 +19,36 @@ To declare a **request** body, you use <a href="https://pydantic-docs.helpmanual
First, you need to import `BaseModel` from `pydantic`:
=== "Python 3.6 and above"
```Python hl_lines="4"
{!> ../../../docs_src/body/tutorial001.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="2"
{!> ../../../docs_src/body/tutorial001_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="4"
{!> ../../../docs_src/body/tutorial001.py!}
```
## Create your data model
Then you declare your data model as a class that inherits from `BaseModel`.
Use standard Python types for all the attributes:
=== "Python 3.6 and above"
```Python hl_lines="7-11"
{!> ../../../docs_src/body/tutorial001.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="5-9"
{!> ../../../docs_src/body/tutorial001_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="7-11"
{!> ../../../docs_src/body/tutorial001.py!}
```
The same as when declaring query parameters, when a model attribute has a default value, it is not required. Otherwise, it is required. Use `None` to make it just optional.
For example, this model above declares a JSON "`object`" (or Python `dict`) like:
@@ -75,18 +75,18 @@ For example, this model above declares a JSON "`object`" (or Python `dict`) like
To add it to your *path operation*, declare it the same way you declared path and query parameters:
=== "Python 3.6 and above"
```Python hl_lines="18"
{!> ../../../docs_src/body/tutorial001.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="16"
{!> ../../../docs_src/body/tutorial001_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="18"
{!> ../../../docs_src/body/tutorial001.py!}
```
...and declare its type as the model you created, `Item`.
## Results
@@ -149,54 +149,54 @@ But you would get the same editor support with <a href="https://www.jetbrains.co
Inside of the function, you can access all the attributes of the model object directly:
=== "Python 3.6 and above"
```Python hl_lines="21"
{!> ../../../docs_src/body/tutorial002.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="19"
{!> ../../../docs_src/body/tutorial002_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="21"
{!> ../../../docs_src/body/tutorial002.py!}
```
## Request body + path parameters
You can declare path parameters and request body at the same time.
**FastAPI** will recognize that the function parameters that match path parameters should be **taken from the path**, and that function parameters that are declared to be Pydantic models should be **taken from the request body**.
=== "Python 3.6 and above"
```Python hl_lines="17-18"
{!> ../../../docs_src/body/tutorial003.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="15-16"
{!> ../../../docs_src/body/tutorial003_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="17-18"
{!> ../../../docs_src/body/tutorial003.py!}
```
## Request body + path + query parameters
You can also declare **body**, **path** and **query** parameters, all at the same time.
**FastAPI** will recognize each of them and take the data from the correct place.
=== "Python 3.6 and above"
```Python hl_lines="18"
{!> ../../../docs_src/body/tutorial004.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="16"
{!> ../../../docs_src/body/tutorial004_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="18"
{!> ../../../docs_src/body/tutorial004.py!}
```
The function parameters will be recognized as follows:
* If the parameter is also declared in the **path**, it will be used as a path parameter.

View File

@@ -6,36 +6,84 @@ You can define Cookie parameters the same way you define `Query` and `Path` para
First import `Cookie`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="3"
{!> ../../../docs_src/cookie_params/tutorial001.py!}
{!> ../../../docs_src/cookie_params/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "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
Prefer to use the `Annotated` version if possible.
```Python hl_lines="1"
{!> ../../../docs_src/cookie_params/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="3"
{!> ../../../docs_src/cookie_params/tutorial001.py!}
```
## Declare `Cookie` parameters
Then declare the cookie parameters using the same structure as with `Path` and `Query`.
The first value is the default value, you can pass all the extra validation or annotation parameters:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="9"
{!> ../../../docs_src/cookie_params/tutorial001.py!}
{!> ../../../docs_src/cookie_params/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "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
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/cookie_params/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/cookie_params/tutorial001.py!}
```
!!! note "Technical Details"
`Cookie` is a "sister" class of `Path` and `Query`. It also inherits from the same common `Param` class.

View File

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

View File

@@ -6,18 +6,42 @@ Before diving deeper into the **Dependency Injection** system, let's upgrade the
In the previous example, we were returning a `dict` from our dependency ("dependable"):
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="9"
{!> ../../../docs_src/dependencies/tutorial001.py!}
{!> ../../../docs_src/dependencies/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="11"
{!> ../../../docs_src/dependencies/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="12"
{!> ../../../docs_src/dependencies/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/dependencies/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="11"
{!> ../../../docs_src/dependencies/tutorial001.py!}
```
But then we get a `dict` in the parameter `commons` of the *path operation function*.
And we know that editors can't provide a lot of support (like completion) for `dict`s, because they can't know their keys and value types.
@@ -79,46 +103,118 @@ That also applies to callables with no parameters at all. The same as it would b
Then, we can change the dependency "dependable" `common_parameters` from above to the class `CommonQueryParams`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="11-15"
{!> ../../../docs_src/dependencies/tutorial002.py!}
{!> ../../../docs_src/dependencies/tutorial002_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="11-15"
{!> ../../../docs_src/dependencies/tutorial002_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="12-16"
{!> ../../../docs_src/dependencies/tutorial002_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9-13"
{!> ../../../docs_src/dependencies/tutorial002_py310.py!}
```
Pay attention to the `__init__` method used to create the instance of the class:
=== "Python 3.6+ non-Annotated"
=== "Python 3.6 and above"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="12"
```Python hl_lines="11-15"
{!> ../../../docs_src/dependencies/tutorial002.py!}
```
=== "Python 3.10 and above"
Pay attention to the `__init__` method used to create the instance of the class:
=== "Python 3.10+"
```Python hl_lines="12"
{!> ../../../docs_src/dependencies/tutorial002_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="12"
{!> ../../../docs_src/dependencies/tutorial002_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="13"
{!> ../../../docs_src/dependencies/tutorial002_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="10"
{!> ../../../docs_src/dependencies/tutorial002_py310.py!}
```
...it has the same parameters as our previous `common_parameters`:
=== "Python 3.6+ non-Annotated"
=== "Python 3.6 and above"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/dependencies/tutorial001.py!}
```Python hl_lines="12"
{!> ../../../docs_src/dependencies/tutorial002.py!}
```
=== "Python 3.10 and above"
...it has the same parameters as our previous `common_parameters`:
=== "Python 3.10+"
```Python hl_lines="8"
{!> ../../../docs_src/dependencies/tutorial001_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/dependencies/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="10"
{!> ../../../docs_src/dependencies/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="6"
{!> ../../../docs_src/dependencies/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/dependencies/tutorial001.py!}
```
Those parameters are what **FastAPI** will use to "solve" the dependency.
In both cases, it will have:
@@ -133,32 +229,67 @@ In both cases the data will be converted, validated, documented on the OpenAPI s
Now you can declare your dependency using this class.
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial002.py!}
{!> ../../../docs_src/dependencies/tutorial002_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial002_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="20"
{!> ../../../docs_src/dependencies/tutorial002_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="17"
{!> ../../../docs_src/dependencies/tutorial002_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial002.py!}
```
**FastAPI** calls the `CommonQueryParams` class. This creates an "instance" of that class and the instance will be passed as the parameter `commons` to your function.
## Type annotation vs `Depends`
Notice how we write `CommonQueryParams` twice in the above code:
```Python
commons: CommonQueryParams = Depends(CommonQueryParams)
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python
commons: CommonQueryParams = Depends(CommonQueryParams)
```
=== "Python 3.6+"
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
```
The last `CommonQueryParams`, in:
```Python
... = Depends(CommonQueryParams)
... Depends(CommonQueryParams)
```
...is what **FastAPI** will actually use to know what is the dependency.
@@ -169,32 +300,78 @@ From it is that FastAPI will extract the declared parameters and that is what Fa
In this case, the first `CommonQueryParams`, in:
```Python
commons: CommonQueryParams ...
```
=== "Python 3.6+"
...doesn't have any special meaning for **FastAPI**. FastAPI won't use it for data conversion, validation, etc. (as it is using the `= Depends(CommonQueryParams)` for that).
```Python
commons: Annotated[CommonQueryParams, ...
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python
commons: CommonQueryParams ...
```
...doesn't have any special meaning for **FastAPI**. FastAPI won't use it for data conversion, validation, etc. (as it is using the `Depends(CommonQueryParams)` for that).
You could actually write just:
```Python
commons = Depends(CommonQueryParams)
```
=== "Python 3.6+"
```Python
commons: Annotated[Any, Depends(CommonQueryParams)]
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python
commons = Depends(CommonQueryParams)
```
..as in:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial003.py!}
{!> ../../../docs_src/dependencies/tutorial003_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial003_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="20"
{!> ../../../docs_src/dependencies/tutorial003_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="17"
{!> ../../../docs_src/dependencies/tutorial003_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial003.py!}
```
But declaring the type is encouraged as that way your editor will know what will be passed as the parameter `commons`, and then it can help you with code completion, type checks, etc:
<img src="/img/tutorial/dependencies/image02.png">
@@ -203,9 +380,20 @@ But declaring the type is encouraged as that way your editor will know what will
But you see that we are having some code repetition here, writing `CommonQueryParams` twice:
```Python
commons: CommonQueryParams = Depends(CommonQueryParams)
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python
commons: CommonQueryParams = Depends(CommonQueryParams)
```
=== "Python 3.6+"
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
```
**FastAPI** provides a shortcut for these cases, in where the dependency is *specifically* a class that **FastAPI** will "call" to create an instance of the class itself.
@@ -213,32 +401,78 @@ For those specific cases, you can do the following:
Instead of writing:
```Python
commons: CommonQueryParams = Depends(CommonQueryParams)
```
=== "Python 3.6+"
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python
commons: CommonQueryParams = Depends(CommonQueryParams)
```
...you write:
```Python
commons: CommonQueryParams = Depends()
```
=== "Python 3.6+"
You declare the dependency as the type of the parameter, and you use `Depends()` as its "default" value (that after the `=`) for that function's parameter, without any parameter in `Depends()`, instead of having to write the full class *again* inside of `Depends(CommonQueryParams)`.
```Python
commons: Annotated[CommonQueryParams, Depends()]
```
=== "Python 3.6 non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python
commons: CommonQueryParams = Depends()
```
You declare the dependency as the type of the parameter, and you use `Depends()` without any parameter, instead of having to write the full class *again* inside of `Depends(CommonQueryParams)`.
The same example would then look like:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial004.py!}
{!> ../../../docs_src/dependencies/tutorial004_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial004_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="20"
{!> ../../../docs_src/dependencies/tutorial004_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="17"
{!> ../../../docs_src/dependencies/tutorial004_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial004.py!}
```
...and **FastAPI** will know what to do.
!!! tip

View File

@@ -14,9 +14,26 @@ The *path operation decorator* receives an optional argument `dependencies`.
It should be a `list` of `Depends()`:
```Python hl_lines="17"
{!../../../docs_src/dependencies/tutorial006.py!}
```
=== "Python 3.9+"
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial006_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="18"
{!> ../../../docs_src/dependencies/tutorial006_an.py!}
```
=== "Python 3.6 non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="17"
{!> ../../../docs_src/dependencies/tutorial006.py!}
```
These dependencies will be executed/solved the same way normal dependencies. But their value (if they return any) won't be passed to your *path operation function*.
@@ -40,17 +57,51 @@ You can use the same dependency *functions* you use normally.
They can declare request requirements (like headers) or other sub-dependencies:
```Python hl_lines="6 11"
{!../../../docs_src/dependencies/tutorial006.py!}
```
=== "Python 3.9+"
```Python hl_lines="8 13"
{!> ../../../docs_src/dependencies/tutorial006_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="7 12"
{!> ../../../docs_src/dependencies/tutorial006_an.py!}
```
=== "Python 3.6 non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="6 11"
{!> ../../../docs_src/dependencies/tutorial006.py!}
```
### Raise exceptions
These dependencies can `raise` exceptions, the same as normal dependencies:
```Python hl_lines="8 13"
{!../../../docs_src/dependencies/tutorial006.py!}
```
=== "Python 3.9+"
```Python hl_lines="10 15"
{!> ../../../docs_src/dependencies/tutorial006_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9 14"
{!> ../../../docs_src/dependencies/tutorial006_an.py!}
```
=== "Python 3.6 non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="8 13"
{!> ../../../docs_src/dependencies/tutorial006.py!}
```
### Return values
@@ -58,9 +109,26 @@ And they can return values or not, the values won't be used.
So, you can re-use a normal dependency (that returns a value) you already use somewhere else, and even though the value won't be used, the dependency will be executed:
```Python hl_lines="9 14"
{!../../../docs_src/dependencies/tutorial006.py!}
```
=== "Python 3.9+"
```Python hl_lines="11 16"
{!> ../../../docs_src/dependencies/tutorial006_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="10 15"
{!> ../../../docs_src/dependencies/tutorial006_an.py!}
```
=== "Python 3.6 non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9 14"
{!> ../../../docs_src/dependencies/tutorial006.py!}
```
## Dependencies for a group of *path operations*

View File

@@ -66,9 +66,26 @@ You can have sub-dependencies and "trees" of sub-dependencies of any size and sh
For example, `dependency_c` can have a dependency on `dependency_b`, and `dependency_b` on `dependency_a`:
```Python hl_lines="4 12 20"
{!../../../docs_src/dependencies/tutorial008.py!}
```
=== "Python 3.9+"
```Python hl_lines="6 14 22"
{!> ../../../docs_src/dependencies/tutorial008_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="5 13 21"
{!> ../../../docs_src/dependencies/tutorial008_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="4 12 20"
{!> ../../../docs_src/dependencies/tutorial008.py!}
```
And all of them can use `yield`.
@@ -76,9 +93,26 @@ In this case `dependency_c`, to execute its exit code, needs the value from `dep
And, in turn, `dependency_b` needs the value from `dependency_a` (here named `dep_a`) to be available for its exit code.
```Python hl_lines="16-17 24-25"
{!../../../docs_src/dependencies/tutorial008.py!}
```
=== "Python 3.9+"
```Python hl_lines="18-19 26-27"
{!> ../../../docs_src/dependencies/tutorial008_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="17-18 25-26"
{!> ../../../docs_src/dependencies/tutorial008_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="16-17 24-25"
{!> ../../../docs_src/dependencies/tutorial008.py!}
```
The same way, you could have dependencies with `yield` and `return` mixed.

View File

@@ -6,9 +6,26 @@ Similar to the way you can [add `dependencies` to the *path operation decorators
In that case, they will be applied to all the *path operations* in the application:
```Python hl_lines="15"
{!../../../docs_src/dependencies/tutorial012.py!}
```
=== "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
Prefer to use the `Annotated` version if possible.
```Python hl_lines="15"
{!> ../../../docs_src/dependencies/tutorial012.py!}
```
And all the ideas in the section about [adding `dependencies` to the *path operation decorators*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} still apply, but in this case, to all of the *path operations* in the app.

View File

@@ -31,18 +31,42 @@ Let's first focus on the dependency.
It is just a function that can take all the same parameters that a *path operation function* can take:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="8-11"
{!> ../../../docs_src/dependencies/tutorial001.py!}
```Python hl_lines="8-9"
{!> ../../../docs_src/dependencies/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="8-11"
{!> ../../../docs_src/dependencies/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9-12"
{!> ../../../docs_src/dependencies/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="6-7"
{!> ../../../docs_src/dependencies/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="8-11"
{!> ../../../docs_src/dependencies/tutorial001.py!}
```
That's it.
**2 lines**.
@@ -63,40 +87,90 @@ And then it just returns a `dict` containing those values.
### Import `Depends`
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="3"
{!> ../../../docs_src/dependencies/tutorial001.py!}
{!> ../../../docs_src/dependencies/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="3"
{!> ../../../docs_src/dependencies/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="3"
{!> ../../../docs_src/dependencies/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="1"
{!> ../../../docs_src/dependencies/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="3"
{!> ../../../docs_src/dependencies/tutorial001.py!}
```
### Declare the dependency, in the "dependant"
The same way you use `Body`, `Query`, etc. with your *path operation function* parameters, use `Depends` with a new parameter:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="15 20"
{!> ../../../docs_src/dependencies/tutorial001.py!}
```Python hl_lines="13 18"
{!> ../../../docs_src/dependencies/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="15 20"
{!> ../../../docs_src/dependencies/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="16 21"
{!> ../../../docs_src/dependencies/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="11 16"
{!> ../../../docs_src/dependencies/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="15 20"
{!> ../../../docs_src/dependencies/tutorial001.py!}
```
Although you use `Depends` in the parameters of your function the same way you use `Body`, `Query`, etc, `Depends` works a bit differently.
You only give `Depends` a single parameter.
This parameter must be something like a function.
You **don't call it** directly (don't add the parenthesis at the end), you just pass it as a parameter to `Depends()`.
And that function takes parameters in the same way that *path operation functions* do.
!!! tip
@@ -126,6 +200,45 @@ This way you write shared code once and **FastAPI** takes care of calling it for
You just pass it to `Depends` and **FastAPI** knows how to do the rest.
## Share `Annotated` dependencies
In the examples above, you see that there's a tiny bit of **code duplication**.
When you need to use the `common_parameters()` dependency, you have to write the whole parameter with the type annotation and `Depends()`:
```Python
commons: Annotated[dict, Depends(common_parameters)]
```
But because we are using `Annotated`, we can store that `Annotated` value in a variable and use it in multiple places:
=== "Python 3.10+"
```Python hl_lines="12 16 21"
{!> ../../../docs_src/dependencies/tutorial001_02_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="14 18 23"
{!> ../../../docs_src/dependencies/tutorial001_02_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="15 19 24"
{!> ../../../docs_src/dependencies/tutorial001_02_an.py!}
```
!!! tip
This is just standard Python, it's called a "type alias", it's actually not specific to **FastAPI**.
But because **FastAPI** is based on the Python standards, including `Annotated`, you can use this trick in your code. 😎
The dependencies will keep working as expected, and the **best part** is that the **type information will be preserved**, which means that your editor will be able to keep providing you with **autocompletion**, **inline errors**, etc. The same for other tools like `mypy`.
This will be especially useful when you use it in a **large code base** where you use **the same dependencies** over and over again in **many *path operations***.
## To `async` or not to `async`
As dependencies will also be called by **FastAPI** (the same as your *path operation functions*), the same rules apply while defining your functions.

View File

@@ -10,18 +10,42 @@ They can be as **deep** as you need them to be.
You could create a first dependency ("dependable") like:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="8-9"
{!> ../../../docs_src/dependencies/tutorial005.py!}
{!> ../../../docs_src/dependencies/tutorial005_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="8-9"
{!> ../../../docs_src/dependencies/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9-10"
{!> ../../../docs_src/dependencies/tutorial005_an.py!}
```
=== "Python 3.10 non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="6-7"
{!> ../../../docs_src/dependencies/tutorial005_py310.py!}
```
=== "Python 3.6 non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="8-9"
{!> ../../../docs_src/dependencies/tutorial005.py!}
```
It declares an optional query parameter `q` as a `str`, and then it just returns it.
This is quite simple (not very useful), but will help us focus on how the sub-dependencies work.
@@ -30,18 +54,42 @@ This is quite simple (not very useful), but will help us focus on how the sub-de
Then you can create another dependency function (a "dependable") that at the same time declares a dependency of its own (so it is a "dependant" too):
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="13"
{!> ../../../docs_src/dependencies/tutorial005.py!}
{!> ../../../docs_src/dependencies/tutorial005_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="13"
{!> ../../../docs_src/dependencies/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="14"
{!> ../../../docs_src/dependencies/tutorial005_an.py!}
```
=== "Python 3.10 non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="11"
{!> ../../../docs_src/dependencies/tutorial005_py310.py!}
```
=== "Python 3.6 non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="13"
{!> ../../../docs_src/dependencies/tutorial005.py!}
```
Let's focus on the parameters declared:
* Even though this function is a dependency ("dependable") itself, it also declares another dependency (it "depends" on something else).
@@ -53,18 +101,42 @@ Let's focus on the parameters declared:
Then we can use the dependency with:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="22"
{!> ../../../docs_src/dependencies/tutorial005.py!}
```Python hl_lines="23"
{!> ../../../docs_src/dependencies/tutorial005_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="23"
{!> ../../../docs_src/dependencies/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="24"
{!> ../../../docs_src/dependencies/tutorial005_an.py!}
```
=== "Python 3.10 non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial005_py310.py!}
```
=== "Python 3.6 non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="22"
{!> ../../../docs_src/dependencies/tutorial005.py!}
```
!!! info
Notice that we are only declaring one dependency in the *path operation function*, the `query_or_cookie_extractor`.
@@ -89,10 +161,22 @@ And it will save the returned value in a <abbr title="A utility/system to store
In an advanced scenario where you know you need the dependency to be called at every step (possibly multiple times) in the same request instead of using the "cached" value, you can set the parameter `use_cache=False` when using `Depends`:
```Python hl_lines="1"
async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
return {"fresh_value": fresh_value}
```
=== "Python 3.6+"
```Python hl_lines="1"
async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
return {"fresh_value": fresh_value}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="1"
async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
return {"fresh_value": fresh_value}
```
## Recap

View File

@@ -20,18 +20,18 @@ You can use `jsonable_encoder` for that.
It receives an object, like a Pydantic model, and returns a JSON compatible version:
=== "Python 3.6 and above"
```Python hl_lines="5 22"
{!> ../../../docs_src/encoder/tutorial001.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="4 21"
{!> ../../../docs_src/encoder/tutorial001_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="5 22"
{!> ../../../docs_src/encoder/tutorial001.py!}
```
In this example, it would convert the Pydantic model to a `dict`, and the `datetime` to a `str`.
The result of calling it is something that can be encoded with the Python standard <a href="https://docs.python.org/3/library/json.html#json.dumps" class="external-link" target="_blank">`json.dumps()`</a>.

View File

@@ -55,28 +55,76 @@ Here are some of the additional data types you can use:
Here's an example *path operation* with parameters using some of the above types.
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="1 3 12-16"
{!> ../../../docs_src/extra_data_types/tutorial001.py!}
{!> ../../../docs_src/extra_data_types/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="1 3 12-16"
{!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 3 13-17"
{!> ../../../docs_src/extra_data_types/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="1 2 11-15"
{!> ../../../docs_src/extra_data_types/tutorial001_py310.py!}
```
Note that the parameters inside the function have their natural data type, and you can, for example, perform normal date manipulations, like:
=== "Python 3.6+ non-Annotated"
=== "Python 3.6 and above"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="18-19"
```Python hl_lines="1 2 12-16"
{!> ../../../docs_src/extra_data_types/tutorial001.py!}
```
=== "Python 3.10 and above"
Note that the parameters inside the function have their natural data type, and you can, for example, perform normal date manipulations, like:
=== "Python 3.10+"
```Python hl_lines="18-19"
{!> ../../../docs_src/extra_data_types/tutorial001_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="18-19"
{!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="19-20"
{!> ../../../docs_src/extra_data_types/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="17-18"
{!> ../../../docs_src/extra_data_types/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="18-19"
{!> ../../../docs_src/extra_data_types/tutorial001.py!}
```

View File

@@ -17,18 +17,18 @@ This is especially the case for user models, because:
Here's a general idea of how the models could look like with their password fields and the places where they are used:
=== "Python 3.6 and above"
```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
{!> ../../../docs_src/extra_models/tutorial001.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="7 9 14 20 22 27-28 31-33 38-39"
{!> ../../../docs_src/extra_models/tutorial001_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
{!> ../../../docs_src/extra_models/tutorial001.py!}
```
### About `**user_in.dict()`
#### Pydantic's `.dict()`
@@ -158,18 +158,18 @@ All the data conversion, validation, documentation, etc. will still work as norm
That way, we can declare just the differences between the models (with plaintext `password`, with `hashed_password` and without password):
=== "Python 3.6 and above"
```Python hl_lines="9 15-16 19-20 23-24"
{!> ../../../docs_src/extra_models/tutorial002.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="7 13-14 17-18 21-22"
{!> ../../../docs_src/extra_models/tutorial002_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="9 15-16 19-20 23-24"
{!> ../../../docs_src/extra_models/tutorial002.py!}
```
## `Union` or `anyOf`
You can declare a response to be the `Union` of two types, that means, that the response would be any of the two.
@@ -181,18 +181,18 @@ To do that, use the standard Python type hint <a href="https://docs.python.org/3
!!! note
When defining a <a href="https://pydantic-docs.helpmanual.io/usage/types/#unions" class="external-link" target="_blank">`Union`</a>, include the most specific type first, followed by the less specific type. In the example below, the more specific `PlaneItem` comes before `CarItem` in `Union[PlaneItem, CarItem]`.
=== "Python 3.6 and above"
```Python hl_lines="1 14-15 18-20 33"
{!> ../../../docs_src/extra_models/tutorial003.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="1 14-15 18-20 33"
{!> ../../../docs_src/extra_models/tutorial003_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 14-15 18-20 33"
{!> ../../../docs_src/extra_models/tutorial003.py!}
```
### `Union` in Python 3.10
In this example we pass `Union[PlaneItem, CarItem]` as the value of the argument `response_model`.
@@ -213,18 +213,18 @@ The same way, you can declare responses of lists of objects.
For that, use the standard Python `typing.List` (or just `list` in Python 3.9 and above):
=== "Python 3.6 and above"
```Python hl_lines="1 20"
{!> ../../../docs_src/extra_models/tutorial004.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="18"
{!> ../../../docs_src/extra_models/tutorial004_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 20"
{!> ../../../docs_src/extra_models/tutorial004.py!}
```
## Response with arbitrary `dict`
You can also declare a response using a plain arbitrary `dict`, declaring just the type of the keys and values, without using a Pydantic model.
@@ -233,18 +233,18 @@ This is useful if you don't know the valid field/attribute names (that would be
In this case, you can use `typing.Dict` (or just `dict` in Python 3.9 and above):
=== "Python 3.6 and above"
```Python hl_lines="1 8"
{!> ../../../docs_src/extra_models/tutorial005.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="6"
{!> ../../../docs_src/extra_models/tutorial005_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 8"
{!> ../../../docs_src/extra_models/tutorial005.py!}
```
## Recap
Use multiple Pydantic models and inherit freely for each case.

View File

@@ -6,36 +6,84 @@ You can define Header parameters the same way you define `Query`, `Path` and `Co
First import `Header`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="3"
{!> ../../../docs_src/header_params/tutorial001.py!}
{!> ../../../docs_src/header_params/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="3"
{!> ../../../docs_src/header_params/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="3"
{!> ../../../docs_src/header_params/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="1"
{!> ../../../docs_src/header_params/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="3"
{!> ../../../docs_src/header_params/tutorial001.py!}
```
## Declare `Header` parameters
Then declare the header parameters using the same structure as with `Path`, `Query` and `Cookie`.
The first value is the default value, you can pass all the extra validation or annotation parameters:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="9"
{!> ../../../docs_src/header_params/tutorial001.py!}
{!> ../../../docs_src/header_params/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/header_params/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="10"
{!> ../../../docs_src/header_params/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/header_params/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/header_params/tutorial001.py!}
```
!!! note "Technical Details"
`Header` is a "sister" class of `Path`, `Query` and `Cookie`. It also inherits from the same common `Param` class.
@@ -60,18 +108,42 @@ So, you can use `user_agent` as you normally would in Python code, instead of ne
If for some reason you need to disable automatic conversion of underscores to hyphens, set the parameter `convert_underscores` of `Header` to `False`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="10"
{!> ../../../docs_src/header_params/tutorial002.py!}
{!> ../../../docs_src/header_params/tutorial002_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="11"
{!> ../../../docs_src/header_params/tutorial002_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="12"
{!> ../../../docs_src/header_params/tutorial002_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="8"
{!> ../../../docs_src/header_params/tutorial002_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="10"
{!> ../../../docs_src/header_params/tutorial002.py!}
```
!!! warning
Before setting `convert_underscores` to `False`, bear in mind that some HTTP proxies and servers disallow the usage of headers with underscores.
@@ -85,22 +157,49 @@ You will receive all the values from the duplicate header as a Python `list`.
For example, to declare a header of `X-Token` that can appear more than once, you can write:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="9"
{!> ../../../docs_src/header_params/tutorial003.py!}
{!> ../../../docs_src/header_params/tutorial003_an_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/header_params/tutorial003_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="10"
{!> ../../../docs_src/header_params/tutorial003_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/header_params/tutorial003_py310.py!}
```
=== "Python 3.9+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/header_params/tutorial003_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+ non-Annotated"
```Python hl_lines="7"
{!> ../../../docs_src/header_params/tutorial003_py310.py!}
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/header_params/tutorial003.py!}
```
If you communicate with that *path operation* sending two HTTP headers like:

View File

@@ -101,7 +101,7 @@ You can configure the two documentation user interfaces included:
* **Swagger UI**: served at `/docs`.
* You can set its URL with the parameter `docs_url`.
* You can disable it by setting `docs_url=None`.
* ReDoc: served at `/redoc`.
* **ReDoc**: served at `/redoc`.
* You can set its URL with the parameter `redoc_url`.
* You can disable it by setting `redoc_url=None`.

View File

@@ -13,22 +13,22 @@ You can pass directly the `int` code, like `404`.
But if you don't remember what each number code is for, you can use the shortcut constants in `status`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="3 17"
{!> ../../../docs_src/path_operation_configuration/tutorial001.py!}
```Python hl_lines="1 15"
{!> ../../../docs_src/path_operation_configuration/tutorial001_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="3 17"
{!> ../../../docs_src/path_operation_configuration/tutorial001_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="1 15"
{!> ../../../docs_src/path_operation_configuration/tutorial001_py310.py!}
```Python hl_lines="3 17"
{!> ../../../docs_src/path_operation_configuration/tutorial001.py!}
```
That status code will be used in the response and will be added to the OpenAPI schema.
@@ -42,22 +42,22 @@ That status code will be used in the response and will be added to the OpenAPI s
You can add tags to your *path operation*, pass the parameter `tags` with a `list` of `str` (commonly just one `str`):
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="17 22 27"
{!> ../../../docs_src/path_operation_configuration/tutorial002.py!}
```Python hl_lines="15 20 25"
{!> ../../../docs_src/path_operation_configuration/tutorial002_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="17 22 27"
{!> ../../../docs_src/path_operation_configuration/tutorial002_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="15 20 25"
{!> ../../../docs_src/path_operation_configuration/tutorial002_py310.py!}
```Python hl_lines="17 22 27"
{!> ../../../docs_src/path_operation_configuration/tutorial002.py!}
```
They will be added to the OpenAPI schema and used by the automatic documentation interfaces:
@@ -80,22 +80,22 @@ In these cases, it could make sense to store the tags in an `Enum`.
You can add a `summary` and `description`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="20-21"
{!> ../../../docs_src/path_operation_configuration/tutorial003.py!}
```Python hl_lines="18-19"
{!> ../../../docs_src/path_operation_configuration/tutorial003_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="20-21"
{!> ../../../docs_src/path_operation_configuration/tutorial003_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="18-19"
{!> ../../../docs_src/path_operation_configuration/tutorial003_py310.py!}
```Python hl_lines="20-21"
{!> ../../../docs_src/path_operation_configuration/tutorial003.py!}
```
## Description from docstring
@@ -104,22 +104,22 @@ As descriptions tend to be long and cover multiple lines, you can declare the *p
You can write <a href="https://en.wikipedia.org/wiki/Markdown" class="external-link" target="_blank">Markdown</a> in the docstring, it will be interpreted and displayed correctly (taking into account docstring indentation).
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="19-27"
{!> ../../../docs_src/path_operation_configuration/tutorial004.py!}
```Python hl_lines="17-25"
{!> ../../../docs_src/path_operation_configuration/tutorial004_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="19-27"
{!> ../../../docs_src/path_operation_configuration/tutorial004_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="17-25"
{!> ../../../docs_src/path_operation_configuration/tutorial004_py310.py!}
```Python hl_lines="19-27"
{!> ../../../docs_src/path_operation_configuration/tutorial004.py!}
```
It will be used in the interactive docs:
@@ -130,22 +130,22 @@ It will be used in the interactive docs:
You can specify the response description with the parameter `response_description`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="21"
{!> ../../../docs_src/path_operation_configuration/tutorial005.py!}
```Python hl_lines="19"
{!> ../../../docs_src/path_operation_configuration/tutorial005_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="21"
{!> ../../../docs_src/path_operation_configuration/tutorial005_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="19"
{!> ../../../docs_src/path_operation_configuration/tutorial005_py310.py!}
```Python hl_lines="21"
{!> ../../../docs_src/path_operation_configuration/tutorial005.py!}
```
!!! info

View File

@@ -4,38 +4,86 @@ In the same way that you can declare more validations and metadata for query par
## Import Path
First, import `Path` from `fastapi`:
First, import `Path` from `fastapi`, and import `Annotated`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="3"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
```Python hl_lines="1 3"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="1 3"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="3-4"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="1"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="3"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
```
## Declare metadata
You can declare all the same parameters as for `Query`.
For example, to declare a `title` metadata value for the path parameter `item_id` you can type:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="10"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="10"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="11"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="8"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="10"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
```
!!! note
A path parameter is always required as it has to be part of the path.
@@ -45,11 +93,14 @@ For example, to declare a `title` metadata value for the path parameter `item_id
## Order the parameters as you need
!!! tip
This is probably not as important or necessary if you use `Annotated`.
Let's say that you want to declare the query parameter `q` as a required `str`.
And you don't need to declare anything else for that parameter, so you don't really need to use `Query`.
But you still need to use `Path` for the `item_id` path parameter.
But you still need to use `Path` for the `item_id` path parameter. And you don't want to use `Annotated` for some reason.
Python will complain if you put a value with a "default" before a value that doesn't have a "default".
@@ -59,13 +110,44 @@ It doesn't matter for **FastAPI**. It will detect the parameters by their names,
So, you can declare your function as:
```Python hl_lines="7"
{!../../../docs_src/path_params_numeric_validations/tutorial002.py!}
```
=== "Python 3.6 non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/path_params_numeric_validations/tutorial002.py!}
```
But have in mind that if you use `Annotated`, you won't have this problem, it won't matter as you're not using the function parameter default values for `Query()` or `Path()`.
=== "Python 3.9+"
```Python hl_lines="10"
{!> ../../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9"
{!> ../../../docs_src/path_params_numeric_validations/tutorial002_an.py!}
```
## Order the parameters as you need, tricks
If you want to declare the `q` query parameter without a `Query` nor any default value, and the path parameter `item_id` using `Path`, and have them in a different order, Python has a little special syntax for that.
!!! tip
This is probably not as important or necessary if you use `Annotated`.
Here's a **small trick** that can be handy, but you won't need it often.
If you want to:
* declare the `q` query parameter without a `Query` nor any default value
* declare the path parameter `item_id` using `Path`
* have them in a different order
* not use `Annotated`
...Python has a little special syntax for that.
Pass `*`, as the first parameter of the function.
@@ -75,15 +157,48 @@ Python won't do anything with that `*`, but it will know that all the following
{!../../../docs_src/path_params_numeric_validations/tutorial003.py!}
```
### Better with `Annotated`
Have in mind that if you use `Annotated`, as you are not using function parameter default values, you won't have this problem, and yo probably won't need to use `*`.
=== "Python 3.9+"
```Python hl_lines="10"
{!> ../../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9"
{!> ../../../docs_src/path_params_numeric_validations/tutorial003_an.py!}
```
## Number validations: greater than or equal
With `Query` and `Path` (and others you'll see later) you can declare number constraints.
Here, with `ge=1`, `item_id` will need to be an integer number "`g`reater than or `e`qual" to `1`.
```Python hl_lines="8"
{!../../../docs_src/path_params_numeric_validations/tutorial004.py!}
```
=== "Python 3.9+"
```Python hl_lines="10"
{!> ../../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9"
{!> ../../../docs_src/path_params_numeric_validations/tutorial004_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="8"
{!> ../../../docs_src/path_params_numeric_validations/tutorial004.py!}
```
## Number validations: greater than and less than or equal
@@ -92,9 +207,26 @@ The same applies for:
* `gt`: `g`reater `t`han
* `le`: `l`ess than or `e`qual
```Python hl_lines="9"
{!../../../docs_src/path_params_numeric_validations/tutorial005.py!}
```
=== "Python 3.9+"
```Python hl_lines="10"
{!> ../../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9"
{!> ../../../docs_src/path_params_numeric_validations/tutorial005_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/path_params_numeric_validations/tutorial005.py!}
```
## Number validations: floats, greater than and less than
@@ -106,9 +238,26 @@ So, `0.5` would be a valid value. But `0.0` or `0` would not.
And the same for <abbr title="less than"><code>lt</code></abbr>.
```Python hl_lines="11"
{!../../../docs_src/path_params_numeric_validations/tutorial006.py!}
```
=== "Python 3.9+"
```Python hl_lines="13"
{!> ../../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="12"
{!> ../../../docs_src/path_params_numeric_validations/tutorial006_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="11"
{!> ../../../docs_src/path_params_numeric_validations/tutorial006.py!}
```
## Recap

View File

@@ -4,18 +4,18 @@
Let's take this application as example:
=== "Python 3.6 and above"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial001.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial001.py!}
```
The query parameter `q` is of type `Union[str, None]` (or `str | None` in Python 3.10), that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required.
!!! note
@@ -27,39 +27,117 @@ The query parameter `q` is of type `Union[str, None]` (or `str | None` in Python
We are going to enforce that even though `q` is optional, whenever it is provided, **its length doesn't exceed 50 characters**.
### Import `Query`
### Import `Query` and `Annotated`
To achieve that, first import `Query` from `fastapi`:
To achieve that, first import:
=== "Python 3.6 and above"
* `Query` from `fastapi`
* `Annotated` from `typing` (or from `typing_extensions` in Python below 3.9)
```Python hl_lines="3"
{!> ../../../docs_src/query_params_str_validations/tutorial002.py!}
=== "Python 3.10+"
In Python 3.9 or above, `Annotated` is part of the standard library, so you can import it from `typing`.
```Python hl_lines="1 3"
{!> ../../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="1"
{!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!}
In versions of Python below Python 3.9 you import `Annotation` from `typing_extensions`.
It will already be installed with FastAPI.
```Python hl_lines="3-4"
{!> ../../../docs_src/query_params_str_validations/tutorial002_an.py!}
```
## Use `Query` as the default value
## Use `Annotated` in the type for the `q` parameter
And now use it as the default value of your parameter, setting the parameter `max_length` to 50:
Remember I told you before that `Annotated` can be used to add metadata to your parameters in the [Python Types Intro](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?
=== "Python 3.6 and above"
Now it's the time to use it with FastAPI. 🚀
We had this type annotation:
=== "Python 3.10+"
```Python
q: str | None = None
```
=== "Python 3.6+"
```Python
q: Union[str, None] = None
```
What we will do is wrap that with `Annotated`, so it becomes:
=== "Python 3.10+"
```Python
q: Annotated[str | None] = None
```
=== "Python 3.6+"
```Python
q: Annotated[Union[str, None]] = None
```
Both of those versions mean the same thing, `q` is a parameter that can be a `str` or `None`, and by default, it is `None`.
Now let's jump to the fun stuff. 🎉
## Add `Query` to `Annotated` in the `q` parameter
Now that we have this `Annotated` where we can put more metadata, add `Query` to it, and set the parameter `max_length` to 50:
=== "Python 3.10+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial002.py!}
{!> ../../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial002_an.py!}
```
Notice that the default value is still `None`, so the parameter is still optional.
But now, having `Query(max_length=50)` inside of `Annotated`, we are telling FastAPI that we want it to extract this value from the query parameters (this would have been the default anyway 🤷) and that we want to have **additional validation** for this value (that's why we do this, to get the additional validation). 😎
FastAPI wll now:
* **Validate** the data making sure that the max length is 50 characters
* Show a **clear error** for the client when the data is not valid
* **Document** the parameter in the OpenAPI schema *path operation* (so it will show up in the **automatic docs UI**)
## Alternative (old) `Query` as the default value
Previous versions of FastAPI (before <abbr title="before 2023-03">0.95.0</abbr>) required you to use `Query` as the default value of your parameter, instead of putting it in `Annotated`, there's a high chance that you will see code using it around, so I'll explain it to you.
!!! tip
For new code and whenever possible, use `Annotated` as explained above. There are multiple advantages (explained below) and no disadvantages. 🍰
This is how you would use `Query()` as the default value of your function parameter, setting the parameter `max_length` to 50:
=== "Python 3.10+"
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!}
```
As we have to replace the default value `None` in the function with `Query()`, we can now set the default value with the parameter `Query(default=None)`, it serves the same purpose of defining that default value.
=== "Python 3.6+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial002.py!}
```
As in this case (without using `Annotated`) we have to replace the default value `None` in the function with `Query()`, we now need to set the default value with the parameter `Query(default=None)`, it serves the same purpose of defining that default value (at least for FastAPI).
So:
@@ -67,7 +145,7 @@ So:
q: Union[str, None] = Query(default=None)
```
...makes the parameter optional, the same as:
...makes the parameter optional, with a default value of `None`, the same as:
```Python
q: Union[str, None] = None
@@ -79,7 +157,7 @@ And in Python 3.10 and above:
q: str | None = Query(default=None)
```
...makes the parameter optional, the same as:
...makes the parameter optional, with a default value of `None`, the same as:
```Python
q: str | None = None
@@ -112,38 +190,124 @@ q: Union[str, None] = Query(default=None, max_length=50)
This will validate the data, show a clear error when the data is not valid, and document the parameter in the OpenAPI schema *path operation*.
### `Query` as the default value or in `Annotated`
Have in mind that when using `Query` inside of `Annotated` you cannot use the `default` parameter for `Query`.
Instead use the actual default value of the function parameter. Otherwise, it would be inconsistent.
For example, this is not allowed:
```Python
q: Annotated[str Query(default="rick")] = "morty"
```
...because it's not clear if the default value should be `"rick"` or `"morty"`.
So, you would use (preferably):
```Python
q: Annotated[str, Query()] = "rick"
```
...or in older code bases you will find:
```Python
q: str = Query(default="rick")
```
### Advantages of `Annotated`
**Using `Annotated` is recommended** instead of the default value in function parameters, it is **better** for multiple reasons. 🤓
The **default** value of the **function parameter** is the **actual default** value, that's more intuitive with Python in general. 😌
You could **call** that same function in **other places** without FastAPI, and it would **work as expected**. If there's a **required** parameter (without a default value), your **editor** will let you know with an error, **Python** will also complain if you run it without passing the required parameter.
When you don't use `Annotated` and instead use the **(old) default value style**, if you call that function without FastAPI in **other place**, you have to **remember** to pass the arguments to the function for it to work correctly, otherwise the values will be different from what you expect (e.g. `QueryInfo` or something similar instead of `str`). And your editor won't complain, and Python won't complain running that function, only when the operations inside error out.
Because `Annotated` can have more than one metadata annotation, you could now even use the same function with other tools, like <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a>. 🚀
## Add more validations
You can also add a parameter `min_length`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial003.py!}
{!> ../../../docs_src/query_params_str_validations/tutorial003_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial003_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="11"
{!> ../../../docs_src/query_params_str_validations/tutorial003_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial003_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial003.py!}
```
## 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:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="11"
{!> ../../../docs_src/query_params_str_validations/tutorial004.py!}
{!> ../../../docs_src/query_params_str_validations/tutorial004_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="11"
{!> ../../../docs_src/query_params_str_validations/tutorial004_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="12"
{!> ../../../docs_src/query_params_str_validations/tutorial004_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial004_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="11"
{!> ../../../docs_src/query_params_str_validations/tutorial004.py!}
```
This specific regular expression checks that the received parameter value:
* `^`: starts with the following characters, doesn't have characters before.
@@ -156,16 +320,33 @@ But whenever you need them and go and learn them, know that you can already use
## Default values
The same way that you can pass `None` as the value for the `default` parameter, you can pass other values.
You can, of course, use default values other than `None`.
Let's say that you want to declare the `q` query parameter to have a `min_length` of `3`, and to have a default value of `"fixedquery"`:
```Python hl_lines="7"
{!../../../docs_src/query_params_str_validations/tutorial005.py!}
```
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial005_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial005_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial005.py!}
```
!!! note
Having a default value also makes the parameter optional.
Having a default value of any type, including `None`, makes the parameter optional (not required).
## Make it required
@@ -183,23 +364,70 @@ q: Union[str, None] = None
But we are now declaring it with `Query`, for example like:
```Python
q: Union[str, None] = Query(default=None, min_length=3)
```
=== "Annotated"
```Python
q: Annotated[Union[str, None], Query(min_length=3)] = None
```
=== "non-Annotated"
```Python
q: Union[str, None] = Query(default=None, min_length=3)
```
So, when you need to declare a value as required while using `Query`, you can simply not declare a default value:
```Python hl_lines="7"
{!../../../docs_src/query_params_str_validations/tutorial006.py!}
```
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial006_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial006_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial006.py!}
```
!!! tip
Notice that, even though in this case the `Query()` is used as the function parameter default value, we don't pass the `default=None` to `Query()`.
Still, probably better to use the `Annotated` version. 😉
### Required with Ellipsis (`...`)
There's an alternative way to explicitly declare that a value is required. You can set the `default` parameter to the literal value `...`:
There's an alternative way to explicitly declare that a value is required. You can set the default to the literal value `...`:
```Python hl_lines="7"
{!../../../docs_src/query_params_str_validations/tutorial006b.py!}
```
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial006b_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial006b_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial006b.py!}
```
!!! info
If you hadn't seen that `...` before: it is a special single value, it is <a href="https://docs.python.org/3/library/constants.html#Ellipsis" class="external-link" target="_blank">part of Python and is called "Ellipsis"</a>.
@@ -212,20 +440,44 @@ This will let **FastAPI** know that this parameter is required.
You can declare that a parameter can accept `None`, but that it's still required. This would force clients to send a value, even if the value is `None`.
To do that, you can declare that `None` is a valid type but still use `default=...`:
To do that, you can declare that `None` is a valid type but still use `...` as the default:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial006c.py!}
{!> ../../../docs_src/query_params_str_validations/tutorial006c_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial006c_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial006c_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial006c_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial006c.py!}
```
!!! tip
Pydantic, which is what powers all the data validation and serialization in FastAPI, has a special behavior when you use `Optional` or `Union[Something, None]` without a default value, you can read more about it in the Pydantic docs about <a href="https://pydantic-docs.helpmanual.io/usage/models/#required-optional-fields" class="external-link" target="_blank">Required Optional fields</a>.
@@ -233,12 +485,29 @@ To do that, you can declare that `None` is a valid type but still use `default=.
If you feel uncomfortable using `...`, you can also import and use `Required` from Pydantic:
```Python hl_lines="2 8"
{!../../../docs_src/query_params_str_validations/tutorial006d.py!}
```
=== "Python 3.9+"
```Python hl_lines="4 10"
{!> ../../../docs_src/query_params_str_validations/tutorial006d_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="2 9"
{!> ../../../docs_src/query_params_str_validations/tutorial006d_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="2 8"
{!> ../../../docs_src/query_params_str_validations/tutorial006d.py!}
```
!!! tip
Remember that in most of the cases, when something is required, you can simply omit the `default` parameter, so you normally don't have to use `...` nor `Required`.
Remember that in most of the cases, when something is required, you can simply omit the default, so you normally don't have to use `...` nor `Required`.
## Query parameter list / multiple values
@@ -246,22 +515,49 @@ When you define a query parameter explicitly with `Query` you can also declare i
For example, to declare a query parameter `q` that can appear multiple times in the URL, you can write:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial011.py!}
{!> ../../../docs_src/query_params_str_validations/tutorial011_an_py310.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial011_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial011_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial011_py310.py!}
```
=== "Python 3.9+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial011_py39.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+ non-Annotated"
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial011_py310.py!}
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial011.py!}
```
Then, with a URL like:
@@ -294,18 +590,36 @@ The interactive API docs will update accordingly, to allow multiple values:
And you can also define a default `list` of values if none are provided:
=== "Python 3.6 and above"
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial012.py!}
{!> ../../../docs_src/query_params_str_validations/tutorial012_an_py39.py!}
```
=== "Python 3.9 and above"
=== "Python 3.6+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial012_an.py!}
```
=== "Python 3.9+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial012_py39.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial012.py!}
```
If you go to:
```
@@ -327,9 +641,26 @@ the default of `q` will be: `["foo", "bar"]` and your response will be:
You can also use `list` directly instead of `List[str]` (or `list[str]` in Python 3.9+):
```Python hl_lines="7"
{!../../../docs_src/query_params_str_validations/tutorial013.py!}
```
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial013_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial013_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial013.py!}
```
!!! note
Have in mind that in this case, FastAPI won't check the contents of the list.
@@ -349,32 +680,80 @@ That information will be included in the generated OpenAPI and used by the docum
You can add a `title`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial007.py!}
{!> ../../../docs_src/query_params_str_validations/tutorial007_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial007_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="11"
{!> ../../../docs_src/query_params_str_validations/tutorial007_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial007_py310.py!}
```
And a `description`:
=== "Python 3.6+ non-Annotated"
=== "Python 3.6 and above"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="13"
{!> ../../../docs_src/query_params_str_validations/tutorial008.py!}
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial007.py!}
```
=== "Python 3.10 and above"
And a `description`:
=== "Python 3.10+"
```Python hl_lines="14"
{!> ../../../docs_src/query_params_str_validations/tutorial008_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="14"
{!> ../../../docs_src/query_params_str_validations/tutorial008_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="15"
{!> ../../../docs_src/query_params_str_validations/tutorial008_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="12"
{!> ../../../docs_src/query_params_str_validations/tutorial008_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="13"
{!> ../../../docs_src/query_params_str_validations/tutorial008.py!}
```
## Alias parameters
Imagine that you want the parameter to be `item-query`.
@@ -393,18 +772,42 @@ But you still need it to be exactly `item-query`...
Then you can declare an `alias`, and that alias is what will be used to find the parameter value:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial009.py!}
{!> ../../../docs_src/query_params_str_validations/tutorial009_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial009_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial009_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial009_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial009.py!}
```
## Deprecating parameters
Now let's say you don't like this parameter anymore.
@@ -413,18 +816,42 @@ You have to leave it there a while because there are clients using it, but you w
Then pass the parameter `deprecated=True` to `Query`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="18"
{!> ../../../docs_src/query_params_str_validations/tutorial010.py!}
```Python hl_lines="19"
{!> ../../../docs_src/query_params_str_validations/tutorial010_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="19"
{!> ../../../docs_src/query_params_str_validations/tutorial010_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="20"
{!> ../../../docs_src/query_params_str_validations/tutorial010_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="17"
{!> ../../../docs_src/query_params_str_validations/tutorial010_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="18"
{!> ../../../docs_src/query_params_str_validations/tutorial010.py!}
```
The docs will show it like this:
<img src="/img/tutorial/query-params-str-validations/image01.png">
@@ -433,18 +860,42 @@ The docs will show it like this:
To exclude a query parameter from the generated OpenAPI schema (and thus, from the automatic documentation systems), set the parameter `include_in_schema` of `Query` to `False`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial014.py!}
{!> ../../../docs_src/query_params_str_validations/tutorial014_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial014_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="11"
{!> ../../../docs_src/query_params_str_validations/tutorial014_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial014_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial014.py!}
```
## Recap
You can declare additional validations and metadata for your parameters.

View File

@@ -63,18 +63,18 @@ The parameter values in your function will be:
The same way, you can declare optional query parameters, by setting their default to `None`:
=== "Python 3.6 and above"
```Python hl_lines="9"
{!> ../../../docs_src/query_params/tutorial002.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="7"
{!> ../../../docs_src/query_params/tutorial002_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params/tutorial002.py!}
```
In this case, the function parameter `q` will be optional, and will be `None` by default.
!!! check
@@ -84,18 +84,18 @@ In this case, the function parameter `q` will be optional, and will be `None` by
You can also declare `bool` types, and they will be converted:
=== "Python 3.6 and above"
```Python hl_lines="9"
{!> ../../../docs_src/query_params/tutorial003.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="7"
{!> ../../../docs_src/query_params/tutorial003_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params/tutorial003.py!}
```
In this case, if you go to:
```
@@ -137,18 +137,18 @@ And you don't have to declare them in any specific order.
They will be detected by name:
=== "Python 3.6 and above"
```Python hl_lines="8 10"
{!> ../../../docs_src/query_params/tutorial004.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="6 8"
{!> ../../../docs_src/query_params/tutorial004_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="8 10"
{!> ../../../docs_src/query_params/tutorial004.py!}
```
## Required query parameters
When you declare a default value for non-path parameters (for now, we have only seen query parameters), then it is not required.
@@ -203,18 +203,18 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
And of course, you can define some parameters as required, some as having a default value, and some entirely optional:
=== "Python 3.6 and above"
```Python hl_lines="10"
{!> ../../../docs_src/query_params/tutorial006.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="8"
{!> ../../../docs_src/query_params/tutorial006_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params/tutorial006.py!}
```
In this case, there are 3 query parameters:
* `needy`, a required `str`.

View File

@@ -13,17 +13,51 @@ You can define files to be uploaded by the client using `File`.
Import `File` and `UploadFile` from `fastapi`:
```Python hl_lines="1"
{!../../../docs_src/request_files/tutorial001.py!}
```
=== "Python 3.9+"
```Python hl_lines="3"
{!> ../../../docs_src/request_files/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="1"
{!> ../../../docs_src/request_files/tutorial001_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="1"
{!> ../../../docs_src/request_files/tutorial001.py!}
```
## Define `File` Parameters
Create file parameters the same way you would for `Body` or `Form`:
```Python hl_lines="7"
{!../../../docs_src/request_files/tutorial001.py!}
```
=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/request_files/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="8"
{!> ../../../docs_src/request_files/tutorial001_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/request_files/tutorial001.py!}
```
!!! info
`File` is a class that inherits directly from `Form`.
@@ -45,9 +79,26 @@ But there are several cases in which you might benefit from using `UploadFile`.
Define a file parameter with a type of `UploadFile`:
```Python hl_lines="12"
{!../../../docs_src/request_files/tutorial001.py!}
```
=== "Python 3.9+"
```Python hl_lines="14"
{!> ../../../docs_src/request_files/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="13"
{!> ../../../docs_src/request_files/tutorial001_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="12"
{!> ../../../docs_src/request_files/tutorial001.py!}
```
Using `UploadFile` has several advantages over `bytes`:
@@ -118,25 +169,66 @@ The way HTML forms (`<form></form>`) sends the data to the server normally uses
You can make a file optional by using standard type annotations and setting a default value of `None`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="9 17"
{!> ../../../docs_src/request_files/tutorial001_02_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="9 17"
{!> ../../../docs_src/request_files/tutorial001_02_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="10 18"
{!> ../../../docs_src/request_files/tutorial001_02_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7 15"
{!> ../../../docs_src/request_files/tutorial001_02_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9 17"
{!> ../../../docs_src/request_files/tutorial001_02.py!}
```
=== "Python 3.10 and above"
```Python hl_lines="7 14"
{!> ../../../docs_src/request_files/tutorial001_02_py310.py!}
```
## `UploadFile` with Additional Metadata
You can also use `File()` with `UploadFile`, for example, to set additional metadata:
```Python hl_lines="13"
{!../../../docs_src/request_files/tutorial001_03.py!}
```
=== "Python 3.9+"
```Python hl_lines="9 15"
{!> ../../../docs_src/request_files/tutorial001_03_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="8 14"
{!> ../../../docs_src/request_files/tutorial001_03_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7 13"
{!> ../../../docs_src/request_files/tutorial001_03.py!}
```
## Multiple File Uploads
@@ -146,18 +238,36 @@ They would be associated to the same "form field" sent using "form data".
To use that, declare a list of `bytes` or `UploadFile`:
=== "Python 3.6 and above"
=== "Python 3.9+"
```Python hl_lines="10 15"
{!> ../../../docs_src/request_files/tutorial002.py!}
{!> ../../../docs_src/request_files/tutorial002_an_py39.py!}
```
=== "Python 3.9 and above"
=== "Python 3.6+"
```Python hl_lines="11 16"
{!> ../../../docs_src/request_files/tutorial002_an.py!}
```
=== "Python 3.9+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="8 13"
{!> ../../../docs_src/request_files/tutorial002_py39.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="10 15"
{!> ../../../docs_src/request_files/tutorial002.py!}
```
You will receive, as declared, a `list` of `bytes` or `UploadFile`s.
!!! note "Technical Details"
@@ -169,18 +279,36 @@ You will receive, as declared, a `list` of `bytes` or `UploadFile`s.
And the same way as before, you can use `File()` to set additional parameters, even for `UploadFile`:
=== "Python 3.6 and above"
=== "Python 3.9+"
```Python hl_lines="18"
{!> ../../../docs_src/request_files/tutorial003.py!}
```Python hl_lines="11 18-20"
{!> ../../../docs_src/request_files/tutorial003_an_py39.py!}
```
=== "Python 3.9 and above"
=== "Python 3.6+"
```Python hl_lines="16"
```Python hl_lines="12 19-21"
{!> ../../../docs_src/request_files/tutorial003_an.py!}
```
=== "Python 3.9+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="9 16"
{!> ../../../docs_src/request_files/tutorial003_py39.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="11 18"
{!> ../../../docs_src/request_files/tutorial003.py!}
```
## Recap
Use `File`, `bytes`, and `UploadFile` to declare files to be uploaded in the request, sent as form data.

View File

@@ -9,17 +9,51 @@ You can define files and form fields at the same time using `File` and `Form`.
## Import `File` and `Form`
```Python hl_lines="1"
{!../../../docs_src/request_forms_and_files/tutorial001.py!}
```
=== "Python 3.9+"
```Python hl_lines="3"
{!> ../../../docs_src/request_forms_and_files/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="1"
{!> ../../../docs_src/request_forms_and_files/tutorial001_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="1"
{!> ../../../docs_src/request_forms_and_files/tutorial001.py!}
```
## Define `File` and `Form` parameters
Create file and form parameters the same way you would for `Body` or `Query`:
```Python hl_lines="8"
{!../../../docs_src/request_forms_and_files/tutorial001.py!}
```
=== "Python 3.9+"
```Python hl_lines="10-12"
{!> ../../../docs_src/request_forms_and_files/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9-11"
{!> ../../../docs_src/request_forms_and_files/tutorial001_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="8"
{!> ../../../docs_src/request_forms_and_files/tutorial001.py!}
```
The files and form fields will be uploaded as form data and you will receive the files and form fields.

View File

@@ -11,17 +11,51 @@ When you need to receive form fields instead of JSON, you can use `Form`.
Import `Form` from `fastapi`:
```Python hl_lines="1"
{!../../../docs_src/request_forms/tutorial001.py!}
```
=== "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+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="1"
{!> ../../../docs_src/request_forms/tutorial001.py!}
```
## Define `Form` parameters
Create form parameters the same way you would for `Body` or `Query`:
```Python hl_lines="7"
{!../../../docs_src/request_forms/tutorial001.py!}
```
=== "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+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/request_forms/tutorial001.py!}
```
For example, in one of the ways the OAuth2 specification can be used (called "password flow") it is required to send a `username` and `password` as form fields.

View File

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

View File

@@ -8,18 +8,18 @@ Here are several ways to do it.
You can declare an `example` 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>:
=== "Python 3.6 and above"
```Python hl_lines="15-23"
{!> ../../../docs_src/schema_extra_example/tutorial001.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="13-21"
{!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="15-23"
{!> ../../../docs_src/schema_extra_example/tutorial001.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.
!!! tip
@@ -33,18 +33,18 @@ When using `Field()` with Pydantic models, you can also declare extra info for t
You can use this to add `example` for each field:
=== "Python 3.6 and above"
```Python hl_lines="4 10-13"
{!> ../../../docs_src/schema_extra_example/tutorial002.py!}
```
=== "Python 3.10 and above"
=== "Python 3.10+"
```Python hl_lines="2 8-11"
{!> ../../../docs_src/schema_extra_example/tutorial002_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="4 10-13"
{!> ../../../docs_src/schema_extra_example/tutorial002.py!}
```
!!! warning
Keep in mind that those extra arguments passed won't add any validation, only extra information, for documentation purposes.
@@ -66,18 +66,39 @@ you can also declare a data `example` or a group of `examples` with additional i
Here we pass an `example` of the data expected in `Body()`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="20-25"
{!> ../../../docs_src/schema_extra_example/tutorial003.py!}
```Python hl_lines="22-27"
{!> ../../../docs_src/schema_extra_example/tutorial003_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="22-27"
{!> ../../../docs_src/schema_extra_example/tutorial003_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="23-28"
{!> ../../../docs_src/schema_extra_example/tutorial003_an.py!}
```
=== "Python 3.10+ non-Annotated"
```Python hl_lines="18-23"
{!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="20-25"
{!> ../../../docs_src/schema_extra_example/tutorial003.py!}
```
### Example in the docs UI
With any of the methods above it would look like this in the `/docs`:
@@ -97,18 +118,39 @@ Each specific example `dict` in the `examples` can contain:
* `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`.
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="21-47"
{!> ../../../docs_src/schema_extra_example/tutorial004.py!}
```Python hl_lines="23-49"
{!> ../../../docs_src/schema_extra_example/tutorial004_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="23-49"
{!> ../../../docs_src/schema_extra_example/tutorial004_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="24-50"
{!> ../../../docs_src/schema_extra_example/tutorial004_an.py!}
```
=== "Python 3.10+ non-Annotated"
```Python hl_lines="19-45"
{!> ../../../docs_src/schema_extra_example/tutorial004_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/tutorial004.py!}
```
### Examples in the docs UI
With `examples` added to `Body()` the `/docs` would look like:

View File

@@ -20,9 +20,27 @@ Let's first just use the code and see how it works, and then we'll come back to
Copy the example in a file `main.py`:
```Python
{!../../../docs_src/security/tutorial001.py!}
```
=== "Python 3.9+"
```Python
{!> ../../../docs_src/security/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python
{!> ../../../docs_src/security/tutorial001_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python
{!> ../../../docs_src/security/tutorial001.py!}
```
## Run it
@@ -116,9 +134,26 @@ In this example we are going to use **OAuth2**, with the **Password** flow, usin
When we create an instance of the `OAuth2PasswordBearer` class we pass in the `tokenUrl` parameter. This parameter contains the URL that the client (the frontend running in the user's browser) will use to send the `username` and `password` in order to get a token.
```Python hl_lines="6"
{!../../../docs_src/security/tutorial001.py!}
```
=== "Python 3.9+"
```Python hl_lines="8"
{!> ../../../docs_src/security/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="7"
{!> ../../../docs_src/security/tutorial001_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="6"
{!> ../../../docs_src/security/tutorial001.py!}
```
!!! tip
Here `tokenUrl="token"` refers to a relative URL `token` that we haven't created yet. As it's a relative URL, it's equivalent to `./token`.
@@ -150,9 +185,26 @@ So, it can be used with `Depends`.
Now you can pass that `oauth2_scheme` in a dependency with `Depends`.
```Python hl_lines="10"
{!../../../docs_src/security/tutorial001.py!}
```
=== "Python 3.9+"
```Python hl_lines="12"
{!> ../../../docs_src/security/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="11"
{!> ../../../docs_src/security/tutorial001_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="10"
{!> ../../../docs_src/security/tutorial001.py!}
```
This dependency will provide a `str` that is assigned to the parameter `token` of the *path operation function*.

View File

@@ -2,9 +2,26 @@
In the previous chapter the security system (which is based on the dependency injection system) was giving the *path operation function* a `token` as a `str`:
```Python hl_lines="10"
{!../../../docs_src/security/tutorial001.py!}
```
=== "Python 3.9+"
```Python hl_lines="12"
{!> ../../../docs_src/security/tutorial001_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="11"
{!> ../../../docs_src/security/tutorial001_an.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="10"
{!> ../../../docs_src/security/tutorial001.py!}
```
But that is still not that useful.
@@ -16,18 +33,42 @@ First, let's create a Pydantic user model.
The same way we use Pydantic to declare bodies, we can use it anywhere else:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="5 12-16"
{!> ../../../docs_src/security/tutorial002.py!}
{!> ../../../docs_src/security/tutorial002_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="5 12-16"
{!> ../../../docs_src/security/tutorial002_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="5 13-17"
{!> ../../../docs_src/security/tutorial002_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="3 10-14"
{!> ../../../docs_src/security/tutorial002_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="5 12-16"
{!> ../../../docs_src/security/tutorial002.py!}
```
## Create a `get_current_user` dependency
Let's create a dependency `get_current_user`.
@@ -38,50 +79,122 @@ Remember that dependencies can have sub-dependencies?
The same as we were doing before in the *path operation* directly, our new dependency `get_current_user` will receive a `token` as a `str` from the sub-dependency `oauth2_scheme`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="25"
{!> ../../../docs_src/security/tutorial002.py!}
{!> ../../../docs_src/security/tutorial002_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="25"
{!> ../../../docs_src/security/tutorial002_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="26"
{!> ../../../docs_src/security/tutorial002_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="23"
{!> ../../../docs_src/security/tutorial002_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="25"
{!> ../../../docs_src/security/tutorial002.py!}
```
## Get the user
`get_current_user` will use a (fake) utility function we created, that takes a token as a `str` and returns our Pydantic `User` model:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="19-22 26-27"
{!> ../../../docs_src/security/tutorial002.py!}
{!> ../../../docs_src/security/tutorial002_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="19-22 26-27"
{!> ../../../docs_src/security/tutorial002_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="20-23 27-28"
{!> ../../../docs_src/security/tutorial002_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="17-20 24-25"
{!> ../../../docs_src/security/tutorial002_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="19-22 26-27"
{!> ../../../docs_src/security/tutorial002.py!}
```
## Inject the current user
So now we can use the same `Depends` with our `get_current_user` in the *path operation*:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="31"
{!> ../../../docs_src/security/tutorial002.py!}
{!> ../../../docs_src/security/tutorial002_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="31"
{!> ../../../docs_src/security/tutorial002_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="32"
{!> ../../../docs_src/security/tutorial002_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="29"
{!> ../../../docs_src/security/tutorial002_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="31"
{!> ../../../docs_src/security/tutorial002.py!}
```
Notice that we declare the type of `current_user` as the Pydantic model `User`.
This will help us inside of the function with all the completion and type checks.
@@ -128,18 +241,42 @@ And all of them (or any portion of them that you want) can take the advantage of
And all these thousands of *path operations* can be as small as 3 lines:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="30-32"
{!> ../../../docs_src/security/tutorial002.py!}
{!> ../../../docs_src/security/tutorial002_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="30-32"
{!> ../../../docs_src/security/tutorial002_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="31-33"
{!> ../../../docs_src/security/tutorial002_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="28-30"
{!> ../../../docs_src/security/tutorial002_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="30-32"
{!> ../../../docs_src/security/tutorial002.py!}
```
## Recap
You can now get the current user directly in your *path operation function*.

View File

@@ -109,18 +109,42 @@ And another utility to verify if a received password matches the hash stored.
And another one to authenticate and return a user.
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="7 48 55-56 59-60 69-75"
{!> ../../../docs_src/security/tutorial004.py!}
{!> ../../../docs_src/security/tutorial004_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="7 48 55-56 59-60 69-75"
{!> ../../../docs_src/security/tutorial004_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="7 49 56-57 60-61 70-76"
{!> ../../../docs_src/security/tutorial004_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="6 47 54-55 58-59 68-74"
{!> ../../../docs_src/security/tutorial004_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="7 48 55-56 59-60 69-75"
{!> ../../../docs_src/security/tutorial004.py!}
```
!!! note
If you check the new (fake) database `fake_users_db`, you will see how the hashed password looks like now: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`.
@@ -152,18 +176,42 @@ Define a Pydantic Model that will be used in the token endpoint for the response
Create a utility function to generate a new access token.
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="6 12-14 28-30 78-86"
{!> ../../../docs_src/security/tutorial004.py!}
{!> ../../../docs_src/security/tutorial004_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="6 12-14 28-30 78-86"
{!> ../../../docs_src/security/tutorial004_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="6 13-15 29-31 79-87"
{!> ../../../docs_src/security/tutorial004_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="5 11-13 27-29 77-85"
{!> ../../../docs_src/security/tutorial004_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="6 12-14 28-30 78-86"
{!> ../../../docs_src/security/tutorial004.py!}
```
## Update the dependencies
Update `get_current_user` to receive the same token as before, but this time, using JWT tokens.
@@ -172,36 +220,84 @@ Decode the received token, verify it, and return the current user.
If the token is invalid, return an HTTP error right away.
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="89-106"
{!> ../../../docs_src/security/tutorial004.py!}
{!> ../../../docs_src/security/tutorial004_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="89-106"
{!> ../../../docs_src/security/tutorial004_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="90-107"
{!> ../../../docs_src/security/tutorial004_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="88-105"
{!> ../../../docs_src/security/tutorial004_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="89-106"
{!> ../../../docs_src/security/tutorial004.py!}
```
## Update the `/token` *path operation*
Create a `timedelta` with the expiration time of the token.
Create a real JWT access token and return it.
Create a real JWT access token and return it
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="115-128"
{!> ../../../docs_src/security/tutorial004.py!}
```Python hl_lines="117-132"
{!> ../../../docs_src/security/tutorial004_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="117-132"
{!> ../../../docs_src/security/tutorial004_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="118-133"
{!> ../../../docs_src/security/tutorial004_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="114-127"
{!> ../../../docs_src/security/tutorial004_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="115-128"
{!> ../../../docs_src/security/tutorial004.py!}
```
### Technical details about the JWT "subject" `sub`
The JWT specification says that there's a key `sub`, with the subject of the token.

View File

@@ -49,18 +49,42 @@ Now let's use the utilities provided by **FastAPI** to handle this.
First, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depends` in the *path operation* for `/token`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="4 76"
{!> ../../../docs_src/security/tutorial003.py!}
```Python hl_lines="4 78"
{!> ../../../docs_src/security/tutorial003_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="4 78"
{!> ../../../docs_src/security/tutorial003_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="4 79"
{!> ../../../docs_src/security/tutorial003_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="2 74"
{!> ../../../docs_src/security/tutorial003_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="4 76"
{!> ../../../docs_src/security/tutorial003.py!}
```
`OAuth2PasswordRequestForm` is a class dependency that declares a form body with:
* The `username`.
@@ -98,18 +122,42 @@ If there is no such user, we return an error saying "incorrect username or passw
For the error, we use the exception `HTTPException`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="3 77-79"
{!> ../../../docs_src/security/tutorial003.py!}
```Python hl_lines="3 79-81"
{!> ../../../docs_src/security/tutorial003_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="3 79-81"
{!> ../../../docs_src/security/tutorial003_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="3 80-82"
{!> ../../../docs_src/security/tutorial003_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="1 75-77"
{!> ../../../docs_src/security/tutorial003_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="3 77-79"
{!> ../../../docs_src/security/tutorial003.py!}
```
### Check the password
At this point we have the user data from our database, but we haven't checked the password.
@@ -134,18 +182,42 @@ If your database is stolen, the thief won't have your users' plaintext passwords
So, the thief won't be able to try to use those same passwords in another system (as many users use the same password everywhere, this would be dangerous).
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="80-83"
{!> ../../../docs_src/security/tutorial003.py!}
```Python hl_lines="82-85"
{!> ../../../docs_src/security/tutorial003_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="82-85"
{!> ../../../docs_src/security/tutorial003_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="83-86"
{!> ../../../docs_src/security/tutorial003_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="78-81"
{!> ../../../docs_src/security/tutorial003_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="80-83"
{!> ../../../docs_src/security/tutorial003.py!}
```
#### About `**user_dict`
`UserInDB(**user_dict)` means:
@@ -180,18 +252,42 @@ For this simple example, we are going to just be completely insecure and return
But for now, let's focus on the specific details we need.
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="85"
{!> ../../../docs_src/security/tutorial003.py!}
```Python hl_lines="87"
{!> ../../../docs_src/security/tutorial003_an_py310.py!}
```
=== "Python 3.10 and above"
=== "Python 3.9+"
```Python hl_lines="87"
{!> ../../../docs_src/security/tutorial003_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="88"
{!> ../../../docs_src/security/tutorial003_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="83"
{!> ../../../docs_src/security/tutorial003_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="85"
{!> ../../../docs_src/security/tutorial003.py!}
```
!!! tip
By the spec, you should return a JSON with an `access_token` and a `token_type`, the same as in this example.
@@ -213,18 +309,42 @@ Both of these dependencies will just return an HTTP error if the user doesn't ex
So, in our endpoint, we will only get a user if the user exists, was correctly authenticated, and is active:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="58-66 69-74 94"
{!> ../../../docs_src/security/tutorial003_an_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="58-66 69-74 94"
{!> ../../../docs_src/security/tutorial003_an_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="59-67 70-75 95"
{!> ../../../docs_src/security/tutorial003_an.py!}
```
=== "Python 3.10+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="56-64 67-70 88"
{!> ../../../docs_src/security/tutorial003_py310.py!}
```
=== "Python 3.6+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
```Python hl_lines="58-66 69-72 90"
{!> ../../../docs_src/security/tutorial003.py!}
```
=== "Python 3.10 and above"
```Python hl_lines="55-64 67-70 88"
{!> ../../../docs_src/security/tutorial003_py310.py!}
```
!!! info
The additional header `WWW-Authenticate` with value `Bearer` we are returning here is also part of the spec.

View File

@@ -262,22 +262,22 @@ So, the user will also have a `password` when creating it.
But for security, the `password` won't be in other Pydantic *models*, for example, it won't be sent from the API when reading a user.
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="3 6-8 11-12 23-24 27-28"
{!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```Python hl_lines="1 4-6 9-10 21-22 25-26"
{!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="3 6-8 11-12 23-24 27-28"
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="1 4-6 9-10 21-22 25-26"
{!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```Python hl_lines="3 6-8 11-12 23-24 27-28"
{!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```
#### SQLAlchemy style and Pydantic style
@@ -306,22 +306,22 @@ The same way, when reading a user, we can now declare that `items` will contain
Not only the IDs of those items, but all the data that we defined in the Pydantic *model* for reading items: `Item`.
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="15-17 31-34"
{!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```Python hl_lines="13-15 29-32"
{!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="15-17 31-34"
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="13-15 29-32"
{!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```Python hl_lines="15-17 31-34"
{!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```
!!! tip
@@ -335,22 +335,22 @@ This <a href="https://pydantic-docs.helpmanual.io/usage/model_config/" class="ex
In the `Config` class, set the attribute `orm_mode = True`.
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python hl_lines="15 19-20 31 36-37"
{!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```Python hl_lines="13 17-18 29 34-35"
{!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="15 19-20 31 36-37"
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python hl_lines="13 17-18 29 34-35"
{!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```Python hl_lines="15 19-20 31 36-37"
{!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```
!!! tip
@@ -481,18 +481,18 @@ And now in the file `sql_app/main.py` let's integrate and use all the other part
In a very simplistic way create the database tables:
=== "Python 3.6 and above"
```Python hl_lines="9"
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="7"
{!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
=== "Python 3.6+"
```Python hl_lines="9"
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
#### Alembic Note
Normally you would probably initialize your database (create tables, etc) with <a href="https://alembic.sqlalchemy.org/en/latest/" class="external-link" target="_blank">Alembic</a>.
@@ -515,18 +515,18 @@ For that, we will create a new dependency with `yield`, as explained before in t
Our dependency will create a new SQLAlchemy `SessionLocal` that will be used in a single request, and then close it once the request is finished.
=== "Python 3.6 and above"
```Python hl_lines="15-20"
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="13-18"
{!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
=== "Python 3.6+"
```Python hl_lines="15-20"
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
!!! info
We put the creation of the `SessionLocal()` and handling of the requests in a `try` block.
@@ -540,18 +540,18 @@ And then, when using the dependency in a *path operation function*, we declare i
This will then give us better editor support inside the *path operation function*, because the editor will know that the `db` parameter is of type `Session`:
=== "Python 3.6 and above"
```Python hl_lines="24 32 38 47 53"
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="22 30 36 45 51"
{!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
=== "Python 3.6+"
```Python hl_lines="24 32 38 47 53"
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
!!! info "Technical Details"
The parameter `db` is actually of type `SessionLocal`, but this class (created with `sessionmaker()`) is a "proxy" of a SQLAlchemy `Session`, so, the editor doesn't really know what methods are provided.
@@ -561,18 +561,18 @@ This will then give us better editor support inside the *path operation function
Now, finally, here's the standard **FastAPI** *path operations* code.
=== "Python 3.6 and above"
```Python hl_lines="23-28 31-34 37-42 45-49 52-55"
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="21-26 29-32 35-40 43-47 50-53"
{!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
=== "Python 3.6+"
```Python hl_lines="23-28 31-34 37-42 45-49 52-55"
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
We are creating the database session before each request in the dependency with `yield`, and then closing it afterwards.
And then we can create the required dependency in the *path operation function*, to get that session directly.
@@ -654,22 +654,22 @@ For example, in a background task worker with <a href="https://docs.celeryq.dev"
* `sql_app/schemas.py`:
=== "Python 3.6 and above"
=== "Python 3.10+"
```Python
{!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
{!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
=== "Python 3.10 and above"
=== "Python 3.6+"
```Python
{!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
{!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```
* `sql_app/crud.py`:
@@ -680,18 +680,18 @@ For example, in a background task worker with <a href="https://docs.celeryq.dev"
* `sql_app/main.py`:
=== "Python 3.6 and above"
```Python
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python
{!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
=== "Python 3.6+"
```Python
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
## Check it
You can copy this code and use it as is.
@@ -739,18 +739,18 @@ A "middleware" is basically a function that is always executed for each request,
The middleware we'll add (just a function) will create a new SQLAlchemy `SessionLocal` for each request, add it to the request and then close it once the request is finished.
=== "Python 3.6 and above"
```Python hl_lines="14-22"
{!> ../../../docs_src/sql_databases/sql_app/alt_main.py!}
```
=== "Python 3.9 and above"
=== "Python 3.9+"
```Python hl_lines="12-20"
{!> ../../../docs_src/sql_databases/sql_app_py39/alt_main.py!}
```
=== "Python 3.6+"
```Python hl_lines="14-22"
{!> ../../../docs_src/sql_databases/sql_app/alt_main.py!}
```
!!! info
We put the creation of the `SessionLocal()` and handling of the requests in a `try` block.

View File

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

View File

@@ -45,6 +45,7 @@ nav:
- fa: /fa/
- fr: /fr/
- he: /he/
- hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
@@ -55,6 +56,7 @@ nav:
- ru: /ru/
- sq: /sq/
- sv: /sv/
- ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -187,7 +189,7 @@ markdown_extensions:
extra:
analytics:
provider: google
property: UA-133183413-1
property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -218,6 +220,8 @@ extra:
name: fr - français
- link: /he/
name: he
- link: /hy/
name: hy
- link: /id/
name: id
- link: /it/
@@ -238,6 +242,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
- link: /ta/
name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/

View File

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

View File

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

View File

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

View File

@@ -45,6 +45,7 @@ nav:
- fa: /fa/
- fr: /fr/
- he: /he/
- hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
@@ -55,6 +56,7 @@ nav:
- ru: /ru/
- sq: /sq/
- sv: /sv/
- ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -90,7 +92,7 @@ markdown_extensions:
extra:
analytics:
provider: google
property: UA-133183413-1
property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -121,6 +123,8 @@ extra:
name: fr - français
- link: /he/
name: he
- link: /hy/
name: hy
- link: /id/
name: id
- link: /it/
@@ -141,6 +145,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
- link: /ta/
name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/

View File

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

View File

@@ -45,6 +45,7 @@ nav:
- fa: /fa/
- fr: /fr/
- he: /he/
- hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
@@ -55,6 +56,7 @@ nav:
- ru: /ru/
- sq: /sq/
- sv: /sv/
- ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -80,7 +82,7 @@ markdown_extensions:
extra:
analytics:
provider: google
property: UA-133183413-1
property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -111,6 +113,8 @@ extra:
name: fr - français
- link: /he/
name: he
- link: /hy/
name: hy
- link: /id/
name: id
- link: /it/
@@ -131,6 +135,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
- link: /ta/
name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/

View File

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

View File

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

View File

@@ -0,0 +1,168 @@
# Configuration avancée des paramètres de chemin
## ID d'opération OpenAPI
!!! Attention
Si vous n'êtes pas un "expert" en OpenAPI, vous n'en avez probablement pas besoin.
Dans OpenAPI, les chemins sont des ressources, tels que /users/ ou /items/, exposées par votre API, et les opérations sont les méthodes HTTP utilisées pour manipuler ces chemins, telles que GET, POST ou DELETE. Les operationId sont des chaînes uniques facultatives utilisées pour identifier une opération d'un chemin. Vous pouvez définir l'OpenAPI `operationId` à utiliser dans votre *opération de chemin* avec le paramètre `operation_id`.
Vous devez vous assurer qu'il est unique pour chaque opération.
```Python hl_lines="6"
{!../../../docs_src/path_operation_advanced_configuration/tutorial001.py!}
```
### Utilisation du nom *path operation function* comme operationId
Si vous souhaitez utiliser les noms de fonction de vos API comme `operationId`, vous pouvez les parcourir tous et remplacer chaque `operation_id` de l'*opération de chemin* en utilisant leur `APIRoute.name`.
Vous devriez le faire après avoir ajouté toutes vos *paramètres de chemin*.
```Python hl_lines="2 12-21 24"
{!../../../docs_src/path_operation_advanced_configuration/tutorial002.py!}
```
!!! Astuce
Si vous appelez manuellement `app.openapi()`, vous devez mettre à jour les `operationId` avant.
!!! Attention
Pour faire cela, vous devez vous assurer que chacun de vos *chemin* ait un nom unique.
Même s'ils se trouvent dans des modules différents (fichiers Python).
## Exclusion d'OpenAPI
Pour exclure un *chemin* du schéma OpenAPI généré (et donc des systèmes de documentation automatiques), utilisez le paramètre `include_in_schema` et assignez-lui la valeur `False` :
```Python hl_lines="6"
{!../../../docs_src/path_operation_advanced_configuration/tutorial003.py!}
```
## Description avancée de docstring
Vous pouvez limiter le texte utilisé de la docstring d'une *fonction de chemin* qui sera affiché sur OpenAPI.
L'ajout d'un `\f` (un caractère d'échappement "form feed") va permettre à **FastAPI** de tronquer la sortie utilisée pour OpenAPI à ce stade.
Il n'apparaîtra pas dans la documentation, mais d'autres outils (tel que Sphinx) pourront utiliser le reste.
```Python hl_lines="19-29"
{!../../../docs_src/path_operation_advanced_configuration/tutorial004.py!}
```
## Réponses supplémentaires
Vous avez probablement vu comment déclarer le `response_model` et le `status_code` pour une *opération de chemin*.
Cela définit les métadonnées sur la réponse principale d'une *opération de chemin*.
Vous pouvez également déclarer des réponses supplémentaires avec leurs modèles, codes de statut, etc.
Il y a un chapitre entier ici dans la documentation à ce sujet, vous pouvez le lire sur [Réponses supplémentaires dans OpenAPI](./additional-responses.md){.internal-link target=_blank}.
## OpenAPI supplémentaire
Lorsque vous déclarez un *chemin* dans votre application, **FastAPI** génère automatiquement les métadonnées concernant ce *chemin* à inclure dans le schéma OpenAPI.
!!! note "Détails techniques"
La spécification OpenAPI appelle ces métaonnées des <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">Objets d'opération</a>.
Il contient toutes les informations sur le *chemin* et est utilisé pour générer automatiquement la documentation.
Il inclut les `tags`, `parameters`, `requestBody`, `responses`, etc.
Ce schéma OpenAPI spécifique aux *operations* est normalement généré automatiquement par **FastAPI**, mais vous pouvez également l'étendre.
!!! Astuce
Si vous avez seulement besoin de déclarer des réponses supplémentaires, un moyen plus pratique de le faire est d'utiliser les [réponses supplémentaires dans OpenAPI](./additional-responses.md){.internal-link target=_blank}.
Vous pouvez étendre le schéma OpenAPI pour une *opération de chemin* en utilisant le paramètre `openapi_extra`.
### Extensions OpenAPI
Cet `openapi_extra` peut être utile, par exemple, pour déclarer [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) :
```Python hl_lines="6"
{!../../../docs_src/path_operation_advanced_configuration/tutorial005.py!}
```
Si vous ouvrez la documentation automatique de l'API, votre extension apparaîtra au bas du *chemin* spécifique.
<img src="/img/tutorial/path-operation-advanced-configuration/image01.png">
Et dans le fichier openapi généré (`/openapi.json`), vous verrez également votre extension dans le cadre du *chemin* spécifique :
```JSON hl_lines="22"
{
"openapi": "3.0.2",
"info": {
"title": "FastAPI",
"version": "0.1.0"
},
"paths": {
"/items/": {
"get": {
"summary": "Read Items",
"operationId": "read_items_items__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
},
"x-aperture-labs-portal": "blue"
}
}
}
}
```
### Personnalisation du Schéma OpenAPI pour un chemin
Le dictionnaire contenu dans la variable `openapi_extra` sera fusionné avec le schéma OpenAPI généré automatiquement pour l'*opération de chemin*.
Ainsi, vous pouvez ajouter des données supplémentaires au schéma généré automatiquement.
Par exemple, vous pouvez décider de lire et de valider la requête avec votre propre code, sans utiliser les fonctionnalités automatiques de validation proposée par Pydantic, mais vous pouvez toujours définir la requête dans le schéma OpenAPI.
Vous pouvez le faire avec `openapi_extra` :
```Python hl_lines="20-37 39-40"
{!../../../docs_src/path_operation_advanced_configuration/tutorial006.py !}
```
Dans cet exemple, nous n'avons déclaré aucun modèle Pydantic. En fait, le corps de la requête n'est même pas <abbr title="converti d'un format simple, comme des octets, en objets Python">parsé</abbr> en tant que JSON, il est lu directement en tant que `bytes`, et la fonction `magic_data_reader()` serait chargé de l'analyser d'une manière ou d'une autre.
Néanmoins, nous pouvons déclarer le schéma attendu pour le corps de la requête.
### Type de contenu OpenAPI personnalisé
En utilisant cette même astuce, vous pouvez utiliser un modèle Pydantic pour définir le schéma JSON qui est ensuite inclus dans la section de schéma OpenAPI personnalisée pour le *chemin* concerné.
Et vous pouvez le faire même si le type de données dans la requête n'est pas au format JSON.
Dans cet exemple, nous n'utilisons pas les fonctionnalités de FastAPI pour extraire le schéma JSON des modèles Pydantic ni la validation automatique pour JSON. En fait, nous déclarons le type de contenu de la requête en tant que YAML, et non JSON :
```Python hl_lines="17-22 24"
{!../../../docs_src/path_operation_advanced_configuration/tutorial007.py!}
```
Néanmoins, bien que nous n'utilisions pas la fonctionnalité par défaut, nous utilisons toujours un modèle Pydantic pour générer manuellement le schéma JSON pour les données que nous souhaitons recevoir en YAML.
Ensuite, nous utilisons directement la requête et extrayons son contenu en tant qu'octets. Cela signifie que FastAPI n'essaiera même pas d'analyser le payload de la requête en tant que JSON.
Et nous analysons directement ce contenu YAML, puis nous utilisons à nouveau le même modèle Pydantic pour valider le contenu YAML :
```Python hl_lines="26-33"
{!../../../docs_src/path_operation_advanced_configuration/tutorial007.py!}
```
!!! Astuce
Ici, nous réutilisons le même modèle Pydantic.
Mais nous aurions pu tout aussi bien pu le valider d'une autre manière.

View File

@@ -0,0 +1,153 @@
# Exécuter un serveur manuellement - Uvicorn
La principale chose dont vous avez besoin pour exécuter une application **FastAPI** sur une machine serveur distante est un programme serveur ASGI tel que **Uvicorn**.
Il existe 3 principales alternatives :
* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a> : un serveur ASGI haute performance.
* <a href="https://pgjones.gitlab.io/hypercorn/" class="external-link" target="_blank">Hypercorn</a> : un serveur
ASGI compatible avec HTTP/2 et Trio entre autres fonctionnalités.
* <a href="https://github.com/django/daphne" class="external-link" target="_blank">Daphne</a> : le serveur ASGI
conçu pour Django Channels.
## Machine serveur et programme serveur
Il y a un petit détail sur les noms à garder à l'esprit. 💡
Le mot "**serveur**" est couramment utilisé pour désigner à la fois l'ordinateur distant/cloud (la machine physique ou virtuelle) et également le programme qui s'exécute sur cette machine (par exemple, Uvicorn).
Gardez cela à l'esprit lorsque vous lisez "serveur" en général, cela pourrait faire référence à l'une de ces deux choses.
Lorsqu'on se réfère à la machine distante, il est courant de l'appeler **serveur**, mais aussi **machine**, **VM** (machine virtuelle), **nœud**. Tout cela fait référence à un type de machine distante, exécutant Linux, en règle générale, sur laquelle vous exécutez des programmes.
## Installer le programme serveur
Vous pouvez installer un serveur compatible ASGI avec :
=== "Uvicorn"
* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>, un serveur ASGI rapide comme l'éclair, basé sur uvloop et httptools.
<div class="termy">
```console
$ pip install "uvicorn[standard]"
---> 100%
```
</div>
!!! tip "Astuce"
En ajoutant `standard`, Uvicorn va installer et utiliser quelques dépendances supplémentaires recommandées.
Cela inclut `uvloop`, le remplaçant performant de `asyncio`, qui fournit le gros gain de performance en matière de concurrence.
=== "Hypercorn"
* <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>, un serveur ASGI également compatible avec HTTP/2.
<div class="termy">
```console
$ pip install hypercorn
---> 100%
```
</div>
...ou tout autre serveur ASGI.
## Exécutez le programme serveur
Vous pouvez ensuite exécuter votre application de la même manière que vous l'avez fait dans les tutoriels, mais sans l'option `--reload`, par exemple :
=== "Uvicorn"
<div class="termy">
```console
$ uvicorn main:app --host 0.0.0.0 --port 80
<span style="color: green;">INFO</span>: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
```
</div>
=== "Hypercorn"
<div class="termy">
```console
$ hypercorn main:app --bind 0.0.0.0:80
Running on 0.0.0.0:8080 over http (CTRL + C to quit)
```
</div>
!!! warning
N'oubliez pas de supprimer l'option `--reload` si vous l'utilisiez.
L'option `--reload` consomme beaucoup plus de ressources, est plus instable, etc.
Cela aide beaucoup pendant le **développement**, mais vous **ne devriez pas** l'utiliser en **production**.
## Hypercorn avec Trio
Starlette et **FastAPI** sont basés sur
<a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, qui les rend
compatibles avec <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a>, de la bibliothèque standard Python et
<a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>.
Néanmoins, Uvicorn n'est actuellement compatible qu'avec asyncio, et il utilise normalement <a href="https://github.
com/MagicStack/uvloop" class="external-link" target="_blank">`uvloop`</a >, le remplaçant hautes performances de `asyncio`.
Mais si vous souhaitez utiliser directement **Trio**, vous pouvez utiliser **Hypercorn** car il le prend en charge. ✨
### Installer Hypercorn avec Trio
Vous devez d'abord installer Hypercorn avec le support Trio :
<div class="termy">
```console
$ pip install "hypercorn[trio]"
---> 100%
```
</div>
### Exécuter avec Trio
Ensuite, vous pouvez passer l'option de ligne de commande `--worker-class` avec la valeur `trio` :
<div class="termy">
```console
$ hypercorn main:app --worker-class trio
```
</div>
Et cela démarrera Hypercorn avec votre application en utilisant Trio comme backend.
Vous pouvez désormais utiliser Trio en interne dans votre application. Ou mieux encore, vous pouvez utiliser AnyIO pour que votre code reste compatible avec Trio et asyncio. 🎉
## Concepts de déploiement
Ces exemples lancent le programme serveur (e.g. Uvicorn), démarrant **un seul processus**, sur toutes les IPs (`0.0.
0.0`) sur un port prédéfini (par example, `80`).
C'est l'idée de base. Mais vous vous préoccuperez probablement de certains concepts supplémentaires, tels que ... :
* la sécurité - HTTPS
* l'exécution au démarrage
* les redémarrages
* la réplication (le nombre de processus en cours d'exécution)
* la mémoire
* les étapes précédant le démarrage
Je vous en dirai plus sur chacun de ces concepts, sur la façon de les aborder, et donnerai quelques exemples concrets avec des stratégies pour les traiter dans les prochains chapitres. 🚀

View File

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

View File

@@ -0,0 +1,112 @@
# <abbr title="En anglais: Debugging">Débogage</abbr>
Vous pouvez connecter le <abbr title="En anglais: debugger">débogueur</abbr> dans votre éditeur, par exemple avec Visual Studio Code ou PyCharm.
## Faites appel à `uvicorn`
Dans votre application FastAPI, importez et exécutez directement `uvicorn` :
```Python hl_lines="1 15"
{!../../../docs_src/debugging/tutorial001.py!}
```
### À propos de `__name__ == "__main__"`
Le but principal de `__name__ == "__main__"` est d'avoir du code qui est exécuté lorsque votre fichier est appelé avec :
<div class="termy">
```console
$ python myapp.py
```
</div>
mais qui n'est pas appelé lorsqu'un autre fichier l'importe, comme dans :
```Python
from myapp import app
```
#### Pour davantage de détails
Imaginons que votre fichier s'appelle `myapp.py`.
Si vous l'exécutez avec :
<div class="termy">
```console
$ python myapp.py
```
</div>
alors la variable interne `__name__` de votre fichier, créée automatiquement par Python, aura pour valeur la chaîne de caractères `"__main__"`.
Ainsi, la section :
```Python
uvicorn.run(app, host="0.0.0.0", port=8000)
```
va s'exécuter.
---
Cela ne se produira pas si vous importez ce module (fichier).
Par exemple, si vous avez un autre fichier `importer.py` qui contient :
```Python
from myapp import app
# Code supplémentaire
```
dans ce cas, la variable automatique `__name__` à l'intérieur de `myapp.py` n'aura pas la valeur `"__main__"`.
Ainsi, la ligne :
```Python
uvicorn.run(app, host="0.0.0.0", port=8000)
```
ne sera pas exécutée.
!!! info
Pour plus d'informations, consultez <a href="https://docs.python.org/3/library/__main__.html" class="external-link" target="_blank">la documentation officielle de Python</a>.
## Exécutez votre code avec votre <abbr title="En anglais: debugger">débogueur</abbr>
Parce que vous exécutez le serveur Uvicorn directement depuis votre code, vous pouvez appeler votre programme Python (votre application FastAPI) directement depuis le <abbr title="En anglais: debugger">débogueur</abbr>.
---
Par exemple, dans Visual Studio Code, vous pouvez :
- Cliquer sur l'onglet "Debug" de la barre d'activités de Visual Studio Code.
- "Add configuration...".
- Sélectionnez "Python".
- Lancez le <abbr title="En anglais: debugger">débogueur</abbr> avec l'option "`Python: Current File (Integrated Terminal)`".
Il démarrera alors le serveur avec votre code **FastAPI**, s'arrêtera à vos points d'arrêt, etc.
Voici à quoi cela pourrait ressembler :
<img src="/img/tutorial/debugging/image01.png">
---
Si vous utilisez Pycharm, vous pouvez :
- Ouvrir le menu "Run".
- Sélectionnez l'option "Debug...".
- Un menu contextuel s'affiche alors.
- Sélectionnez le fichier à déboguer (dans ce cas, `main.py`).
Il démarrera alors le serveur avec votre code **FastAPI**, s'arrêtera à vos points d'arrêt, etc.
Voici à quoi cela pourrait ressembler :
<img src="/img/tutorial/debugging/image02.png">

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