mirror of https://github.com/tiangolo/fastapi.git
Merge branch 'master' into master
This commit is contained in:
commit
bee76daa4d
|
|
@ -36,9 +36,9 @@ jobs:
|
|||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docs-zip
|
||||
path: ./docs.zip
|
||||
path: ./site/docs.zip
|
||||
- name: Deploy to Netlify
|
||||
uses: nwtgck/actions-netlify@v1.2.4
|
||||
uses: nwtgck/actions-netlify@v2.0.0
|
||||
with:
|
||||
publish-dir: './site'
|
||||
production-branch: master
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Clean site
|
||||
run: |
|
||||
rm -rf ./site
|
||||
mkdir ./site
|
||||
- name: Download Artifact Docs
|
||||
uses: dawidd6/action-download-artifact@v2.24.2
|
||||
with:
|
||||
|
|
@ -18,14 +22,15 @@ jobs:
|
|||
workflow: build-docs.yml
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
name: docs-zip
|
||||
path: ./site/
|
||||
- name: Unzip docs
|
||||
run: |
|
||||
rm -rf ./site
|
||||
cd ./site
|
||||
unzip docs.zip
|
||||
rm -f docs.zip
|
||||
- name: Deploy to Netlify
|
||||
id: netlify
|
||||
uses: nwtgck/actions-netlify@v1.2.4
|
||||
uses: nwtgck/actions-netlify@v2.0.0
|
||||
with:
|
||||
publish-dir: './site'
|
||||
production-deploy: false
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ jobs:
|
|||
- name: Build distribution
|
||||
run: python -m build
|
||||
- name: Publish
|
||||
uses: pypa/gh-action-pypi-publish@v1.5.1
|
||||
uses: pypa/gh-action-pypi-publish@v1.5.2
|
||||
with:
|
||||
password: ${{ secrets.PYPI_API_TOKEN }}
|
||||
- name: Dump GitHub context
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ repos:
|
|||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.1.0
|
||||
rev: v3.2.2
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args:
|
||||
|
|
|
|||
|
|
@ -8,12 +8,15 @@ sponsors:
|
|||
- login: cryptapi
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/44925437?u=61369138589bc7fee6c417f3fbd50fbd38286cc4&v=4
|
||||
url: https://github.com/cryptapi
|
||||
- - login: ObliviousAI
|
||||
- login: jrobbins-LiveData
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/79278744?u=bae8175fc3f09db281aca1f97a9ddc1a914a8c4f&v=4
|
||||
url: https://github.com/jrobbins-LiveData
|
||||
- - login: nihpo
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1841030?u=0264956d7580f7e46687a762a7baa629f84cf97c&v=4
|
||||
url: https://github.com/nihpo
|
||||
- login: ObliviousAI
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/65656077?v=4
|
||||
url: https://github.com/ObliviousAI
|
||||
- login: Lovage-Labs
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/71685552?v=4
|
||||
url: https://github.com/Lovage-Labs
|
||||
- login: chaserowbotham
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/97751084?v=4
|
||||
url: https://github.com/chaserowbotham
|
||||
|
|
@ -38,9 +41,18 @@ sponsors:
|
|||
- - login: InesIvanova
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22920417?u=409882ec1df6dbd77455788bb383a8de223dbf6f&v=4
|
||||
url: https://github.com/InesIvanova
|
||||
- - login: SendCloud
|
||||
- - login: vyos
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5647000?v=4
|
||||
url: https://github.com/vyos
|
||||
- login: SendCloud
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7831959?v=4
|
||||
url: https://github.com/SendCloud
|
||||
- login: matallan
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/12107723?v=4
|
||||
url: https://github.com/matallan
|
||||
- login: takashi-yoneya
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4
|
||||
url: https://github.com/takashi-yoneya
|
||||
- login: mercedes-benz
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/34240465?v=4
|
||||
url: https://github.com/mercedes-benz
|
||||
|
|
@ -56,12 +68,18 @@ sponsors:
|
|||
- - login: johnadjei
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/767860?v=4
|
||||
url: https://github.com/johnadjei
|
||||
- login: gvisniuc
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1614747?u=502dfdb2b087ddcf5460026297c98c7907bc2795&v=4
|
||||
url: https://github.com/gvisniuc
|
||||
- login: HiredScore
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3908850?v=4
|
||||
url: https://github.com/HiredScore
|
||||
- login: Trivie
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8161763?v=4
|
||||
url: https://github.com/Trivie
|
||||
- login: Lovage-Labs
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/71685552?v=4
|
||||
url: https://github.com/Lovage-Labs
|
||||
- - login: moellenbeck
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/169372?v=4
|
||||
url: https://github.com/moellenbeck
|
||||
|
|
@ -80,27 +98,18 @@ sponsors:
|
|||
- login: jmaralc
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4
|
||||
url: https://github.com/jmaralc
|
||||
- login: takashi-yoneya
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4
|
||||
url: https://github.com/takashi-yoneya
|
||||
- login: mainframeindustries
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/55092103?v=4
|
||||
url: https://github.com/mainframeindustries
|
||||
- login: DelfinaCare
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4
|
||||
url: https://github.com/DelfinaCare
|
||||
- - login: karelhusa
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11407706?u=4f787cffc30ea198b15935c751940f0b48a26a17&v=4
|
||||
url: https://github.com/karelhusa
|
||||
- - login: povilasb
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1213442?u=b11f58ed6ceea6e8297c9b310030478ebdac894d&v=4
|
||||
url: https://github.com/povilasb
|
||||
- login: primer-io
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4
|
||||
url: https://github.com/primer-io
|
||||
- - login: DucNgn
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43587865?u=a9f9f61569aebdc0ce74df85b8cc1a219a7ab570&v=4
|
||||
url: https://github.com/DucNgn
|
||||
- - login: indeedeng
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2905043?v=4
|
||||
url: https://github.com/indeedeng
|
||||
- login: A-Edge
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/59514131?v=4
|
||||
url: https://github.com/A-Edge
|
||||
|
|
@ -119,9 +128,6 @@ sponsors:
|
|||
- login: kamalgill
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4
|
||||
url: https://github.com/kamalgill
|
||||
- login: gazpachoking
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/187133?v=4
|
||||
url: https://github.com/gazpachoking
|
||||
- login: dekoza
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/210980?u=c03c78a8ae1039b500dfe343665536ebc51979b2&v=4
|
||||
url: https://github.com/dekoza
|
||||
|
|
@ -155,6 +161,12 @@ sponsors:
|
|||
- login: ltieman
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1084689?u=e69b17de17cb3ca141a17daa7ccbe173ceb1eb17&v=4
|
||||
url: https://github.com/ltieman
|
||||
- login: mrkmcknz
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1089376?u=2b9b8a8c25c33a4f6c220095638bd821cdfd13a3&v=4
|
||||
url: https://github.com/mrkmcknz
|
||||
- login: coffeewasmyidea
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1636488?u=8e32a4f200eff54dd79cd79d55d254bfce5e946d&v=4
|
||||
url: https://github.com/coffeewasmyidea
|
||||
- login: corleyma
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2080732?u=aed2ff652294a87d666b1c3f6dbe98104db76d26&v=4
|
||||
url: https://github.com/corleyma
|
||||
|
|
@ -170,8 +182,11 @@ sponsors:
|
|||
- login: Shark009
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3163309?u=0c6f4091b0eda05c44c390466199826e6dc6e431&v=4
|
||||
url: https://github.com/Shark009
|
||||
- login: ColliotL
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3412402?u=ca64b07ecbef2f9da1cc2cac3f37522aa4814902&v=4
|
||||
url: https://github.com/ColliotL
|
||||
- login: grillazz
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=0b32b7073ae1ab8b7f6d2db0188c2e1e357ff451&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=453cd1725c8d7fe3e258016bc19cff861d4fcb53&v=4
|
||||
url: https://github.com/grillazz
|
||||
- login: dblackrun
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3528486?v=4
|
||||
|
|
@ -179,20 +194,20 @@ sponsors:
|
|||
- login: zsinx6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4
|
||||
url: https://github.com/zsinx6
|
||||
- login: bauyrzhanospan
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3536037?u=25c86201d0212497aefcc1688cccf509057a1dc4&v=4
|
||||
url: https://github.com/bauyrzhanospan
|
||||
- login: MarekBleschke
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3616870?v=4
|
||||
url: https://github.com/MarekBleschke
|
||||
- login: aacayaco
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3634801?u=eaadda178c964178fcb64886f6c732172c8f8219&v=4
|
||||
url: https://github.com/aacayaco
|
||||
- login: anomaly
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3654837?v=4
|
||||
url: https://github.com/anomaly
|
||||
- login: peterHoburg
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3860655?u=f55f47eb2d6a9b495e806ac5a044e3ae01ccc1fa&v=4
|
||||
url: https://github.com/peterHoburg
|
||||
- login: jgreys
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4136890?u=b579fd97033269a5e703ab509c7d5478b146cc2d&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4136890?u=c66ae617d614f6c886f1f1c1799d22100b3c848d&v=4
|
||||
url: https://github.com/jgreys
|
||||
- login: gorhack
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4141690?u=ec119ebc4bdf00a7bc84657a71aa17834f4f27f3&v=4
|
||||
|
|
@ -203,6 +218,9 @@ sponsors:
|
|||
- login: oliverxchen
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4471774?u=534191f25e32eeaadda22dfab4b0a428733d5489&v=4
|
||||
url: https://github.com/oliverxchen
|
||||
- login: Rey8d01
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4836190?u=5942598a23a377602c1669522334ab5ebeaf9165&v=4
|
||||
url: https://github.com/Rey8d01
|
||||
- login: ScrimForever
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5040124?u=091ec38bfe16d6e762099e91309b59f248616a65&v=4
|
||||
url: https://github.com/ScrimForever
|
||||
|
|
@ -239,9 +257,9 @@ sponsors:
|
|||
- login: wdwinslow
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4
|
||||
url: https://github.com/wdwinslow
|
||||
- login: Ge0f3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11887760?u=ccd80f1ac36dcb8517ef5c4e702e8cc5a80cad2f&v=4
|
||||
url: https://github.com/Ge0f3
|
||||
- login: bapi24
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11890901?u=45cc721d8f66ad2f62b086afc3d4761d0c16b9c6&v=4
|
||||
url: https://github.com/bapi24
|
||||
- login: svats2k
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/12378398?u=ecf28c19f61052e664bdfeb2391f8107d137915c&v=4
|
||||
url: https://github.com/svats2k
|
||||
|
|
@ -257,15 +275,12 @@ sponsors:
|
|||
- login: pablonnaoji
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/15187159?u=afc15bd5a4ba9c5c7206bbb1bcaeef606a0932e0&v=4
|
||||
url: https://github.com/pablonnaoji
|
||||
- login: robintully
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/17059673?u=862b9bb01513f5acd30df97433cb97a24dbfb772&v=4
|
||||
url: https://github.com/robintully
|
||||
- login: wedwardbeck
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/19333237?u=1de4ae2bf8d59eb4c013f21d863cbe0f2010575f&v=4
|
||||
url: https://github.com/wedwardbeck
|
||||
- login: RedCarpetUp
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/20360440?v=4
|
||||
url: https://github.com/RedCarpetUp
|
||||
- login: m4knV
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/19666130?u=843383978814886be93c137d10d2e20e9f13af07&v=4
|
||||
url: https://github.com/m4knV
|
||||
- login: Filimoa
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=75e02d102d2ee3e3d793e555fa5c63045913ccb0&v=4
|
||||
url: https://github.com/Filimoa
|
||||
|
|
@ -302,6 +317,9 @@ sponsors:
|
|||
- login: ProteinQure
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33707203?v=4
|
||||
url: https://github.com/ProteinQure
|
||||
- login: faviasono
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37707874?u=f0b75ca4248987c08ed8fb8ed682e7e74d5d7091&v=4
|
||||
url: https://github.com/faviasono
|
||||
- login: ybressler
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=41e2c00f1eebe3c402635f0325e41b4e6511462c&v=4
|
||||
url: https://github.com/ybressler
|
||||
|
|
@ -341,9 +359,12 @@ sponsors:
|
|||
- login: anthonycepeda
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=4252c6b6dc5024af502a823a3ac5e7a03a69963f&v=4
|
||||
url: https://github.com/anthonycepeda
|
||||
- login: dotlas
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/88832003?v=4
|
||||
url: https://github.com/dotlas
|
||||
- login: fpiem
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/77389987?u=f667a25cd4832b28801189013b74450e06cc232c&v=4
|
||||
url: https://github.com/fpiem
|
||||
- login: DelfinaCare
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4
|
||||
url: https://github.com/DelfinaCare
|
||||
- login: programvx
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/96057906?v=4
|
||||
url: https://github.com/programvx
|
||||
|
|
@ -354,7 +375,7 @@ sponsors:
|
|||
avatarUrl: https://avatars.githubusercontent.com/u/115501964?v=4
|
||||
url: https://github.com/Dagmaara
|
||||
- - login: linux-china
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/46711?v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/46711?u=cd77c65338b158750eb84dc7ff1acf3209ccfc4f&v=4
|
||||
url: https://github.com/linux-china
|
||||
- login: ddanier
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/113563?u=ed1dc79de72f93bd78581f88ebc6952b62f472da&v=4
|
||||
|
|
@ -371,15 +392,9 @@ sponsors:
|
|||
- login: hhatto
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/150309?u=3e8f63c27bf996bfc68464b0ce3f7a3e40e6ea7f&v=4
|
||||
url: https://github.com/hhatto
|
||||
- login: yourkin
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/178984?u=b43a7e5f8818f7d9083d3b110118d9c27d48a794&v=4
|
||||
url: https://github.com/yourkin
|
||||
- login: slafs
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4
|
||||
url: https://github.com/slafs
|
||||
- login: assem-ch
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/315228?u=e0c5ab30726d3243a40974bb9bae327866e42d9b&v=4
|
||||
url: https://github.com/assem-ch
|
||||
- login: adamghill
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/317045?u=f1349d5ffe84a19f324e204777859fbf69ddf633&v=4
|
||||
url: https://github.com/adamghill
|
||||
|
|
@ -494,9 +509,6 @@ sponsors:
|
|||
- login: logan-connolly
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16244943?u=8ae66dfbba936463cc8aa0dd7a6d2b4c0cc757eb&v=4
|
||||
url: https://github.com/logan-connolly
|
||||
- login: stevenayers
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16361214?u=098b797d8d48afb8cd964b717847943b61d24a6d&v=4
|
||||
url: https://github.com/stevenayers
|
||||
- login: cdsre
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16945936?v=4
|
||||
url: https://github.com/cdsre
|
||||
|
|
@ -521,6 +533,9 @@ sponsors:
|
|||
- login: SebTota
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/25122511?v=4
|
||||
url: https://github.com/SebTota
|
||||
- login: joerambo
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/26282974?v=4
|
||||
url: https://github.com/joerambo
|
||||
- login: mertguvencli
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4
|
||||
url: https://github.com/mertguvencli
|
||||
|
|
@ -533,6 +548,9 @@ sponsors:
|
|||
- login: engineerjoe440
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33275230?u=eb223cad27017bb1e936ee9b429b450d092d0236&v=4
|
||||
url: https://github.com/engineerjoe440
|
||||
- login: bnkc
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=20f362505e2a994805233f42e69f9f14b4a9dd0c&v=4
|
||||
url: https://github.com/bnkc
|
||||
- login: declon
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4
|
||||
url: https://github.com/declon
|
||||
|
|
@ -590,12 +608,9 @@ sponsors:
|
|||
- login: pondDevThai
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/71592181?u=08af9a59bccfd8f6b101de1005aa9822007d0a44&v=4
|
||||
url: https://github.com/pondDevThai
|
||||
- login: marlonmartins2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/87719558?u=d07ffecfdabf4fd9aca987f8b5cd9128c65e598e&v=4
|
||||
url: https://github.com/marlonmartins2
|
||||
- - login: 2niuhe
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/13382324?u=ac918d72e0329c87ba29b3bf85e03e98a4ee9427&v=4
|
||||
url: https://github.com/2niuhe
|
||||
- - login: wardal
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/15804042?v=4
|
||||
url: https://github.com/wardal
|
||||
- login: gabrielmbmb
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=6d1e00b5d558e96718312ff910a2318f47cc3145&v=4
|
||||
url: https://github.com/gabrielmbmb
|
||||
|
|
@ -605,6 +620,3 @@ sponsors:
|
|||
- login: Moises6669
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/66188523?u=96af25b8d5be9f983cb96e9dd7c605c716caf1f5&v=4
|
||||
url: https://github.com/Moises6669
|
||||
- login: su-shubham
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/75021117?v=4
|
||||
url: https://github.com/su-shubham
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
maintainers:
|
||||
- login: tiangolo
|
||||
answers: 1315
|
||||
prs: 342
|
||||
answers: 1837
|
||||
prs: 360
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4
|
||||
url: https://github.com/tiangolo
|
||||
experts:
|
||||
- login: Kludex
|
||||
count: 367
|
||||
count: 374
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: dmontagu
|
||||
|
|
@ -15,14 +15,14 @@ experts:
|
|||
url: https://github.com/dmontagu
|
||||
- login: ycd
|
||||
count: 221
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=fa40e037060d62bf82e16b505d870a2866725f38&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: Mause
|
||||
count: 207
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4
|
||||
url: https://github.com/Mause
|
||||
- login: JarroVGIT
|
||||
count: 187
|
||||
count: 192
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
|
||||
url: https://github.com/JarroVGIT
|
||||
- login: euri10
|
||||
|
|
@ -33,22 +33,26 @@ experts:
|
|||
count: 130
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4
|
||||
url: https://github.com/phy25
|
||||
- login: iudeen
|
||||
count: 87
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
|
||||
url: https://github.com/iudeen
|
||||
- login: raphaelauv
|
||||
count: 77
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
url: https://github.com/raphaelauv
|
||||
- login: iudeen
|
||||
count: 76
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
|
||||
url: https://github.com/iudeen
|
||||
- login: ArcLightSlavik
|
||||
count: 71
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4
|
||||
url: https://github.com/ArcLightSlavik
|
||||
- login: falkben
|
||||
count: 58
|
||||
count: 59
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4
|
||||
url: https://github.com/falkben
|
||||
- login: jgould22
|
||||
count: 55
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
|
||||
url: https://github.com/jgould22
|
||||
- login: sm-Fifteen
|
||||
count: 50
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4
|
||||
|
|
@ -57,10 +61,6 @@ experts:
|
|||
count: 46
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4
|
||||
url: https://github.com/insomnes
|
||||
- login: jgould22
|
||||
count: 46
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
|
||||
url: https://github.com/jgould22
|
||||
- login: Dustyposa
|
||||
count: 45
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4
|
||||
|
|
@ -78,19 +78,19 @@ experts:
|
|||
avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4
|
||||
url: https://github.com/STeveShary
|
||||
- login: chbndrhnns
|
||||
count: 35
|
||||
count: 36
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4
|
||||
url: https://github.com/chbndrhnns
|
||||
- login: frankie567
|
||||
count: 33
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
|
||||
url: https://github.com/frankie567
|
||||
- login: prostomarkeloff
|
||||
count: 33
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4
|
||||
url: https://github.com/prostomarkeloff
|
||||
- login: frankie567
|
||||
count: 31
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
|
||||
url: https://github.com/frankie567
|
||||
- login: acidjunk
|
||||
count: 31
|
||||
count: 32
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
|
||||
url: https://github.com/acidjunk
|
||||
- login: krishnardt
|
||||
|
|
@ -113,12 +113,16 @@ experts:
|
|||
count: 25
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4
|
||||
url: https://github.com/dbanty
|
||||
- login: yinziyan1206
|
||||
count: 25
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
|
||||
url: https://github.com/yinziyan1206
|
||||
- login: SirTelemak
|
||||
count: 24
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4
|
||||
url: https://github.com/SirTelemak
|
||||
- login: odiseo0
|
||||
count: 23
|
||||
count: 24
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
|
||||
url: https://github.com/odiseo0
|
||||
- login: acnebs
|
||||
|
|
@ -137,14 +141,14 @@ experts:
|
|||
count: 19
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4
|
||||
url: https://github.com/retnikt
|
||||
- login: rafsaf
|
||||
count: 19
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
|
||||
url: https://github.com/rafsaf
|
||||
- login: Hultner
|
||||
count: 18
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4
|
||||
url: https://github.com/Hultner
|
||||
- login: rafsaf
|
||||
count: 18
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
|
||||
url: https://github.com/rafsaf
|
||||
- login: jorgerpo
|
||||
count: 17
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4
|
||||
|
|
@ -161,10 +165,6 @@ experts:
|
|||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
- login: yinziyan1206
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4
|
||||
url: https://github.com/yinziyan1206
|
||||
- login: dstlny
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4
|
||||
|
|
@ -173,6 +173,10 @@ experts:
|
|||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4
|
||||
url: https://github.com/jonatasoli
|
||||
- login: mbroton
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/50829834?u=a48610bf1bffaa9c75d03228926e2eb08a2e24ee&v=4
|
||||
url: https://github.com/mbroton
|
||||
- login: hellocoldworld
|
||||
count: 14
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/47581948?u=3d2186796434c507a6cb6de35189ab0ad27c356f&v=4
|
||||
|
|
@ -193,27 +197,39 @@ experts:
|
|||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4
|
||||
url: https://github.com/n8sty
|
||||
- login: mbroton
|
||||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/50829834?u=a48610bf1bffaa9c75d03228926e2eb08a2e24ee&v=4
|
||||
url: https://github.com/mbroton
|
||||
last_month_active:
|
||||
- login: JarroVGIT
|
||||
count: 18
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
|
||||
url: https://github.com/JarroVGIT
|
||||
- login: jgould22
|
||||
count: 9
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
|
||||
url: https://github.com/jgould22
|
||||
- login: yinziyan1206
|
||||
count: 9
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
|
||||
url: https://github.com/yinziyan1206
|
||||
- login: iudeen
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
|
||||
url: https://github.com/iudeen
|
||||
- login: mbroton
|
||||
- login: Kludex
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: JarroVGIT
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
|
||||
url: https://github.com/JarroVGIT
|
||||
- login: TheJumpyWizard
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90986815?u=67e9c13c9f063dd4313db7beb64eaa2f3a37f1fe&v=4
|
||||
url: https://github.com/TheJumpyWizard
|
||||
- login: mbroton
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/50829834?u=a48610bf1bffaa9c75d03228926e2eb08a2e24ee&v=4
|
||||
url: https://github.com/mbroton
|
||||
- login: yinziyan1206
|
||||
- login: mateoradman
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37829370?v=4
|
||||
url: https://github.com/yinziyan1206
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/48420316?u=066f36b8e8e263b0d90798113b0f291d3266db7c&v=4
|
||||
url: https://github.com/mateoradman
|
||||
top_contributors:
|
||||
- login: waynerv
|
||||
count: 25
|
||||
|
|
@ -223,22 +239,18 @@ top_contributors:
|
|||
count: 22
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
|
||||
url: https://github.com/tokusumi
|
||||
- login: jaystone776
|
||||
count: 17
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4
|
||||
url: https://github.com/jaystone776
|
||||
- login: dmontagu
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
|
||||
url: https://github.com/dmontagu
|
||||
- login: jaystone776
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4
|
||||
url: https://github.com/jaystone776
|
||||
- login: Kludex
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: dependabot
|
||||
count: 14
|
||||
avatarUrl: https://avatars.githubusercontent.com/in/29110?v=4
|
||||
url: https://github.com/apps/dependabot
|
||||
- login: euri10
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
|
||||
|
|
@ -267,10 +279,6 @@ top_contributors:
|
|||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
|
||||
url: https://github.com/rjNemo
|
||||
- login: pre-commit-ci
|
||||
count: 6
|
||||
avatarUrl: https://avatars.githubusercontent.com/in/68672?v=4
|
||||
url: https://github.com/apps/pre-commit-ci
|
||||
- login: wshayes
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
|
||||
|
|
@ -287,6 +295,10 @@ top_contributors:
|
|||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=f440bc9062afb3c43b9b9c6cdfdcfe31d58699ef&v=4
|
||||
url: https://github.com/ComicShrimp
|
||||
- login: batlopes
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4
|
||||
url: https://github.com/batlopes
|
||||
- login: jekirl
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4
|
||||
|
|
@ -301,7 +313,7 @@ top_contributors:
|
|||
url: https://github.com/jfunez
|
||||
- login: ycd
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=fa40e037060d62bf82e16b505d870a2866725f38&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: komtaki
|
||||
count: 4
|
||||
|
|
@ -319,21 +331,17 @@ top_contributors:
|
|||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4
|
||||
url: https://github.com/NinaHwang
|
||||
- login: batlopes
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4
|
||||
url: https://github.com/batlopes
|
||||
top_reviewers:
|
||||
- login: Kludex
|
||||
count: 108
|
||||
count: 109
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: BilalAlpaslan
|
||||
count: 65
|
||||
count: 70
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4
|
||||
url: https://github.com/BilalAlpaslan
|
||||
- login: yezz123
|
||||
count: 56
|
||||
count: 59
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4
|
||||
url: https://github.com/yezz123
|
||||
- login: tokusumi
|
||||
|
|
@ -350,7 +358,7 @@ top_reviewers:
|
|||
url: https://github.com/Laineyzhang55
|
||||
- login: ycd
|
||||
count: 45
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=fa40e037060d62bf82e16b505d870a2866725f38&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: cikay
|
||||
count: 41
|
||||
|
|
@ -364,30 +372,30 @@ top_reviewers:
|
|||
count: 33
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=b2ea249c6b41ddf98679c8d110d0f67d4a3ebf93&v=4
|
||||
url: https://github.com/AdrianDeAnda
|
||||
- login: iudeen
|
||||
count: 33
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
|
||||
url: https://github.com/iudeen
|
||||
- login: ArcLightSlavik
|
||||
count: 31
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4
|
||||
url: https://github.com/ArcLightSlavik
|
||||
- login: iudeen
|
||||
count: 26
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
|
||||
url: https://github.com/iudeen
|
||||
- login: komtaki
|
||||
count: 27
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4
|
||||
url: https://github.com/komtaki
|
||||
- login: cassiobotaro
|
||||
count: 25
|
||||
count: 26
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4
|
||||
url: https://github.com/cassiobotaro
|
||||
- login: lsglucas
|
||||
count: 25
|
||||
count: 26
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
|
||||
url: https://github.com/lsglucas
|
||||
- login: dmontagu
|
||||
count: 23
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
|
||||
url: https://github.com/dmontagu
|
||||
- login: komtaki
|
||||
count: 21
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4
|
||||
url: https://github.com/komtaki
|
||||
- login: hard-coders
|
||||
count: 20
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4
|
||||
|
|
@ -429,7 +437,7 @@ top_reviewers:
|
|||
avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4
|
||||
url: https://github.com/delhi09
|
||||
- login: odiseo0
|
||||
count: 14
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
|
||||
url: https://github.com/odiseo0
|
||||
- login: sh0nk
|
||||
|
|
@ -464,6 +472,14 @@ top_reviewers:
|
|||
count: 10
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=f440bc9062afb3c43b9b9c6cdfdcfe31d58699ef&v=4
|
||||
url: https://github.com/ComicShrimp
|
||||
- login: peidrao
|
||||
count: 10
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=88c2cb42a99e0f50cdeae3606992568184783ee5&v=4
|
||||
url: https://github.com/peidrao
|
||||
- login: izaguerreiro
|
||||
count: 9
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4
|
||||
url: https://github.com/izaguerreiro
|
||||
- login: graingert
|
||||
count: 9
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/413772?u=64b77b6aa405c68a9c6bcf45f84257c66eea5f32&v=4
|
||||
|
|
@ -480,10 +496,6 @@ top_reviewers:
|
|||
count: 9
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4
|
||||
url: https://github.com/bezaca
|
||||
- login: izaguerreiro
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4
|
||||
url: https://github.com/izaguerreiro
|
||||
- login: raphaelauv
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
|
|
@ -504,6 +516,10 @@ top_reviewers:
|
|||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/662249?v=4
|
||||
url: https://github.com/dimaqq
|
||||
- login: Xewus
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=4bdd4a0300530a504987db27488ba79c37f2fb18&v=4
|
||||
url: https://github.com/Xewus
|
||||
- login: Serrones
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4
|
||||
|
|
@ -512,11 +528,3 @@ top_reviewers:
|
|||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4
|
||||
url: https://github.com/jovicon
|
||||
- login: ryuckel
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/36391432?u=094eec0cfddd5013f76f31e55e56147d78b19553&v=4
|
||||
url: https://github.com/ryuckel
|
||||
- login: NastasiaSaby
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8245071?u=b3afd005f9e4bf080c219ef61a592b3a8004b764&v=4
|
||||
url: https://github.com/NastasiaSaby
|
||||
|
|
|
|||
|
|
@ -2,12 +2,36 @@
|
|||
|
||||
## Latest Changes
|
||||
|
||||
* ⬆ Bump nwtgck/actions-netlify from 1.2.4 to 2.0.0. PR [#5757](https://github.com/tiangolo/fastapi/pull/5757) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* 👷 Refactor CI artifact upload/download for docs previews. PR [#5793](https://github.com/tiangolo/fastapi/pull/5793) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆ Bump pypa/gh-action-pypi-publish from 1.5.1 to 1.5.2. PR [#5714](https://github.com/tiangolo/fastapi/pull/5714) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* 👥 Update FastAPI People. PR [#5722](https://github.com/tiangolo/fastapi/pull/5722) by [@github-actions[bot]](https://github.com/apps/github-actions).
|
||||
* 🔧 Update sponsors, disable course bundle. PR [#5713](https://github.com/tiangolo/fastapi/pull/5713) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆ Update typer[all] requirement from <0.7.0,>=0.6.1 to >=0.6.1,<0.8.0. PR [#5639](https://github.com/tiangolo/fastapi/pull/5639) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
|
||||
## 0.88.0
|
||||
|
||||
### Upgrades
|
||||
|
||||
* ⬆ Bump Starlette to version `0.22.0` to fix bad encoding for query parameters in new `TestClient`. PR [#5659](https://github.com/tiangolo/fastapi/pull/5659) by [@azogue](https://github.com/azogue).
|
||||
|
||||
### Docs
|
||||
|
||||
* ✏️ Fix typo in docs for `docs/en/docs/advanced/middleware.md`. PR [#5376](https://github.com/tiangolo/fastapi/pull/5376) by [@rifatrakib](https://github.com/rifatrakib).
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Add Portuguese translation for `docs/pt/docs/deployment/docker.md`. PR [#5663](https://github.com/tiangolo/fastapi/pull/5663) by [@ayr-ton](https://github.com/ayr-ton).
|
||||
|
||||
### Internal
|
||||
|
||||
* 👷 Tweak build-docs to improve CI performance. PR [#5699](https://github.com/tiangolo/fastapi/pull/5699) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#5566](https://github.com/tiangolo/fastapi/pull/5566) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
|
||||
* ⬆️ Upgrade Ruff. PR [#5698](https://github.com/tiangolo/fastapi/pull/5698) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Remove pip cache for Smokeshow as it depends on a requirements.txt. PR [#5700](https://github.com/tiangolo/fastapi/pull/5700) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 💚 Fix pip cache for Smokeshow. PR [#5697](https://github.com/tiangolo/fastapi/pull/5697) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Fix and tweak CI cache handling. PR [#5696](https://github.com/tiangolo/fastapi/pull/5696) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Update `setup-python` action in tests to use new caching feature. PR [#5680](https://github.com/tiangolo/fastapi/pull/5680) by [@madkinsz](https://github.com/madkinsz).
|
||||
* ✏️ Fix typo in docs for `docs/en/docs/advanced/middleware.md`. PR [#5376](https://github.com/tiangolo/fastapi/pull/5376) by [@rifatrakib](https://github.com/rifatrakib).
|
||||
* ⬆ Bump black from 22.8.0 to 22.10.0. PR [#5569](https://github.com/tiangolo/fastapi/pull/5569) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
|
||||
## 0.87.0
|
||||
|
|
|
|||
|
|
@ -22,12 +22,6 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="announce-right" style="position: relative;">
|
||||
<div class="item">
|
||||
<a title="Get three courses at 10% off their current prices! Plus, we'll be donating 10% of all profits from sales of this bundle to the FastAPI team." style="display: block; position: relative;" href="https://testdriven.io/talkpython/" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/fastapi-course-bundle-banner.png" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="The data structure for unstructured multimodal data" style="display: block; position: relative;" href="https://bit.ly/3AcNTYL" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
|
|
@ -40,12 +34,6 @@
|
|||
<img class="sponsor-image" src="/img/sponsors/cryptapi-banner.svg" />
|
||||
</a>
|
||||
</div>
|
||||
<!-- <div class="item">
|
||||
<a title="The ultimate solution to unlimited and forever cloud storage." style="display: block; position: relative;" href="https://app.imgwhale.xyz/" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/imgwhale-banner.svg" />
|
||||
</a>
|
||||
</div> -->
|
||||
<div class="item">
|
||||
<a title="Help us migrate doist to FastAPI" style="display: block; position: relative;" href="https://doist.com/careers/9B437B1615-wa-senior-backend-engineer-python" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,701 @@
|
|||
# FastAPI em contêineres - Docker
|
||||
|
||||
Ao fazer o deploy de aplicações FastAPI uma abordagem comum é construir uma **imagem de contêiner Linux**. Isso normalmente é feito usando o <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>. Você pode a partir disso fazer o deploy dessa imagem de algumas maneiras.
|
||||
|
||||
Usando contêineres Linux você tem diversas vantagens incluindo **segurança**, **replicabilidade**, **simplicidade**, entre outras.
|
||||
|
||||
!!! Dica
|
||||
Está com pressa e já sabe dessas coisas? Pode ir direto para [`Dockerfile` abaixo 👇](#build-a-docker-image-for-fastapi).
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Visualização do Dockerfile 👀</summary>
|
||||
|
||||
```Dockerfile
|
||||
FROM python:3.9
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
COPY ./app /code/app
|
||||
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
|
||||
# If running behind a proxy like Nginx or Traefik add --proxy-headers
|
||||
# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers"]
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## O que é um Contêiner
|
||||
|
||||
Contêineres (especificamente contêineres Linux) são um jeito muito **leve** de empacotar aplicações contendo todas as dependências e arquivos necessários enquanto os mantém isolados de outros contêineres (outras aplicações ou componentes) no mesmo sistema.
|
||||
|
||||
Contêineres Linux rodam usando o mesmo kernel Linux do hospedeiro (máquina, máquina virtual, servidor na nuvem, etc). Isso simplesmente significa que eles são muito leves (comparados com máquinas virtuais emulando um sistema operacional completo).
|
||||
|
||||
Dessa forma, contêineres consomem **poucos recursos**, uma quantidade comparável com rodar os processos diretamente (uma máquina virtual consumiria muito mais).
|
||||
|
||||
Contêineres também possuem seus próprios processos (comumente um único processo), sistema de arquivos e rede **isolados** simplificando deploy, segurança, desenvolvimento, etc.
|
||||
|
||||
## O que é uma Imagem de Contêiner
|
||||
|
||||
Um **contêiner** roda a partir de uma **imagem de contêiner**.
|
||||
|
||||
Uma imagem de contêiner é uma versão **estática** de todos os arquivos, variáveis de ambiente e do comando/programa padrão que deve estar presente num contêiner. **Estática** aqui significa que a **imagem** de contêiner não está rodando, não está sendo executada, somente contém os arquivos e metadados empacotados.
|
||||
|
||||
Em contraste com a "**imagem de contêiner**" que contém os conteúdos estáticos armazenados, um "**contêiner**" normalmente se refere à instância rodando, a coisa que está sendo **executada**.
|
||||
|
||||
Quando o **contêiner** é iniciado e está rodando (iniciado a partir de uma **imagem de contêiner**), ele pode criar ou modificar arquivos, variáveis de ambiente, etc. Essas mudanças vão existir somente nesse contêiner, mas não persistirão na imagem subjacente do container (não serão salvas no disco).
|
||||
|
||||
Uma imagem de contêiner é comparável ao arquivo de **programa** e seus conteúdos, ex.: `python` e algum arquivo `main.py`.
|
||||
|
||||
E o **contêiner** em si (em contraste à **imagem de contêiner**) é a própria instância da imagem rodando, comparável a um **processo**. Na verdade, um contêiner está rodando somente quando há um **processo rodando** (e normalmente é somente um processo). O contêiner finaliza quando não há um processo rodando nele.
|
||||
|
||||
## Imagens de contêiner
|
||||
|
||||
Docker tem sido uma das principais ferramentas para criar e gerenciar **imagens de contêiner** e **contêineres**.
|
||||
|
||||
E existe um <a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a> público com **imagens de contêiner oficiais** pré-prontas para diversas ferramentas, ambientes, bancos de dados e aplicações.
|
||||
|
||||
Por exemplo, há uma <a href="https://hub.docker.com/_/python" class="external-link" target="_blank">Imagem Python</a> oficial.
|
||||
|
||||
E existe muitas outras imagens para diferentes coisas, como bancos de dados, por exemplo:
|
||||
|
||||
* <a href="https://hub.docker.com/_/postgres" class="external-link" target="_blank">PostgreSQL</a>
|
||||
* <a href="https://hub.docker.com/_/mysql" class="external-link" target="_blank">MySQL</a>
|
||||
* <a href="https://hub.docker.com/_/mongo" class="external-link" target="_blank">MongoDB</a>
|
||||
* <a href="https://hub.docker.com/_/redis" class="external-link" target="_blank">Redis</a>, etc.
|
||||
|
||||
Usando imagens de contêiner pré-prontas é muito fácil **combinar** e usar diferentes ferramentas. Por exemplo, para testar um novo banco de dados. Em muitos casos, você pode usar as **imagens oficiais** precisando somente de variáveis de ambiente para configurá-las.
|
||||
|
||||
Dessa forma, em muitos casos você pode aprender sobre contêineres e Docker e re-usar essa experiência com diversos componentes e ferramentas.
|
||||
|
||||
Então, você rodaria **vários contêineres** com coisas diferentes, como um banco de dados, uma aplicação Python, um servidor web com uma aplicação frontend React, e conectá-los juntos via sua rede interna.
|
||||
|
||||
Todos os sistemas de gerenciamento de contêineres (como Docker ou Kubernetes) possuem essas funcionalidades de rede integradas a eles.
|
||||
|
||||
## Contêineres e Processos
|
||||
|
||||
Uma **imagem de contêiner** normalmente inclui em seus metadados o programa padrão ou comando que deve ser executado quando o **contêiner** é iniciado e os parâmetros a serem passados para esse programa. Muito similar ao que seria se estivesse na linha de comando.
|
||||
|
||||
Quando um **contêiner** é iniciado, ele irá rodar esse comando/programa (embora você possa sobrescrevê-lo e fazer com que ele rode um comando/programa diferente).
|
||||
|
||||
Um contêiner está rodando enquanto o **processo principal** (comando ou programa) estiver rodando.
|
||||
|
||||
Um contêiner normalmente tem um **único processo**, mas também é possível iniciar sub-processos a partir do processo principal, e dessa forma você terá **vários processos** no mesmo contêiner.
|
||||
|
||||
Mas não é possível ter um contêiner rodando sem **pelo menos um processo rodando**. Se o processo principal parar, o contêiner também para.
|
||||
|
||||
## Construindo uma Imagem Docker para FastAPI
|
||||
|
||||
Okay, vamos construir algo agora! 🚀
|
||||
|
||||
Eu vou mostrar como construir uma **imagem Docker** para FastAPI **do zero**, baseado na **imagem oficial do Python**.
|
||||
|
||||
Isso é o que você quer fazer na **maioria dos casos**, por exemplo:
|
||||
|
||||
* Usando **Kubernetes** ou ferramentas similares
|
||||
* Quando rodando em uma **Raspberry Pi**
|
||||
* Usando um serviço em nuvem que irá rodar uma imagem de contêiner para você, etc.
|
||||
|
||||
### O Pacote Requirements
|
||||
|
||||
Você normalmente teria os **requisitos do pacote** para sua aplicação em algum arquivo.
|
||||
|
||||
Isso pode depender principalmente da ferramenta que você usa para **instalar** esses requisitos.
|
||||
|
||||
O caminho mais comum de fazer isso é ter um arquivo `requirements.txt` com os nomes dos pacotes e suas versões, um por linha.
|
||||
|
||||
Você, naturalmente, usaria as mesmas ideias que você leu em [Sobre Versões do FastAPI](./versions.md){.internal-link target=_blank} para definir os intervalos de versões.
|
||||
|
||||
Por exemplo, seu `requirements.txt` poderia parecer com:
|
||||
|
||||
```
|
||||
fastapi>=0.68.0,<0.69.0
|
||||
pydantic>=1.8.0,<2.0.0
|
||||
uvicorn>=0.15.0,<0.16.0
|
||||
```
|
||||
|
||||
E você normalmente instalaria essas dependências de pacote com `pip`, por exemplo:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install -r requirements.txt
|
||||
---> 100%
|
||||
Successfully installed fastapi pydantic uvicorn
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
!!! info
|
||||
Há outros formatos e ferramentas para definir e instalar dependências de pacote.
|
||||
|
||||
Eu vou mostrar um exemplo depois usando Poetry em uma seção abaixo. 👇
|
||||
|
||||
### Criando o Código do **FastAPI**
|
||||
|
||||
* Crie um diretório `app` e entre nele.
|
||||
* Crie um arquivo vazio `__init__.py`.
|
||||
* Crie um arquivo `main.py` com:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
### Dockerfile
|
||||
|
||||
Agora, no mesmo diretório do projeto, crie um arquivo `Dockerfile` com:
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
# (1)
|
||||
FROM python:3.9
|
||||
|
||||
# (2)
|
||||
WORKDIR /code
|
||||
|
||||
# (3)
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
# (4)
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
# (5)
|
||||
COPY ./app /code/app
|
||||
|
||||
# (6)
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
1. Inicie a partir da imagem base oficial do Python.
|
||||
|
||||
2. Defina o diretório de trabalho atual para `/code`.
|
||||
|
||||
Esse é o diretório onde colocaremos o arquivo `requirements.txt` e o diretório `app`.
|
||||
|
||||
3. Copie o arquivo com os requisitos para o diretório `/code`.
|
||||
|
||||
Copie **somente** o arquivo com os requisitos primeiro, não o resto do código.
|
||||
|
||||
Como esse arquivo **não muda com frequência**, o Docker irá detectá-lo e usar o **cache** para esse passo, habilitando o cache para o próximo passo também.
|
||||
|
||||
4. Instale as dependências de pacote vindas do arquivo de requisitos.
|
||||
|
||||
A opção `--no-cache-dir` diz ao `pip` para não salvar os pacotes baixados localmente, pois isso só aconteceria se `pip` fosse executado novamente para instalar os mesmos pacotes, mas esse não é o caso quando trabalhamos com contêineres.
|
||||
|
||||
!!! note
|
||||
`--no-cache-dir` é apenas relacionado ao `pip`, não tem nada a ver com Docker ou contêineres.
|
||||
|
||||
A opção `--upgrade` diz ao `pip` para atualizar os pacotes se eles já estiverem instalados.
|
||||
|
||||
Por causa do passo anterior de copiar o arquivo, ele pode ser detectado pelo **cache do Docker**, esse passo também **usará o cache do Docker** quando disponível.
|
||||
|
||||
Usando o cache nesse passo irá **salvar** muito **tempo** quando você for construir a imagem repetidas vezes durante o desenvolvimento, ao invés de **baixar e instalar** todas as dependências **toda vez**.
|
||||
|
||||
5. Copie o diretório `./app` dentro do diretório `/code`.
|
||||
|
||||
Como isso tem todo o código contendo o que **muda com mais frequência**, o **cache do Docker** não será usado para esse passo ou para **qualquer passo seguinte** facilmente.
|
||||
|
||||
Então, é importante colocar isso **perto do final** do `Dockerfile`, para otimizar o tempo de construção da imagem do contêiner.
|
||||
|
||||
6. Defina o **comando** para rodar o servidor `uvicorn`.
|
||||
|
||||
`CMD` recebe uma lista de strings, cada uma dessas strings é o que você digitaria na linha de comando separado por espaços.
|
||||
|
||||
Esse comando será executado a partir do **diretório de trabalho atual**, o mesmo diretório `/code` que você definiu acima com `WORKDIR /code`.
|
||||
|
||||
Porque o programa será iniciado em `/code` e dentro dele está o diretório `./app` com seu código, o **Uvicorn** será capaz de ver e **importar** `app` de `app.main`.
|
||||
|
||||
!!! tip
|
||||
Revise o que cada linha faz clicando em cada bolha com o número no código. 👆
|
||||
|
||||
Agora você deve ter uma estrutura de diretório como:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ └── main.py
|
||||
├── Dockerfile
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
#### Por Trás de um Proxy de Terminação TLS
|
||||
|
||||
Se você está executando seu contêiner atrás de um Proxy de Terminação TLS (load balancer) como Nginx ou Traefik, adicione a opção `--proxy-headers`, isso fará com que o Uvicorn confie nos cabeçalhos enviados por esse proxy, informando que o aplicativo está sendo executado atrás do HTTPS, etc.
|
||||
|
||||
```Dockerfile
|
||||
CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
#### Cache Docker
|
||||
|
||||
Existe um truque importante nesse `Dockerfile`, primeiro copiamos o **arquivo com as dependências sozinho**, não o resto do código. Deixe-me te contar o porquê disso.
|
||||
|
||||
```Dockerfile
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
```
|
||||
|
||||
Docker e outras ferramentas **constróem** essas imagens de contêiner **incrementalmente**, adicionando **uma camada em cima da outra**, começando do topo do `Dockerfile` e adicionando qualquer arquivo criado por cada uma das instruções do `Dockerfile`.
|
||||
|
||||
Docker e ferramentas similares também usam um **cache interno** ao construir a imagem, se um arquivo não mudou desde a última vez que a imagem do contêiner foi construída, então ele irá **reutilizar a mesma camada** criada na última vez, ao invés de copiar o arquivo novamente e criar uma nova camada do zero.
|
||||
|
||||
Somente evitar a cópia de arquivos não melhora muito as coisas, mas porque ele usou o cache para esse passo, ele pode **usar o cache para o próximo passo**. Por exemplo, ele pode usar o cache para a instrução que instala as dependências com:
|
||||
|
||||
```Dockerfile
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
```
|
||||
|
||||
O arquivo com os requisitos de pacote **não muda com frequência**. Então, ao copiar apenas esse arquivo, o Docker será capaz de **usar o cache** para esse passo.
|
||||
|
||||
E então, o Docker será capaz de **usar o cache para o próximo passo** que baixa e instala essas dependências. E é aqui que **salvamos muito tempo**. ✨ ...e evitamos tédio esperando. 😪😆
|
||||
|
||||
Baixar e instalar as dependências do pacote **pode levar minutos**, mas usando o **cache** leva **segundos** no máximo.
|
||||
|
||||
E como você estaria construindo a imagem do contêiner novamente e novamente durante o desenvolvimento para verificar se suas alterações de código estão funcionando, há muito tempo acumulado que isso economizaria.
|
||||
|
||||
A partir daí, perto do final do `Dockerfile`, copiamos todo o código. Como isso é o que **muda com mais frequência**, colocamos perto do final, porque quase sempre, qualquer coisa depois desse passo não será capaz de usar o cache.
|
||||
|
||||
```Dockerfile
|
||||
COPY ./app /code/app
|
||||
```
|
||||
|
||||
### Construindo a Imagem Docker
|
||||
|
||||
Agora que todos os arquivos estão no lugar, vamos construir a imagem do contêiner.
|
||||
|
||||
* Vá para o diretório do projeto (onde está o seu `Dockerfile`, contendo o diretório `app`).
|
||||
* Construa sua imagem FastAPI:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ docker build -t myimage .
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
!!! tip
|
||||
Note o `.` no final, é equivalente a `./`, ele diz ao Docker o diretório a ser usado para construir a imagem do contêiner.
|
||||
|
||||
Nesse caso, é o mesmo diretório atual (`.`).
|
||||
|
||||
### Inicie o contêiner Docker
|
||||
|
||||
* Execute um contêiner baseado na sua imagem:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ docker run -d --name mycontêiner -p 80:80 myimage
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Verifique
|
||||
|
||||
Você deve ser capaz de verificar isso no URL do seu contêiner Docker, por exemplo: <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> ou <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (ou equivalente, usando seu host Docker).
|
||||
|
||||
Você verá algo como:
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
## Documentação interativa da API
|
||||
|
||||
Agora você pode ir para <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> ou <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (ou equivalente, usando seu host Docker).
|
||||
|
||||
Você verá a documentação interativa automática da API (fornecida pelo <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
|
||||
|
||||

|
||||
|
||||
## Documentação alternativa da API
|
||||
|
||||
E você também pode ir para <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> ou <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (ou equivalente, usando seu host Docker).
|
||||
|
||||
Você verá a documentação alternativa automática (fornecida pela <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
|
||||
|
||||

|
||||
|
||||
## Construindo uma Imagem Docker com um Arquivo Único FastAPI
|
||||
|
||||
Se seu FastAPI for um único arquivo, por exemplo, `main.py` sem um diretório `./app`, sua estrutura de arquivos poderia ser assim:
|
||||
|
||||
```
|
||||
.
|
||||
├── Dockerfile
|
||||
├── main.py
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
Então você só teria que alterar os caminhos correspondentes para copiar o arquivo dentro do `Dockerfile`:
|
||||
|
||||
```{ .dockerfile .annotate hl_lines="10 13" }
|
||||
FROM python:3.9
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
# (1)
|
||||
COPY ./main.py /code/
|
||||
|
||||
# (2)
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
1. Copie o arquivo `main.py` para o diretório `/code` diretamente (sem nenhum diretório `./app`).
|
||||
|
||||
2. Execute o Uvicorn e diga a ele para importar o objeto `app` de `main` (em vez de importar de `app.main`).
|
||||
|
||||
Então ajuste o comando Uvicorn para usar o novo módulo `main` em vez de `app.main` para importar o objeto FastAPI `app`.
|
||||
|
||||
## Conceitos de Implantação
|
||||
|
||||
Vamos falar novamente sobre alguns dos mesmos [Conceitos de Implantação](./concepts.md){.internal-link target=_blank} em termos de contêineres.
|
||||
|
||||
Contêineres são principalmente uma ferramenta para simplificar o processo de **construção e implantação** de um aplicativo, mas eles não impõem uma abordagem particular para lidar com esses **conceitos de implantação** e existem várias estratégias possíveis.
|
||||
|
||||
A **boa notícia** é que com cada estratégia diferente há uma maneira de cobrir todos os conceitos de implantação. 🎉
|
||||
|
||||
Vamos revisar esses **conceitos de implantação** em termos de contêineres:
|
||||
|
||||
* HTTPS
|
||||
* Executando na inicialização
|
||||
* Reinicializações
|
||||
* Replicação (número de processos rodando)
|
||||
* Memória
|
||||
* Passos anteriores antes de começar
|
||||
|
||||
## HTTPS
|
||||
|
||||
Se nos concentrarmos apenas na **imagem do contêiner** para um aplicativo FastAPI (e posteriormente no **contêiner** em execução), o HTTPS normalmente seria tratado **externamente** por outra ferramenta.
|
||||
|
||||
Isso poderia ser outro contêiner, por exemplo, com <a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>, lidando com **HTTPS** e aquisição **automática** de **certificados**.
|
||||
|
||||
!!! tip
|
||||
Traefik tem integrações com Docker, Kubernetes e outros, portanto, é muito fácil configurar e configurar o HTTPS para seus contêineres com ele.
|
||||
|
||||
Alternativamente, o HTTPS poderia ser tratado por um provedor de nuvem como um de seus serviços (enquanto ainda executasse o aplicativo em um contêiner).
|
||||
|
||||
## Executando na inicialização e reinicializações
|
||||
|
||||
Normalmente, outra ferramenta é responsável por **iniciar e executar** seu contêiner.
|
||||
|
||||
Ela poderia ser o **Docker** diretamente, **Docker Compose**, **Kubernetes**, um **serviço de nuvem**, etc.
|
||||
|
||||
Na maioria (ou em todos) os casos, há uma opção simples para habilitar a execução do contêiner na inicialização e habilitar reinicializações em falhas. Por exemplo, no Docker, é a opção de linha de comando `--restart`.
|
||||
|
||||
Sem usar contêineres, fazer aplicativos executarem na inicialização e com reinicializações pode ser trabalhoso e difícil. Mas quando **trabalhando com contêineres** em muitos casos essa funcionalidade é incluída por padrão. ✨
|
||||
|
||||
## Replicação - Número de Processos
|
||||
|
||||
Se você tiver um <abbr title="Um grupo de máquinas que são configuradas para estarem conectadas e trabalharem juntas de alguma forma">cluster</abbr> de máquinas com **Kubernetes**, Docker Swarm Mode, Nomad ou outro sistema complexo semelhante para gerenciar contêineres distribuídos em várias máquinas, então provavelmente desejará **lidar com a replicação** no **nível do cluster** em vez de usar um **gerenciador de processos** (como o Gunicorn com workers) em cada contêiner.
|
||||
|
||||
Um desses sistemas de gerenciamento de contêineres distribuídos como o Kubernetes normalmente tem alguma maneira integrada de lidar com a **replicação de contêineres** enquanto ainda oferece **balanceamento de carga** para as solicitações recebidas. Tudo no **nível do cluster**.
|
||||
|
||||
Nesses casos, você provavelmente desejará criar uma **imagem do contêiner do zero** como [explicado acima](#dockerfile), instalando suas dependências e executando **um único processo Uvicorn** em vez de executar algo como Gunicorn com trabalhadores Uvicorn.
|
||||
|
||||
### Balanceamento de Carga
|
||||
|
||||
Quando usando contêineres, normalmente você terá algum componente **escutando na porta principal**. Poderia ser outro contêiner que também é um **Proxy de Terminação TLS** para lidar com **HTTPS** ou alguma ferramenta semelhante.
|
||||
|
||||
Como esse componente assumiria a **carga** de solicitações e distribuiria isso entre os trabalhadores de uma maneira (esperançosamente) **balanceada**, ele também é comumente chamado de **Balanceador de Carga**.
|
||||
|
||||
!!! tip
|
||||
O mesmo componente **Proxy de Terminação TLS** usado para HTTPS provavelmente também seria um **Balanceador de Carga**.
|
||||
|
||||
E quando trabalhar com contêineres, o mesmo sistema que você usa para iniciar e gerenciá-los já terá ferramentas internas para transmitir a **comunicação de rede** (por exemplo, solicitações HTTP) do **balanceador de carga** (que também pode ser um **Proxy de Terminação TLS**) para o(s) contêiner(es) com seu aplicativo.
|
||||
|
||||
### Um Balanceador de Carga - Múltiplos Contêineres de Workers
|
||||
|
||||
Quando trabalhando com **Kubernetes** ou sistemas similares de gerenciamento de contêiner distribuído, usando seus mecanismos de rede internos permitiria que o único **balanceador de carga** que estivesse escutando na **porta principal** transmitisse comunicação (solicitações) para possivelmente **múltiplos contêineres** executando seu aplicativo.
|
||||
|
||||
Cada um desses contêineres executando seu aplicativo normalmente teria **apenas um processo** (ex.: um processo Uvicorn executando seu aplicativo FastAPI). Todos seriam **contêineres idênticos**, executando a mesma coisa, mas cada um com seu próprio processo, memória, etc. Dessa forma, você aproveitaria a **paralelização** em **núcleos diferentes** da CPU, ou até mesmo em **máquinas diferentes**.
|
||||
|
||||
E o sistema de contêiner com o **balanceador de carga** iria **distribuir as solicitações** para cada um dos contêineres com seu aplicativo **em turnos**. Portanto, cada solicitação poderia ser tratada por um dos múltiplos **contêineres replicados** executando seu aplicativo.
|
||||
|
||||
E normalmente esse **balanceador de carga** seria capaz de lidar com solicitações que vão para *outros* aplicativos em seu cluster (por exemplo, para um domínio diferente, ou sob um prefixo de URL diferente), e transmitiria essa comunicação para os contêineres certos para *esse outro* aplicativo em execução em seu cluster.
|
||||
|
||||
### Um Processo por Contêiner
|
||||
|
||||
Nesse tipo de cenário, provavelmente você desejará ter **um único processo (Uvicorn) por contêiner**, pois já estaria lidando com a replicação no nível do cluster.
|
||||
|
||||
Então, nesse caso, você **não** desejará ter um gerenciador de processos como o Gunicorn com trabalhadores Uvicorn, ou o Uvicorn usando seus próprios trabalhadores Uvicorn. Você desejará ter apenas um **único processo Uvicorn** por contêiner (mas provavelmente vários contêineres).
|
||||
|
||||
Tendo outro gerenciador de processos dentro do contêiner (como seria com o Gunicorn ou o Uvicorn gerenciando trabalhadores Uvicorn) só adicionaria **complexidade desnecessária** que você provavelmente já está cuidando com seu sistema de cluster.
|
||||
|
||||
### Contêineres com Múltiplos Processos e Casos Especiais
|
||||
|
||||
Claro, existem **casos especiais** em que você pode querer ter um **contêiner** com um **gerenciador de processos Gunicorn** iniciando vários **processos trabalhadores Uvicorn** dentro.
|
||||
|
||||
Nesses casos, você pode usar a **imagem oficial do Docker** que inclui o **Gunicorn** como um gerenciador de processos executando vários **processos trabalhadores Uvicorn**, e algumas configurações padrão para ajustar o número de trabalhadores com base nos atuais núcleos da CPU automaticamente. Eu vou te contar mais sobre isso abaixo em [Imagem Oficial do Docker com Gunicorn - Uvicorn](#imagem-oficial-do-docker-com-gunicorn-uvicorn).
|
||||
|
||||
Aqui estão alguns exemplos de quando isso pode fazer sentido:
|
||||
|
||||
#### Um Aplicativo Simples
|
||||
|
||||
Você pode querer um gerenciador de processos no contêiner se seu aplicativo for **simples o suficiente** para que você não precise (pelo menos não agora) ajustar muito o número de processos, e você pode simplesmente usar um padrão automatizado (com a imagem oficial do Docker), e você está executando em um **único servidor**, não em um cluster.
|
||||
|
||||
#### Docker Compose
|
||||
|
||||
Você pode estar implantando em um **único servidor** (não em um cluster) com o **Docker Compose**, então você não teria uma maneira fácil de gerenciar a replicação de contêineres (com o Docker Compose) enquanto preserva a rede compartilhada e o **balanceamento de carga**.
|
||||
|
||||
Então você pode querer ter **um único contêiner** com um **gerenciador de processos** iniciando **vários processos trabalhadores** dentro.
|
||||
|
||||
#### Prometheus and Outros Motivos
|
||||
|
||||
Você também pode ter **outros motivos** que tornariam mais fácil ter um **único contêiner** com **múltiplos processos** em vez de ter **múltiplos contêineres** com **um único processo** em cada um deles.
|
||||
|
||||
Por exemplo (dependendo de sua configuração), você poderia ter alguma ferramenta como um exportador do Prometheus no mesmo contêiner que deve ter acesso a **cada uma das solicitações** que chegam.
|
||||
|
||||
Nesse caso, se você tivesse **múltiplos contêineres**, por padrão, quando o Prometheus fosse **ler as métricas**, ele receberia as métricas de **um único contêiner cada vez** (para o contêiner que tratou essa solicitação específica), em vez de receber as **métricas acumuladas** de todos os contêineres replicados.
|
||||
|
||||
Então, nesse caso, poderia ser mais simples ter **um único contêiner** com **múltiplos processos**, e uma ferramenta local (por exemplo, um exportador do Prometheus) no mesmo contêiner coletando métricas do Prometheus para todos os processos internos e expor essas métricas no único contêiner.
|
||||
|
||||
---
|
||||
|
||||
O ponto principal é que **nenhum** desses são **regras escritas em pedra** que você deve seguir cegamente. Você pode usar essas idéias para **avaliar seu próprio caso de uso** e decidir qual é a melhor abordagem para seu sistema, verificando como gerenciar os conceitos de:
|
||||
|
||||
* Segurança - HTTPS
|
||||
* Executando na inicialização
|
||||
* Reinicializações
|
||||
* Replicação (o número de processos em execução)
|
||||
* Memória
|
||||
* Passos anteriores antes de inicializar
|
||||
|
||||
## Memória
|
||||
|
||||
Se você executar **um único processo por contêiner**, terá uma quantidade mais ou menos bem definida, estável e limitada de memória consumida por cada um desses contêineres (mais de um se eles forem replicados).
|
||||
|
||||
E então você pode definir esses mesmos limites e requisitos de memória em suas configurações para seu sistema de gerenciamento de contêineres (por exemplo, no **Kubernetes**). Dessa forma, ele poderá **replicar os contêineres** nas **máquinas disponíveis** levando em consideração a quantidade de memória necessária por eles e a quantidade disponível nas máquinas no cluster.
|
||||
|
||||
Se sua aplicação for **simples**, isso provavelmente **não será um problema**, e você pode não precisar especificar limites de memória rígidos. Mas se você estiver **usando muita memória** (por exemplo, com **modelos de aprendizado de máquina**), deve verificar quanta memória está consumindo e ajustar o **número de contêineres** que executa em **cada máquina** (e talvez adicionar mais máquinas ao seu cluster).
|
||||
|
||||
Se você executar **múltiplos processos por contêiner** (por exemplo, com a imagem oficial do Docker), deve garantir que o número de processos iniciados não **consuma mais memória** do que o disponível.
|
||||
|
||||
## Passos anteriores antes de inicializar e contêineres
|
||||
|
||||
Se você estiver usando contêineres (por exemplo, Docker, Kubernetes), existem duas abordagens principais que você pode usar.
|
||||
|
||||
### Contêineres Múltiplos
|
||||
|
||||
Se você tiver **múltiplos contêineres**, provavelmente cada um executando um **único processo** (por exemplo, em um cluster do **Kubernetes**), então provavelmente você gostaria de ter um **contêiner separado** fazendo o trabalho dos **passos anteriores** em um único contêiner, executando um único processo, **antes** de executar os contêineres trabalhadores replicados.
|
||||
|
||||
!!! info
|
||||
Se você estiver usando o Kubernetes, provavelmente será um <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init Container</a>.
|
||||
|
||||
Se no seu caso de uso não houver problema em executar esses passos anteriores **em paralelo várias vezes** (por exemplo, se você não estiver executando migrações de banco de dados, mas apenas verificando se o banco de dados está pronto), então você também pode colocá-los em cada contêiner logo antes de iniciar o processo principal.
|
||||
|
||||
### Contêiner Único
|
||||
|
||||
Se você tiver uma configuração simples, com um **único contêiner** que então inicia vários **processos trabalhadores** (ou também apenas um processo), então poderia executar esses passos anteriores no mesmo contêiner, logo antes de iniciar o processo com o aplicativo. A imagem oficial do Docker suporta isso internamente.
|
||||
|
||||
## Imagem Oficial do Docker com Gunicorn - Uvicorn
|
||||
|
||||
Há uma imagem oficial do Docker que inclui o Gunicorn executando com trabalhadores Uvicorn, conforme detalhado em um capítulo anterior: [Server Workers - Gunicorn com Uvicorn](./server-workers.md){.internal-link target=_blank}.
|
||||
|
||||
Essa imagem seria útil principalmente nas situações descritas acima em: [Contêineres com Múltiplos Processos e Casos Especiais](#contêineres-com-múltiplos-processos-e-casos-Especiais).
|
||||
|
||||
* <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
|
||||
|
||||
!!! warning
|
||||
Existe uma grande chance de que você **não** precise dessa imagem base ou de qualquer outra semelhante, e seria melhor construir a imagem do zero, como [descrito acima em: Construa uma Imagem Docker para o FastAPI](#construa-uma-imagem-docker-para-o-fastapi).
|
||||
|
||||
Essa imagem tem um mecanismo de **auto-ajuste** incluído para definir o **número de processos trabalhadores** com base nos núcleos de CPU disponíveis.
|
||||
|
||||
Isso tem **padrões sensíveis**, mas você ainda pode alterar e atualizar todas as configurações com **variáveis de ambiente** ou arquivos de configuração.
|
||||
|
||||
Há também suporte para executar <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker#pre_start_path" class="external-link" target="_blank">**passos anteriores antes de iniciar**</a> com um script.
|
||||
|
||||
!!! tip
|
||||
Para ver todas as configurações e opções, vá para a página da imagem Docker: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
|
||||
|
||||
### Número de Processos na Imagem Oficial do Docker
|
||||
|
||||
O **número de processos** nesta imagem é **calculado automaticamente** a partir dos **núcleos de CPU** disponíveis.
|
||||
|
||||
Isso significa que ele tentará **aproveitar** o máximo de **desempenho** da CPU possível.
|
||||
|
||||
Você também pode ajustá-lo com as configurações usando **variáveis de ambiente**, etc.
|
||||
|
||||
Mas isso também significa que, como o número de processos depende da CPU do contêiner em execução, a **quantidade de memória consumida** também dependerá disso.
|
||||
|
||||
Então, se seu aplicativo consumir muito memória (por exemplo, com modelos de aprendizado de máquina), e seu servidor tiver muitos núcleos de CPU **mas pouca memória**, então seu contêiner pode acabar tentando usar mais memória do que está disponível e degradar o desempenho muito (ou até mesmo travar). 🚨
|
||||
|
||||
### Criando um `Dockerfile`
|
||||
|
||||
Aqui está como você criaria um `Dockerfile` baseado nessa imagem:
|
||||
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
|
||||
|
||||
COPY ./requirements.txt /app/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
|
||||
|
||||
COPY ./app /app
|
||||
```
|
||||
|
||||
### Aplicações Maiores
|
||||
|
||||
Se você seguiu a seção sobre a criação de [Aplicações Maiores com Múltiplos Arquivos](../tutorial/bigger-applications.md){.internal-link target=_blank}, seu `Dockerfile` pode parecer com isso:
|
||||
|
||||
```Dockerfile
|
||||
|
||||
```Dockerfile hl_lines="7"
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
|
||||
|
||||
COPY ./requirements.txt /app/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
|
||||
|
||||
COPY ./app /app/app
|
||||
```
|
||||
|
||||
### Quando Usar
|
||||
|
||||
Você provavelmente **não** deve usar essa imagem base oficial (ou qualquer outra semelhante) se estiver usando **Kubernetes** (ou outros) e já estiver definindo **replicação** no nível do cluster, com vários **contêineres**. Nesses casos, é melhor **construir uma imagem do zero** conforme descrito acima: [Construindo uma Imagem Docker para FastAPI](#construindo-uma-imagem-docker-para-fastapi).
|
||||
|
||||
Essa imagem seria útil principalmente nos casos especiais descritos acima em [Contêineres com Múltiplos Processos e Casos Especiais](#contêineres-com-múltiplos-processos-e-casos-Especiais). Por exemplo, se sua aplicação for **simples o suficiente** para que a configuração padrão de número de processos com base na CPU funcione bem, você não quer se preocupar com a configuração manual da replicação no nível do cluster e não está executando mais de um contêiner com seu aplicativo. Ou se você estiver implantando com **Docker Compose**, executando em um único servidor, etc.
|
||||
|
||||
## Deploy da Imagem do Contêiner
|
||||
|
||||
Depois de ter uma imagem de contêiner (Docker), existem várias maneiras de implantá-la.
|
||||
|
||||
Por exemplo:
|
||||
|
||||
* Com **Docker Compose** em um único servidor
|
||||
* Com um cluster **Kubernetes**
|
||||
* Com um cluster Docker Swarm Mode
|
||||
* Com outra ferramenta como o Nomad
|
||||
* Com um serviço de nuvem que pega sua imagem de contêiner e a implanta
|
||||
|
||||
## Imagem Docker com Poetry
|
||||
|
||||
Se você usa <a href="https://python-poetry.org/" class="external-link" target="_blank">Poetry</a> para gerenciar as dependências do seu projeto, pode usar a construção multi-estágio do Docker:
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
# (1)
|
||||
FROM python:3.9 as requirements-stage
|
||||
|
||||
# (2)
|
||||
WORKDIR /tmp
|
||||
|
||||
# (3)
|
||||
RUN pip install poetry
|
||||
|
||||
# (4)
|
||||
COPY ./pyproject.toml ./poetry.lock* /tmp/
|
||||
|
||||
# (5)
|
||||
RUN poetry export -f requirements.txt --output requirements.txt --without-hashes
|
||||
|
||||
# (6)
|
||||
FROM python:3.9
|
||||
|
||||
# (7)
|
||||
WORKDIR /code
|
||||
|
||||
# (8)
|
||||
COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt
|
||||
|
||||
# (9)
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
# (10)
|
||||
COPY ./app /code/app
|
||||
|
||||
# (11)
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
1. Esse é o primeiro estágio, ele é chamado `requirements-stage`.
|
||||
|
||||
2. Defina `/tmp` como o diretório de trabalho atual.
|
||||
|
||||
Aqui é onde geraremos o arquivo `requirements.txt`
|
||||
|
||||
3. Instale o Poetry nesse estágio do Docker.
|
||||
|
||||
4. Copie os arquivos `pyproject.toml` e `poetry.lock` para o diretório `/tmp`.
|
||||
|
||||
Porque está usando `./poetry.lock*` (terminando com um `*`), não irá falhar se esse arquivo ainda não estiver disponível.
|
||||
|
||||
5. Gere o arquivo `requirements.txt`.
|
||||
|
||||
6. Este é o estágio final, tudo aqui será preservado na imagem final do contêiner.
|
||||
|
||||
7. Defina o diretório de trabalho atual como `/code`.
|
||||
|
||||
8. Copie o arquivo `requirements.txt` para o diretório `/code`.
|
||||
|
||||
Essse arquivo só existe no estágio anterior do Docker, é por isso que usamos `--from-requirements-stage` para copiá-lo.
|
||||
|
||||
9. Instale as dependências de pacote do arquivo `requirements.txt` gerado.
|
||||
|
||||
10. Copie o diretório `app` para o diretório `/code`.
|
||||
|
||||
11. Execute o comando `uvicorn`, informando-o para usar o objeto `app` importado de `app.main`.
|
||||
|
||||
!!! tip
|
||||
Clique nos números das bolhas para ver o que cada linha faz.
|
||||
|
||||
Um **estágio do Docker** é uma parte de um `Dockerfile` que funciona como uma **imagem temporária do contêiner** que só é usada para gerar alguns arquivos para serem usados posteriormente.
|
||||
|
||||
O primeiro estágio será usado apenas para **instalar Poetry** e para **gerar o `requirements.txt`** com as dependências do seu projeto a partir do arquivo `pyproject.toml` do Poetry.
|
||||
|
||||
Esse arquivo `requirements.txt` será usado com `pip` mais tarde no **próximo estágio**.
|
||||
|
||||
Na imagem final do contêiner, **somente o estágio final** é preservado. Os estágios anteriores serão descartados.
|
||||
|
||||
Quando usar Poetry, faz sentido usar **construções multi-estágio do Docker** porque você realmente não precisa ter o Poetry e suas dependências instaladas na imagem final do contêiner, você **apenas precisa** ter o arquivo `requirements.txt` gerado para instalar as dependências do seu projeto.
|
||||
|
||||
Então, no próximo (e último) estágio, você construiria a imagem mais ou menos da mesma maneira descrita anteriormente.
|
||||
|
||||
### Por trás de um proxy de terminação TLS - Poetry
|
||||
|
||||
Novamente, se você estiver executando seu contêiner atrás de um proxy de terminação TLS (balanceador de carga) como Nginx ou Traefik, adicione a opção `--proxy-headers` ao comando:
|
||||
|
||||
```Dockerfile
|
||||
CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
## Recapitulando
|
||||
|
||||
Usando sistemas de contêiner (por exemplo, com **Docker** e **Kubernetes**), torna-se bastante simples lidar com todos os **conceitos de implantação**:
|
||||
|
||||
* HTTPS
|
||||
* Executando na inicialização
|
||||
* Reinícios
|
||||
* Replicação (o número de processos rodando)
|
||||
* Memória
|
||||
* Passos anteriores antes de inicializar
|
||||
|
||||
Na maioria dos casos, você provavelmente não desejará usar nenhuma imagem base e, em vez disso, **construir uma imagem de contêiner do zero** baseada na imagem oficial do Docker Python.
|
||||
|
||||
Tendo cuidado com a **ordem** das instruções no `Dockerfile` e o **cache do Docker**, você pode **minimizar os tempos de construção**, para maximizar sua produtividade (e evitar a tédio). 😎
|
||||
|
||||
Em alguns casos especiais, você pode querer usar a imagem oficial do Docker para o FastAPI. 🤓
|
||||
|
|
@ -87,6 +87,7 @@ nav:
|
|||
- deployment/versions.md
|
||||
- deployment/https.md
|
||||
- deployment/deta.md
|
||||
- deployment/docker.md
|
||||
- alternatives.md
|
||||
- history-design-future.md
|
||||
- external-links.md
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
||||
|
||||
__version__ = "0.87.0"
|
||||
__version__ = "0.88.0"
|
||||
|
||||
from starlette import status as status
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ classifiers = [
|
|||
"Topic :: Internet :: WWW/HTTP",
|
||||
]
|
||||
dependencies = [
|
||||
"starlette==0.21.0",
|
||||
"starlette==0.22.0",
|
||||
"pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0",
|
||||
]
|
||||
dynamic = ["version"]
|
||||
|
|
@ -83,7 +83,7 @@ doc = [
|
|||
"mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0",
|
||||
# TODO: upgrade and enable typer-cli once it supports Click 8.x.x
|
||||
# "typer-cli >=0.0.12,<0.0.13",
|
||||
"typer[all] >=0.6.1,<0.7.0",
|
||||
"typer[all] >=0.6.1,<0.8.0",
|
||||
"pyyaml >=5.3.1,<7.0.0",
|
||||
]
|
||||
dev = [
|
||||
|
|
|
|||
|
|
@ -284,7 +284,9 @@ def build_all():
|
|||
continue
|
||||
langs.append(lang.name)
|
||||
cpu_count = os.cpu_count() or 1
|
||||
with Pool(cpu_count * 2) as p:
|
||||
process_pool_size = cpu_count * 4
|
||||
typer.echo(f"Using process pool size: {process_pool_size}")
|
||||
with Pool(process_pool_size) as p:
|
||||
p.map(build_lang, langs)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
set -x
|
||||
set -e
|
||||
|
||||
cd ./site
|
||||
|
||||
if [ -f docs.zip ]; then
|
||||
rm -rf docs.zip
|
||||
fi
|
||||
zip -r docs.zip ./site
|
||||
zip -r docs.zip ./
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from fastapi import FastAPI, Path
|
||||
from fastapi import FastAPI, Path, Query
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
app = FastAPI()
|
||||
|
|
@ -19,6 +19,11 @@ def path_convertor(param: str = Path()):
|
|||
return {"path": param}
|
||||
|
||||
|
||||
@app.get("/query/")
|
||||
def query_convertor(param: str = Query()):
|
||||
return {"query": param}
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
|
|
@ -45,6 +50,13 @@ def test_route_converters_path():
|
|||
assert response.json() == {"path": "some/example"}
|
||||
|
||||
|
||||
def test_route_converters_query():
|
||||
# Test query conversion
|
||||
response = client.get("/query", params={"param": "Qué tal!"})
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {"query": "Qué tal!"}
|
||||
|
||||
|
||||
def test_url_path_for_path_convertor():
|
||||
assert (
|
||||
app.url_path_for("path_convertor", param="some/example") == "/path/some/example"
|
||||
|
|
|
|||
Loading…
Reference in New Issue