mirror of
https://github.com/fastapi/fastapi.git
synced 2025-12-27 16:21:06 -05:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5614b94ccc | ||
|
|
e170c86412 | ||
|
|
180bdf31ac | ||
|
|
1e58a3e44c | ||
|
|
dfe3f614ed | ||
|
|
97c747fe54 | ||
|
|
fdb6c9ccc5 | ||
|
|
4fdcdf341c | ||
|
|
e2a6341c60 | ||
|
|
7046d80a23 | ||
|
|
9f89399f5e | ||
|
|
ed0fe9f369 | ||
|
|
6e9b771abf | ||
|
|
4a93562a3d | ||
|
|
3f478b7733 | ||
|
|
c660d96dce | ||
|
|
6de9f5890d | ||
|
|
a16ecf2f91 | ||
|
|
7a2c5526d4 | ||
|
|
d6b5bc9401 | ||
|
|
e6f8aa8756 | ||
|
|
f0a14a9ab6 | ||
|
|
c3dbf4ef7c | ||
|
|
52dd5924d7 | ||
|
|
a960c42178 | ||
|
|
436b023fe4 | ||
|
|
f1759297c7 | ||
|
|
f1ca8da6e1 | ||
|
|
478f157013 | ||
|
|
5c8b41abf2 | ||
|
|
4236c99b7f | ||
|
|
1a816fd6a0 | ||
|
|
02b7d988ae | ||
|
|
1b70a1cbf6 | ||
|
|
259c55f7cd | ||
|
|
6a05f1774e | ||
|
|
6189aacd0f | ||
|
|
9e6b069c09 | ||
|
|
6ffc8a547f |
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -45,6 +45,7 @@ The key features are:
|
||||
<!-- sponsors -->
|
||||
|
||||
<a href="https://www.deta.sh/?ref=fastapi" target="_blank" title="The launchpad for all your (team's) ideas"><img src="https://fastapi.tiangolo.com/img/sponsors/deta.svg"></a>
|
||||
<a href="https://www.investsuite.com/" target="_blank" title="Wealthtech as a service"><img src="https://fastapi.tiangolo.com/img/sponsors/investsuite.svg"></a>
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
@@ -124,7 +125,7 @@ You will also need an ASGI server, for production such as <a href="https://www.u
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
maintainers:
|
||||
- login: tiangolo
|
||||
answers: 979
|
||||
prs: 189
|
||||
answers: 998
|
||||
prs: 200
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/1326112?u=05f95ca7fdead36edd9c86be46b4ef6c3c71f876&v=4
|
||||
url: https://github.com/tiangolo
|
||||
experts:
|
||||
@@ -18,37 +18,45 @@ experts:
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/331403?v=4
|
||||
url: https://github.com/phy25
|
||||
- login: Kludex
|
||||
count: 104
|
||||
count: 123
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: Mause
|
||||
count: 99
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/1405026?v=4
|
||||
url: https://github.com/Mause
|
||||
- login: ycd
|
||||
count: 61
|
||||
count: 92
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/62724709?u=496a800351ea1009678e40b26288a2a6c0dfa8bd&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: ArcLightSlavik
|
||||
count: 44
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/31127044?u=b81d0c33b056152513fb14749a9fe00f39887a8e&v=4
|
||||
url: https://github.com/ArcLightSlavik
|
||||
- login: sm-Fifteen
|
||||
count: 39
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4
|
||||
url: https://github.com/sm-Fifteen
|
||||
- login: ArcLightSlavik
|
||||
count: 35
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/31127044?u=b81d0c33b056152513fb14749a9fe00f39887a8e&v=4
|
||||
url: https://github.com/ArcLightSlavik
|
||||
- login: prostomarkeloff
|
||||
count: 33
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4
|
||||
url: https://github.com/prostomarkeloff
|
||||
- login: Mause
|
||||
count: 32
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/1405026?v=4
|
||||
url: https://github.com/Mause
|
||||
- login: wshayes
|
||||
count: 29
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
|
||||
url: https://github.com/wshayes
|
||||
- login: includeamin
|
||||
count: 29
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4
|
||||
url: https://github.com/includeamin
|
||||
- login: dbanty
|
||||
count: 25
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/43723790?u=0cf33e4f40efc2ea206a1189fd63a11344eb88ed&v=4
|
||||
url: https://github.com/dbanty
|
||||
- login: raphaelauv
|
||||
count: 24
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
url: https://github.com/raphaelauv
|
||||
- login: SirTelemak
|
||||
count: 23
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4
|
||||
@@ -73,18 +81,10 @@ experts:
|
||||
count: 19
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/24581770?v=4
|
||||
url: https://github.com/retnikt
|
||||
- login: raphaelauv
|
||||
count: 18
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
url: https://github.com/raphaelauv
|
||||
- login: jorgerpo
|
||||
count: 17
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4
|
||||
url: https://github.com/jorgerpo
|
||||
- login: includeamin
|
||||
count: 17
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4
|
||||
url: https://github.com/includeamin
|
||||
- login: Slyfoxy
|
||||
count: 17
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/28262306?u=66ee21316275ef356081c2efc4ed7a4572e690dc&v=4
|
||||
@@ -102,47 +102,39 @@ experts:
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/20441825?u=ee1e59446b98f8ec2363caeda4c17164d0d9cc7d&v=4
|
||||
url: https://github.com/stefanondisponibile
|
||||
last_month_active:
|
||||
- login: ycd
|
||||
count: 19
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/62724709?u=496a800351ea1009678e40b26288a2a6c0dfa8bd&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: Mause
|
||||
count: 18
|
||||
count: 51
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/1405026?v=4
|
||||
url: https://github.com/Mause
|
||||
- login: ycd
|
||||
count: 22
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/62724709?u=496a800351ea1009678e40b26288a2a6c0dfa8bd&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: Kludex
|
||||
count: 11
|
||||
count: 14
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: includeamin
|
||||
count: 11
|
||||
count: 12
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4
|
||||
url: https://github.com/includeamin
|
||||
- login: eseglem
|
||||
count: 7
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/5920492?u=208d419cf667b8ac594c82a8db01932c7e50d057&v=4
|
||||
url: https://github.com/eseglem
|
||||
- login: ArcLightSlavik
|
||||
count: 5
|
||||
count: 9
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/31127044?u=b81d0c33b056152513fb14749a9fe00f39887a8e&v=4
|
||||
url: https://github.com/ArcLightSlavik
|
||||
- login: SirTelemak
|
||||
count: 4
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4
|
||||
url: https://github.com/SirTelemak
|
||||
- login: clmno
|
||||
count: 3
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/17064666?v=4
|
||||
url: https://github.com/clmno
|
||||
- login: raphaelauv
|
||||
count: 6
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
url: https://github.com/raphaelauv
|
||||
top_contributors:
|
||||
- login: waynerv
|
||||
count: 17
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
- login: dmontagu
|
||||
count: 16
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
|
||||
url: https://github.com/dmontagu
|
||||
- login: waynerv
|
||||
count: 16
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
- login: euri10
|
||||
count: 13
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/1104190?u=ffd411da5d3b7ad3aa18261317f7ddc76f763c33&v=4
|
||||
@@ -152,9 +144,13 @@ top_contributors:
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
|
||||
url: https://github.com/tokusumi
|
||||
- login: mariacamilagl
|
||||
count: 8
|
||||
count: 9
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
|
||||
url: https://github.com/mariacamilagl
|
||||
- login: RunningIkkyu
|
||||
count: 7
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4
|
||||
url: https://github.com/RunningIkkyu
|
||||
- login: Serrones
|
||||
count: 6
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4
|
||||
@@ -167,27 +163,43 @@ top_contributors:
|
||||
count: 4
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/2546697?v=4
|
||||
url: https://github.com/jekirl
|
||||
- login: komtaki
|
||||
count: 4
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/39375566?v=4
|
||||
url: https://github.com/komtaki
|
||||
top_reviewers:
|
||||
- login: Kludex
|
||||
count: 53
|
||||
count: 62
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: tokusumi
|
||||
count: 40
|
||||
count: 41
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
|
||||
url: https://github.com/tokusumi
|
||||
- login: ycd
|
||||
count: 24
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/62724709?u=496a800351ea1009678e40b26288a2a6c0dfa8bd&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: dmontagu
|
||||
count: 23
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
|
||||
url: https://github.com/dmontagu
|
||||
- login: ycd
|
||||
count: 17
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/62724709?u=496a800351ea1009678e40b26288a2a6c0dfa8bd&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: Laineyzhang55
|
||||
count: 21
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/59285379?v=4
|
||||
url: https://github.com/Laineyzhang55
|
||||
- login: AdrianDeAnda
|
||||
count: 16
|
||||
count: 20
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/1024932?u=bb7f8a0d6c9de4e9d0320a9f271210206e202250&v=4
|
||||
url: https://github.com/AdrianDeAnda
|
||||
- login: komtaki
|
||||
count: 19
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/39375566?v=4
|
||||
url: https://github.com/komtaki
|
||||
- login: waynerv
|
||||
count: 18
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
- login: SwftAlpc
|
||||
count: 16
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4
|
||||
@@ -196,18 +208,14 @@ top_reviewers:
|
||||
count: 14
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4
|
||||
url: https://github.com/cassiobotaro
|
||||
- login: Laineyzhang55
|
||||
count: 12
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/59285379?v=4
|
||||
url: https://github.com/Laineyzhang55
|
||||
- login: yanever
|
||||
count: 11
|
||||
count: 14
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/21978760?v=4
|
||||
url: https://github.com/yanever
|
||||
- login: waynerv
|
||||
count: 10
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
- login: RunningIkkyu
|
||||
count: 11
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4
|
||||
url: https://github.com/RunningIkkyu
|
||||
- login: mariacamilagl
|
||||
count: 10
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
|
||||
@@ -216,14 +224,10 @@ top_reviewers:
|
||||
count: 10
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/1175560?v=4
|
||||
url: https://github.com/Attsun1031
|
||||
- login: RunningIkkyu
|
||||
count: 9
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4
|
||||
url: https://github.com/RunningIkkyu
|
||||
- login: komtaki
|
||||
count: 9
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/39375566?v=4
|
||||
url: https://github.com/komtaki
|
||||
- login: maoyibo
|
||||
count: 10
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/7887703?v=4
|
||||
url: https://github.com/maoyibo
|
||||
- login: Serrones
|
||||
count: 7
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4
|
||||
@@ -232,10 +236,18 @@ top_reviewers:
|
||||
count: 7
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/36391432?u=094eec0cfddd5013f76f31e55e56147d78b19553&v=4
|
||||
url: https://github.com/ryuckel
|
||||
- login: ArcLightSlavik
|
||||
count: 6
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/31127044?u=b81d0c33b056152513fb14749a9fe00f39887a8e&v=4
|
||||
url: https://github.com/ArcLightSlavik
|
||||
- login: MashhadiNima
|
||||
count: 5
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/49960770?u=e39b11d47188744ee07b2a1c7ce1a1bdf3c80760&v=4
|
||||
url: https://github.com/MashhadiNima
|
||||
- login: raphaelauv
|
||||
count: 5
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
url: https://github.com/raphaelauv
|
||||
- login: euri10
|
||||
count: 4
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/1104190?u=ffd411da5d3b7ad3aa18261317f7ddc76f763c33&v=4
|
||||
@@ -244,10 +256,6 @@ top_reviewers:
|
||||
count: 4
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/23391143?u=56ab6bff50be950fa8cae5cf736f2ae66e319ff3&v=4
|
||||
url: https://github.com/rkbeatss
|
||||
- login: raphaelauv
|
||||
count: 4
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
url: https://github.com/raphaelauv
|
||||
sponsors:
|
||||
- login: samuelcolvin
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4
|
||||
@@ -258,6 +266,9 @@ sponsors:
|
||||
- login: wshayes
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
|
||||
url: https://github.com/wshayes
|
||||
- login: lukin0110
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/992275?u=d20b7e18b213ae7004585b382eccb542db5ffe48&v=4
|
||||
url: https://github.com/lukin0110
|
||||
- login: ltieman
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/1084689?u=c9bf77f5e57f98b49694870219b9bd9d1cc862e7&v=4
|
||||
url: https://github.com/ltieman
|
||||
@@ -267,9 +278,6 @@ sponsors:
|
||||
- login: timdrijvers
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/1694939?v=4
|
||||
url: https://github.com/timdrijvers
|
||||
- login: abdelhai
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/1752577?u=8f8f2bce75f3ab68188cea2b5da37c784197acd8&v=4
|
||||
url: https://github.com/abdelhai
|
||||
- login: ddahan
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/1933516?u=4068dc3c5db5d3605116c4f5df6deb9fee324c33&v=4
|
||||
url: https://github.com/ddahan
|
||||
@@ -292,10 +300,13 @@ sponsors:
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4
|
||||
url: https://github.com/pawamoy
|
||||
- login: p141592
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/5256328?u=7f9fdf3329bf90017cff00c8a78781bd7a2b48aa&v=4
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/5256328?u=07bc6374282ab3d08511afebaa5d511987d034f1&v=4
|
||||
url: https://github.com/p141592
|
||||
- login: ginomempin
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/6091865?v=4
|
||||
url: https://github.com/ginomempin
|
||||
- login: fabboe
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/7251331?v=4
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/7251331?u=43098dddeee6514a552ee5e98bc198ecfd18fdb7&v=4
|
||||
url: https://github.com/fabboe
|
||||
- login: Shackelford-Arden
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/7362263?v=4
|
||||
@@ -303,9 +314,9 @@ sponsors:
|
||||
- login: macleodmac
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/8996312?u=e39c68c3e0b1d264dcba4850134a291680f46355&v=4
|
||||
url: https://github.com/macleodmac
|
||||
- login: cristeaadrian
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/9112724?u=76099d546d6ee44b3ad7269773ecb916590c6a36&v=4
|
||||
url: https://github.com/cristeaadrian
|
||||
- login: hard-coders
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4
|
||||
url: https://github.com/hard-coders
|
||||
- login: otivvormes
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/11317418?u=6de1edefb6afd0108c0ad2816bd6efc4464a9c44&v=4
|
||||
url: https://github.com/otivvormes
|
||||
@@ -321,9 +332,6 @@ sponsors:
|
||||
- login: robintully
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/17059673?u=862b9bb01513f5acd30df97433cb97a24dbfb772&v=4
|
||||
url: https://github.com/robintully
|
||||
- login: Duval23
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/17622958?v=4
|
||||
url: https://github.com/Duval23
|
||||
- login: wedwardbeck
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/19333237?u=1de4ae2bf8d59eb4c013f21d863cbe0f2010575f&v=4
|
||||
url: https://github.com/wedwardbeck
|
||||
@@ -349,8 +357,11 @@ sponsors:
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/34250156?u=c50c9df0e34f411f7e5f050a72e8d89696284eba&v=4
|
||||
url: https://github.com/d3vzer0
|
||||
- login: AjitZK
|
||||
avatarUrl: https://avatars0.githubusercontent.com/u/40203625?u=70c479337ab95d76ab59ae17ba0a988f1b43c0c6&v=4
|
||||
avatarUrl: https://avatars3.githubusercontent.com/u/40203625?u=9638bfeacfa5940358188f8205ce662bba022b53&v=4
|
||||
url: https://github.com/AjitZK
|
||||
- login: ilias-ant
|
||||
avatarUrl: https://avatars1.githubusercontent.com/u/42189572?u=064bf3a60fcb3c445ab038386321098920b3f4e4&v=4
|
||||
url: https://github.com/ilias-ant
|
||||
- login: dbanty
|
||||
avatarUrl: https://avatars2.githubusercontent.com/u/43723790?u=0cf33e4f40efc2ea206a1189fd63a11344eb88ed&v=4
|
||||
url: https://github.com/dbanty
|
||||
|
||||
@@ -2,6 +2,9 @@ gold:
|
||||
- url: https://www.deta.sh/?ref=fastapi
|
||||
title: The launchpad for all your (team's) ideas
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/deta.svg
|
||||
- url: https://www.investsuite.com/
|
||||
title: Wealthtech as a service
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/investsuite.svg
|
||||
silver:
|
||||
- url: https://testdriven.io/courses/tdd-fastapi/
|
||||
title: Learn to build high-quality web apps with best practices
|
||||
|
||||
@@ -55,3 +55,11 @@ a.internal-link::after {
|
||||
font-size: 80%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
a.announce:link, a.announce:visited {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
a.announce:hover {
|
||||
color: var(--md-accent-fg-color);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Deploy on Deta
|
||||
# Deploy FastAPI on Deta
|
||||
|
||||
In this section you will learn how to easily deploy a **FastAPI** application on <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> using the free plan. 🎁
|
||||
|
||||
|
||||
@@ -11,13 +11,18 @@ You just need to install an ASGI compatible server like:
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
!!! tip
|
||||
By adding the `standard`, Uvicorn will install and use some recommended extra dependencies.
|
||||
|
||||
That including `uvloop`, the high-performance drop-in replacement for `asyncio`, that provides the big concurrency performance boost.
|
||||
|
||||
=== "Hypercorn"
|
||||
|
||||
* <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>, an ASGI server also compatible with HTTP/2.
|
||||
|
||||
@@ -10,6 +10,16 @@ There are very simple ways to help (several involve just one or two clicks).
|
||||
|
||||
And there are several ways to get help too.
|
||||
|
||||
## Subscribe to the newsletter
|
||||
|
||||
You can subscribe to the (infrequent) [**FastAPI and friends** newsletter](/newsletter/){.internal-link target=_blank} to stay updated about:
|
||||
|
||||
* News about FastAPI and friends 🚀
|
||||
* Guides 📝
|
||||
* Features ✨
|
||||
* Breaking changes 🚨
|
||||
* Tips and tricks ✅
|
||||
|
||||
## Star **FastAPI** in GitHub
|
||||
|
||||
You can "star" FastAPI in GitHub (clicking the star button at the top right): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. ⭐️
|
||||
|
||||
114
docs/en/docs/img/sponsors/investsuite.svg
Normal file
114
docs/en/docs/img/sponsors/investsuite.svg
Normal file
@@ -0,0 +1,114 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="240"
|
||||
height="100"
|
||||
viewBox="0 0 63.5 26.458334"
|
||||
version="1.1"
|
||||
id="svg975">
|
||||
<defs
|
||||
id="defs969">
|
||||
<clipPath
|
||||
id="clip0">
|
||||
<rect
|
||||
width="770"
|
||||
height="222.03999"
|
||||
fill="#ffffff"
|
||||
id="rect14"
|
||||
x="0"
|
||||
y="0" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clip0-7">
|
||||
<rect
|
||||
width="770"
|
||||
height="222.03999"
|
||||
fill="#ffffff"
|
||||
id="rect14-5"
|
||||
x="0"
|
||||
y="0" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clip0-2">
|
||||
<rect
|
||||
width="770"
|
||||
height="222.03999"
|
||||
fill="#ffffff"
|
||||
id="rect14-0"
|
||||
x="0"
|
||||
y="0" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata972">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.342717;stop-color:#000000"
|
||||
id="rect945"
|
||||
width="63.5"
|
||||
height="26.458334"
|
||||
x="4e-07"
|
||||
y="-1.5122477e-07" />
|
||||
<g
|
||||
id="g967"
|
||||
transform="translate(0.17210258,1.0583333)">
|
||||
<g
|
||||
id="g955"
|
||||
transform="matrix(0.65843845,0,0,0.65843845,0.27576501,1.1223943)">
|
||||
<path
|
||||
d="m 8.9812622,1.4378695 1.2474488,0.00173 7.302287,7.3022874 0.0018,1.3131081 -7.022162,7.02216 -1.7676605,-0.0025 -6.8470822,-6.847084 -0.00242,-1.7019627 7.0877822,-7.087706 z"
|
||||
fill="#d10622"
|
||||
fill-rule="evenodd"
|
||||
id="path884"
|
||||
style="fill:#b3b3b3;stroke-width:0.0383523" />
|
||||
<path
|
||||
d="m 12.889758,1.4378695 1.24741,0.00173 7.302287,7.3022874 0.0018,1.3131081 -7.022161,7.022161 -1.76766,-0.0025 -6.8470835,-6.847084 -0.00242,-1.7019627 7.0878215,-7.0877058 z"
|
||||
fill="#f7c0bd"
|
||||
fill-rule="evenodd"
|
||||
id="path895"
|
||||
style="stroke-width:0.0383523" />
|
||||
<path
|
||||
d="m 16.798207,1.4378695 1.24741,0.00173 7.302287,7.3022874 0.0018,1.3131081 -7.022162,7.022161 -1.767659,-0.0025 -6.8470836,-6.847084 -0.0024,-1.7019626 7.0877436,-7.0877059 z"
|
||||
fill="#0000ff"
|
||||
fill-rule="evenodd"
|
||||
opacity="0.8"
|
||||
id="path906"
|
||||
style="stroke-width:0.0383523" />
|
||||
<path
|
||||
d="m 20.706643,1.4378692 1.247449,0.00173 7.302287,7.3022875 0.0018,1.3131083 -7.022161,7.022161 -1.76766,-0.0025 -6.847122,-6.847084 -0.0024,-1.7019627 7.087783,-7.0877061 z"
|
||||
fill="#ffffff"
|
||||
fill-rule="evenodd"
|
||||
id="path917"
|
||||
style="fill:#e7285d;fill-opacity:1;stroke-width:0.0383523" />
|
||||
</g>
|
||||
<path
|
||||
d="m 58.713926,8.3808577 h 2.793359 l 0.084,-0.04316 c 0.04201,-0.09527 0.04201,-0.173052 0.04201,-0.216608 0,-1.168599 -0.713215,-2.120589 -1.761649,-2.120589 -1.21643,0 -2.013255,0.95199 -2.013255,2.129144 0,1.2036 0.964434,2.1991443 2.180866,2.1991443 0.629215,0 1.216431,-0.30333 1.594038,-0.5627163 v -0.909211 l -0.04201,-0.04277 c -0.419605,0.432439 -1.006435,0.692215 -1.55165,0.692215 -0.713214,0 -1.216431,-0.475995 -1.325708,-1.125434 z m -0.04667,-0.757546 c 0.124051,-0.446441 0.565828,-0.811214 1.184543,-0.811214 0.486495,0 0.928657,0.364773 0.972601,0.811214 z M 56.35728,10.328782 c 0.279997,0 0.726048,-0.118994 0.962101,-0.255108 V 9.2671277 l -0.04394,-0.04277 a 1.5905386,1.5905386 0 0 1 -0.917766,0.297497 c -0.349996,0 -0.656048,-0.254721 -0.656048,-0.934492 v -1.529096 h 1.573817 l 0.04395,-0.04277 v -0.764547 l -0.04395,-0.04239 h -1.57382 v -0.968322 l -0.04395,-0.05094 h -0.787101 l -0.04355,0.04239 v 0.976879 h -0.6996 l -0.04355,0.04277 v 0.764158 l 0.04355,0.04239 h 0.699603 v 1.571483 c 0,1.104433 0.56855,1.6994263 1.530262,1.6994263 z m -3.580069,-4.8696143 0.497773,-0.499328 v -0.08322 l -0.497773,-0.49933 h -0.08284 l -0.497769,0.499329 v 0.08322 l 0.497772,0.499328 z m -1.431873,4.7443943 0.04201,-0.04201 V 6.3127617 l -0.04201,-0.04201 h -0.754437 l -0.04238,0.04201 v 2.802693 c -0.20961,0.25122 -0.629216,0.418441 -1.048434,0.418441 -0.713214,0 -1.048434,-0.418441 -1.048434,-1.087712 v -2.133422 l -0.04201,-0.04201 h -0.755214 l -0.04161,0.04201 v 2.175421 c 0,1.128934 0.628827,1.8405923 1.887258,1.8405923 0.377218,0 0.754825,-0.125609 1.048433,-0.292829 v 0.125608 l 0.04201,0.04161 h 0.754826 z M 44.157191,5.6403867 c 0,-0.373329 0.24772,-0.62377 0.581384,-0.636603 v -0.0016 c 0.510994,0.0062 0.811992,0.302941 1.069433,0.851657 h 0.08711 l 0.6506,-0.511772 c -0.303326,-0.766816 -0.953931,-1.235422 -1.82231,-1.235422 v 0.0023 c -0.88238,0.02061 -1.564093,0.692603 -1.564093,1.532206 0,1.661704 2.646748,1.576538 2.646748,2.769636 0,0.59655 -0.390828,1.022768 -0.954711,1.022768 -0.520717,0 -0.824437,-0.298274 -1.08499,-0.852047 h -0.08672 l -0.650608,0.511383 c 0.30333,0.76727 0.954712,1.2358763 1.822315,1.2358763 1.084987,0 1.9522,-0.8524353 1.9522,-1.9179803 0,-1.959979 -2.646361,-1.917589 -2.646361,-2.770025 z m -2.629248,4.6883953 c 0.279218,0 0.725268,-0.118994 0.961323,-0.255108 V 9.2671277 l -0.04355,-0.04277 c -0.34105,0.237998 -0.673548,0.297497 -0.917766,0.297497 -0.349997,0 -0.656438,-0.254721 -0.656438,-0.934492 v -1.529096 h 1.574204 l 0.04355,-0.04277 v -0.764547 l -0.04355,-0.04239 h -1.574212 v -0.968322 l -0.04355,-0.05094 H 40.04085 l -0.04355,0.04239 v 0.976879 h -0.699992 l -0.04355,0.04277 v 0.764158 l 0.04395,0.04239 h 0.699603 v 1.571483 c 0,1.104433 0.568162,1.6994263 1.530263,1.6994263 z M 38.984247,9.0299077 c 0,-1.68776 -2.341086,-1.081878 -2.341086,-1.817648 0,-0.21622 0.21272,-0.389662 0.595772,-0.389662 0.425439,0 0.851268,0.129886 1.277097,0.432828 l 0.04277,-0.04317 v -0.865656 c -0.340654,-0.216609 -0.808872,-0.346108 -1.319865,-0.346108 -0.894436,0 -1.490206,0.51916 -1.490206,1.211764 0,1.601427 2.341085,0.995546 2.341085,1.818037 0,0.302942 -0.169943,0.475995 -0.766103,0.475995 -0.467828,0 -1.0216,-0.173053 -1.489428,-0.475995 l -0.04277,0.04317 v 0.865658 c 0.383051,0.2597753 1.0216,0.3896613 1.532206,0.3896613 1.021989,0 1.660538,-0.5627163 1.660538,-1.2988743 z m -5.63805,1.2988743 c 0.629603,0 1.216431,-0.30333 1.594038,-0.5627163 v -0.909212 l -0.04199,-0.04277 c -0.419218,0.432439 -1.006434,0.692214 -1.551651,0.692214 -0.713213,0 -1.216431,-0.475995 -1.325319,-1.125433 h 2.79297 l 0.084,-0.04316 c 0.04199,-0.09527 0.04199,-0.173053 0.04199,-0.216609 0,-1.168599 -0.712826,-2.120589 -1.761649,-2.120589 -1.21643,0 -2.013257,0.95199 -2.013257,2.129145 0,1.203599 0.964825,2.1991443 2.180868,2.1991443 z M 31.974211,7.6233117 c 0.124051,-0.446441 0.565828,-0.811214 1.184543,-0.811214 0.486106,0 0.928268,0.364773 0.972601,0.811214 z m -2.409531,2.6623043 1.600649,-3.9716793 -0.04201,-0.04277 h -0.842714 l -0.04201,0.04277 -1.095488,2.849359 -1.0951,-2.849359 -0.04238,-0.04277 h -0.842324 l -0.04238,0.04277 1.601039,3.9720693 0.04201,0.04316 h 0.758316 l 0.04238,-0.04277 z m -2.755247,-0.227498 0.04201,-0.04161 V 7.8410877 c 0,-1.129711 -0.629216,-1.840592 -1.887258,-1.840592 -0.377608,0 -0.755215,0.125227 -1.048824,0.29283 v -0.125609 l -0.04161,-0.04201 h -0.755599 l -0.04201,0.04201 v 3.8487913 l 0.04201,0.04161 h 0.755214 l 0.04161,-0.04161 V 7.2134267 c 0.209997,-0.250831 0.629215,-0.418051 1.048821,-0.418051 0.712825,0 1.048433,0.418051 1.048433,1.087322 v 2.1338103 l 0.04201,0.04161 h 0.754824 z M 21.996206,5.9604407 h 0.0019 v -1.583151 h -0.115497 l -0.693381,0.730715 v 5.1780013 l 0.04044,0.04277 h 0.725659 l 0.04045,-0.04277 V 5.9608287 Z m 30.510342,0.310329 -0.04045,0.04317 v 3.9720693 l 0.04045,0.04316 h 0.727992 l 0.04045,-0.04277 V 6.3135577 l -0.04045,-0.04277 h -0.728382 z"
|
||||
fill="#f7c0bd"
|
||||
fill-rule="evenodd"
|
||||
id="path934"
|
||||
style="fill:#e7285d;fill-opacity:1;stroke-width:0.388885" />
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.65251px;line-height:1.25;font-family:Roboto, sans-serif;-inkscape-font-specification:'Roboto, sans-serif';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;stroke-width:0.116313"
|
||||
x="31.727283"
|
||||
y="21.847746"
|
||||
id="text959"><tspan
|
||||
id="tspan957"
|
||||
x="31.727282"
|
||||
y="21.847746"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto, sans-serif;-inkscape-font-specification:'Roboto, sans-serif';text-align:center;text-anchor:middle;stroke-width:0.116313">Wealthtech as a service</tspan></text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.6 KiB |
@@ -128,7 +128,7 @@ You will also need an ASGI server, for production such as <a href="https://www.u
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
5
docs/en/docs/newsletter.md
Normal file
5
docs/en/docs/newsletter.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# FastAPI and friends newsletter
|
||||
|
||||
<iframe class="mj-w-res-iframe" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://app.mailjet.com/widget/iframe/6gQ4/GDo" width="100%"></iframe>
|
||||
|
||||
<script type="text/javascript" src="https://app.mailjet.com/statics/js/iframeResizer.min.js"></script>
|
||||
@@ -2,6 +2,45 @@
|
||||
|
||||
## Latest Changes
|
||||
|
||||
## 0.63.0
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Improve type annotations, add support for mypy --strict, internally and for external packages. PR [#2547](https://github.com/tiangolo/fastapi/pull/2547) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* ⬆️ Upgrade Uvicorn when installing `fastapi[all]` to the latest version including `uvloop`, the new range is `uvicorn[standard] >=0.12.0,<0.14.0`. PR [#2548](https://github.com/tiangolo/fastapi/pull/2548) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Fixes
|
||||
|
||||
* 🐛 PR [#2547](https://github.com/tiangolo/fastapi/pull/2547) (read above) also fixes some false-positive mypy errors with `callbacks` parameters and when using the `OAuth2` class.
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Update Uvicorn installation instructions to use uvicorn[standard] (includes uvloop). PR [#2543](https://github.com/tiangolo/fastapi/pull/2543) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Update title for Deta tutorial. PR [#2466](https://github.com/tiangolo/fastapi/pull/2466) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👥 Update FastAPI People. PR [#2454](https://github.com/tiangolo/fastapi/pull/2454) by [@github-actions[bot]](https://github.com/apps/github-actions).
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Add docs lang selector widget. PR [#2542](https://github.com/tiangolo/fastapi/pull/2542) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Add Chinese translation for Tutorial - Response Status Code. PR [#2442](https://github.com/tiangolo/fastapi/pull/2442) by [@waynerv](https://github.com/waynerv).
|
||||
* 🌐 Start translation of the documentation for the Albanian language. PR [#2516](https://github.com/tiangolo/fastapi/pull/2516) by [@vjanz](https://github.com/vjanz).
|
||||
* 🌐 Add Chinese translation for Tutorial - Extra Models. PR [#2416](https://github.com/tiangolo/fastapi/pull/2416) by [@waynerv](https://github.com/waynerv).
|
||||
* 🌐 Add Chinese translation for Tutorial - Response Model. PR [#2414](https://github.com/tiangolo/fastapi/pull/2414) by [@waynerv](https://github.com/waynerv).
|
||||
* 🌐 Add Chinese translation for Tutorial - Schema Extra Example. PR [#2411](https://github.com/tiangolo/fastapi/pull/2411) by [@maoyibo](https://github.com/maoyibo).
|
||||
* 🌐 Add Korean translation for Index. PR [#2192](https://github.com/tiangolo/fastapi/pull/2192) by [@hard-coders](https://github.com/hard-coders).
|
||||
* 🌐 Add Japanese translation for Advanced User Guide - Additional Status Codes. PR [#2145](https://github.com/tiangolo/fastapi/pull/2145) by [@Attsun1031](https://github.com/Attsun1031).
|
||||
|
||||
### Internal
|
||||
|
||||
* 🐛 Fix docs overrides directory for translations. PR [#2541](https://github.com/tiangolo/fastapi/pull/2541) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ➖ Remove Typer as a docs building dependency (covered by typer-cli) to fix pip resolver conflicts. PR [#2539](https://github.com/tiangolo/fastapi/pull/2539) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ✨ Add newsletter: FastAPI and friends. PR [#2509](https://github.com/tiangolo/fastapi/pull/2509) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ✨ Add new Gold Sponsor: InvestSuite 🎉. PR [#2508](https://github.com/tiangolo/fastapi/pull/2508) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Add issue template configs. PR [#2476](https://github.com/tiangolo/fastapi/pull/2476) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.62.0
|
||||
|
||||
### Features
|
||||
|
||||
@@ -64,7 +64,7 @@ $ pip install fastapi[all]
|
||||
Also install `uvicorn` to work as the server:
|
||||
|
||||
```
|
||||
pip install uvicorn
|
||||
pip install uvicorn[standard]
|
||||
```
|
||||
|
||||
And the same for each of the optional dependencies that you want to use.
|
||||
|
||||
@@ -3,6 +3,7 @@ site_description: FastAPI framework, high performance, easy to learn, fast to co
|
||||
site_url: https://fastapi.tiangolo.com/
|
||||
theme:
|
||||
name: material
|
||||
custom_dir: overrides
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: teal
|
||||
@@ -45,6 +46,7 @@ nav:
|
||||
- ko: /ko/
|
||||
- pt: /pt/
|
||||
- ru: /ru/
|
||||
- sq: /sq/
|
||||
- tr: /tr/
|
||||
- uk: /uk/
|
||||
- zh: /zh/
|
||||
@@ -181,6 +183,31 @@ extra:
|
||||
link: https://medium.com/@tiangolo
|
||||
- icon: fontawesome/solid/globe
|
||||
link: https://tiangolo.com
|
||||
alternate:
|
||||
- link: /
|
||||
name: en - English
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /it/
|
||||
name: it - italiano
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /sq/
|
||||
name: sq - shqip
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh/
|
||||
name: zh - 汉语
|
||||
extra_css:
|
||||
- css/termynal.css
|
||||
- css/custom.css
|
||||
|
||||
9
docs/en/overrides/main.html
Normal file
9
docs/en/overrides/main.html
Normal file
@@ -0,0 +1,9 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block announce %}
|
||||
<a class="announce" href="https://fastapi.tiangolo.com/newsletter/">
|
||||
<span class="twemoji">
|
||||
{% include ".icons/material/email.svg" %}
|
||||
</span> Subscribe to the <strong>FastAPI and friends</strong> newsletter 🎉
|
||||
</a>
|
||||
{% endblock %}
|
||||
@@ -127,7 +127,7 @@ También vas a necesitar un servidor ASGI para producción cómo <a href="https:
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
@@ -64,7 +64,7 @@ $ pip install fastapi[all]
|
||||
También debes instalar `uvicorn` para que funcione como tu servidor:
|
||||
|
||||
```
|
||||
pip install uvicorn
|
||||
pip install uvicorn[standard]
|
||||
```
|
||||
|
||||
Y lo mismo para cada una de las dependencias opcionales que quieras utilizar.
|
||||
|
||||
@@ -3,6 +3,7 @@ site_description: FastAPI framework, high performance, easy to learn, fast to co
|
||||
site_url: https://fastapi.tiangolo.com/es/
|
||||
theme:
|
||||
name: material
|
||||
custom_dir: overrides
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: teal
|
||||
@@ -45,6 +46,7 @@ nav:
|
||||
- ko: /ko/
|
||||
- pt: /pt/
|
||||
- ru: /ru/
|
||||
- sq: /sq/
|
||||
- tr: /tr/
|
||||
- uk: /uk/
|
||||
- zh: /zh/
|
||||
@@ -85,6 +87,31 @@ extra:
|
||||
link: https://medium.com/@tiangolo
|
||||
- icon: fontawesome/solid/globe
|
||||
link: https://tiangolo.com
|
||||
alternate:
|
||||
- link: /
|
||||
name: en - English
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /it/
|
||||
name: it - italiano
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /sq/
|
||||
name: sq - shqip
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh/
|
||||
name: zh - 汉语
|
||||
extra_css:
|
||||
- https://fastapi.tiangolo.com/css/termynal.css
|
||||
- https://fastapi.tiangolo.com/css/custom.css
|
||||
|
||||
0
docs/es/overrides/.gitignore
vendored
Normal file
0
docs/es/overrides/.gitignore
vendored
Normal file
@@ -132,7 +132,7 @@ You will also need an ASGI server, for production such as <a href="https://www.u
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
@@ -3,6 +3,7 @@ site_description: FastAPI framework, high performance, easy to learn, fast to co
|
||||
site_url: https://fastapi.tiangolo.com/fr/
|
||||
theme:
|
||||
name: material
|
||||
custom_dir: overrides
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: teal
|
||||
@@ -45,6 +46,7 @@ nav:
|
||||
- ko: /ko/
|
||||
- pt: /pt/
|
||||
- ru: /ru/
|
||||
- sq: /sq/
|
||||
- tr: /tr/
|
||||
- uk: /uk/
|
||||
- zh: /zh/
|
||||
@@ -78,6 +80,31 @@ extra:
|
||||
link: https://medium.com/@tiangolo
|
||||
- icon: fontawesome/solid/globe
|
||||
link: https://tiangolo.com
|
||||
alternate:
|
||||
- link: /
|
||||
name: en - English
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /it/
|
||||
name: it - italiano
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /sq/
|
||||
name: sq - shqip
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh/
|
||||
name: zh - 汉语
|
||||
extra_css:
|
||||
- https://fastapi.tiangolo.com/css/termynal.css
|
||||
- https://fastapi.tiangolo.com/css/custom.css
|
||||
|
||||
0
docs/fr/overrides/.gitignore
vendored
Normal file
0
docs/fr/overrides/.gitignore
vendored
Normal file
@@ -132,7 +132,7 @@ You will also need an ASGI server, for production such as <a href="https://www.u
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
@@ -3,6 +3,7 @@ site_description: FastAPI framework, high performance, easy to learn, fast to co
|
||||
site_url: https://fastapi.tiangolo.com/it/
|
||||
theme:
|
||||
name: material
|
||||
custom_dir: overrides
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: teal
|
||||
@@ -45,6 +46,7 @@ nav:
|
||||
- ko: /ko/
|
||||
- pt: /pt/
|
||||
- ru: /ru/
|
||||
- sq: /sq/
|
||||
- tr: /tr/
|
||||
- uk: /uk/
|
||||
- zh: /zh/
|
||||
@@ -78,6 +80,31 @@ extra:
|
||||
link: https://medium.com/@tiangolo
|
||||
- icon: fontawesome/solid/globe
|
||||
link: https://tiangolo.com
|
||||
alternate:
|
||||
- link: /
|
||||
name: en - English
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /it/
|
||||
name: it - italiano
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /sq/
|
||||
name: sq - shqip
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh/
|
||||
name: zh - 汉语
|
||||
extra_css:
|
||||
- https://fastapi.tiangolo.com/css/termynal.css
|
||||
- https://fastapi.tiangolo.com/css/custom.css
|
||||
|
||||
0
docs/it/overrides/.gitignore
vendored
Normal file
0
docs/it/overrides/.gitignore
vendored
Normal file
37
docs/ja/docs/advanced/additional-status-codes.md
Normal file
37
docs/ja/docs/advanced/additional-status-codes.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# 追加のステータスコード
|
||||
|
||||
デフォルトでは、 **FastAPI** は `JSONResponse` を使ってレスポンスを返します。その `JSONResponse` の中には、 *path operation* が返した内容が入ります。
|
||||
|
||||
それは、デフォルトのステータスコードか、 *path operation* でセットしたものを利用します。
|
||||
|
||||
## 追加のステータスコード
|
||||
|
||||
メインのステータスコードとは別に、他のステータスコードを返したい場合は、`Response` (`JSONResponse` など) に追加のステータスコードを設定して直接返します。
|
||||
|
||||
例えば、itemを更新し、成功した場合は200 "OK"のHTTPステータスコードを返す *path operation* を作りたいとします。
|
||||
|
||||
しかし、新しいitemも許可したいです。itemが存在しない場合は、それらを作成して201 "Created"を返します。
|
||||
|
||||
これを達成するには、 `JSONResponse` をインポートし、 `status_code` を設定して直接内容を返します。
|
||||
|
||||
```Python hl_lines="4 23"
|
||||
{!../../../docs_src/additional_status_codes/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! warning "注意"
|
||||
上記の例のように `Response` を明示的に返す場合、それは直接返されます。
|
||||
|
||||
モデルなどはシリアライズされません。
|
||||
|
||||
必要なデータが含まれていることや、値が有効なJSONであること (`JSONResponse` を使う場合) を確認してください。
|
||||
|
||||
!!! note "技術詳細"
|
||||
`from starlette.responses import JSONResponse` を利用することもできます。
|
||||
|
||||
**FastAPI** は `fastapi.responses` と同じ `starlette.responses` を、開発者の利便性のために提供しています。しかし有効なレスポンスはほとんどStarletteから来ています。 `status` についても同じです。
|
||||
|
||||
## OpenAPIとAPIドキュメント
|
||||
|
||||
ステータスコードとレスポンスを直接返す場合、それらはOpenAPIスキーマ (APIドキュメント) には含まれません。なぜなら、FastAPIは何が返されるのか事前に知ることができないからです。
|
||||
|
||||
しかし、 [Additional Responses](additional-responses.md){.internal-link target=_blank} を使ってコードの中にドキュメントを書くことができます。
|
||||
@@ -128,7 +128,7 @@ $ pip install fastapi
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
@@ -64,7 +64,7 @@ $ pip install fastapi[all]
|
||||
また、サーバーとして動作するように`uvicorn` をインストールします:
|
||||
|
||||
```
|
||||
pip install uvicorn
|
||||
pip install uvicorn[standard]
|
||||
```
|
||||
|
||||
そして、使用したい依存関係をそれぞれ同様にインストールします。
|
||||
|
||||
@@ -3,6 +3,7 @@ site_description: FastAPI framework, high performance, easy to learn, fast to co
|
||||
site_url: https://fastapi.tiangolo.com/ja/
|
||||
theme:
|
||||
name: material
|
||||
custom_dir: overrides
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: teal
|
||||
@@ -45,6 +46,7 @@ nav:
|
||||
- ko: /ko/
|
||||
- pt: /pt/
|
||||
- ru: /ru/
|
||||
- sq: /sq/
|
||||
- tr: /tr/
|
||||
- uk: /uk/
|
||||
- zh: /zh/
|
||||
@@ -57,10 +59,11 @@ nav:
|
||||
- tutorial/body.md
|
||||
- tutorial/query-params-str-validations.md
|
||||
- tutorial/header-params.md
|
||||
- tutorial/cors.md
|
||||
- セキュリティ:
|
||||
- tutorial/security/first-steps.md
|
||||
- tutorial/cors.md
|
||||
- 高度なユーザーガイド:
|
||||
- advanced/additional-status-codes.md
|
||||
- advanced/response-directly.md
|
||||
- advanced/custom-response.md
|
||||
- project-generation.md
|
||||
@@ -99,6 +102,31 @@ extra:
|
||||
link: https://medium.com/@tiangolo
|
||||
- icon: fontawesome/solid/globe
|
||||
link: https://tiangolo.com
|
||||
alternate:
|
||||
- link: /
|
||||
name: en - English
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /it/
|
||||
name: it - italiano
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /sq/
|
||||
name: sq - shqip
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh/
|
||||
name: zh - 汉语
|
||||
extra_css:
|
||||
- https://fastapi.tiangolo.com/css/termynal.css
|
||||
- https://fastapi.tiangolo.com/css/custom.css
|
||||
|
||||
0
docs/ja/overrides/.gitignore
vendored
Normal file
0
docs/ja/overrides/.gitignore
vendored
Normal file
@@ -1,12 +1,8 @@
|
||||
|
||||
{!../../../docs/missing-translation.md!}
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
|
||||
<em>FastAPI 프레임워크, 고성능, 간편한 학습, 빠른 코드 작성, 준비된 프로덕션</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/tiangolo/fastapi/actions?query=workflow%3ATest" target="_blank">
|
||||
@@ -22,29 +18,29 @@
|
||||
|
||||
---
|
||||
|
||||
**Documentation**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
|
||||
**문서**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
|
||||
|
||||
**Source Code**: <a href="https://github.com/tiangolo/fastapi" target="_blank">https://github.com/tiangolo/fastapi</a>
|
||||
**소스 코드**: <a href="https://github.com/tiangolo/fastapi" target="_blank">https://github.com/tiangolo/fastapi</a>
|
||||
|
||||
---
|
||||
|
||||
FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.
|
||||
FastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트에 기초한 Python3.6+의 API를 빌드하기 위한 웹 프레임워크입니다.
|
||||
|
||||
The key features are:
|
||||
주요 특징으로:
|
||||
|
||||
* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance).
|
||||
* **빠름**: (Starlette과 Pydantic 덕분에) **NodeJS** 및 **Go**와 대등할 정도로 매우 높은 성능. [사용 가능한 가장 빠른 파이썬 프레임워크 중 하나](#performance).
|
||||
|
||||
* **Fast to code**: Increase the speed to develop features by about 200% to 300%. *
|
||||
* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. *
|
||||
* **Intuitive**: Great editor support. <abbr title="also known as auto-complete, autocompletion, IntelliSense">Completion</abbr> everywhere. Less time debugging.
|
||||
* **Easy**: Designed to be easy to use and learn. Less time reading docs.
|
||||
* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
|
||||
* **Robust**: Get production-ready code. With automatic interactive documentation.
|
||||
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
* **빠른 코드 작성**: 약 200%에서 300%까지 기능 개발 속도 증가. *
|
||||
* **적은 버그**: 사람(개발자)에 의한 에러 약 40% 감소. *
|
||||
* **직관적**: 훌륭한 편집기 지원. 모든 곳에서 <abbr title="also known as auto-complete, autocompletion, IntelliSense">자동완성</abbr>. 적은 디버깅 시간.
|
||||
* **쉬움**: 쉽게 사용하고 배우도록 설계. 적은 문서 읽기 시간.
|
||||
* **짧음**: 코드 중복 최소화. 각 매개변수 선언의 여러 기능. 적은 버그.
|
||||
* **견고함**: 준비된 프로덕션 용 코드를 얻으세요. 자동 대화형 문서와 함께.
|
||||
* **표준 기반**: API에 대한 (완전히 호환되는) 개방형 표준 기반: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (이전에 Swagger로 알려졌던) 및 <a href="http://json-schema.org/" class="external-link" target="_blank">JSON 스키마</a>.
|
||||
|
||||
<small>* estimation based on tests on an internal development team, building production applications.</small>
|
||||
<small>* 내부 개발팀의 프로덕션 애플리케이션을 빌드한 테스트에 근거한 측정</small>
|
||||
|
||||
## Gold Sponsors
|
||||
## 골드 스폰서
|
||||
|
||||
<!-- sponsors -->
|
||||
|
||||
@@ -56,66 +52,66 @@ The key features are:
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">Other sponsors</a>
|
||||
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">다른 스폰서</a>
|
||||
|
||||
## Opinions
|
||||
## 의견들
|
||||
|
||||
"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._"
|
||||
"_[...] 저는 요즘 **FastAPI**를 많이 사용하고 있습니다. [...] 사실 우리 팀의 **마이크로소프트 ML 서비스** 전부를 바꿀 계획입니다. 그중 일부는 핵심 **Windows**와 몇몇의 **Office** 제품들이 통합되고 있습니다._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/tiangolo/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>마이크로소프트</strong> <a href="https://github.com/tiangolo/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_"
|
||||
"_**FastAPI** 라이브러리를 채택하여 **예측**을 얻기 위해 쿼리를 실행 할 수 있는 **REST** 서버를 생성했습니다. [Ludwig을 위해]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin 그리고 Sai Sumanth Miryala - <strong>우버</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_"
|
||||
"_**Netflix**는 우리의 오픈 소스 배포판인 **위기 관리** 오케스트레이션 프레임워크를 발표할 수 있어 기쁩니다: 바로 **Dispatch**입니다! [**FastAPI**로 빌드]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>넷플릭스</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_I’m over the moon excited about **FastAPI**. It’s so fun!_"
|
||||
"_**FastAPI**가 너무 좋아서 구름 위를 걷는듯 합니다. 정말 즐겁습니다!_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://twitter.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> 팟캐스트 호스트</strong> <a href="https://twitter.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._"
|
||||
"_솔직히, 당신이 만든 것은 매우 견고하고 세련되어 보입니다. 여러 면에서 **Hug**가 이렇게 되었으면 합니다 - 그걸 만든 누군가를 보는 것은 많은 영감을 줍니다._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="http://www.hug.rest/" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="http://www.hug.rest/" target="_blank">Hug</a> 제작자</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_"
|
||||
"_REST API를 만들기 위해 **현대적인 프레임워크**를 찾고 있다면 **FastAPI**를 확인해 보세요. [...] 빠르고, 쓰기 쉽고, 배우기도 쉽습니다 [...]_"
|
||||
|
||||
"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_"
|
||||
"_우리 **API**를 **FastAPI**로 바꿨습니다 [...] 아마 여러분도 좋아하실 겁니다 [...]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> founders - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://twitter.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://twitter.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> 설립자 - <a href="https://spacy.io" target="_blank">spaCy</a> 제작자</strong> <a href="https://twitter.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://twitter.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
## **Typer**, the FastAPI of CLIs
|
||||
## **Typer**, FastAPI의 CLI
|
||||
|
||||
<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>
|
||||
|
||||
If you are building a <abbr title="Command Line Interface">CLI</abbr> app to be used in the terminal instead of a web API, check out <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
|
||||
웹 API 대신 터미널에서 사용할 <abbr title="Command Line Interface">CLI</abbr> 앱을 만들고 있다면, <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>를 확인해 보세요.
|
||||
|
||||
**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀
|
||||
**Typer**는 FastAPI의 동생입니다. 그리고 **FastAPI의 CLI**가 되기 위해 생겼습니다. ⌨️ 🚀
|
||||
|
||||
## Requirements
|
||||
## 요구사항
|
||||
|
||||
Python 3.6+
|
||||
|
||||
FastAPI stands on the shoulders of giants:
|
||||
FastAPI는 거인들의 어깨 위에 서 있습니다:
|
||||
|
||||
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> for the web parts.
|
||||
* <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> for the data parts.
|
||||
* 웹 부분을 위한 <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a>.
|
||||
* 데이터 부분을 위한 <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a>.
|
||||
|
||||
## Installation
|
||||
## 설치
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -127,23 +123,23 @@ $ pip install fastapi
|
||||
|
||||
</div>
|
||||
|
||||
You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
|
||||
프로덕션을 위해 <a href="http://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> 또는 <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>과 같은 ASGI 서버도 필요할 겁니다.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Example
|
||||
## 예제
|
||||
|
||||
### Create it
|
||||
### 만들기
|
||||
|
||||
* Create a file `main.py` with:
|
||||
* `main.py` 파일을 만드세요:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
@@ -164,9 +160,9 @@ def read_item(item_id: int, q: Optional[str] = None):
|
||||
```
|
||||
|
||||
<details markdown="1">
|
||||
<summary>Or use <code>async def</code>...</summary>
|
||||
<summary>또는 <code>async def</code> 사용하기...</summary>
|
||||
|
||||
If your code uses `async` / `await`, use `async def`:
|
||||
여러분의 코드가 `async` / `await`을 사용한다면, `async def`를 사용하세요:
|
||||
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Optional
|
||||
@@ -188,13 +184,13 @@ async def read_item(item_id: int, q: Optional[str] = None):
|
||||
|
||||
**Note**:
|
||||
|
||||
If you don't know, check the _"In a hurry?"_ section about <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` and `await` in the docs</a>.
|
||||
잘 모르겠다면, <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">문서에서 `async`와 `await`</a>에 관한 _"급하세요?"_ 섹션을 확인해 보세요.
|
||||
|
||||
</details>
|
||||
|
||||
### Run it
|
||||
### 실행하기
|
||||
|
||||
Run the server with:
|
||||
서버를 실행하세요:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -211,54 +207,54 @@ INFO: Application startup complete.
|
||||
</div>
|
||||
|
||||
<details markdown="1">
|
||||
<summary>About the command <code>uvicorn main:app --reload</code>...</summary>
|
||||
<summary><code>uvicorn main:app --reload</code> 명령에 관하여...</summary>
|
||||
|
||||
The command `uvicorn main:app` refers to:
|
||||
명령 `uvicorn main:app`은 다음을 나타냅니다:
|
||||
|
||||
* `main`: the file `main.py` (the Python "module").
|
||||
* `main`: `main.py` 파일 (파이썬 "모듈").
|
||||
* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
|
||||
* `--reload`: make the server restart after code changes. Only do this for development.
|
||||
* `--reload`: 코드가 변경된 후 서버 재시작하기. 개발환경에서만 사용하세요.
|
||||
|
||||
</details>
|
||||
|
||||
### Check it
|
||||
### 확인하기
|
||||
|
||||
Open your browser at <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
|
||||
브라우저로 <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>를 열어보세요.
|
||||
|
||||
You will see the JSON response as:
|
||||
아래의 JSON 응답을 볼 수 있습니다:
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
You already created an API that:
|
||||
여러분은 벌써 API를 만들었습니다:
|
||||
|
||||
* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`.
|
||||
* Both _paths_ take `GET` <em>operations</em> (also known as HTTP _methods_).
|
||||
* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`.
|
||||
* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`.
|
||||
* _경로_ `/` 및 `/items/{item_id}`에서 HTTP 요청 받기.
|
||||
* 두 _경로_ 모두 `GET` <em>연산</em>(HTTP _메소드_ 로 알려진)을 받습니다.
|
||||
* _경로_ `/items/{item_id}`는 _경로 매개변수_ `int`형 이어야 하는 `item_id`를 가지고 있습니다.
|
||||
* _경로_ `/items/{item_id}`는 선택적인 `str`형 이어야 하는 _경로 매개변수_ `q`를 가지고 있습니다.
|
||||
|
||||
### Interactive API docs
|
||||
### 대화형 API 문서
|
||||
|
||||
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
이제 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>로 가보세요.
|
||||
|
||||
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
|
||||
자동 대화형 API 문서를 볼 수 있습니다 (<a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a> 제공):
|
||||
|
||||

|
||||
|
||||
### Alternative API docs
|
||||
### 대안 API 문서
|
||||
|
||||
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
그리고 이제 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>로 가보세요.
|
||||
|
||||
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
|
||||
다른 자동 문서를 볼 수 있습니다(<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> 제공):
|
||||
|
||||

|
||||
|
||||
## Example upgrade
|
||||
## 예제 개선
|
||||
|
||||
Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||
이제 `PUT` 요청에 있는 본문(Body)을 받기 위해 `main.py`를 수정해봅시다.
|
||||
|
||||
Declare the body using standard Python types, thanks to Pydantic.
|
||||
Pydantic을 이용해 파이썬 표준 타입으로 본문을 선언합니다.
|
||||
|
||||
```Python hl_lines="4 9 10 11 12 25 26 27"
|
||||
from typing import Optional
|
||||
@@ -290,175 +286,175 @@ def update_item(item_id: int, item: Item):
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
The server should reload automatically (because you added `--reload` to the `uvicorn` command above).
|
||||
서버가 자동으로 리로딩 할 수 있어야 합니다 (위에서 `uvicorn` 명령에 `--reload`을 추가 했기 때문입니다).
|
||||
|
||||
### Interactive API docs upgrade
|
||||
### 대화형 API 문서 업그레이드
|
||||
|
||||
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
이제 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>로 이동합니다.
|
||||
|
||||
* The interactive API documentation will be automatically updated, including the new body:
|
||||
* 대화형 API 문서가 새 본문과 함께 자동으로 업데이트 합니다:
|
||||
|
||||

|
||||
|
||||
* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API:
|
||||
* "Try it out" 버튼을 클릭하면, 매개변수를 채울 수 있게 해주고 직접 API와 상호작용 할 수 있습니다:
|
||||
|
||||

|
||||
|
||||
* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen:
|
||||
* 그러고 나서 "Execute" 버튼을 누르면, 사용자 인터페이스는 API와 통신하고 매개변수를 전송하며 그 결과를 가져와서 화면에 표시합니다:
|
||||
|
||||

|
||||
|
||||
### Alternative API docs upgrade
|
||||
### 대안 API 문서 업그레이드
|
||||
|
||||
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
그리고 이제, <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>로 이동합니다.
|
||||
|
||||
* The alternative documentation will also reflect the new query parameter and body:
|
||||
* 대안 문서 역시 새 쿼리 매개변수와 본문을 반영합니다:
|
||||
|
||||

|
||||
|
||||
### Recap
|
||||
### 요약
|
||||
|
||||
In summary, you declare **once** the types of parameters, body, etc. as function parameters.
|
||||
요약하면, 여러분은 매개변수의 타입, 본문 등을 함수 매개변수로써 **한번에** 선언했습니다.
|
||||
|
||||
You do that with standard modern Python types.
|
||||
여러분은 현대 표준 파이썬 타입으로 이를 행했습니다.
|
||||
|
||||
You don't have to learn a new syntax, the methods or classes of a specific library, etc.
|
||||
새로운 문법, 특정 라이브러리의 메소드나 클래스 등을 배울 필요가 없습니다.
|
||||
|
||||
Just standard **Python 3.6+**.
|
||||
그저 표준 **Python 3.6+**입니다.
|
||||
|
||||
For example, for an `int`:
|
||||
예를 들어, `int`에 대해선:
|
||||
|
||||
```Python
|
||||
item_id: int
|
||||
```
|
||||
|
||||
or for a more complex `Item` model:
|
||||
또는 좀 더 복잡한 `Item` 모델에 대해선:
|
||||
|
||||
```Python
|
||||
item: Item
|
||||
```
|
||||
|
||||
...and with that single declaration you get:
|
||||
...그리고 단 하나의 선언으로 여러분이 얻는 것은:
|
||||
|
||||
* Editor support, including:
|
||||
* Completion.
|
||||
* Type checks.
|
||||
* Validation of data:
|
||||
* Automatic and clear errors when the data is invalid.
|
||||
* Validation even for deeply nested JSON objects.
|
||||
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of input data: coming from the network to Python data and types. Reading from:
|
||||
* 다음을 포함한 편집기 지원:
|
||||
* 자동완성.
|
||||
* 타입 검사.
|
||||
* 데이터 검증:
|
||||
* 데이터가 유효하지 않을 때 자동으로 생성하는 명확한 에러.
|
||||
* 중첩된 JSON 객체에 대한 유효성 검사.
|
||||
* 입력 데이터 <abbr title="다음으로 알려진: 직렬화, 파싱, 마샬링">변환</abbr>: 네트워크에서 파이썬 데이터 및 타입으로 전송. 읽을 수 있는 것들:
|
||||
* JSON.
|
||||
* Path parameters.
|
||||
* Query parameters.
|
||||
* Cookies.
|
||||
* Headers.
|
||||
* Forms.
|
||||
* Files.
|
||||
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of output data: converting from Python data and types to network data (as JSON):
|
||||
* Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
|
||||
* `datetime` objects.
|
||||
* `UUID` objects.
|
||||
* Database models.
|
||||
* ...and many more.
|
||||
* Automatic interactive API documentation, including 2 alternative user interfaces:
|
||||
* 경로 매개변수.
|
||||
* 쿼리 매개변수.
|
||||
* 쿠키.
|
||||
* 헤더.
|
||||
* 폼(Forms).
|
||||
* 파일.
|
||||
* 출력 데이터 <abbr title="다음으로 알려진: 직렬화, 파싱, 마샬링">변환</abbr>: 파이썬 데이터 및 타입을 네트워크 데이터로 전환(JSON 형식으로):
|
||||
* 파이썬 타입 변환 (`str`, `int`, `float`, `bool`, `list`, 등).
|
||||
* `datetime` 객체.
|
||||
* `UUID` 객체.
|
||||
* 데이터베이스 모델.
|
||||
* ...더 많은 것들.
|
||||
* 대안가능한 사용자 인터페이스를 2개 포함한 자동 대화형 API 문서:
|
||||
* Swagger UI.
|
||||
* ReDoc.
|
||||
|
||||
---
|
||||
|
||||
Coming back to the previous code example, **FastAPI** will:
|
||||
이전 코드 예제로 돌아가서, **FastAPI**는 다음처럼 처리합니다:
|
||||
|
||||
* Validate that there is an `item_id` in the path for `GET` and `PUT` requests.
|
||||
* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests.
|
||||
* If it is not, the client will see a useful, clear error.
|
||||
* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests.
|
||||
* As the `q` parameter is declared with `= None`, it is optional.
|
||||
* Without the `None` it would be required (as is the body in the case with `PUT`).
|
||||
* For `PUT` requests to `/items/{item_id}`, Read the body as JSON:
|
||||
* Check that it has a required attribute `name` that should be a `str`.
|
||||
* Check that it has a required attribute `price` that has to be a `float`.
|
||||
* Check that it has an optional attribute `is_offer`, that should be a `bool`, if present.
|
||||
* All this would also work for deeply nested JSON objects.
|
||||
* Convert from and to JSON automatically.
|
||||
* Document everything with OpenAPI, that can be used by:
|
||||
* Interactive documentation systems.
|
||||
* Automatic client code generation systems, for many languages.
|
||||
* Provide 2 interactive documentation web interfaces directly.
|
||||
* `GET` 및 `PUT` 요청에 `item_id`가 경로에 있는지 검증.
|
||||
* `GET` 및 `PUT` 요청에 `item_id`가 `int` 타입인지 검증.
|
||||
* 그렇지 않다면 클라이언트는 유용하고 명확한 에러를 볼 수 있습니다.
|
||||
* `GET` 요청에 `q`라는 선택적인 쿼리 매개변수가 검사(`http://127.0.0.1:8000/items/foo?q=somequery`처럼).
|
||||
* `q` 매개변수는 `= None`으로 선언되었기 때문에 선택사항입니다.
|
||||
* `None`이 없다면 필수사항입니다(`PUT`의 경우와 마찬가지로).
|
||||
* `/items/{item_id}`으로의 `PUT` 요청은 본문을 JSON으로 읽음:
|
||||
* `name`을 필수 속성으로 갖고 `str` 형인지 검사.
|
||||
* `price`을 필수 속성으로 갖고 `float` 형인지 검사.
|
||||
* 만약 주어진다면, `is_offer`를 선택 속성으로 갖고 `bool` 형인지 검사.
|
||||
* 이 모든 것은 깊이 중첩된 JSON 객체에도 적용됩니다.
|
||||
* JSON으로, 그리고 에서부터 자동 변환.
|
||||
* 다음에서 사용할 수 있는 모든 것을 OpenAPI로 문서화:
|
||||
* 대화형 문서 시스템.
|
||||
* 여러 언어들에 대한 자동 클라이언트 코드 생성 시스템.
|
||||
* 2개의 대화형 문서 웹 인터페이스를 직접 제공.
|
||||
|
||||
---
|
||||
|
||||
We just scratched the surface, but you already get the idea of how it all works.
|
||||
우리는 그저 수박 겉핡기만 했을 뿐인데 여러분은 벌써 어떻게 작동하는지 알고 있습니다.
|
||||
|
||||
Try changing the line with:
|
||||
다음 줄을 바꿔보세요:
|
||||
|
||||
```Python
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
...from:
|
||||
...에서:
|
||||
|
||||
```Python
|
||||
... "item_name": item.name ...
|
||||
```
|
||||
|
||||
...to:
|
||||
...으로:
|
||||
|
||||
```Python
|
||||
... "item_price": item.price ...
|
||||
```
|
||||
|
||||
...and see how your editor will auto-complete the attributes and know their types:
|
||||
...그러고 나서 여러분의 편집기가 속성과 타입을 알고 자동 완성하는지 보세요:
|
||||
|
||||

|
||||
|
||||
For a more complete example including more features, see the <a href="https://fastapi.tiangolo.com/tutorial/">Tutorial - User Guide</a>.
|
||||
더 많은 기능을 포함한 보다 완전한 예제의 경우, <a href="https://fastapi.tiangolo.com/tutorial/">튜토리얼 - 사용자 가이드</a>를 보세요.
|
||||
|
||||
**Spoiler alert**: the tutorial - user guide includes:
|
||||
**스포일러 주의**: 튜토리얼 - 사용자 가이드는:
|
||||
|
||||
* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**.
|
||||
* How to set **validation constraints** as `maximum_length` or `regex`.
|
||||
* A very powerful and easy to use **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** system.
|
||||
* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth.
|
||||
* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic).
|
||||
* Many extra features (thanks to Starlette) as:
|
||||
* **WebSockets**
|
||||
* 서로 다른 장소에서 **매개변수** 선언: **헤더**, **쿠키**, **폼 필드** 그리고 **파일**.
|
||||
* `maximum_length` 또는 `regex`처럼 **유효성 제약**하는 방법.
|
||||
* 강력하고 사용하기 쉬운 **<abbr title="컴포넌트, 리소스, 제공자, 서비스, injectables라 알려진">의존성 주입</abbr>** 시스템.
|
||||
* **OAuth2** 지원을 포함한 **JWT tokens** 및 **HTTP Basic**을 갖는 보안과 인증.
|
||||
* (Pydantic 덕분에) **깊은 중첩 JSON 모델**을 선언하는데 더 진보한 (하지만 마찬가지로 쉬운) 기술.
|
||||
* (Starlette 덕분에) 많은 추가 기능:
|
||||
* **웹 소켓**
|
||||
* **GraphQL**
|
||||
* extremely easy tests based on `requests` and `pytest`
|
||||
* `requests` 및 `pytest`에 기반한 극히 쉬운 테스트
|
||||
* **CORS**
|
||||
* **Cookie Sessions**
|
||||
* ...and more.
|
||||
* **쿠키 세션**
|
||||
* ...기타 등등.
|
||||
|
||||
## Performance
|
||||
## 성능
|
||||
|
||||
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
|
||||
독립된 TechEmpower 벤치마크에서 Uvicorn에서 작동하는 FastAPI 어플리케이션이 <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">사용 가능한 가장 빠른 프레임워크 중 하나</a>로 Starlette와 Uvicorn(FastAPI에서 내부적으로 사용)에만 밑돌고 있습니다. (*)
|
||||
|
||||
To understand more about it, see the section <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
|
||||
자세한 내용은 <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">벤치마크</a> 섹션을 보세요.
|
||||
|
||||
## Optional Dependencies
|
||||
## 선택가능한 종속사항
|
||||
|
||||
Used by Pydantic:
|
||||
Pydantic이 사용하는:
|
||||
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
|
||||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - 더 빠른 JSON <abbr title="HTTP 요청에서 파이썬 데이터로 가는 문자열 변환">"파싱"</abbr>.
|
||||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - 이메일 유효성 검사.
|
||||
|
||||
Used by Starlette:
|
||||
Starlette이 사용하는:
|
||||
|
||||
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
|
||||
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
||||
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
|
||||
* <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - Required for `GraphQLApp` support.
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Required if you want to use `UJSONResponse`.
|
||||
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - `TestClient`를 사용하려면 필요.
|
||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - `FileResponse` 또는 `StaticFiles`를 사용하려면 필요.
|
||||
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - 기본 템플릿 설정을 사용하려면 필요.
|
||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - `request.form()`과 함께 <abbr title="HTTP 요청에서 파이썬 데이터로 가는 문자열 변환">"parsing"</abbr>의 지원을 원하면 필요.
|
||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` 지원을 위해 필요.
|
||||
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Starlette의 `SchemaGenerator` 지원을 위해 필요 (FastAPI와 쓸때는 필요가 없을 겁니다).
|
||||
* <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - `GraphQLApp` 지원을 위해 필요.
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - `UJSONResponse`를 사용하려면 필요.
|
||||
|
||||
Used by FastAPI / Starlette:
|
||||
FastAPI / Starlette이 사용하는:
|
||||
|
||||
* <a href="http://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - for the server that loads and serves your application.
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Required if you want to use `ORJSONResponse`.
|
||||
* <a href="http://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - 애플리케이션을 로드하고 제공하는 서버.
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - `ORJSONResponse`을 사용하려면 필요.
|
||||
|
||||
You can install all of these with `pip install fastapi[all]`.
|
||||
`pip install fastapi[all]`를 통해 이 모두를 설치 할 수 있습니다.
|
||||
|
||||
## License
|
||||
## 라이센스
|
||||
|
||||
This project is licensed under the terms of the MIT license.
|
||||
이 프로젝트는 MIT 라이센스 조약에 따라 라이센스가 부여됩니다.
|
||||
|
||||
@@ -3,6 +3,7 @@ site_description: FastAPI framework, high performance, easy to learn, fast to co
|
||||
site_url: https://fastapi.tiangolo.com/ko/
|
||||
theme:
|
||||
name: material
|
||||
custom_dir: overrides
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: teal
|
||||
@@ -45,6 +46,7 @@ nav:
|
||||
- ko: /ko/
|
||||
- pt: /pt/
|
||||
- ru: /ru/
|
||||
- sq: /sq/
|
||||
- tr: /tr/
|
||||
- uk: /uk/
|
||||
- zh: /zh/
|
||||
@@ -78,6 +80,31 @@ extra:
|
||||
link: https://medium.com/@tiangolo
|
||||
- icon: fontawesome/solid/globe
|
||||
link: https://tiangolo.com
|
||||
alternate:
|
||||
- link: /
|
||||
name: en - English
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /it/
|
||||
name: it - italiano
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /sq/
|
||||
name: sq - shqip
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh/
|
||||
name: zh - 汉语
|
||||
extra_css:
|
||||
- https://fastapi.tiangolo.com/css/termynal.css
|
||||
- https://fastapi.tiangolo.com/css/custom.css
|
||||
|
||||
0
docs/ko/overrides/.gitignore
vendored
Normal file
0
docs/ko/overrides/.gitignore
vendored
Normal file
@@ -336,7 +336,7 @@ Você apenas precisa instalar um servidor ASGI compatível como:
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
@@ -121,7 +121,7 @@ Você também precisará de um servidor ASGI para produção, tal como <a href="
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
@@ -64,7 +64,7 @@ $ pip install fastapi[all]
|
||||
Também instale o `uvicorn` para funcionar como servidor:
|
||||
|
||||
```
|
||||
pip install uvicorn
|
||||
pip install uvicorn[standard]
|
||||
```
|
||||
|
||||
E o mesmo para cada dependência opcional que você quiser usar.
|
||||
|
||||
@@ -3,6 +3,7 @@ site_description: FastAPI framework, high performance, easy to learn, fast to co
|
||||
site_url: https://fastapi.tiangolo.com/pt/
|
||||
theme:
|
||||
name: material
|
||||
custom_dir: overrides
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: teal
|
||||
@@ -45,6 +46,7 @@ nav:
|
||||
- ko: /ko/
|
||||
- pt: /pt/
|
||||
- ru: /ru/
|
||||
- sq: /sq/
|
||||
- tr: /tr/
|
||||
- uk: /uk/
|
||||
- zh: /zh/
|
||||
@@ -86,6 +88,31 @@ extra:
|
||||
link: https://medium.com/@tiangolo
|
||||
- icon: fontawesome/solid/globe
|
||||
link: https://tiangolo.com
|
||||
alternate:
|
||||
- link: /
|
||||
name: en - English
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /it/
|
||||
name: it - italiano
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /sq/
|
||||
name: sq - shqip
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh/
|
||||
name: zh - 汉语
|
||||
extra_css:
|
||||
- https://fastapi.tiangolo.com/css/termynal.css
|
||||
- https://fastapi.tiangolo.com/css/custom.css
|
||||
|
||||
0
docs/pt/overrides/.gitignore
vendored
Normal file
0
docs/pt/overrides/.gitignore
vendored
Normal file
@@ -132,7 +132,7 @@ You will also need an ASGI server, for production such as <a href="https://www.u
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
@@ -3,6 +3,7 @@ site_description: FastAPI framework, high performance, easy to learn, fast to co
|
||||
site_url: https://fastapi.tiangolo.com/ru/
|
||||
theme:
|
||||
name: material
|
||||
custom_dir: overrides
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: teal
|
||||
@@ -45,6 +46,7 @@ nav:
|
||||
- ko: /ko/
|
||||
- pt: /pt/
|
||||
- ru: /ru/
|
||||
- sq: /sq/
|
||||
- tr: /tr/
|
||||
- uk: /uk/
|
||||
- zh: /zh/
|
||||
@@ -78,6 +80,31 @@ extra:
|
||||
link: https://medium.com/@tiangolo
|
||||
- icon: fontawesome/solid/globe
|
||||
link: https://tiangolo.com
|
||||
alternate:
|
||||
- link: /
|
||||
name: en - English
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /it/
|
||||
name: it - italiano
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /sq/
|
||||
name: sq - shqip
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh/
|
||||
name: zh - 汉语
|
||||
extra_css:
|
||||
- https://fastapi.tiangolo.com/css/termynal.css
|
||||
- https://fastapi.tiangolo.com/css/custom.css
|
||||
|
||||
0
docs/ru/overrides/.gitignore
vendored
Normal file
0
docs/ru/overrides/.gitignore
vendored
Normal file
464
docs/sq/docs/index.md
Normal file
464
docs/sq/docs/index.md
Normal file
@@ -0,0 +1,464 @@
|
||||
|
||||
{!../../../docs/missing-translation.md!}
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/tiangolo/fastapi/actions?query=workflow%3ATest" target="_blank">
|
||||
<img src="https://github.com/tiangolo/fastapi/workflows/Test/badge.svg" alt="Test">
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/tiangolo/fastapi" target="_blank">
|
||||
<img src="https://img.shields.io/codecov/c/github/tiangolo/fastapi?color=%2334D058" alt="Coverage">
|
||||
</a>
|
||||
<a href="https://pypi.org/project/fastapi" target="_blank">
|
||||
<img src="https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package" alt="Package version">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
**Documentation**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
|
||||
|
||||
**Source Code**: <a href="https://github.com/tiangolo/fastapi" target="_blank">https://github.com/tiangolo/fastapi</a>
|
||||
|
||||
---
|
||||
|
||||
FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.
|
||||
|
||||
The key features are:
|
||||
|
||||
* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance).
|
||||
|
||||
* **Fast to code**: Increase the speed to develop features by about 200% to 300%. *
|
||||
* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. *
|
||||
* **Intuitive**: Great editor support. <abbr title="also known as auto-complete, autocompletion, IntelliSense">Completion</abbr> everywhere. Less time debugging.
|
||||
* **Easy**: Designed to be easy to use and learn. Less time reading docs.
|
||||
* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
|
||||
* **Robust**: Get production-ready code. With automatic interactive documentation.
|
||||
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
|
||||
<small>* estimation based on tests on an internal development team, building production applications.</small>
|
||||
|
||||
## Gold Sponsors
|
||||
|
||||
<!-- sponsors -->
|
||||
|
||||
{% if sponsors %}
|
||||
{% for sponsor in sponsors.gold -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">Other sponsors</a>
|
||||
|
||||
## Opinions
|
||||
|
||||
"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/tiangolo/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_I’m over the moon excited about **FastAPI**. It’s so fun!_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://twitter.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://www.hug.rest/" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_"
|
||||
|
||||
"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> founders - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://twitter.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://twitter.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
## **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>
|
||||
|
||||
If you are building a <abbr title="Command Line Interface">CLI</abbr> app to be used in the terminal instead of a web API, check out <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
|
||||
|
||||
**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀
|
||||
|
||||
## Requirements
|
||||
|
||||
Python 3.6+
|
||||
|
||||
FastAPI stands on the shoulders of giants:
|
||||
|
||||
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> for the web parts.
|
||||
* <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> for the data parts.
|
||||
|
||||
## Installation
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install fastapi
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
You will also need an ASGI server, for production such as <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Example
|
||||
|
||||
### Create it
|
||||
|
||||
* Create a file `main.py` with:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
<details markdown="1">
|
||||
<summary>Or use <code>async def</code>...</summary>
|
||||
|
||||
If your code uses `async` / `await`, use `async def`:
|
||||
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def read_root():
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
**Note**:
|
||||
|
||||
If you don't know, check the _"In a hurry?"_ section about <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` and `await` in the docs</a>.
|
||||
|
||||
</details>
|
||||
|
||||
### Run it
|
||||
|
||||
Run the server with:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
INFO: Started reloader process [28720]
|
||||
INFO: Started server process [28722]
|
||||
INFO: Waiting for application startup.
|
||||
INFO: Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
<details markdown="1">
|
||||
<summary>About the command <code>uvicorn main:app --reload</code>...</summary>
|
||||
|
||||
The command `uvicorn main:app` refers to:
|
||||
|
||||
* `main`: the file `main.py` (the Python "module").
|
||||
* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
|
||||
* `--reload`: make the server restart after code changes. Only do this for development.
|
||||
|
||||
</details>
|
||||
|
||||
### Check it
|
||||
|
||||
Open your browser at <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
|
||||
|
||||
You will see the JSON response as:
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
You already created an API that:
|
||||
|
||||
* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`.
|
||||
* Both _paths_ take `GET` <em>operations</em> (also known as HTTP _methods_).
|
||||
* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`.
|
||||
* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`.
|
||||
|
||||
### Interactive API docs
|
||||
|
||||
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
|
||||
|
||||

|
||||
|
||||
### Alternative API docs
|
||||
|
||||
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
|
||||
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
|
||||
|
||||

|
||||
|
||||
## Example upgrade
|
||||
|
||||
Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||
|
||||
Declare the body using standard Python types, thanks to Pydantic.
|
||||
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: Optional[bool] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
def update_item(item_id: int, item: Item):
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
The server should reload automatically (because you added `--reload` to the `uvicorn` command above).
|
||||
|
||||
### Interactive API docs upgrade
|
||||
|
||||
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
* The interactive API documentation will be automatically updated, including the new body:
|
||||
|
||||

|
||||
|
||||
* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API:
|
||||
|
||||

|
||||
|
||||
* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen:
|
||||
|
||||

|
||||
|
||||
### Alternative API docs upgrade
|
||||
|
||||
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
|
||||
* The alternative documentation will also reflect the new query parameter and body:
|
||||
|
||||

|
||||
|
||||
### Recap
|
||||
|
||||
In summary, you declare **once** the types of parameters, body, etc. as function parameters.
|
||||
|
||||
You do that with standard modern Python types.
|
||||
|
||||
You don't have to learn a new syntax, the methods or classes of a specific library, etc.
|
||||
|
||||
Just standard **Python 3.6+**.
|
||||
|
||||
For example, for an `int`:
|
||||
|
||||
```Python
|
||||
item_id: int
|
||||
```
|
||||
|
||||
or for a more complex `Item` model:
|
||||
|
||||
```Python
|
||||
item: Item
|
||||
```
|
||||
|
||||
...and with that single declaration you get:
|
||||
|
||||
* Editor support, including:
|
||||
* Completion.
|
||||
* Type checks.
|
||||
* Validation of data:
|
||||
* Automatic and clear errors when the data is invalid.
|
||||
* Validation even for deeply nested JSON objects.
|
||||
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of input data: coming from the network to Python data and types. Reading from:
|
||||
* JSON.
|
||||
* Path parameters.
|
||||
* Query parameters.
|
||||
* Cookies.
|
||||
* Headers.
|
||||
* Forms.
|
||||
* Files.
|
||||
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of output data: converting from Python data and types to network data (as JSON):
|
||||
* Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
|
||||
* `datetime` objects.
|
||||
* `UUID` objects.
|
||||
* Database models.
|
||||
* ...and many more.
|
||||
* Automatic interactive API documentation, including 2 alternative user interfaces:
|
||||
* Swagger UI.
|
||||
* ReDoc.
|
||||
|
||||
---
|
||||
|
||||
Coming back to the previous code example, **FastAPI** will:
|
||||
|
||||
* Validate that there is an `item_id` in the path for `GET` and `PUT` requests.
|
||||
* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests.
|
||||
* If it is not, the client will see a useful, clear error.
|
||||
* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests.
|
||||
* As the `q` parameter is declared with `= None`, it is optional.
|
||||
* Without the `None` it would be required (as is the body in the case with `PUT`).
|
||||
* For `PUT` requests to `/items/{item_id}`, Read the body as JSON:
|
||||
* Check that it has a required attribute `name` that should be a `str`.
|
||||
* Check that it has a required attribute `price` that has to be a `float`.
|
||||
* Check that it has an optional attribute `is_offer`, that should be a `bool`, if present.
|
||||
* All this would also work for deeply nested JSON objects.
|
||||
* Convert from and to JSON automatically.
|
||||
* Document everything with OpenAPI, that can be used by:
|
||||
* Interactive documentation systems.
|
||||
* Automatic client code generation systems, for many languages.
|
||||
* Provide 2 interactive documentation web interfaces directly.
|
||||
|
||||
---
|
||||
|
||||
We just scratched the surface, but you already get the idea of how it all works.
|
||||
|
||||
Try changing the line with:
|
||||
|
||||
```Python
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
...from:
|
||||
|
||||
```Python
|
||||
... "item_name": item.name ...
|
||||
```
|
||||
|
||||
...to:
|
||||
|
||||
```Python
|
||||
... "item_price": item.price ...
|
||||
```
|
||||
|
||||
...and see how your editor will auto-complete the attributes and know their types:
|
||||
|
||||

|
||||
|
||||
For a more complete example including more features, see the <a href="https://fastapi.tiangolo.com/tutorial/">Tutorial - User Guide</a>.
|
||||
|
||||
**Spoiler alert**: the tutorial - user guide includes:
|
||||
|
||||
* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**.
|
||||
* How to set **validation constraints** as `maximum_length` or `regex`.
|
||||
* A very powerful and easy to use **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** system.
|
||||
* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth.
|
||||
* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic).
|
||||
* Many extra features (thanks to Starlette) as:
|
||||
* **WebSockets**
|
||||
* **GraphQL**
|
||||
* extremely easy tests based on `requests` and `pytest`
|
||||
* **CORS**
|
||||
* **Cookie Sessions**
|
||||
* ...and more.
|
||||
|
||||
## Performance
|
||||
|
||||
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
|
||||
|
||||
To understand more about it, see the section <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
|
||||
|
||||
## Optional Dependencies
|
||||
|
||||
Used by Pydantic:
|
||||
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
|
||||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
|
||||
|
||||
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://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
||||
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
|
||||
* <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - Required for `GraphQLApp` support.
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Required if you want to use `UJSONResponse`.
|
||||
|
||||
Used by FastAPI / Starlette:
|
||||
|
||||
* <a href="https://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - for the server that loads and serves your application.
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Required if you want to use `ORJSONResponse`.
|
||||
|
||||
You can install all of these with `pip install fastapi[all]`.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the terms of the MIT license.
|
||||
114
docs/sq/mkdocs.yml
Normal file
114
docs/sq/mkdocs.yml
Normal file
@@ -0,0 +1,114 @@
|
||||
site_name: FastAPI
|
||||
site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
|
||||
site_url: https://fastapi.tiangolo.com/sq/
|
||||
theme:
|
||||
name: material
|
||||
custom_dir: overrides
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: teal
|
||||
accent: amber
|
||||
toggle:
|
||||
icon: material/lightbulb-outline
|
||||
name: Switch to light mode
|
||||
- scheme: slate
|
||||
primary: teal
|
||||
accent: amber
|
||||
toggle:
|
||||
icon: material/lightbulb
|
||||
name: Switch to dark mode
|
||||
features:
|
||||
- search.suggest
|
||||
- search.highlight
|
||||
icon:
|
||||
repo: fontawesome/brands/github-alt
|
||||
logo: https://fastapi.tiangolo.com/img/icon-white.svg
|
||||
favicon: https://fastapi.tiangolo.com/img/favicon.png
|
||||
language: en
|
||||
repo_name: tiangolo/fastapi
|
||||
repo_url: https://github.com/tiangolo/fastapi
|
||||
edit_uri: ''
|
||||
google_analytics:
|
||||
- UA-133183413-1
|
||||
- auto
|
||||
plugins:
|
||||
- search
|
||||
- markdownextradata:
|
||||
data: data
|
||||
nav:
|
||||
- FastAPI: index.md
|
||||
- Languages:
|
||||
- en: /
|
||||
- es: /es/
|
||||
- fr: /fr/
|
||||
- it: /it/
|
||||
- ja: /ja/
|
||||
- ko: /ko/
|
||||
- pt: /pt/
|
||||
- ru: /ru/
|
||||
- sq: /sq/
|
||||
- tr: /tr/
|
||||
- uk: /uk/
|
||||
- zh: /zh/
|
||||
markdown_extensions:
|
||||
- toc:
|
||||
permalink: true
|
||||
- markdown.extensions.codehilite:
|
||||
guess_lang: false
|
||||
- markdown_include.include:
|
||||
base_path: docs
|
||||
- admonition
|
||||
- codehilite
|
||||
- extra
|
||||
- pymdownx.superfences:
|
||||
custom_fences:
|
||||
- name: mermaid
|
||||
class: mermaid
|
||||
format: !!python/name:pymdownx.superfences.fence_div_format ''
|
||||
- pymdownx.tabbed
|
||||
extra:
|
||||
social:
|
||||
- icon: fontawesome/brands/github-alt
|
||||
link: https://github.com/tiangolo/typer
|
||||
- icon: fontawesome/brands/twitter
|
||||
link: https://twitter.com/tiangolo
|
||||
- icon: fontawesome/brands/linkedin
|
||||
link: https://www.linkedin.com/in/tiangolo
|
||||
- icon: fontawesome/brands/dev
|
||||
link: https://dev.to/tiangolo
|
||||
- icon: fontawesome/brands/medium
|
||||
link: https://medium.com/@tiangolo
|
||||
- icon: fontawesome/solid/globe
|
||||
link: https://tiangolo.com
|
||||
alternate:
|
||||
- link: /
|
||||
name: en - English
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /it/
|
||||
name: it - italiano
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /sq/
|
||||
name: sq - shqip
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh/
|
||||
name: zh - 汉语
|
||||
extra_css:
|
||||
- https://fastapi.tiangolo.com/css/termynal.css
|
||||
- https://fastapi.tiangolo.com/css/custom.css
|
||||
extra_javascript:
|
||||
- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js
|
||||
- https://fastapi.tiangolo.com/js/termynal.js
|
||||
- https://fastapi.tiangolo.com/js/custom.js
|
||||
0
docs/sq/overrides/.gitignore
vendored
Normal file
0
docs/sq/overrides/.gitignore
vendored
Normal file
@@ -132,7 +132,7 @@ You will also need an ASGI server, for production such as <a href="https://www.u
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
@@ -3,6 +3,7 @@ site_description: FastAPI framework, high performance, easy to learn, fast to co
|
||||
site_url: https://fastapi.tiangolo.com/tr/
|
||||
theme:
|
||||
name: material
|
||||
custom_dir: overrides
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: teal
|
||||
@@ -45,6 +46,7 @@ nav:
|
||||
- ko: /ko/
|
||||
- pt: /pt/
|
||||
- ru: /ru/
|
||||
- sq: /sq/
|
||||
- tr: /tr/
|
||||
- uk: /uk/
|
||||
- zh: /zh/
|
||||
@@ -78,6 +80,31 @@ extra:
|
||||
link: https://medium.com/@tiangolo
|
||||
- icon: fontawesome/solid/globe
|
||||
link: https://tiangolo.com
|
||||
alternate:
|
||||
- link: /
|
||||
name: en - English
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /it/
|
||||
name: it - italiano
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /sq/
|
||||
name: sq - shqip
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh/
|
||||
name: zh - 汉语
|
||||
extra_css:
|
||||
- https://fastapi.tiangolo.com/css/termynal.css
|
||||
- https://fastapi.tiangolo.com/css/custom.css
|
||||
|
||||
0
docs/tr/overrides/.gitignore
vendored
Normal file
0
docs/tr/overrides/.gitignore
vendored
Normal file
@@ -132,7 +132,7 @@ You will also need an ASGI server, for production such as <a href="https://www.u
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
@@ -3,6 +3,7 @@ site_description: FastAPI framework, high performance, easy to learn, fast to co
|
||||
site_url: https://fastapi.tiangolo.com/uk/
|
||||
theme:
|
||||
name: material
|
||||
custom_dir: overrides
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: teal
|
||||
@@ -45,6 +46,7 @@ nav:
|
||||
- ko: /ko/
|
||||
- pt: /pt/
|
||||
- ru: /ru/
|
||||
- sq: /sq/
|
||||
- tr: /tr/
|
||||
- uk: /uk/
|
||||
- zh: /zh/
|
||||
@@ -78,6 +80,31 @@ extra:
|
||||
link: https://medium.com/@tiangolo
|
||||
- icon: fontawesome/solid/globe
|
||||
link: https://tiangolo.com
|
||||
alternate:
|
||||
- link: /
|
||||
name: en - English
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /it/
|
||||
name: it - italiano
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /sq/
|
||||
name: sq - shqip
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh/
|
||||
name: zh - 汉语
|
||||
extra_css:
|
||||
- https://fastapi.tiangolo.com/css/termynal.css
|
||||
- https://fastapi.tiangolo.com/css/custom.css
|
||||
|
||||
0
docs/uk/overrides/.gitignore
vendored
Normal file
0
docs/uk/overrides/.gitignore
vendored
Normal file
@@ -338,7 +338,7 @@ Traefik 也集成了 Docker,所以你也可以在每个应用的配置中声
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
@@ -128,7 +128,7 @@ $ pip install fastapi
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
199
docs/zh/docs/tutorial/extra-models.md
Normal file
199
docs/zh/docs/tutorial/extra-models.md
Normal file
@@ -0,0 +1,199 @@
|
||||
# 额外的模型
|
||||
|
||||
我们从前面的示例继续,拥有多个相关的模型是很常见的。
|
||||
|
||||
对用户模型来说尤其如此,因为:
|
||||
|
||||
* **输入模型**需要拥有密码属性。
|
||||
* **输出模型**不应该包含密码。
|
||||
* **数据库模型**很可能需要保存密码的哈希值。
|
||||
|
||||
!!! danger
|
||||
永远不要存储用户的明文密码。始终存储一个可以用于验证的「安全哈希值」。
|
||||
|
||||
如果你尚未了解该知识,你可以在[安全章节](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}中学习何为「密码哈希值」。
|
||||
|
||||
## 多个模型
|
||||
|
||||
下面是应该如何根据它们的密码字段以及使用位置去定义模型的大概思路:
|
||||
|
||||
```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
|
||||
{!../../../docs_src/extra_models/tutorial001.py!}
|
||||
```
|
||||
|
||||
### 关于 `**user_in.dict()`
|
||||
|
||||
#### Pydantic 的 `.dict()`
|
||||
|
||||
`user_in` 是一个 `UserIn` 类的 Pydantic 模型.
|
||||
|
||||
Pydantic 模型具有 `.dict()` 方法,该方法返回一个拥有模型数据的 `dict`。
|
||||
|
||||
因此,如果我们像下面这样创建一个 Pydantic 对象 `user_in`:
|
||||
|
||||
```Python
|
||||
user_in = UserIn(username="john", password="secret", email="john.doe@example.com")
|
||||
```
|
||||
|
||||
然后我们调用:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
```
|
||||
|
||||
现在我们有了一个数据位于变量 `user_dict` 中的 `dict`(它是一个 `dict` 而不是 Pydantic 模型对象)。
|
||||
|
||||
如果我们调用:
|
||||
|
||||
```Python
|
||||
print(user_dict)
|
||||
```
|
||||
|
||||
我们将获得一个这样的 Python `dict`:
|
||||
|
||||
```Python
|
||||
{
|
||||
'username': 'john',
|
||||
'password': 'secret',
|
||||
'email': 'john.doe@example.com',
|
||||
'full_name': None,
|
||||
}
|
||||
```
|
||||
|
||||
#### 解包 `dict`
|
||||
|
||||
如果我们将 `user_dict` 这样的 `dict` 以 `**user_dict` 形式传递给一个函数(或类),Python将对其进行「解包」。它会将 `user_dict` 的键和值作为关键字参数直接传递。
|
||||
|
||||
因此,从上面的 `user_dict` 继续,编写:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
会产生类似于以下的结果:
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
username="john",
|
||||
password="secret",
|
||||
email="john.doe@example.com",
|
||||
full_name=None,
|
||||
)
|
||||
```
|
||||
|
||||
或者更确切地,直接使用 `user_dict` 来表示将来可能包含的任何内容:
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
username = user_dict["username"],
|
||||
password = user_dict["password"],
|
||||
email = user_dict["email"],
|
||||
full_name = user_dict["full_name"],
|
||||
)
|
||||
```
|
||||
|
||||
#### 来自于其他模型内容的 Pydantic 模型
|
||||
|
||||
如上例所示,我们从 `user_in.dict()` 中获得了 `user_dict`,此代码:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
等同于:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict())
|
||||
```
|
||||
|
||||
...因为 `user_in.dict()` 是一个 `dict`,然后我们通过以`**`开头传递给 `UserInDB` 来使 Python「解包」它。
|
||||
|
||||
这样,我们获得了一个来自于其他 Pydantic 模型中的数据的 Pydantic 模型。
|
||||
|
||||
#### 解包 `dict` 和额外关键字
|
||||
|
||||
然后添加额外的关键字参数 `hashed_password=hashed_password`,例如:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict(), hashed_password=hashed_password)
|
||||
```
|
||||
|
||||
...最终的结果如下:
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
username = user_dict["username"],
|
||||
password = user_dict["password"],
|
||||
email = user_dict["email"],
|
||||
full_name = user_dict["full_name"],
|
||||
hashed_password = hashed_password,
|
||||
)
|
||||
```
|
||||
|
||||
!!! warning
|
||||
辅助性的额外函数只是为了演示可能的数据流,但它们显然不能提供任何真正的安全性。
|
||||
|
||||
## 减少重复
|
||||
|
||||
减少代码重复是 **FastAPI** 的核心思想之一。
|
||||
|
||||
因为代码重复会增加出现 bug、安全性问题、代码失步问题(当你在一个位置更新了代码但没有在其他位置更新)等的可能性。
|
||||
|
||||
上面的这些模型都共享了大量数据,并拥有重复的属性名称和类型。
|
||||
|
||||
我们可以做得更好。
|
||||
|
||||
我们可以声明一个 `UserBase` 模型作为其他模型的基类。然后我们可以创建继承该模型属性(类型声明,校验等)的子类。
|
||||
|
||||
所有的数据转换、校验、文档生成等仍将正常运行。
|
||||
|
||||
这样,我们可以仅声明模型之间的差异部分(具有明文的 `password`、具有 `hashed_password` 以及不包括密码)。
|
||||
|
||||
```Python hl_lines="9 15-16 19-20 23-24"
|
||||
{!../../../docs_src/extra_models/tutorial002.py!}
|
||||
```
|
||||
|
||||
## `Union` 或者 `anyOf`
|
||||
|
||||
你可以将一个响应声明为两种类型的 `Union`,这意味着该响应将是两种类型中的任何一种。
|
||||
|
||||
这将在 OpenAPI 中使用 `anyOf` 进行定义。
|
||||
|
||||
为此,请使用标准的 Python 类型提示 <a href="https://docs.python.org/3/library/typing.html#typing.Union" class="external-link" target="_blank">`typing.Union`</a>:
|
||||
|
||||
|
||||
!!! note
|
||||
定义一个 <a href="https://pydantic-docs.helpmanual.io/usage/types/#unions" class="external-link" target="_blank">`Union`</a> 类型时,首先包括最详细的类型,然后是不太详细的类型。在下面的示例中,更详细的 `PlaneItem` 位于 `Union[PlaneItem,CarItem]` 中的 `CarItem` 之前。
|
||||
|
||||
```Python hl_lines="1 14-15 18-20 33"
|
||||
{!../../../docs_src/extra_models/tutorial003.py!}
|
||||
```
|
||||
|
||||
## 模型列表
|
||||
|
||||
你可以用同样的方式声明由对象列表构成的响应。
|
||||
|
||||
为此,请使用标准的 Python `typing.List`:
|
||||
|
||||
```Python hl_lines="1 20"
|
||||
{!../../../docs_src/extra_models/tutorial004.py!}
|
||||
```
|
||||
|
||||
## 任意 `dict` 构成的响应
|
||||
|
||||
你还可以使用一个任意的普通 `dict` 声明响应,仅声明键和值的类型,而不使用 Pydantic 模型。
|
||||
|
||||
如果你事先不知道有效的字段/属性名称(对于 Pydantic 模型是必需的),这将很有用。
|
||||
|
||||
在这种情况下,你可以使用 `typing.Dict`:
|
||||
|
||||
```Python hl_lines="1 8"
|
||||
{!../../../docs_src/extra_models/tutorial005.py!}
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
使用多个 Pydantic 模型,并针对不同场景自由地继承。
|
||||
|
||||
如果一个实体必须能够具有不同的「状态」,你无需为每个状态的实体定义单独的数据模型。以用户「实体」为例,其状态有包含 `password`、包含 `password_hash` 以及不含密码。
|
||||
@@ -64,7 +64,7 @@ $ pip install fastapi[all]
|
||||
并且安装`uvicorn`来作为服务器:
|
||||
|
||||
```
|
||||
pip install uvicorn
|
||||
pip install uvicorn[standard]
|
||||
```
|
||||
|
||||
然后对你想使用的每个可选依赖项也执行相同的操作。
|
||||
|
||||
209
docs/zh/docs/tutorial/response-model.md
Normal file
209
docs/zh/docs/tutorial/response-model.md
Normal file
@@ -0,0 +1,209 @@
|
||||
# 响应模型
|
||||
|
||||
你可以在任意的*路径操作*中使用 `response_model` 参数来声明用于响应的模型:
|
||||
|
||||
* `@app.get()`
|
||||
* `@app.post()`
|
||||
* `@app.put()`
|
||||
* `@app.delete()`
|
||||
* 等等。
|
||||
|
||||
```Python hl_lines="17"
|
||||
{!../../../docs_src/response_model/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
注意,`response_model`是「装饰器」方法(`get`,`post` 等)的一个参数。不像之前的所有参数和请求体,它不属于*路径操作函数*。
|
||||
|
||||
它接收的类型与你将为 Pydantic 模型属性所声明的类型相同,因此它可以是一个 Pydantic 模型,但也可以是一个由 Pydantic 模型组成的 `list`,例如 `List[Item]`。
|
||||
|
||||
FastAPI 将使用此 `response_model` 来:
|
||||
|
||||
* 将输出数据转换为其声明的类型。
|
||||
* 校验数据。
|
||||
* 在 OpenAPI 的*路径操作*中为响应添加一个 JSON Schema。
|
||||
* 并在自动生成文档系统中使用。
|
||||
|
||||
但最重要的是:
|
||||
|
||||
* 会将输出数据限制在该模型定义内。下面我们会看到这一点有多重要。
|
||||
|
||||
!!! note "技术细节"
|
||||
响应模型在参数中被声明,而不是作为函数返回类型的注解,这是因为路径函数可能不会真正返回该响应模型,而是返回一个 `dict`、数据库对象或其他模型,然后再使用 `response_model` 来执行字段约束和序列化。
|
||||
|
||||
## 返回与输入相同的数据
|
||||
|
||||
现在我们声明一个 `UserIn` 模型,它将包含一个明文密码属性。
|
||||
|
||||
```Python hl_lines="9 11"
|
||||
{!../../../docs_src/response_model/tutorial002.py!}
|
||||
```
|
||||
|
||||
我们正在使用此模型声明输入数据,并使用同一模型声明输出数据:
|
||||
|
||||
```Python hl_lines="17-18"
|
||||
{!../../../docs_src/response_model/tutorial002.py!}
|
||||
```
|
||||
|
||||
现在,每当浏览器使用一个密码创建用户时,API 都会在响应中返回相同的密码。
|
||||
|
||||
在这个案例中,这可能不算是问题,因为用户自己正在发送密码。
|
||||
|
||||
但是,如果我们在其他的*路径操作*中使用相同的模型,则可能会将用户的密码发送给每个客户端。
|
||||
|
||||
!!! danger
|
||||
永远不要存储用户的明文密码,也不要在响应中发送密码。
|
||||
|
||||
## 添加输出模型
|
||||
|
||||
相反,我们可以创建一个有明文密码的输入模型和一个没有明文密码的输出模型:
|
||||
|
||||
```Python hl_lines="9 11 16"
|
||||
{!../../../docs_src/response_model/tutorial003.py!}
|
||||
```
|
||||
|
||||
这样,即便我们的*路径操作函数*将会返回包含密码的相同输入用户:
|
||||
|
||||
```Python hl_lines="24"
|
||||
{!../../../docs_src/response_model/tutorial003.py!}
|
||||
```
|
||||
|
||||
...我们已经将 `response_model` 声明为了不包含密码的 `UserOut` 模型:
|
||||
|
||||
```Python hl_lines="22"
|
||||
{!../../../docs_src/response_model/tutorial003.py!}
|
||||
```
|
||||
|
||||
因此,**FastAPI** 将会负责过滤掉未在输出模型中声明的所有数据(使用 Pydantic)。
|
||||
|
||||
## 在文档中查看
|
||||
|
||||
当你查看自动化文档时,你可以检查输入模型和输出模型是否都具有自己的 JSON Schema:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/response-model/image01.png">
|
||||
|
||||
并且两种模型都将在交互式 API 文档中使用:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/response-model/image02.png">
|
||||
|
||||
## 响应模型编码参数
|
||||
|
||||
你的响应模型可以具有默认值,例如:
|
||||
|
||||
```Python hl_lines="11 13-14"
|
||||
{!../../../docs_src/response_model/tutorial004.py!}
|
||||
```
|
||||
|
||||
* `description: Optional[str] = None` 具有默认值 `None`。
|
||||
* `tax: float = 10.5` 具有默认值 `10.5`.
|
||||
* `tags: List[str] = []` 具有一个空列表作为默认值: `[]`.
|
||||
|
||||
但如果它们并没有存储实际的值,你可能想从结果中忽略它们的默认值。
|
||||
|
||||
举个例子,当你在 NoSQL 数据库中保存了具有许多可选属性的模型,但你又不想发送充满默认值的很长的 JSON 响应。
|
||||
|
||||
### 使用 `response_model_exclude_unset` 参数
|
||||
|
||||
你可以设置*路径操作装饰器*的 `response_model_exclude_unset=True` 参数:
|
||||
|
||||
```Python hl_lines="24"
|
||||
{!../../../docs_src/response_model/tutorial004.py!}
|
||||
```
|
||||
|
||||
然后响应中将不会包含那些默认值,而是仅有实际设置的值。
|
||||
|
||||
因此,如果你向*路径操作*发送 ID 为 `foo` 的商品的请求,则响应(不包括默认值)将为:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"name": "Foo",
|
||||
"price": 50.2
|
||||
}
|
||||
```
|
||||
|
||||
!!! info
|
||||
FastAPI 通过 Pydantic 模型的 `.dict()` 配合 <a href="https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict" class="external-link" target="_blank">该方法的 `exclude_unset` 参数</a> 来实现此功能。
|
||||
|
||||
!!! info
|
||||
你还可以使用:
|
||||
|
||||
* `response_model_exclude_defaults=True`
|
||||
* `response_model_exclude_none=True`
|
||||
|
||||
参考 <a href="https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict" class="external-link" target="_blank">Pydantic 文档</a> 中对 `exclude_defaults` 和 `exclude_none` 的描述。
|
||||
|
||||
#### 默认值字段有实际值的数据
|
||||
|
||||
但是,如果你的数据在具有默认值的模型字段中有实际的值,例如 ID 为 `bar` 的项:
|
||||
|
||||
```Python hl_lines="3 5"
|
||||
{
|
||||
"name": "Bar",
|
||||
"description": "The bartenders",
|
||||
"price": 62,
|
||||
"tax": 20.2
|
||||
}
|
||||
```
|
||||
|
||||
这些值将包含在响应中。
|
||||
|
||||
#### 具有与默认值相同值的数据
|
||||
|
||||
如果数据具有与默认值相同的值,例如 ID 为 `baz` 的项:
|
||||
|
||||
```Python hl_lines="3 5-6"
|
||||
{
|
||||
"name": "Baz",
|
||||
"description": None,
|
||||
"price": 50.2,
|
||||
"tax": 10.5,
|
||||
"tags": []
|
||||
}
|
||||
```
|
||||
|
||||
即使 `description`、`tax` 和 `tags` 具有与默认值相同的值,FastAPI 足够聪明 (实际上是 Pydantic 足够聪明) 去认识到这一点,它们的值被显式地所设定(而不是取自默认值)。
|
||||
|
||||
因此,它们将包含在 JSON 响应中。
|
||||
|
||||
!!! tip
|
||||
请注意默认值可以是任何值,而不仅是`None`。
|
||||
|
||||
它们可以是一个列表(`[]`),一个值为 `10.5`的 `float`,等等。
|
||||
|
||||
### `response_model_include` 和 `response_model_exclude`
|
||||
|
||||
你还可以使用*路径操作装饰器*的 `response_model_include` 和 `response_model_exclude` 参数。
|
||||
|
||||
它们接收一个由属性名称 `str` 组成的 `set` 来包含(忽略其他的)或者排除(包含其他的)这些属性。
|
||||
|
||||
如果你只有一个 Pydantic 模型,并且想要从输出中移除一些数据,则可以使用这种快捷方法。
|
||||
|
||||
!!! tip
|
||||
但是依然建议你使用上面提到的主意,使用多个类而不是这些参数。
|
||||
|
||||
这是因为即使使用 `response_model_include` 或 `response_model_exclude` 来省略某些属性,在应用程序的 OpenAPI 定义(和文档)中生成的 JSON Schema 仍将是完整的模型。
|
||||
|
||||
这也适用于作用类似的 `response_model_by_alias`。
|
||||
|
||||
```Python hl_lines="31 37"
|
||||
{!../../../docs_src/response_model/tutorial005.py!}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
`{"name", "description"}` 语法创建一个具有这两个值的 `set`。
|
||||
|
||||
等同于 `set(["name", "description"])`。
|
||||
|
||||
#### 使用 `list` 而不是 `set`
|
||||
|
||||
如果你忘记使用 `set` 而是使用 `list` 或 `tuple`,FastAPI 仍会将其转换为 `set` 并且正常工作:
|
||||
|
||||
```Python hl_lines="31 37"
|
||||
{!../../../docs_src/response_model/tutorial006.py!}
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
使用*路径操作装饰器*的 `response_model` 参数来定义响应模型,特别是确保私有数据被过滤掉。
|
||||
|
||||
使用 `response_model_exclude_unset` 来仅返回显式设定的值。
|
||||
89
docs/zh/docs/tutorial/response-status-code.md
Normal file
89
docs/zh/docs/tutorial/response-status-code.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# 响应状态码
|
||||
|
||||
与指定响应模型的方式相同,你也可以在以下任意的*路径操作*中使用 `status_code` 参数来声明用于响应的 HTTP 状态码:
|
||||
|
||||
* `@app.get()`
|
||||
* `@app.post()`
|
||||
* `@app.put()`
|
||||
* `@app.delete()`
|
||||
* 等等。
|
||||
|
||||
```Python hl_lines="6"
|
||||
{!../../../docs_src/response_status_code/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
注意,`status_code` 是「装饰器」方法(`get`,`post` 等)的一个参数。不像之前的所有参数和请求体,它不属于*路径操作函数*。
|
||||
|
||||
`status_code` 参数接收一个表示 HTTP 状态码的数字。
|
||||
|
||||
!!! info
|
||||
`status_code` 也能够接收一个 `IntEnum` 类型,比如 Python 的 <a href="https://docs.python.org/3/library/http.html#http.HTTPStatus" class="external-link" target="_blank">`http.HTTPStatus`</a>。
|
||||
|
||||
它将会:
|
||||
|
||||
* 在响应中返回该状态码。
|
||||
* 在 OpenAPI 模式中(以及在用户界面中)将其记录为:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/response-status-code/image01.png">
|
||||
|
||||
!!! note
|
||||
一些响应状态码(请参阅下一部分)表示响应没有响应体。
|
||||
|
||||
FastAPI 知道这一点,并将生成表明没有响应体的 OpenAPI 文档。
|
||||
|
||||
## 关于 HTTP 状态码
|
||||
|
||||
!!! note
|
||||
如果你已经了解什么是 HTTP 状态码,请跳到下一部分。
|
||||
|
||||
在 HTTP 协议中,你将发送 3 位数的数字状态码作为响应的一部分。
|
||||
|
||||
这些状态码有一个识别它们的关联名称,但是重要的还是数字。
|
||||
|
||||
简而言之:
|
||||
|
||||
* `100` 及以上状态码用于「消息」响应。你很少直接使用它们。具有这些状态代码的响应不能带有响应体。
|
||||
* **`200`** 及以上状态码用于「成功」响应。这些是你最常使用的。
|
||||
* `200` 是默认状态代码,它表示一切「正常」。
|
||||
* 另一个例子会是 `201`,「已创建」。它通常在数据库中创建了一条新记录后使用。
|
||||
* 一个特殊的例子是 `204`,「无内容」。此响应在没有内容返回给客户端时使用,因此该响应不能包含响应体。
|
||||
* **`300`** 及以上状态码用于「重定向」。具有这些状态码的响应可能有或者可能没有响应体,但 `304`「未修改」是个例外,该响应不得含有响应体。
|
||||
* **`400`** 及以上状态码用于「客户端错误」响应。这些可能是你第二常使用的类型。
|
||||
* 一个例子是 `404`,用于「未找到」响应。
|
||||
* 对于来自客户端的一般错误,你可以只使用 `400`。
|
||||
* `500` 及以上状态码用于服务器端错误。你几乎永远不会直接使用它们。当你的应用程序代码或服务器中的某些部分出现问题时,它将自动返回这些状态代码之一。
|
||||
|
||||
!!! tip
|
||||
要了解有关每个状态代码以及适用场景的更多信息,请查看 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> 关于 HTTP 状态码的文档</a>。
|
||||
|
||||
## 记住名称的捷径
|
||||
|
||||
让我们再次看看之前的例子:
|
||||
|
||||
```Python hl_lines="6"
|
||||
{!../../../docs_src/response_status_code/tutorial001.py!}
|
||||
```
|
||||
|
||||
`201` 是表示「已创建」的状态码。
|
||||
|
||||
但是你不必去记住每个代码的含义。
|
||||
|
||||
你可以使用来自 `fastapi.status` 的便捷变量。
|
||||
|
||||
```Python hl_lines="1 6"
|
||||
{!../../../docs_src/response_status_code/tutorial002.py!}
|
||||
```
|
||||
|
||||
它们只是一种便捷方式,它们具有同样的数字代码,但是这样使用你就可以使用编辑器的自动补全功能来查找它们:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/response-status-code/image02.png">
|
||||
|
||||
!!! note "技术细节"
|
||||
你也可以使用 `from starlette import status`。
|
||||
|
||||
为了给你(即开发者)提供方便,**FastAPI** 提供了与 `starlette.status` 完全相同的 `fastapi.status`。但它直接来自于 Starlette。
|
||||
|
||||
## 更改默认状态码
|
||||
|
||||
稍后,在[高级用户指南](../advanced/response-change-status-code.md){.internal-link target=_blank}中你将了解如何返回与在此声明的默认状态码不同的状态码。
|
||||
58
docs/zh/docs/tutorial/schema-extra-example.md
Normal file
58
docs/zh/docs/tutorial/schema-extra-example.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# 模式的额外信息 - 例子
|
||||
|
||||
您可以在JSON模式中定义额外的信息。
|
||||
|
||||
一个常见的用例是添加一个将在文档中显示的`example`。
|
||||
|
||||
有几种方法可以声明额外的 JSON 模式信息。
|
||||
|
||||
## Pydantic `schema_extra`
|
||||
|
||||
您可以使用 `Config` 和 `schema_extra` 为Pydantic模型声明一个示例,如<a href="https://pydantic-docs.helpmanual.io/usage/schema/#schema-customization" class="external-link" target="_blank">Pydantic 文档:定制 Schema </a>中所述:
|
||||
|
||||
```Python hl_lines="15-23"
|
||||
{!../../../docs_src/schema_extra_example/tutorial001.py!}
|
||||
```
|
||||
|
||||
这些额外的信息将按原样添加到输出的JSON模式中。
|
||||
|
||||
## `Field` 的附加参数
|
||||
|
||||
在 `Field`, `Path`, `Query`, `Body` 和其他你之后将会看到的工厂函数,你可以为JSON 模式声明额外信息,你也可以通过给工厂函数传递其他的任意参数来给JSON 模式声明额外信息,比如增加 `example`:
|
||||
|
||||
```Python hl_lines="4 10-13"
|
||||
{!../../../docs_src/schema_extra_example/tutorial002.py!}
|
||||
```
|
||||
|
||||
!!! warning
|
||||
请记住,传递的那些额外参数不会添加任何验证,只会添加注释,用于文档的目的。
|
||||
|
||||
## `Body` 额外参数
|
||||
|
||||
你可以通过传递额外信息给 `Field` 同样的方式操作`Path`, `Query`, `Body`等。
|
||||
|
||||
比如,你可以将请求体的一个 `example` 传递给 `Body`:
|
||||
|
||||
```Python hl_lines="21-26"
|
||||
{!../../../docs_src/schema_extra_example/tutorial003.py!}
|
||||
```
|
||||
|
||||
## 文档 UI 中的例子
|
||||
|
||||
使用上面的任何方法,它在 `/docs` 中看起来都是这样的:
|
||||
|
||||
<img src="/img/tutorial/body-fields/image01.png">
|
||||
|
||||
## 技术细节
|
||||
|
||||
关于 `example` 和 `examples`...
|
||||
|
||||
JSON Schema在最新的一个版本中定义了一个字段 <a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a> ,但是 OpenAPI 基于之前的一个旧版JSON Schema,并没有 `examples`.
|
||||
|
||||
所以 OpenAPI为了相似的目的定义了自己的 <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#fixed-fields-20" class="external-link" target="_blank">`example`</a> (使用 `example`, 而不是 `examples`), 这也是文档 UI 所使用的 (使用 Swagger UI).
|
||||
|
||||
所以,虽然 `example` 不是JSON Schema的一部分,但它是OpenAPI的一部分,这将被文档UI使用。
|
||||
|
||||
## 其他信息
|
||||
|
||||
同样的方法,你可以添加你自己的额外信息,这些信息将被添加到每个模型的JSON模式中,例如定制前端用户界面,等等。
|
||||
@@ -3,6 +3,7 @@ site_description: FastAPI framework, high performance, easy to learn, fast to co
|
||||
site_url: https://fastapi.tiangolo.com/zh/
|
||||
theme:
|
||||
name: material
|
||||
custom_dir: overrides
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: teal
|
||||
@@ -45,6 +46,7 @@ nav:
|
||||
- ko: /ko/
|
||||
- pt: /pt/
|
||||
- ru: /ru/
|
||||
- sq: /sq/
|
||||
- tr: /tr/
|
||||
- uk: /uk/
|
||||
- zh: /zh/
|
||||
@@ -61,6 +63,10 @@ nav:
|
||||
- tutorial/body-multiple-params.md
|
||||
- tutorial/body-fields.md
|
||||
- tutorial/body-nested-models.md
|
||||
- tutorial/response-model.md
|
||||
- tutorial/extra-models.md
|
||||
- tutorial/response-status-code.md
|
||||
- tutorial/schema-extra-example.md
|
||||
- 高级用户指南:
|
||||
- advanced/index.md
|
||||
- advanced/path-operation-advanced-configuration.md
|
||||
@@ -101,6 +107,31 @@ extra:
|
||||
link: https://medium.com/@tiangolo
|
||||
- icon: fontawesome/solid/globe
|
||||
link: https://tiangolo.com
|
||||
alternate:
|
||||
- link: /
|
||||
name: en - English
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /it/
|
||||
name: it - italiano
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /sq/
|
||||
name: sq - shqip
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh/
|
||||
name: zh - 汉语
|
||||
extra_css:
|
||||
- https://fastapi.tiangolo.com/css/termynal.css
|
||||
- https://fastapi.tiangolo.com/css/custom.css
|
||||
|
||||
0
docs/zh/overrides/.gitignore
vendored
Normal file
0
docs/zh/overrides/.gitignore
vendored
Normal file
@@ -26,7 +26,7 @@ invoices_callback_router = APIRouter()
|
||||
|
||||
|
||||
@invoices_callback_router.post(
|
||||
"{$callback_url}/invoices/{$request.body.id}", response_model=InvoiceEventReceived,
|
||||
"{$callback_url}/invoices/{$request.body.id}", response_model=InvoiceEventReceived
|
||||
)
|
||||
def invoice_notification(body: InvoiceEvent):
|
||||
pass
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
||||
|
||||
__version__ = "0.62.0"
|
||||
__version__ = "0.63.0"
|
||||
|
||||
from starlette import status
|
||||
from starlette import status as status
|
||||
|
||||
from .applications import FastAPI
|
||||
from .background import BackgroundTasks
|
||||
from .datastructures import UploadFile
|
||||
from .exceptions import HTTPException
|
||||
from .param_functions import (
|
||||
Body,
|
||||
Cookie,
|
||||
Depends,
|
||||
File,
|
||||
Form,
|
||||
Header,
|
||||
Path,
|
||||
Query,
|
||||
Security,
|
||||
)
|
||||
from .requests import Request
|
||||
from .responses import Response
|
||||
from .routing import APIRouter
|
||||
from .websockets import WebSocket, WebSocketDisconnect
|
||||
from .applications import FastAPI as FastAPI
|
||||
from .background import BackgroundTasks as BackgroundTasks
|
||||
from .datastructures import UploadFile as UploadFile
|
||||
from .exceptions import HTTPException as HTTPException
|
||||
from .param_functions import Body as Body
|
||||
from .param_functions import Cookie as Cookie
|
||||
from .param_functions import Depends as Depends
|
||||
from .param_functions import File as File
|
||||
from .param_functions import Form as Form
|
||||
from .param_functions import Header as Header
|
||||
from .param_functions import Path as Path
|
||||
from .param_functions import Query as Query
|
||||
from .param_functions import Security as Security
|
||||
from .requests import Request as Request
|
||||
from .responses import Response as Response
|
||||
from .routing import APIRouter as APIRouter
|
||||
from .websockets import WebSocket as WebSocket
|
||||
from .websockets import WebSocketDisconnect as WebSocketDisconnect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Any, Callable, Dict, List, Optional, Sequence, Type, Union
|
||||
from typing import Any, Callable, Coroutine, Dict, List, Optional, Sequence, Type, Union
|
||||
|
||||
from fastapi import routing
|
||||
from fastapi.concurrency import AsyncExitStack
|
||||
@@ -17,6 +17,7 @@ from fastapi.openapi.docs import (
|
||||
)
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
from fastapi.params import Depends
|
||||
from fastapi.types import DecoratedCallable
|
||||
from starlette.applications import Starlette
|
||||
from starlette.datastructures import State
|
||||
from starlette.exceptions import HTTPException
|
||||
@@ -24,7 +25,7 @@ from starlette.middleware import Middleware
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import HTMLResponse, JSONResponse, Response
|
||||
from starlette.routing import BaseRoute
|
||||
from starlette.types import Receive, Scope, Send
|
||||
from starlette.types import ASGIApp, Receive, Scope, Send
|
||||
|
||||
|
||||
class FastAPI(Starlette):
|
||||
@@ -44,24 +45,27 @@ class FastAPI(Starlette):
|
||||
docs_url: Optional[str] = "/docs",
|
||||
redoc_url: Optional[str] = "/redoc",
|
||||
swagger_ui_oauth2_redirect_url: Optional[str] = "/docs/oauth2-redirect",
|
||||
swagger_ui_init_oauth: Optional[dict] = None,
|
||||
swagger_ui_init_oauth: Optional[Dict[str, Any]] = None,
|
||||
middleware: Optional[Sequence[Middleware]] = None,
|
||||
exception_handlers: Optional[
|
||||
Dict[Union[int, Type[Exception]], Callable]
|
||||
Dict[
|
||||
Union[int, Type[Exception]],
|
||||
Callable[[Request, Any], Coroutine[Any, Any, Response]],
|
||||
]
|
||||
] = None,
|
||||
on_startup: Optional[Sequence[Callable]] = None,
|
||||
on_shutdown: Optional[Sequence[Callable]] = None,
|
||||
on_startup: Optional[Sequence[Callable[[], Any]]] = None,
|
||||
on_shutdown: Optional[Sequence[Callable[[], Any]]] = None,
|
||||
openapi_prefix: str = "",
|
||||
root_path: str = "",
|
||||
root_path_in_servers: bool = True,
|
||||
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
|
||||
callbacks: Optional[List[routing.APIRoute]] = None,
|
||||
deprecated: bool = None,
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
deprecated: Optional[bool] = None,
|
||||
include_in_schema: bool = True,
|
||||
**extra: Any,
|
||||
) -> None:
|
||||
self._debug = debug
|
||||
self.state = State()
|
||||
self._debug: bool = debug
|
||||
self.state: State = State()
|
||||
self.router: routing.APIRouter = routing.APIRouter(
|
||||
routes=routes,
|
||||
dependency_overrides_provider=self,
|
||||
@@ -74,7 +78,10 @@ class FastAPI(Starlette):
|
||||
include_in_schema=include_in_schema,
|
||||
responses=responses,
|
||||
)
|
||||
self.exception_handlers = (
|
||||
self.exception_handlers: Dict[
|
||||
Union[int, Type[Exception]],
|
||||
Callable[[Request, Any], Coroutine[Any, Any, Response]],
|
||||
] = (
|
||||
{} if exception_handlers is None else dict(exception_handlers)
|
||||
)
|
||||
self.exception_handlers.setdefault(HTTPException, http_exception_handler)
|
||||
@@ -82,8 +89,10 @@ class FastAPI(Starlette):
|
||||
RequestValidationError, request_validation_exception_handler
|
||||
)
|
||||
|
||||
self.user_middleware = [] if middleware is None else list(middleware)
|
||||
self.middleware_stack = self.build_middleware_stack()
|
||||
self.user_middleware: List[Middleware] = (
|
||||
[] if middleware is None else list(middleware)
|
||||
)
|
||||
self.middleware_stack: ASGIApp = self.build_middleware_stack()
|
||||
|
||||
self.title = title
|
||||
self.description = description
|
||||
@@ -106,7 +115,7 @@ class FastAPI(Starlette):
|
||||
self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url
|
||||
self.swagger_ui_init_oauth = swagger_ui_init_oauth
|
||||
self.extra = extra
|
||||
self.dependency_overrides: Dict[Callable, Callable] = {}
|
||||
self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {}
|
||||
|
||||
self.openapi_version = "3.0.2"
|
||||
|
||||
@@ -116,7 +125,7 @@ class FastAPI(Starlette):
|
||||
self.openapi_schema: Optional[Dict[str, Any]] = None
|
||||
self.setup()
|
||||
|
||||
def openapi(self) -> Dict:
|
||||
def openapi(self) -> Dict[str, Any]:
|
||||
if not self.openapi_schema:
|
||||
self.openapi_schema = get_openapi(
|
||||
title=self.title,
|
||||
@@ -194,7 +203,7 @@ class FastAPI(Starlette):
|
||||
def add_api_route(
|
||||
self,
|
||||
path: str,
|
||||
endpoint: Callable,
|
||||
endpoint: Callable[..., Coroutine[Any, Any, Response]],
|
||||
*,
|
||||
response_model: Optional[Type[Any]] = None,
|
||||
status_code: int = 200,
|
||||
@@ -268,8 +277,8 @@ class FastAPI(Starlette):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
) -> Callable:
|
||||
def decorator(func: Callable) -> Callable:
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
||||
self.router.add_api_route(
|
||||
path,
|
||||
func,
|
||||
@@ -299,12 +308,14 @@ class FastAPI(Starlette):
|
||||
return decorator
|
||||
|
||||
def add_api_websocket_route(
|
||||
self, path: str, endpoint: Callable, name: Optional[str] = None
|
||||
self, path: str, endpoint: Callable[..., Any], name: Optional[str] = None
|
||||
) -> None:
|
||||
self.router.add_api_websocket_route(path, endpoint, name=name)
|
||||
|
||||
def websocket(self, path: str, name: Optional[str] = None) -> Callable:
|
||||
def decorator(func: Callable) -> Callable:
|
||||
def websocket(
|
||||
self, path: str, name: Optional[str] = None
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
||||
self.add_api_websocket_route(path, func, name=name)
|
||||
return func
|
||||
|
||||
@@ -318,10 +329,10 @@ class FastAPI(Starlette):
|
||||
tags: Optional[List[str]] = None,
|
||||
dependencies: Optional[Sequence[Depends]] = None,
|
||||
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
|
||||
deprecated: bool = None,
|
||||
deprecated: Optional[bool] = None,
|
||||
include_in_schema: bool = True,
|
||||
default_response_class: Type[Response] = Default(JSONResponse),
|
||||
callbacks: Optional[List[routing.APIRoute]] = None,
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> None:
|
||||
self.router.include_router(
|
||||
router,
|
||||
@@ -358,8 +369,8 @@ class FastAPI(Starlette):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[routing.APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.router.get(
|
||||
path,
|
||||
response_model=response_model,
|
||||
@@ -407,8 +418,8 @@ class FastAPI(Starlette):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[routing.APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.router.put(
|
||||
path,
|
||||
response_model=response_model,
|
||||
@@ -456,8 +467,8 @@ class FastAPI(Starlette):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[routing.APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.router.post(
|
||||
path,
|
||||
response_model=response_model,
|
||||
@@ -505,8 +516,8 @@ class FastAPI(Starlette):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[routing.APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.router.delete(
|
||||
path,
|
||||
response_model=response_model,
|
||||
@@ -554,8 +565,8 @@ class FastAPI(Starlette):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[routing.APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.router.options(
|
||||
path,
|
||||
response_model=response_model,
|
||||
@@ -603,8 +614,8 @@ class FastAPI(Starlette):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[routing.APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.router.head(
|
||||
path,
|
||||
response_model=response_model,
|
||||
@@ -652,8 +663,8 @@ class FastAPI(Starlette):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[routing.APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.router.patch(
|
||||
path,
|
||||
response_model=response_model,
|
||||
@@ -701,8 +712,8 @@ class FastAPI(Starlette):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[routing.APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.router.trace(
|
||||
path,
|
||||
response_model=response_model,
|
||||
|
||||
@@ -1 +1 @@
|
||||
from starlette.background import BackgroundTasks # noqa
|
||||
from starlette.background import BackgroundTasks as BackgroundTasks # noqa
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from typing import Any, Callable
|
||||
|
||||
from starlette.concurrency import iterate_in_threadpool # noqa
|
||||
from starlette.concurrency import run_in_threadpool # noqa
|
||||
from starlette.concurrency import run_until_first_complete # noqa
|
||||
from starlette.concurrency import iterate_in_threadpool as iterate_in_threadpool # noqa
|
||||
from starlette.concurrency import run_in_threadpool as run_in_threadpool # noqa
|
||||
from starlette.concurrency import ( # noqa
|
||||
run_until_first_complete as run_until_first_complete,
|
||||
)
|
||||
|
||||
asynccontextmanager_error_message = """
|
||||
FastAPI's contextmanager_in_threadpool require Python 3.7 or above,
|
||||
@@ -11,7 +13,7 @@ or the backport for Python 3.6, installed with:
|
||||
"""
|
||||
|
||||
|
||||
def _fake_asynccontextmanager(func: Callable) -> Callable:
|
||||
def _fake_asynccontextmanager(func: Callable[..., Any]) -> Callable[..., Any]:
|
||||
def raiser(*args: Any, **kwargs: Any) -> Any:
|
||||
raise RuntimeError(asynccontextmanager_error_message)
|
||||
|
||||
@@ -19,23 +21,25 @@ def _fake_asynccontextmanager(func: Callable) -> Callable:
|
||||
|
||||
|
||||
try:
|
||||
from contextlib import asynccontextmanager # type: ignore
|
||||
from contextlib import asynccontextmanager as asynccontextmanager # type: ignore
|
||||
except ImportError:
|
||||
try:
|
||||
from async_generator import asynccontextmanager # type: ignore
|
||||
from async_generator import ( # type: ignore # isort: skip
|
||||
asynccontextmanager as asynccontextmanager,
|
||||
)
|
||||
except ImportError: # pragma: no cover
|
||||
asynccontextmanager = _fake_asynccontextmanager
|
||||
|
||||
try:
|
||||
from contextlib import AsyncExitStack # type: ignore
|
||||
from contextlib import AsyncExitStack as AsyncExitStack # type: ignore
|
||||
except ImportError:
|
||||
try:
|
||||
from async_exit_stack import AsyncExitStack # type: ignore
|
||||
from async_exit_stack import AsyncExitStack as AsyncExitStack # type: ignore
|
||||
except ImportError: # pragma: no cover
|
||||
AsyncExitStack = None # type: ignore
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
@asynccontextmanager # type: ignore
|
||||
async def contextmanager_in_threadpool(cm: Any) -> Any:
|
||||
try:
|
||||
yield await run_in_threadpool(cm.__enter__)
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from typing import Any, Callable, Iterable, Type, TypeVar
|
||||
|
||||
from starlette.datastructures import State as State # noqa: F401
|
||||
from starlette.datastructures import UploadFile as StarletteUploadFile
|
||||
|
||||
|
||||
class UploadFile(StarletteUploadFile):
|
||||
@classmethod
|
||||
def __get_validators__(cls: Type["UploadFile"]) -> Iterable[Callable]:
|
||||
def __get_validators__(cls: Type["UploadFile"]) -> Iterable[Callable[..., Any]]:
|
||||
yield cls.validate
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Callable, List, Optional, Sequence
|
||||
from typing import Any, Callable, List, Optional, Sequence
|
||||
|
||||
from fastapi.security.base import SecurityBase
|
||||
from pydantic.fields import ModelField
|
||||
@@ -24,7 +24,7 @@ class Dependant:
|
||||
dependencies: Optional[List["Dependant"]] = None,
|
||||
security_schemes: Optional[List[SecurityRequirement]] = None,
|
||||
name: Optional[str] = None,
|
||||
call: Optional[Callable] = None,
|
||||
call: Optional[Callable[..., Any]] = None,
|
||||
request_param_name: Optional[str] = None,
|
||||
websocket_param_name: Optional[str] = None,
|
||||
http_connection_param_name: Optional[str] = None,
|
||||
|
||||
@@ -90,12 +90,12 @@ def check_file_field(field: ModelField) -> None:
|
||||
if isinstance(field_info, params.Form):
|
||||
try:
|
||||
# __version__ is available in both multiparts, and can be mocked
|
||||
from multipart import __version__
|
||||
from multipart import __version__ # type: ignore
|
||||
|
||||
assert __version__
|
||||
try:
|
||||
# parse_options_header is only available in the right multipart
|
||||
from multipart.multipart import parse_options_header
|
||||
from multipart.multipart import parse_options_header # type: ignore
|
||||
|
||||
assert parse_options_header
|
||||
except ImportError:
|
||||
@@ -133,7 +133,7 @@ def get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> De
|
||||
def get_sub_dependant(
|
||||
*,
|
||||
depends: params.Depends,
|
||||
dependency: Callable,
|
||||
dependency: Callable[..., Any],
|
||||
path: str,
|
||||
name: Optional[str] = None,
|
||||
security_scopes: Optional[List[str]] = None,
|
||||
@@ -163,7 +163,7 @@ def get_sub_dependant(
|
||||
return sub_dependant
|
||||
|
||||
|
||||
CacheKey = Tuple[Optional[Callable], Tuple[str, ...]]
|
||||
CacheKey = Tuple[Optional[Callable[..., Any]], Tuple[str, ...]]
|
||||
|
||||
|
||||
def get_flat_dependant(
|
||||
@@ -240,7 +240,7 @@ def is_scalar_sequence_field(field: ModelField) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def get_typed_signature(call: Callable) -> inspect.Signature:
|
||||
def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
|
||||
signature = inspect.signature(call)
|
||||
globalns = getattr(call, "__globals__", {})
|
||||
typed_params = [
|
||||
@@ -259,9 +259,7 @@ def get_typed_signature(call: Callable) -> inspect.Signature:
|
||||
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any:
|
||||
annotation = param.annotation
|
||||
if isinstance(annotation, str):
|
||||
# Temporary ignore type
|
||||
# Ref: https://github.com/samuelcolvin/pydantic/issues/1738
|
||||
annotation = ForwardRef(annotation) # type: ignore
|
||||
annotation = ForwardRef(annotation)
|
||||
annotation = evaluate_forwardref(annotation, globalns, globalns)
|
||||
return annotation
|
||||
|
||||
@@ -281,7 +279,7 @@ def check_dependency_contextmanagers() -> None:
|
||||
def get_dependant(
|
||||
*,
|
||||
path: str,
|
||||
call: Callable,
|
||||
call: Callable[..., Any],
|
||||
name: Optional[str] = None,
|
||||
security_scopes: Optional[List[str]] = None,
|
||||
use_cache: bool = True,
|
||||
@@ -423,7 +421,7 @@ def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
|
||||
dependant.cookie_params.append(field)
|
||||
|
||||
|
||||
def is_coroutine_callable(call: Callable) -> bool:
|
||||
def is_coroutine_callable(call: Callable[..., Any]) -> bool:
|
||||
if inspect.isroutine(call):
|
||||
return inspect.iscoroutinefunction(call)
|
||||
if inspect.isclass(call):
|
||||
@@ -432,14 +430,14 @@ def is_coroutine_callable(call: Callable) -> bool:
|
||||
return inspect.iscoroutinefunction(call)
|
||||
|
||||
|
||||
def is_async_gen_callable(call: Callable) -> bool:
|
||||
def is_async_gen_callable(call: Callable[..., Any]) -> bool:
|
||||
if inspect.isasyncgenfunction(call):
|
||||
return True
|
||||
call = getattr(call, "__call__", None)
|
||||
return inspect.isasyncgenfunction(call)
|
||||
|
||||
|
||||
def is_gen_callable(call: Callable) -> bool:
|
||||
def is_gen_callable(call: Callable[..., Any]) -> bool:
|
||||
if inspect.isgeneratorfunction(call):
|
||||
return True
|
||||
call = getattr(call, "__call__", None)
|
||||
@@ -447,7 +445,7 @@ def is_gen_callable(call: Callable) -> bool:
|
||||
|
||||
|
||||
async def solve_generator(
|
||||
*, call: Callable, stack: AsyncExitStack, sub_values: Dict[str, Any]
|
||||
*, call: Callable[..., Any], stack: AsyncExitStack, sub_values: Dict[str, Any]
|
||||
) -> Any:
|
||||
if is_gen_callable(call):
|
||||
cm = contextmanager_in_threadpool(contextmanager(call)(**sub_values))
|
||||
@@ -472,29 +470,29 @@ async def solve_dependencies(
|
||||
background_tasks: Optional[BackgroundTasks] = None,
|
||||
response: Optional[Response] = None,
|
||||
dependency_overrides_provider: Optional[Any] = None,
|
||||
dependency_cache: Optional[Dict[Tuple[Callable, Tuple[str]], Any]] = None,
|
||||
dependency_cache: Optional[Dict[Tuple[Callable[..., Any], Tuple[str]], Any]] = None,
|
||||
) -> Tuple[
|
||||
Dict[str, Any],
|
||||
List[ErrorWrapper],
|
||||
Optional[BackgroundTasks],
|
||||
Response,
|
||||
Dict[Tuple[Callable, Tuple[str]], Any],
|
||||
Dict[Tuple[Callable[..., Any], Tuple[str]], Any],
|
||||
]:
|
||||
values: Dict[str, Any] = {}
|
||||
errors: List[ErrorWrapper] = []
|
||||
response = response or Response(
|
||||
content=None,
|
||||
status_code=None, # type: ignore
|
||||
headers=None,
|
||||
media_type=None,
|
||||
background=None,
|
||||
headers=None, # type: ignore # in Starlette
|
||||
media_type=None, # type: ignore # in Starlette
|
||||
background=None, # type: ignore # in Starlette
|
||||
)
|
||||
dependency_cache = dependency_cache or {}
|
||||
sub_dependant: Dependant
|
||||
for sub_dependant in dependant.dependencies:
|
||||
sub_dependant.call = cast(Callable, sub_dependant.call)
|
||||
sub_dependant.call = cast(Callable[..., Any], sub_dependant.call)
|
||||
sub_dependant.cache_key = cast(
|
||||
Tuple[Callable, Tuple[str]], sub_dependant.cache_key
|
||||
Tuple[Callable[..., Any], Tuple[str]], sub_dependant.cache_key
|
||||
)
|
||||
call = sub_dependant.call
|
||||
use_sub_dependant = sub_dependant
|
||||
|
||||
@@ -12,9 +12,11 @@ DictIntStrAny = Dict[Union[int, str], Any]
|
||||
|
||||
|
||||
def generate_encoders_by_class_tuples(
|
||||
type_encoder_map: Dict[Any, Callable]
|
||||
) -> Dict[Callable, Tuple]:
|
||||
encoders_by_class_tuples: Dict[Callable, Tuple] = defaultdict(tuple)
|
||||
type_encoder_map: Dict[Any, Callable[[Any], Any]]
|
||||
) -> Dict[Callable[[Any], Any], Tuple[Any, ...]]:
|
||||
encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict(
|
||||
tuple
|
||||
)
|
||||
for type_, encoder in type_encoder_map.items():
|
||||
encoders_by_class_tuples[encoder] += (type_,)
|
||||
return encoders_by_class_tuples
|
||||
@@ -31,7 +33,7 @@ def jsonable_encoder(
|
||||
exclude_unset: bool = False,
|
||||
exclude_defaults: bool = False,
|
||||
exclude_none: bool = False,
|
||||
custom_encoder: dict = {},
|
||||
custom_encoder: Dict[Any, Callable[[Any], Any]] = {},
|
||||
sqlalchemy_safe: bool = True,
|
||||
) -> Any:
|
||||
if include is not None and not isinstance(include, set):
|
||||
@@ -43,8 +45,8 @@ def jsonable_encoder(
|
||||
if custom_encoder:
|
||||
encoder.update(custom_encoder)
|
||||
obj_dict = obj.dict(
|
||||
include=include,
|
||||
exclude=exclude,
|
||||
include=include, # type: ignore # in Pydantic
|
||||
exclude=exclude, # type: ignore # in Pydantic
|
||||
by_alias=by_alias,
|
||||
exclude_unset=exclude_unset,
|
||||
exclude_none=exclude_none,
|
||||
|
||||
@@ -1 +1 @@
|
||||
from starlette.middleware import Middleware
|
||||
from starlette.middleware import Middleware as Middleware
|
||||
|
||||
@@ -1 +1 @@
|
||||
from starlette.middleware.cors import CORSMiddleware # noqa
|
||||
from starlette.middleware.cors import CORSMiddleware as CORSMiddleware # noqa
|
||||
|
||||
@@ -1 +1 @@
|
||||
from starlette.middleware.gzip import GZipMiddleware # noqa
|
||||
from starlette.middleware.gzip import GZipMiddleware as GZipMiddleware # noqa
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware # noqa
|
||||
from starlette.middleware.httpsredirect import ( # noqa
|
||||
HTTPSRedirectMiddleware as HTTPSRedirectMiddleware,
|
||||
)
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
from starlette.middleware.trustedhost import TrustedHostMiddleware # noqa
|
||||
from starlette.middleware.trustedhost import ( # noqa
|
||||
TrustedHostMiddleware as TrustedHostMiddleware,
|
||||
)
|
||||
|
||||
@@ -1 +1 @@
|
||||
from starlette.middleware.wsgi import WSGIMiddleware # noqa
|
||||
from starlette.middleware.wsgi import WSGIMiddleware as WSGIMiddleware # noqa
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import json
|
||||
from typing import Optional
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
from starlette.responses import HTMLResponse
|
||||
@@ -13,7 +13,7 @@ def get_swagger_ui_html(
|
||||
swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui.css",
|
||||
swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
|
||||
oauth2_redirect_url: Optional[str] = None,
|
||||
init_oauth: Optional[dict] = None,
|
||||
init_oauth: Optional[Dict[str, Any]] = None,
|
||||
) -> HTMLResponse:
|
||||
|
||||
html = f"""
|
||||
|
||||
@@ -5,7 +5,7 @@ from fastapi.logger import logger
|
||||
from pydantic import AnyUrl, BaseModel, Field
|
||||
|
||||
try:
|
||||
import email_validator
|
||||
import email_validator # type: ignore
|
||||
|
||||
assert email_validator # make autoflake ignore the unused import
|
||||
from pydantic import EmailStr
|
||||
@@ -13,7 +13,7 @@ except ImportError: # pragma: no cover
|
||||
|
||||
class EmailStr(str): # type: ignore
|
||||
@classmethod
|
||||
def __get_validators__(cls) -> Iterable[Callable]:
|
||||
def __get_validators__(cls) -> Iterable[Callable[..., Any]]:
|
||||
yield cls.validate
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -14,6 +14,7 @@ from fastapi.openapi.constants import (
|
||||
)
|
||||
from fastapi.openapi.models import OpenAPI
|
||||
from fastapi.params import Body, Param
|
||||
from fastapi.responses import Response
|
||||
from fastapi.utils import (
|
||||
deep_dict_update,
|
||||
generate_operation_id_for_path,
|
||||
@@ -64,7 +65,9 @@ status_code_ranges: Dict[str, str] = {
|
||||
}
|
||||
|
||||
|
||||
def get_openapi_security_definitions(flat_dependant: Dependant) -> Tuple[Dict, List]:
|
||||
def get_openapi_security_definitions(
|
||||
flat_dependant: Dependant,
|
||||
) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
|
||||
security_definitions = {}
|
||||
operation_security = []
|
||||
for security_requirement in flat_dependant.security_requirements:
|
||||
@@ -88,13 +91,12 @@ def get_openapi_operation_parameters(
|
||||
for param in all_route_params:
|
||||
field_info = param.field_info
|
||||
field_info = cast(Param, field_info)
|
||||
# ignore mypy error until enum schemas are released
|
||||
parameter = {
|
||||
"name": param.alias,
|
||||
"in": field_info.in_.value,
|
||||
"required": param.required,
|
||||
"schema": field_schema(
|
||||
param, model_name_map=model_name_map, ref_prefix=REF_PREFIX # type: ignore
|
||||
param, model_name_map=model_name_map, ref_prefix=REF_PREFIX
|
||||
)[0],
|
||||
}
|
||||
if field_info.description:
|
||||
@@ -109,13 +111,12 @@ def get_openapi_operation_request_body(
|
||||
*,
|
||||
body_field: Optional[ModelField],
|
||||
model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str],
|
||||
) -> Optional[Dict]:
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
if not body_field:
|
||||
return None
|
||||
assert isinstance(body_field, ModelField)
|
||||
# ignore mypy error until enum schemas are released
|
||||
body_schema, _, _ = field_schema(
|
||||
body_field, model_name_map=model_name_map, ref_prefix=REF_PREFIX # type: ignore
|
||||
body_field, model_name_map=model_name_map, ref_prefix=REF_PREFIX
|
||||
)
|
||||
field_info = cast(Body, body_field.field_info)
|
||||
request_media_type = field_info.media_type
|
||||
@@ -140,7 +141,9 @@ def generate_operation_summary(*, route: routing.APIRoute, method: str) -> str:
|
||||
return route.name.replace("_", " ").title()
|
||||
|
||||
|
||||
def get_openapi_operation_metadata(*, route: routing.APIRoute, method: str) -> Dict:
|
||||
def get_openapi_operation_metadata(
|
||||
*, route: routing.APIRoute, method: str
|
||||
) -> Dict[str, Any]:
|
||||
operation: Dict[str, Any] = {}
|
||||
if route.tags:
|
||||
operation["tags"] = route.tags
|
||||
@@ -154,14 +157,14 @@ def get_openapi_operation_metadata(*, route: routing.APIRoute, method: str) -> D
|
||||
|
||||
|
||||
def get_openapi_path(
|
||||
*, route: routing.APIRoute, model_name_map: Dict[Type, str]
|
||||
) -> Tuple[Dict, Dict, Dict]:
|
||||
*, route: routing.APIRoute, model_name_map: Dict[type, str]
|
||||
) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:
|
||||
path = {}
|
||||
security_schemes: Dict[str, Any] = {}
|
||||
definitions: Dict[str, Any] = {}
|
||||
assert route.methods is not None, "Methods must be a list"
|
||||
if isinstance(route.response_class, DefaultPlaceholder):
|
||||
current_response_class: Type[routing.Response] = route.response_class.value
|
||||
current_response_class: Type[Response] = route.response_class.value
|
||||
else:
|
||||
current_response_class = route.response_class
|
||||
assert current_response_class, "A response class is needed to generate OpenAPI"
|
||||
@@ -169,7 +172,7 @@ def get_openapi_path(
|
||||
if route.include_in_schema:
|
||||
for method in route.methods:
|
||||
operation = get_openapi_operation_metadata(route=route, method=method)
|
||||
parameters: List[Dict] = []
|
||||
parameters: List[Dict[str, Any]] = []
|
||||
flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True)
|
||||
security_definitions, operation_security = get_openapi_security_definitions(
|
||||
flat_dependant=flat_dependant
|
||||
@@ -196,10 +199,15 @@ def get_openapi_path(
|
||||
if route.callbacks:
|
||||
callbacks = {}
|
||||
for callback in route.callbacks:
|
||||
cb_path, cb_security_schemes, cb_definitions, = get_openapi_path(
|
||||
route=callback, model_name_map=model_name_map
|
||||
)
|
||||
callbacks[callback.name] = {callback.path: cb_path}
|
||||
if isinstance(callback, routing.APIRoute):
|
||||
(
|
||||
cb_path,
|
||||
cb_security_schemes,
|
||||
cb_definitions,
|
||||
) = get_openapi_path(
|
||||
route=callback, model_name_map=model_name_map
|
||||
)
|
||||
callbacks[callback.name] = {callback.path: cb_path}
|
||||
operation["callbacks"] = callbacks
|
||||
status_code = str(route.status_code)
|
||||
operation.setdefault("responses", {}).setdefault(status_code, {})[
|
||||
@@ -332,21 +340,19 @@ def get_openapi(
|
||||
routes: Sequence[BaseRoute],
|
||||
tags: Optional[List[Dict[str, Any]]] = None,
|
||||
servers: Optional[List[Dict[str, Union[str, Any]]]] = None,
|
||||
) -> Dict:
|
||||
) -> Dict[str, Any]:
|
||||
info = {"title": title, "version": version}
|
||||
if description:
|
||||
info["description"] = description
|
||||
output: Dict[str, Any] = {"openapi": openapi_version, "info": info}
|
||||
if servers:
|
||||
output["servers"] = servers
|
||||
components: Dict[str, Dict] = {}
|
||||
paths: Dict[str, Dict] = {}
|
||||
components: Dict[str, Dict[str, Any]] = {}
|
||||
paths: Dict[str, Dict[str, Any]] = {}
|
||||
flat_models = get_flat_models_from_routes(routes)
|
||||
# ignore mypy error until enum schemas are released
|
||||
model_name_map = get_model_name_map(flat_models) # type: ignore
|
||||
# ignore mypy error until enum schemas are released
|
||||
model_name_map = get_model_name_map(flat_models)
|
||||
definitions = get_model_definitions(
|
||||
flat_models=flat_models, model_name_map=model_name_map # type: ignore
|
||||
flat_models=flat_models, model_name_map=model_name_map
|
||||
)
|
||||
for route in routes:
|
||||
if isinstance(route, routing.APIRoute):
|
||||
@@ -368,4 +374,4 @@ def get_openapi(
|
||||
output["paths"] = paths
|
||||
if tags:
|
||||
output["tags"] = tags
|
||||
return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True)
|
||||
return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True) # type: ignore
|
||||
|
||||
@@ -239,13 +239,13 @@ def File( # noqa: N802
|
||||
|
||||
|
||||
def Depends( # noqa: N802
|
||||
dependency: Optional[Callable] = None, *, use_cache: bool = True
|
||||
dependency: Optional[Callable[..., Any]] = None, *, use_cache: bool = True
|
||||
) -> Any:
|
||||
return params.Depends(dependency=dependency, use_cache=use_cache)
|
||||
|
||||
|
||||
def Security( # noqa: N802
|
||||
dependency: Optional[Callable] = None,
|
||||
dependency: Optional[Callable[..., Any]] = None,
|
||||
*,
|
||||
scopes: Optional[Sequence[str]] = None,
|
||||
use_cache: bool = True,
|
||||
|
||||
@@ -315,7 +315,7 @@ class File(Form):
|
||||
|
||||
class Depends:
|
||||
def __init__(
|
||||
self, dependency: Optional[Callable] = None, *, use_cache: bool = True
|
||||
self, dependency: Optional[Callable[..., Any]] = None, *, use_cache: bool = True
|
||||
):
|
||||
self.dependency = dependency
|
||||
self.use_cache = use_cache
|
||||
@@ -329,7 +329,7 @@ class Depends:
|
||||
class Security(Depends):
|
||||
def __init__(
|
||||
self,
|
||||
dependency: Optional[Callable] = None,
|
||||
dependency: Optional[Callable[..., Any]] = None,
|
||||
*,
|
||||
scopes: Optional[Sequence[str]] = None,
|
||||
use_cache: bool = True,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
from typing import Any
|
||||
|
||||
from starlette.responses import FileResponse # noqa
|
||||
from starlette.responses import HTMLResponse # noqa
|
||||
from starlette.responses import JSONResponse # noqa
|
||||
from starlette.responses import PlainTextResponse # noqa
|
||||
from starlette.responses import RedirectResponse # noqa
|
||||
from starlette.responses import Response # noqa
|
||||
from starlette.responses import StreamingResponse # noqa
|
||||
from starlette.responses import UJSONResponse # noqa
|
||||
from starlette.responses import FileResponse as FileResponse # noqa
|
||||
from starlette.responses import HTMLResponse as HTMLResponse # noqa
|
||||
from starlette.responses import JSONResponse as JSONResponse # noqa
|
||||
from starlette.responses import PlainTextResponse as PlainTextResponse # noqa
|
||||
from starlette.responses import RedirectResponse as RedirectResponse # noqa
|
||||
from starlette.responses import Response as Response # noqa
|
||||
from starlette.responses import StreamingResponse as StreamingResponse # noqa
|
||||
from starlette.responses import UJSONResponse as UJSONResponse # noqa
|
||||
|
||||
try:
|
||||
import orjson
|
||||
|
||||
@@ -2,7 +2,18 @@ import asyncio
|
||||
import enum
|
||||
import inspect
|
||||
import json
|
||||
from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Type, Union
|
||||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
Coroutine,
|
||||
Dict,
|
||||
List,
|
||||
Optional,
|
||||
Sequence,
|
||||
Set,
|
||||
Type,
|
||||
Union,
|
||||
)
|
||||
|
||||
from fastapi import params
|
||||
from fastapi.datastructures import Default, DefaultPlaceholder
|
||||
@@ -16,6 +27,7 @@ from fastapi.dependencies.utils import (
|
||||
from fastapi.encoders import DictIntStrAny, SetIntStr, jsonable_encoder
|
||||
from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
|
||||
from fastapi.openapi.constants import STATUS_CODES_WITH_NO_BODY
|
||||
from fastapi.types import DecoratedCallable
|
||||
from fastapi.utils import (
|
||||
create_cloned_field,
|
||||
create_response_field,
|
||||
@@ -30,7 +42,8 @@ from starlette.concurrency import run_in_threadpool
|
||||
from starlette.exceptions import HTTPException
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import JSONResponse, Response
|
||||
from starlette.routing import Mount # noqa
|
||||
from starlette.routing import BaseRoute
|
||||
from starlette.routing import Mount as Mount # noqa
|
||||
from starlette.routing import (
|
||||
compile_path,
|
||||
get_name,
|
||||
@@ -150,7 +163,7 @@ def get_request_handler(
|
||||
response_model_exclude_defaults: bool = False,
|
||||
response_model_exclude_none: bool = False,
|
||||
dependency_overrides_provider: Optional[Any] = None,
|
||||
) -> Callable:
|
||||
) -> Callable[[Request], Coroutine[Any, Any, Response]]:
|
||||
assert dependant.call is not None, "dependant.call must be a function"
|
||||
is_coroutine = asyncio.iscoroutinefunction(dependant.call)
|
||||
is_body_form = body_field and isinstance(body_field.field_info, params.Form)
|
||||
@@ -207,7 +220,7 @@ def get_request_handler(
|
||||
response = actual_response_class(
|
||||
content=response_data,
|
||||
status_code=status_code,
|
||||
background=background_tasks,
|
||||
background=background_tasks, # type: ignore # in Starlette
|
||||
)
|
||||
response.headers.raw.extend(sub_response.headers.raw)
|
||||
if sub_response.status_code:
|
||||
@@ -219,7 +232,7 @@ def get_request_handler(
|
||||
|
||||
def get_websocket_app(
|
||||
dependant: Dependant, dependency_overrides_provider: Optional[Any] = None
|
||||
) -> Callable:
|
||||
) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]:
|
||||
async def app(websocket: WebSocket) -> None:
|
||||
solved_result = await solve_dependencies(
|
||||
request=websocket,
|
||||
@@ -240,7 +253,7 @@ class APIWebSocketRoute(routing.WebSocketRoute):
|
||||
def __init__(
|
||||
self,
|
||||
path: str,
|
||||
endpoint: Callable,
|
||||
endpoint: Callable[..., Any],
|
||||
*,
|
||||
name: Optional[str] = None,
|
||||
dependency_overrides_provider: Optional[Any] = None,
|
||||
@@ -262,7 +275,7 @@ class APIRoute(routing.Route):
|
||||
def __init__(
|
||||
self,
|
||||
path: str,
|
||||
endpoint: Callable,
|
||||
endpoint: Callable[..., Any],
|
||||
*,
|
||||
response_model: Optional[Type[Any]] = None,
|
||||
status_code: int = 200,
|
||||
@@ -287,7 +300,7 @@ class APIRoute(routing.Route):
|
||||
JSONResponse
|
||||
),
|
||||
dependency_overrides_provider: Optional[Any] = None,
|
||||
callbacks: Optional[List["APIRoute"]] = None,
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> None:
|
||||
# normalise enums e.g. http.HTTPStatus
|
||||
if isinstance(status_code, enum.IntEnum):
|
||||
@@ -298,7 +311,7 @@ class APIRoute(routing.Route):
|
||||
self.path_regex, self.path_format, self.param_convertors = compile_path(path)
|
||||
if methods is None:
|
||||
methods = ["GET"]
|
||||
self.methods = set([method.upper() for method in methods])
|
||||
self.methods: Set[str] = set([method.upper() for method in methods])
|
||||
self.unique_id = generate_operation_id_for_path(
|
||||
name=self.name, path=self.path_format, method=list(methods)[0]
|
||||
)
|
||||
@@ -375,7 +388,7 @@ class APIRoute(routing.Route):
|
||||
self.callbacks = callbacks
|
||||
self.app = request_response(self.get_route_handler())
|
||||
|
||||
def get_route_handler(self) -> Callable:
|
||||
def get_route_handler(self) -> Callable[[Request], Coroutine[Any, Any, Response]]:
|
||||
return get_request_handler(
|
||||
dependant=self.dependant,
|
||||
body_field=self.body_field,
|
||||
@@ -401,23 +414,23 @@ class APIRouter(routing.Router):
|
||||
dependencies: Optional[Sequence[params.Depends]] = None,
|
||||
default_response_class: Type[Response] = Default(JSONResponse),
|
||||
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
|
||||
callbacks: Optional[List[APIRoute]] = None,
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
routes: Optional[List[routing.BaseRoute]] = None,
|
||||
redirect_slashes: bool = True,
|
||||
default: Optional[ASGIApp] = None,
|
||||
dependency_overrides_provider: Optional[Any] = None,
|
||||
route_class: Type[APIRoute] = APIRoute,
|
||||
on_startup: Optional[Sequence[Callable]] = None,
|
||||
on_shutdown: Optional[Sequence[Callable]] = None,
|
||||
deprecated: bool = None,
|
||||
on_startup: Optional[Sequence[Callable[[], Any]]] = None,
|
||||
on_shutdown: Optional[Sequence[Callable[[], Any]]] = None,
|
||||
deprecated: Optional[bool] = None,
|
||||
include_in_schema: bool = True,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
routes=routes,
|
||||
routes=routes, # type: ignore # in Starlette
|
||||
redirect_slashes=redirect_slashes,
|
||||
default=default,
|
||||
on_startup=on_startup,
|
||||
on_shutdown=on_shutdown,
|
||||
default=default, # type: ignore # in Starlette
|
||||
on_startup=on_startup, # type: ignore # in Starlette
|
||||
on_shutdown=on_shutdown, # type: ignore # in Starlette
|
||||
)
|
||||
if prefix:
|
||||
assert prefix.startswith("/"), "A path prefix must start with '/'"
|
||||
@@ -438,7 +451,7 @@ class APIRouter(routing.Router):
|
||||
def add_api_route(
|
||||
self,
|
||||
path: str,
|
||||
endpoint: Callable,
|
||||
endpoint: Callable[..., Any],
|
||||
*,
|
||||
response_model: Optional[Type[Any]] = None,
|
||||
status_code: int = 200,
|
||||
@@ -463,7 +476,7 @@ class APIRouter(routing.Router):
|
||||
),
|
||||
name: Optional[str] = None,
|
||||
route_class_override: Optional[Type[APIRoute]] = None,
|
||||
callbacks: Optional[List[APIRoute]] = None,
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> None:
|
||||
route_class = route_class_override or self.route_class
|
||||
responses = responses or {}
|
||||
@@ -532,9 +545,9 @@ class APIRouter(routing.Router):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[APIRoute]] = None,
|
||||
) -> Callable:
|
||||
def decorator(func: Callable) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
||||
self.add_api_route(
|
||||
path,
|
||||
func,
|
||||
@@ -565,7 +578,7 @@ class APIRouter(routing.Router):
|
||||
return decorator
|
||||
|
||||
def add_api_websocket_route(
|
||||
self, path: str, endpoint: Callable, name: Optional[str] = None
|
||||
self, path: str, endpoint: Callable[..., Any], name: Optional[str] = None
|
||||
) -> None:
|
||||
route = APIWebSocketRoute(
|
||||
path,
|
||||
@@ -575,8 +588,10 @@ class APIRouter(routing.Router):
|
||||
)
|
||||
self.routes.append(route)
|
||||
|
||||
def websocket(self, path: str, name: Optional[str] = None) -> Callable:
|
||||
def decorator(func: Callable) -> Callable:
|
||||
def websocket(
|
||||
self, path: str, name: Optional[str] = None
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
||||
self.add_api_websocket_route(path, func, name=name)
|
||||
return func
|
||||
|
||||
@@ -591,8 +606,8 @@ class APIRouter(routing.Router):
|
||||
dependencies: Optional[Sequence[params.Depends]] = None,
|
||||
default_response_class: Type[Response] = Default(JSONResponse),
|
||||
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
|
||||
callbacks: Optional[List[APIRoute]] = None,
|
||||
deprecated: bool = None,
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
deprecated: Optional[bool] = None,
|
||||
include_in_schema: bool = True,
|
||||
) -> None:
|
||||
if prefix:
|
||||
@@ -663,10 +678,11 @@ class APIRouter(routing.Router):
|
||||
callbacks=current_callbacks,
|
||||
)
|
||||
elif isinstance(route, routing.Route):
|
||||
methods = list(route.methods or []) # type: ignore # in Starlette
|
||||
self.add_route(
|
||||
prefix + route.path,
|
||||
route.endpoint,
|
||||
methods=list(route.methods or []),
|
||||
methods=methods,
|
||||
include_in_schema=route.include_in_schema,
|
||||
name=route.name,
|
||||
)
|
||||
@@ -706,8 +722,8 @@ class APIRouter(routing.Router):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.api_route(
|
||||
path=path,
|
||||
response_model=response_model,
|
||||
@@ -756,8 +772,8 @@ class APIRouter(routing.Router):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.api_route(
|
||||
path=path,
|
||||
response_model=response_model,
|
||||
@@ -806,8 +822,8 @@ class APIRouter(routing.Router):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.api_route(
|
||||
path=path,
|
||||
response_model=response_model,
|
||||
@@ -856,8 +872,8 @@ class APIRouter(routing.Router):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.api_route(
|
||||
path=path,
|
||||
response_model=response_model,
|
||||
@@ -906,8 +922,8 @@ class APIRouter(routing.Router):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.api_route(
|
||||
path=path,
|
||||
response_model=response_model,
|
||||
@@ -956,8 +972,8 @@ class APIRouter(routing.Router):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.api_route(
|
||||
path=path,
|
||||
response_model=response_model,
|
||||
@@ -1006,8 +1022,8 @@ class APIRouter(routing.Router):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.api_route(
|
||||
path=path,
|
||||
response_model=response_model,
|
||||
@@ -1056,8 +1072,8 @@ class APIRouter(routing.Router):
|
||||
include_in_schema: bool = True,
|
||||
response_class: Type[Response] = Default(JSONResponse),
|
||||
name: Optional[str] = None,
|
||||
callbacks: Optional[List[APIRoute]] = None,
|
||||
) -> Callable:
|
||||
callbacks: Optional[List[BaseRoute]] = None,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
|
||||
return self.api_route(
|
||||
path=path,
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
from .api_key import APIKeyCookie, APIKeyHeader, APIKeyQuery
|
||||
from .http import (
|
||||
HTTPAuthorizationCredentials,
|
||||
HTTPBasic,
|
||||
HTTPBasicCredentials,
|
||||
HTTPBearer,
|
||||
HTTPDigest,
|
||||
)
|
||||
from .oauth2 import (
|
||||
OAuth2,
|
||||
OAuth2AuthorizationCodeBearer,
|
||||
OAuth2PasswordBearer,
|
||||
OAuth2PasswordRequestForm,
|
||||
OAuth2PasswordRequestFormStrict,
|
||||
SecurityScopes,
|
||||
)
|
||||
from .open_id_connect_url import OpenIdConnect
|
||||
from .api_key import APIKeyCookie as APIKeyCookie
|
||||
from .api_key import APIKeyHeader as APIKeyHeader
|
||||
from .api_key import APIKeyQuery as APIKeyQuery
|
||||
from .http import HTTPAuthorizationCredentials as HTTPAuthorizationCredentials
|
||||
from .http import HTTPBasic as HTTPBasic
|
||||
from .http import HTTPBasicCredentials as HTTPBasicCredentials
|
||||
from .http import HTTPBearer as HTTPBearer
|
||||
from .http import HTTPDigest as HTTPDigest
|
||||
from .oauth2 import OAuth2 as OAuth2
|
||||
from .oauth2 import OAuth2AuthorizationCodeBearer as OAuth2AuthorizationCodeBearer
|
||||
from .oauth2 import OAuth2PasswordBearer as OAuth2PasswordBearer
|
||||
from .oauth2 import OAuth2PasswordRequestForm as OAuth2PasswordRequestForm
|
||||
from .oauth2 import OAuth2PasswordRequestFormStrict as OAuth2PasswordRequestFormStrict
|
||||
from .oauth2 import SecurityScopes as SecurityScopes
|
||||
from .open_id_connect_url import OpenIdConnect as OpenIdConnect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List, Optional
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
from fastapi.exceptions import HTTPException
|
||||
from fastapi.openapi.models import OAuth2 as OAuth2Model
|
||||
@@ -116,7 +116,7 @@ class OAuth2(SecurityBase):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
flows: OAuthFlowsModel = OAuthFlowsModel(),
|
||||
flows: Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]] = OAuthFlowsModel(),
|
||||
scheme_name: Optional[str] = None,
|
||||
auto_error: Optional[bool] = True
|
||||
):
|
||||
@@ -141,7 +141,7 @@ class OAuth2PasswordBearer(OAuth2):
|
||||
self,
|
||||
tokenUrl: str,
|
||||
scheme_name: Optional[str] = None,
|
||||
scopes: Optional[dict] = None,
|
||||
scopes: Optional[Dict[str, str]] = None,
|
||||
auto_error: bool = True,
|
||||
):
|
||||
if not scopes:
|
||||
@@ -171,7 +171,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
|
||||
tokenUrl: str,
|
||||
refreshUrl: Optional[str] = None,
|
||||
scheme_name: Optional[str] = None,
|
||||
scopes: Optional[dict] = None,
|
||||
scopes: Optional[Dict[str, str]] = None,
|
||||
auto_error: bool = True,
|
||||
):
|
||||
if not scopes:
|
||||
|
||||
@@ -1 +1 @@
|
||||
from starlette.staticfiles import StaticFiles # noqa
|
||||
from starlette.staticfiles import StaticFiles as StaticFiles # noqa
|
||||
|
||||
@@ -1 +1 @@
|
||||
from starlette.templating import Jinja2Templates # noqa
|
||||
from starlette.templating import Jinja2Templates as Jinja2Templates # noqa
|
||||
|
||||
@@ -1 +1 @@
|
||||
from starlette.testclient import TestClient # noqa
|
||||
from starlette.testclient import TestClient as TestClient # noqa
|
||||
|
||||
3
fastapi/types.py
Normal file
3
fastapi/types.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from typing import Any, Callable, TypeVar
|
||||
|
||||
DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any])
|
||||
@@ -19,11 +19,10 @@ def get_model_definitions(
|
||||
flat_models: Set[Union[Type[BaseModel], Type[Enum]]],
|
||||
model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str],
|
||||
) -> Dict[str, Any]:
|
||||
definitions: Dict[str, Dict] = {}
|
||||
definitions: Dict[str, Dict[str, Any]] = {}
|
||||
for model in flat_models:
|
||||
# ignore mypy error until enum schemas are released
|
||||
m_schema, m_definitions, m_nested_models = model_process_schema(
|
||||
model, model_name_map=model_name_map, ref_prefix=REF_PREFIX # type: ignore
|
||||
model, model_name_map=model_name_map, ref_prefix=REF_PREFIX
|
||||
)
|
||||
definitions.update(m_definitions)
|
||||
model_name = model_name_map[model]
|
||||
@@ -80,7 +79,7 @@ def create_cloned_field(
|
||||
cloned_types = dict()
|
||||
original_type = field.type_
|
||||
if is_dataclass(original_type) and hasattr(original_type, "__pydantic_model__"):
|
||||
original_type = original_type.__pydantic_model__ # type: ignore
|
||||
original_type = original_type.__pydantic_model__
|
||||
use_type = original_type
|
||||
if lenient_issubclass(original_type, BaseModel):
|
||||
original_type = cast(Type[BaseModel], original_type)
|
||||
@@ -127,7 +126,7 @@ def generate_operation_id_for_path(*, name: str, path: str, method: str) -> str:
|
||||
return operation_id
|
||||
|
||||
|
||||
def deep_dict_update(main_dict: dict, update_dict: dict) -> None:
|
||||
def deep_dict_update(main_dict: Dict[Any, Any], update_dict: Dict[Any, Any]) -> None:
|
||||
for key in update_dict:
|
||||
if (
|
||||
key in main_dict
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
from starlette.websockets import WebSocket # noqa
|
||||
from starlette.websockets import WebSocketDisconnect # noqa
|
||||
from starlette.websockets import WebSocket as WebSocket # noqa
|
||||
from starlette.websockets import WebSocketDisconnect as WebSocketDisconnect # noqa
|
||||
|
||||
22
mypy.ini
22
mypy.ini
@@ -1,3 +1,25 @@
|
||||
[mypy]
|
||||
|
||||
# --strict
|
||||
disallow_any_generics = True
|
||||
disallow_subclassing_any = True
|
||||
disallow_untyped_calls = True
|
||||
disallow_untyped_defs = True
|
||||
disallow_incomplete_defs = True
|
||||
check_untyped_defs = True
|
||||
disallow_untyped_decorators = True
|
||||
no_implicit_optional = True
|
||||
warn_redundant_casts = True
|
||||
warn_unused_ignores = True
|
||||
warn_return_any = True
|
||||
implicit_reexport = False
|
||||
strict_equality = True
|
||||
# --strict end
|
||||
|
||||
[mypy-fastapi.concurrency]
|
||||
warn_unused_ignores = False
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-fastapi.tests.*]
|
||||
ignore_missing_imports = True
|
||||
check_untyped_defs = True
|
||||
|
||||
@@ -46,9 +46,9 @@ test = [
|
||||
"pytest ==5.4.3",
|
||||
"pytest-cov ==2.10.0",
|
||||
"pytest-asyncio >=0.14.0,<0.15.0",
|
||||
"mypy ==0.782",
|
||||
"mypy ==0.790",
|
||||
"flake8 >=3.8.3,<4.0.0",
|
||||
"black ==19.10b0",
|
||||
"black ==20.8b1",
|
||||
"isort >=5.0.6,<6.0.0",
|
||||
"requests >=2.24.0,<3.0.0",
|
||||
"httpx >=0.14.0,<0.15.0",
|
||||
@@ -68,7 +68,6 @@ doc = [
|
||||
"mkdocs-material >=6.1.4,<7.0.0",
|
||||
"markdown-include >=0.5.1,<0.6.0",
|
||||
"mkdocs-markdownextradata-plugin >=0.1.7,<0.2.0",
|
||||
"typer >=0.3.0,<0.4.0",
|
||||
"typer-cli >=0.0.9,<0.0.10",
|
||||
"pyyaml >=5.3.1,<6.0.0"
|
||||
]
|
||||
@@ -77,7 +76,7 @@ dev = [
|
||||
"passlib[bcrypt] >=1.7.2,<2.0.0",
|
||||
"autoflake >=1.3.1,<2.0.0",
|
||||
"flake8 >=3.8.3,<4.0.0",
|
||||
"uvicorn >=0.11.5,<0.12.0",
|
||||
"uvicorn[standard] >=0.12.0,<0.14.0",
|
||||
"graphene >=2.1.8,<3.0.0"
|
||||
]
|
||||
all = [
|
||||
@@ -91,7 +90,7 @@ all = [
|
||||
"ujson >=3.0.0,<4.0.0",
|
||||
"orjson >=3.2.1,<4.0.0",
|
||||
"email_validator >=1.1.1,<2.0.0",
|
||||
"uvicorn >=0.11.5,<0.12.0",
|
||||
"uvicorn[standard] >=0.12.0,<0.14.0",
|
||||
"async_exit_stack >=1.0.1,<2.0.0",
|
||||
"async_generator >=1.10,<2.0.0"
|
||||
]
|
||||
|
||||
@@ -4,7 +4,7 @@ import shutil
|
||||
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
||||
from multiprocessing import Pool
|
||||
from pathlib import Path
|
||||
from typing import Dict, Optional, Tuple
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
import mkdocs.commands.build
|
||||
import mkdocs.commands.serve
|
||||
@@ -136,6 +136,12 @@ def build_lang(
|
||||
shutil.rmtree(build_lang_path, ignore_errors=True)
|
||||
shutil.copytree(lang_path, build_lang_path)
|
||||
shutil.copytree(en_docs_path / "data", build_lang_path / "data")
|
||||
overrides_src = en_docs_path / "overrides"
|
||||
overrides_dest = build_lang_path / "overrides"
|
||||
for path in overrides_src.iterdir():
|
||||
dest_path = overrides_dest / path.name
|
||||
if not dest_path.exists():
|
||||
shutil.copy(path, dest_path)
|
||||
en_config_path: Path = en_lang_path / mkdocs_name
|
||||
en_config: dict = mkdocs.utils.yaml_load(en_config_path.read_text(encoding="utf-8"))
|
||||
nav = en_config["nav"]
|
||||
@@ -358,12 +364,24 @@ def update_config(lang: str):
|
||||
config["nav"] = current_config["nav"]
|
||||
config["theme"]["language"] = current_config["theme"]["language"]
|
||||
languages = [{"en": "/"}]
|
||||
for lang in get_lang_paths():
|
||||
if lang.name == "en" or not lang.is_dir():
|
||||
alternate: List[Dict[str, str]] = config["extra"].get("alternate", [])
|
||||
alternate_dict = {alt["link"]: alt["name"] for alt in alternate}
|
||||
new_alternate: List[Dict[str, str]] = []
|
||||
for lang_path in get_lang_paths():
|
||||
if lang_path.name == "en" or not lang_path.is_dir():
|
||||
continue
|
||||
name = lang.name
|
||||
name = lang_path.name
|
||||
languages.append({name: f"/{name}/"})
|
||||
for lang_dict in languages:
|
||||
name = list(lang_dict.keys())[0]
|
||||
url = lang_dict[name]
|
||||
if url not in alternate_dict:
|
||||
new_alternate.append({"link": url, "name": name})
|
||||
else:
|
||||
use_name = alternate_dict[url]
|
||||
new_alternate.append({"link": url, "name": use_name})
|
||||
config["nav"][1] = {"Languages": languages}
|
||||
config["extra"]["alternate"] = new_alternate
|
||||
config_path.write_text(
|
||||
yaml.dump(config, sort_keys=False, width=200, allow_unicode=True),
|
||||
encoding="utf-8",
|
||||
|
||||
@@ -2,6 +2,7 @@ import pytest
|
||||
from fastapi import APIRouter, FastAPI
|
||||
from fastapi.routing import APIRoute
|
||||
from fastapi.testclient import TestClient
|
||||
from starlette.routing import Route
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -106,9 +107,9 @@ def test_get_path(path, expected_status, expected_response):
|
||||
|
||||
def test_route_classes():
|
||||
routes = {}
|
||||
r: APIRoute
|
||||
for r in app.router.routes:
|
||||
assert isinstance(r, Route)
|
||||
routes[r.path] = r
|
||||
assert routes["/a/"].x_type == "A"
|
||||
assert routes["/a/b/"].x_type == "B"
|
||||
assert routes["/a/b/c/"].x_type == "C"
|
||||
assert getattr(routes["/a/"], "x_type") == "A"
|
||||
assert getattr(routes["/a/b/"], "x_type") == "B"
|
||||
assert getattr(routes["/a/b/c/"], "x_type") == "C"
|
||||
|
||||
@@ -7,7 +7,7 @@ app = FastAPI()
|
||||
|
||||
class Product(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: str = None # type: ignore
|
||||
price: float
|
||||
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ async def path3_override_router2_override(level3: str):
|
||||
return level3
|
||||
|
||||
|
||||
@router2_override.get("/default3",)
|
||||
@router2_override.get("/default3")
|
||||
async def path3_default_router2_override(level3: str):
|
||||
return level3
|
||||
|
||||
@@ -217,7 +217,9 @@ async def path5_override_router4_override(level5: str):
|
||||
return level5
|
||||
|
||||
|
||||
@router4_override.get("/default5",)
|
||||
@router4_override.get(
|
||||
"/default5",
|
||||
)
|
||||
async def path5_default_router4_override(level5: str):
|
||||
return level5
|
||||
|
||||
@@ -238,7 +240,9 @@ async def path5_override_router4_default(level5: str):
|
||||
return level5
|
||||
|
||||
|
||||
@router4_default.get("/default5",)
|
||||
@router4_default.get(
|
||||
"/default5",
|
||||
)
|
||||
async def path5_default_router4_default(level5: str):
|
||||
return level5
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ class MyUuid:
|
||||
def __str__(self):
|
||||
return self.uuid
|
||||
|
||||
@property
|
||||
@property # type: ignore
|
||||
def __class__(self):
|
||||
return uuid.UUID
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ class ModelWithAlias(BaseModel):
|
||||
|
||||
|
||||
class ModelWithDefault(BaseModel):
|
||||
foo: str = ...
|
||||
foo: str = ... # type: ignore
|
||||
bar: str = "bar"
|
||||
bla: str = "bla"
|
||||
|
||||
@@ -88,7 +88,7 @@ def fixture_model_with_path(request):
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
ModelWithPath = create_model(
|
||||
"ModelWithPath", path=(request.param, ...), __config__=Config
|
||||
"ModelWithPath", path=(request.param, ...), __config__=Config # type: ignore
|
||||
)
|
||||
return ModelWithPath(path=request.param("/foo", "bar"))
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
|
||||
|
||||
def test_strings_in_generated_swagger():
|
||||
sig = inspect.signature(get_swagger_ui_html)
|
||||
swagger_js_url = sig.parameters.get("swagger_js_url").default
|
||||
swagger_css_url = sig.parameters.get("swagger_css_url").default
|
||||
swagger_favicon_url = sig.parameters.get("swagger_favicon_url").default
|
||||
swagger_js_url = sig.parameters.get("swagger_js_url").default # type: ignore
|
||||
swagger_css_url = sig.parameters.get("swagger_css_url").default # type: ignore
|
||||
swagger_favicon_url = sig.parameters.get("swagger_favicon_url").default # type: ignore
|
||||
html = get_swagger_ui_html(openapi_url="/docs", title="title")
|
||||
body_content = html.body.decode()
|
||||
assert swagger_js_url in body_content
|
||||
@@ -34,8 +34,8 @@ def test_strings_in_custom_swagger():
|
||||
|
||||
def test_strings_in_generated_redoc():
|
||||
sig = inspect.signature(get_redoc_html)
|
||||
redoc_js_url = sig.parameters.get("redoc_js_url").default
|
||||
redoc_favicon_url = sig.parameters.get("redoc_favicon_url").default
|
||||
redoc_js_url = sig.parameters.get("redoc_js_url").default # type: ignore
|
||||
redoc_favicon_url = sig.parameters.get("redoc_favicon_url").default # type: ignore
|
||||
html = get_redoc_html(openapi_url="/docs", title="title")
|
||||
body_content = html.body.decode()
|
||||
assert redoc_js_url in body_content
|
||||
|
||||
@@ -10,7 +10,7 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
age: condecimal(gt=Decimal(0.0))
|
||||
age: condecimal(gt=Decimal(0.0)) # type: ignore
|
||||
|
||||
|
||||
@app.post("/items/")
|
||||
|
||||
@@ -8,7 +8,7 @@ app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
def read_items(q: Optional[str] = Param(None)):
|
||||
def read_items(q: Optional[str] = Param(None)): # type: ignore
|
||||
return {"q": q}
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user