Compare commits
823 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
717a1ec409 | ||
|
|
eba2c66532 | ||
|
|
3788ca4640 | ||
|
|
97fa743ecb | ||
|
|
e726b7b771 | ||
|
|
6a22b75afd | ||
|
|
4093d9b22a | ||
|
|
18daf8f301 | ||
|
|
962578bec2 | ||
|
|
85cff59109 | ||
|
|
b869c7c872 | ||
|
|
016c3f0d5b | ||
|
|
4eb9c60652 | ||
|
|
8879757a88 | ||
|
|
fadfcfda4a | ||
|
|
b8c4149e89 | ||
|
|
836bb97a2d | ||
|
|
7db359182d | ||
|
|
4eada92883 | ||
|
|
6a74f3a0c1 | ||
|
|
daa0765653 | ||
|
|
27e26b5939 | ||
|
|
6f45f43709 | ||
|
|
6c80e9a8e0 | ||
|
|
3b2e891917 | ||
|
|
9121fccf55 | ||
|
|
fa2c750443 | ||
|
|
29e7b31ee6 | ||
|
|
bb6c6ed5d1 | ||
|
|
1a5273773e | ||
|
|
3f40c37905 | ||
|
|
996dfd05bd | ||
|
|
0a1dd7894c | ||
|
|
dbfd3f7e18 | ||
|
|
a0209a0d2c | ||
|
|
099aab79e6 | ||
|
|
7dc5b94d45 | ||
|
|
684c0077cc | ||
|
|
75d8a6b5c2 | ||
|
|
96fdfc53cc | ||
|
|
49517d3310 | ||
|
|
9355cc4eaa | ||
|
|
1ce59152e7 | ||
|
|
1241f7f0b7 | ||
|
|
fd74c0f6a4 | ||
|
|
e4eac12c34 | ||
|
|
b235653a6c | ||
|
|
4cb4bdb984 | ||
|
|
ba596152d9 | ||
|
|
a1227624c8 | ||
|
|
9ce1ae771c | ||
|
|
b9fed9b485 | ||
|
|
0d97e1f97d | ||
|
|
1ce7258a01 | ||
|
|
bcd06fdfdf | ||
|
|
fc35b7d18d | ||
|
|
8c12ab0d5b | ||
|
|
38194a29bc | ||
|
|
6b65de6033 | ||
|
|
f80230d654 | ||
|
|
f6cc418d79 | ||
|
|
3ce9407093 | ||
|
|
ef1716c39e | ||
|
|
9ab7da6562 | ||
|
|
fcfff5e8e5 | ||
|
|
67ef62a4dd | ||
|
|
7741635b3b | ||
|
|
3d81bc638b | ||
|
|
c1801738b0 | ||
|
|
ba84f167f5 | ||
|
|
0a38c51b9e | ||
|
|
db5b2bdf56 | ||
|
|
5ac84120b3 | ||
|
|
2d296c5d07 | ||
|
|
71c96d9eb9 | ||
|
|
5342a0a00f | ||
|
|
163b086f21 | ||
|
|
0876d3df1d | ||
|
|
50baf5e804 | ||
|
|
3d6da2c32d | ||
|
|
e721d04350 | ||
|
|
8cc6f9baac | ||
|
|
dfd453e001 | ||
|
|
7e9d5aacf8 | ||
|
|
d27a218bc3 | ||
|
|
0c4ded88fe | ||
|
|
0e0931d308 | ||
|
|
dcfa9eb8fe | ||
|
|
6ebf60b175 | ||
|
|
a4d0724a97 | ||
|
|
c235e9b78c | ||
|
|
5fa3e239db | ||
|
|
3d1b107d70 | ||
|
|
18e0828daf | ||
|
|
f16c7729bd | ||
|
|
9f3c8cd139 | ||
|
|
a7a35aee61 | ||
|
|
dc5a966548 | ||
|
|
ea8d7f689e | ||
|
|
0ed6c92341 | ||
|
|
79f52c76cf | ||
|
|
b725e9eb45 | ||
|
|
787e54b096 | ||
|
|
15fd60b29a | ||
|
|
edf6b2d61f | ||
|
|
7eb17fc874 | ||
|
|
7e4bfaf0e9 | ||
|
|
e1d4fc5325 | ||
|
|
faec748ef6 | ||
|
|
afec8c4580 | ||
|
|
8a1f0aa3b6 | ||
|
|
f784644510 | ||
|
|
710a2f745c | ||
|
|
bd230fe473 | ||
|
|
9c5b000956 | ||
|
|
a9f2a25feb | ||
|
|
c00c2d1ecf | ||
|
|
dd7bbae837 | ||
|
|
0a84d48a82 | ||
|
|
e5d0b97dee | ||
|
|
811c3f873f | ||
|
|
662fc81544 | ||
|
|
5e2f2d541d | ||
|
|
8116d8158b | ||
|
|
e6836781d5 | ||
|
|
098088c763 | ||
|
|
4bf9a52043 | ||
|
|
eb6f964ede | ||
|
|
4473a9bcbf | ||
|
|
fdc7c96ece | ||
|
|
a694be81ae | ||
|
|
0abb743e9c | ||
|
|
acda3f06b0 | ||
|
|
3127bc4e05 | ||
|
|
18b24df9c8 | ||
|
|
b27758fe13 | ||
|
|
a0b2006230 | ||
|
|
bd143ffa5a | ||
|
|
77c1988a8b | ||
|
|
26a36f79fa | ||
|
|
97d8d4016b | ||
|
|
246e80512d | ||
|
|
fc6827d68a | ||
|
|
4d91f978d2 | ||
|
|
aabe2c7d66 | ||
|
|
377234ad8e | ||
|
|
38b785813f | ||
|
|
fa7e3c996e | ||
|
|
90120dd6e8 | ||
|
|
36772548b7 | ||
|
|
40bb0c5f36 | ||
|
|
60918d25a1 | ||
|
|
3afce2c4b8 | ||
|
|
9f6f25d54c | ||
|
|
d5b09cd958 | ||
|
|
aece74982d | ||
|
|
2b1e5b9f82 | ||
|
|
43df5d05ed | ||
|
|
eaa49ebd20 | ||
|
|
a6293397bc | ||
|
|
b890bd1dc5 | ||
|
|
3819a11b5f | ||
|
|
4aed0411e9 | ||
|
|
04ac466748 | ||
|
|
d75126a4ce | ||
|
|
c654e8384b | ||
|
|
7c9d0168ff | ||
|
|
e956ba4d4a | ||
|
|
85b32f51ff | ||
|
|
08fabb7b2e | ||
|
|
273b2cd646 | ||
|
|
de1a5125f8 | ||
|
|
da86791224 | ||
|
|
c646eaa6bb | ||
|
|
bf44b428dd | ||
|
|
c2907b189c | ||
|
|
75317d230b | ||
|
|
e662654c49 | ||
|
|
2a67321130 | ||
|
|
8d9d2c0d3f | ||
|
|
dc6a78c357 | ||
|
|
73d1def114 | ||
|
|
3dc74ba29f | ||
|
|
d9d6031db5 | ||
|
|
6135417789 | ||
|
|
6d138f218b | ||
|
|
e10a4375f9 | ||
|
|
3e32eb55f0 | ||
|
|
b3f139c0d9 | ||
|
|
3b4c692534 | ||
|
|
05c859f324 | ||
|
|
48a33b0453 | ||
|
|
70746a7bf0 | ||
|
|
69e3c6e3d3 | ||
|
|
388e5c0c25 | ||
|
|
61db5ebcc2 | ||
|
|
23845979ea | ||
|
|
83f7a36d05 | ||
|
|
462014e296 | ||
|
|
5da5ae5554 | ||
|
|
f3a985cb81 | ||
|
|
22528373bb | ||
|
|
ce0ec06e8a | ||
|
|
10397ddc30 | ||
|
|
6f72a27632 | ||
|
|
2783667f80 | ||
|
|
d8c1d040d4 | ||
|
|
7f037f1bdc | ||
|
|
f31104585f | ||
|
|
5934a75ddd | ||
|
|
650abf091b | ||
|
|
66f18e9282 | ||
|
|
f044f13121 | ||
|
|
0250cfa398 | ||
|
|
f4ce2510f3 | ||
|
|
8f0a604a37 | ||
|
|
0f4c2b6ee0 | ||
|
|
368d314e11 | ||
|
|
4e79cb0be4 | ||
|
|
973595b3cb | ||
|
|
fa779017d2 | ||
|
|
b2e27de2fc | ||
|
|
31a7bfd227 | ||
|
|
47dde41c6c | ||
|
|
413a86998e | ||
|
|
36721d4362 | ||
|
|
c09e950bd2 | ||
|
|
4d208b2b90 | ||
|
|
071c6a17dd | ||
|
|
4ab79c679b | ||
|
|
33be5fc8ba | ||
|
|
a7a353e1f5 | ||
|
|
c153d9b83e | ||
|
|
2875d88ccf | ||
|
|
9e0cca828d | ||
|
|
5dc3ec4a65 | ||
|
|
bda392cba6 | ||
|
|
f22137346a | ||
|
|
f108741a82 | ||
|
|
8433e8efe2 | ||
|
|
e6a1a9e193 | ||
|
|
bbb22813e6 | ||
|
|
f0f8e287ec | ||
|
|
0af6cbe990 | ||
|
|
9e9e068762 | ||
|
|
9fda0149da | ||
|
|
95a713b3e2 | ||
|
|
2da3d62d37 | ||
|
|
7dd2e92d7e | ||
|
|
6d06e13284 | ||
|
|
a2199c545b | ||
|
|
08cbc6c8ff | ||
|
|
f730160037 | ||
|
|
20360c207e | ||
|
|
568a54dff2 | ||
|
|
91cacc9c92 | ||
|
|
b3899333f4 | ||
|
|
6b6a310e54 | ||
|
|
cb2dce03c0 | ||
|
|
7122687f25 | ||
|
|
af6fcf1413 | ||
|
|
cd8b90a5a4 | ||
|
|
c88fb2eef0 | ||
|
|
17781e3596 | ||
|
|
a381642558 | ||
|
|
5828043b69 | ||
|
|
909a81f88a | ||
|
|
faec713e0d | ||
|
|
60addbcdd5 | ||
|
|
a27a1bc53c | ||
|
|
41f291524d | ||
|
|
6b3bc7384e | ||
|
|
561bbfb5d2 | ||
|
|
8ce1c81398 | ||
|
|
cb40e27db2 | ||
|
|
f031973848 | ||
|
|
307d37d85c | ||
|
|
bf290fa5f0 | ||
|
|
26f313d524 | ||
|
|
73021d7261 | ||
|
|
f54fb88ad5 | ||
|
|
b3d2f47bc8 | ||
|
|
52f170b3fe | ||
|
|
9442845ca5 | ||
|
|
fe31b0caae | ||
|
|
d2ca3df033 | ||
|
|
838ea752b2 | ||
|
|
2b49b8c70a | ||
|
|
05b024d61b | ||
|
|
c7742e3c56 | ||
|
|
4f9104ce97 | ||
|
|
07a8f7b5b5 | ||
|
|
f2a28f4b5b | ||
|
|
5a4a61ca67 | ||
|
|
71ac76c3cd | ||
|
|
68dca8f42d | ||
|
|
a38e6f4e2c | ||
|
|
ca26f2274c | ||
|
|
8108cd89bb | ||
|
|
8560151090 | ||
|
|
91805cdf03 | ||
|
|
48cba16578 | ||
|
|
7098e3b150 | ||
|
|
a7cc25eb11 | ||
|
|
d2eb4a71ee | ||
|
|
54eeb3161f | ||
|
|
4fabcfa3ab | ||
|
|
5c29daadcc | ||
|
|
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 | ||
|
|
51e920e2fc | ||
|
|
c27b9dcf9d | ||
|
|
c7e137c6e0 | ||
|
|
7e4d7fe895 | ||
|
|
2c57ea57bf | ||
|
|
be7d15ce3a | ||
|
|
afc2bb0801 | ||
|
|
313bbe802f | ||
|
|
d550738fa2 | ||
|
|
cc99e23e82 | ||
|
|
dbdcf86a11 | ||
|
|
2434980968 | ||
|
|
ee27f7790f | ||
|
|
d2cc2627ba | ||
|
|
f6a285c13c | ||
|
|
8af0b136b1 | ||
|
|
159a61d2b0 | ||
|
|
94fe5495fa | ||
|
|
8cc3ac1329 | ||
|
|
6b49f67d11 | ||
|
|
9972b76efa | ||
|
|
410da16a14 | ||
|
|
8997f96540 | ||
|
|
b8331b13d7 | ||
|
|
7a3c244c07 | ||
|
|
7a692d2c7b | ||
|
|
b53c443a06 | ||
|
|
7d7289aeb8 | ||
|
|
24b638faf6 | ||
|
|
2561a17225 | ||
|
|
d8cfa8ac87 | ||
|
|
76083559f0 | ||
|
|
df56655361 | ||
|
|
2e67f2fa6d | ||
|
|
ac073b2f5f | ||
|
|
4bcdbc5673 | ||
|
|
97adeca0a4 | ||
|
|
ac99792762 | ||
|
|
d01e0a10d8 | ||
|
|
de0f466ef8 | ||
|
|
77f7447ee8 | ||
|
|
48827eb7fc | ||
|
|
5786d2ef78 | ||
|
|
166088775a | ||
|
|
1052914c20 | ||
|
|
7bdc86b6b4 | ||
|
|
733218f199 | ||
|
|
3fb6d2982f | ||
|
|
b323726d86 | ||
|
|
2db2381b68 | ||
|
|
d31648c82e | ||
|
|
e6c2343691 | ||
|
|
ab0379ee52 | ||
|
|
790fa217f7 | ||
|
|
b892b5e028 | ||
|
|
39eedb31f7 | ||
|
|
8355832c7c | ||
|
|
5821ea8a69 | ||
|
|
3dbdc74366 | ||
|
|
939acef803 | ||
|
|
22a5960d36 | ||
|
|
8c5efe0b4b | ||
|
|
730ded2870 | ||
|
|
1a000d7e5f | ||
|
|
104ee630fc | ||
|
|
ea69c373ac | ||
|
|
9118749128 | ||
|
|
87ad6a46e8 | ||
|
|
75c64b6e4c | ||
|
|
ccd3b97f03 | ||
|
|
074d39fa17 | ||
|
|
f1419322b3 | ||
|
|
b8e6d18385 | ||
|
|
82a1300257 | ||
|
|
13d9de4a49 | ||
|
|
f931dd0717 | ||
|
|
24d2226326 | ||
|
|
0c895f1eaf | ||
|
|
c041c52d91 | ||
|
|
cc9e6b3484 | ||
|
|
dfcc6bc154 | ||
|
|
7e708f7411 | ||
|
|
e09646441d | ||
|
|
1631f981af | ||
|
|
4ce18167e7 | ||
|
|
a676899557 | ||
|
|
b299792ebf | ||
|
|
9fcec3abe9 | ||
|
|
5df00f3ec4 | ||
|
|
20ba6e8b97 | ||
|
|
a42c690496 | ||
|
|
bed0f065fa | ||
|
|
76632fcf24 | ||
|
|
32a010394f | ||
|
|
8d572faa24 | ||
|
|
f495d98fae | ||
|
|
3702cef08d | ||
|
|
9474706ec2 | ||
|
|
e1755f4fa6 | ||
|
|
c75c13c3b0 | ||
|
|
8673e1c127 | ||
|
|
360868fe25 | ||
|
|
b46b3f00bf | ||
|
|
c6e950dc9c | ||
|
|
4e74d40736 | ||
|
|
612d114f3a | ||
|
|
f88ffd1a0b | ||
|
|
cdf0f8a933 | ||
|
|
8650dee4bc | ||
|
|
dca9cc3ec5 | ||
|
|
d6f37b2138 | ||
|
|
5a13f78078 | ||
|
|
d625963cc5 | ||
|
|
142710a0f3 | ||
|
|
47fcacd4d6 | ||
|
|
00104c9259 | ||
|
|
8386e61f17 | ||
|
|
9b7125f66b | ||
|
|
68dc9bd5ac | ||
|
|
7a02d862aa | ||
|
|
479e87e467 | ||
|
|
1ea24e1813 | ||
|
|
492c0924c4 | ||
|
|
048355f01d | ||
|
|
fe889f38e8 | ||
|
|
1dd2bc7675 | ||
|
|
91ffa0ed27 | ||
|
|
6ab0f89858 | ||
|
|
bfc9733660 | ||
|
|
9c00618710 | ||
|
|
beedd199e8 | ||
|
|
ae580deaea | ||
|
|
e1231eeef1 | ||
|
|
8a1ebb38e2 | ||
|
|
e9413f2711 | ||
|
|
7434d2bec7 | ||
|
|
f2c565d8e4 | ||
|
|
cb55d7cdde | ||
|
|
d513680005 | ||
|
|
a5ee4d93d2 | ||
|
|
3a2d4434ce | ||
|
|
d1dfc812f1 | ||
|
|
0b76b675db | ||
|
|
5a776fbff5 | ||
|
|
7667605520 | ||
|
|
642762564d | ||
|
|
78ead585f8 | ||
|
|
48bf243050 | ||
|
|
0e920e6f02 | ||
|
|
afac22dfd2 | ||
|
|
2836e10e2d | ||
|
|
aa62d9212f | ||
|
|
620bffc2b4 | ||
|
|
b56cf6c08f | ||
|
|
cead6ba887 | ||
|
|
23772f3c49 | ||
|
|
45304562a6 | ||
|
|
3d767008df | ||
|
|
5c6811c4ef | ||
|
|
25e1a2602d | ||
|
|
b6272a36af | ||
|
|
db91255ede | ||
|
|
ab52e1c7e4 | ||
|
|
4924d08e7e | ||
|
|
a7c65271ac | ||
|
|
030f1f2ae2 | ||
|
|
74f13e522b | ||
|
|
a4f88f74f2 | ||
|
|
3826129b16 | ||
|
|
636f06cd6b | ||
|
|
c8365bd339 | ||
|
|
df38e53723 | ||
|
|
c606407929 | ||
|
|
f59f85d755 | ||
|
|
42bb15de22 | ||
|
|
e96b002599 | ||
|
|
75b83ce3aa | ||
|
|
ad5aa33864 | ||
|
|
952cd736ac | ||
|
|
026039cae2 | ||
|
|
e2609dff95 | ||
|
|
8486b41349 | ||
|
|
e77ea63577 | ||
|
|
097df92c1c | ||
|
|
be669059fb | ||
|
|
dfdd371c52 | ||
|
|
e1e8627168 | ||
|
|
0916c1c3ef | ||
|
|
11656f7bd5 | ||
|
|
483d092af8 | ||
|
|
60aa63b68a | ||
|
|
eb547bd4fd | ||
|
|
0dfde6e284 | ||
|
|
2d7038e03e | ||
|
|
4f0a3a9e4d | ||
|
|
1701930c86 | ||
|
|
a6897963d5 | ||
|
|
c14803e3fa | ||
|
|
cdba8481c2 | ||
|
|
64ca596a11 | ||
|
|
e1758d107e | ||
|
|
3390182fc9 | ||
|
|
912a43ee3d | ||
|
|
4020304945 | ||
|
|
0a2fc78fea | ||
|
|
b91acfb457 | ||
|
|
b9a0179a03 | ||
|
|
5ed48ccdc8 | ||
|
|
f32d67c8b9 | ||
|
|
0752c7242d | ||
|
|
be855c696b | ||
|
|
da9b5201c4 | ||
|
|
4daa6ef4e4 | ||
|
|
4ad7c55618 | ||
|
|
79e08a2541 | ||
|
|
1c9c80ba93 | ||
|
|
25cb05c876 | ||
|
|
694fbab074 | ||
|
|
2fd28434dd | ||
|
|
d15556b152 | ||
|
|
38d8bab770 | ||
|
|
52f0f8657e | ||
|
|
aedf5c895a | ||
|
|
117f9e4abe | ||
|
|
604fea9fc1 | ||
|
|
994bfd4591 | ||
|
|
02722923b1 | ||
|
|
d63a93429b | ||
|
|
b93e216dc7 | ||
|
|
95a29b6e67 | ||
|
|
272f01a153 | ||
|
|
1a345ae7fc | ||
|
|
c5c138b8eb | ||
|
|
da20e33414 | ||
|
|
7fbe3737bc | ||
|
|
f63cec9c95 | ||
|
|
3063ad83ec | ||
|
|
78680e5bee | ||
|
|
55b9faeb48 | ||
|
|
72645dfeab | ||
|
|
3223de5598 | ||
|
|
1afa4e8e75 | ||
|
|
6fd3736da2 | ||
|
|
7e043e5e6f | ||
|
|
d1585c42b9 | ||
|
|
fc494e3527 | ||
|
|
b344cc9415 | ||
|
|
38b71a9298 | ||
|
|
769ee73240 | ||
|
|
1df2f14c64 | ||
|
|
eab9a0e139 | ||
|
|
b86ac6739a | ||
|
|
9840d9e59d | ||
|
|
0ec52157df | ||
|
|
f1c5330b65 | ||
|
|
306ec8de04 | ||
|
|
6d7c9893d4 | ||
|
|
6264709054 | ||
|
|
76c2077f47 | ||
|
|
9cc4428de3 | ||
|
|
a63b1efc29 | ||
|
|
9863c3fca8 | ||
|
|
6fb97f44cf | ||
|
|
f64c448329 | ||
|
|
df6cbc5ec6 | ||
|
|
0f0af751e4 | ||
|
|
6c9dca55bc | ||
|
|
d71e807401 | ||
|
|
7df9ddfe4e | ||
|
|
4170659359 | ||
|
|
2940a7fdfa | ||
|
|
dadd6650ed | ||
|
|
c5a21354af | ||
|
|
8bafe2a482 | ||
|
|
42f1716b48 | ||
|
|
6ab2841dbb | ||
|
|
0f54657377 | ||
|
|
79e5b36551 | ||
|
|
074868d77e | ||
|
|
3dd16a9458 | ||
|
|
62c23ab5fa | ||
|
|
11c05beece | ||
|
|
7b3ef43127 | ||
|
|
e0080e5f75 | ||
|
|
e1ba54bd12 | ||
|
|
7032dfb4f1 | ||
|
|
14e7f7c1f4 | ||
|
|
9ed6f1e419 | ||
|
|
b268c39758 | ||
|
|
4dd386b807 | ||
|
|
b7251f1654 | ||
|
|
780d3e65ad | ||
|
|
cc8cac200f | ||
|
|
e7be5c8ac5 | ||
|
|
8f52864899 | ||
|
|
47a630721a | ||
|
|
10ae6de111 | ||
|
|
2b47f3e56b | ||
|
|
d60dd1b60e | ||
|
|
2822f7ca64 | ||
|
|
ff6afeaf78 | ||
|
|
74852d406c | ||
|
|
921642dc7b | ||
|
|
5c01d44ee9 | ||
|
|
135704dcc8 | ||
|
|
88793bb6c2 | ||
|
|
70a51b3aff | ||
|
|
340a582be7 | ||
|
|
5f66b5466f | ||
|
|
d2169ee567 | ||
|
|
a5c03ba1b7 | ||
|
|
e4ea6426dc | ||
|
|
8bf7cd1dc6 | ||
|
|
92feb3ade7 | ||
|
|
d0e739d8f2 | ||
|
|
4efa6bd75e | ||
|
|
600f15faa0 | ||
|
|
250fa519f9 | ||
|
|
3c6dafcc8e | ||
|
|
8447000eee | ||
|
|
fe453f80ed | ||
|
|
3ff504f03f | ||
|
|
eea9ab6106 | ||
|
|
e9e07c41bb | ||
|
|
17a5e18f46 | ||
|
|
9148bd8b6f | ||
|
|
39766d0f96 | ||
|
|
2d9bca56b2 | ||
|
|
f158d95ce9 | ||
|
|
7a4164ef60 | ||
|
|
f3730a79af | ||
|
|
42eff23a79 | ||
|
|
25bc33350d | ||
|
|
b84d082005 | ||
|
|
1f01ce9615 | ||
|
|
352c5f5ecc | ||
|
|
e5594e860f | ||
|
|
50926faead | ||
|
|
a303afc0e5 | ||
|
|
12607e85e3 | ||
|
|
38fd363e89 | ||
|
|
7f62cfd231 | ||
|
|
c5168bd036 | ||
|
|
be472c5215 | ||
|
|
adac38ecea | ||
|
|
c8b634226e | ||
|
|
ca4cf7cc70 | ||
|
|
b87072bc12 | ||
|
|
04e2bfafbc | ||
|
|
181a32236a | ||
|
|
1f54a8e0a1 | ||
|
|
d63475bb7d | ||
|
|
5a3c5f1523 | ||
|
|
12bc9285f7 | ||
|
|
31df2ea940 | ||
|
|
50b90dd6a4 | ||
|
|
7dd881334d | ||
|
|
530fc8ff3f | ||
|
|
ef460b4d23 | ||
|
|
b591de2ace | ||
|
|
34c857b7cb | ||
|
|
c78bc0c82d | ||
|
|
194446e51a | ||
|
|
777e2151e6 | ||
|
|
5ce5bdba0b | ||
|
|
e4300769ac | ||
|
|
c6dd627bdd | ||
|
|
6576f724bb | ||
|
|
91a6736d0e | ||
|
|
8fb755703d | ||
|
|
748bedd37c | ||
|
|
bf58788f29 | ||
|
|
5f78ba4a31 | ||
|
|
db9f827263 | ||
|
|
dd9e94cf21 | ||
|
|
e482d74241 | ||
|
|
bd2acbcabb | ||
|
|
f913d469a8 | ||
|
|
66cb266641 | ||
|
|
74954894c5 | ||
|
|
ceedfccde0 | ||
|
|
2ee0eedf23 | ||
|
|
c0f3019764 | ||
|
|
dd6d0cb23c | ||
|
|
fe15620df3 | ||
|
|
6af857f206 | ||
|
|
7ce756f9dd | ||
|
|
c0b1fddb31 | ||
|
|
9aea85a84e | ||
|
|
fddd1c12de | ||
|
|
b13a4baf32 | ||
|
|
5ffa18f10f | ||
|
|
828915baf5 | ||
|
|
a071ddf3cd | ||
|
|
3651b8a30f | ||
|
|
0d73b9ff1c | ||
|
|
43235cf236 | ||
|
|
269a155583 | ||
|
|
12433d51dd | ||
|
|
3699e17212 | ||
|
|
8231fbede4 | ||
|
|
50bc14b835 | ||
|
|
4310c89c83 | ||
|
|
d39dd06a22 | ||
|
|
a0ab47e89e | ||
|
|
5cbcb9a965 | ||
|
|
801ceaec80 | ||
|
|
c7334ae9f8 | ||
|
|
d737599a2c | ||
|
|
d2d72a8e4a | ||
|
|
7895c12fa1 | ||
|
|
5f6a14c413 | ||
|
|
2b4e88fa98 | ||
|
|
11723bca27 | ||
|
|
b49517a64f | ||
|
|
f910e0c96c | ||
|
|
c1ba2a3127 | ||
|
|
28396173c7 | ||
|
|
69974b792e | ||
|
|
352412a3cb | ||
|
|
745ab48d65 | ||
|
|
4a5cda0d77 | ||
|
|
b90bf2da9e | ||
|
|
a552cbdf59 | ||
|
|
2351fb5623 | ||
|
|
807522c616 | ||
|
|
81a529c251 | ||
|
|
7efc15aeef | ||
|
|
d66d8379c0 | ||
|
|
5a00467951 | ||
|
|
434d32b891 | ||
|
|
535247ffc4 | ||
|
|
7e2518350a | ||
|
|
1b2a7546af | ||
|
|
2d9bb64047 | ||
|
|
072c2bc7f9 | ||
|
|
da7826b0eb | ||
|
|
2f478eeca6 | ||
|
|
543ef7753a | ||
|
|
88a887329e | ||
|
|
8cfe254400 | ||
|
|
bfd46e562b | ||
|
|
a0e4d38bea | ||
|
|
b0414b9929 | ||
|
|
3b4413f9f5 | ||
|
|
374cdf29a9 | ||
|
|
8d844bc5cf | ||
|
|
1092261ae1 | ||
|
|
5984233223 | ||
|
|
98bb9f13da | ||
|
|
d375dc6ebe | ||
|
|
ee335bca82 | ||
|
|
601d8eb809 | ||
|
|
b99f350a18 | ||
|
|
c1b0e796c6 | ||
|
|
d9e65147c7 | ||
|
|
6001513c4f | ||
|
|
3fa033d8d5 | ||
|
|
59f7e66ac3 | ||
|
|
08e8dfccbe | ||
|
|
fc70a2f36f | ||
|
|
f5c5dbb739 | ||
|
|
ca939fabf7 | ||
|
|
cc3d795bea | ||
|
|
7fc1bac54b | ||
|
|
27367df90c | ||
|
|
f93861e321 | ||
|
|
30e56ec835 | ||
|
|
48ccef9ad2 | ||
|
|
b79e002635 | ||
|
|
1fa28b7cb6 | ||
|
|
22f7eae3f2 | ||
|
|
ae93773465 | ||
|
|
0f387553d1 | ||
|
|
d53a253c8d | ||
|
|
f8f0a6e462 |
5
.flake8
Normal file
@@ -0,0 +1,5 @@
|
||||
[flake8]
|
||||
max-line-length = 88
|
||||
select = C,E,F,W,B,B9
|
||||
ignore = E203, E501, W503
|
||||
exclude = __init__.py
|
||||
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
github: [tiangolo]
|
||||
62
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,62 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: "[BUG]"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Describe the bug
|
||||
|
||||
Write here a clear and concise description of what the bug is.
|
||||
|
||||
### To Reproduce
|
||||
|
||||
Steps to reproduce the behavior with a minimum self-contained file.
|
||||
|
||||
Replace each part with your own scenario:
|
||||
|
||||
1. Create a file with:
|
||||
|
||||
```Python
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
```
|
||||
|
||||
3. Open the browser and call the endpoint `/`.
|
||||
4. It returns a JSON with `{"Hello": "World"}`.
|
||||
5. But I expected it to return `{"Hello": "Sara"}`.
|
||||
|
||||
### Expected behavior
|
||||
|
||||
Add a clear and concise description of what you expected to happen.
|
||||
|
||||
### Screenshots
|
||||
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
### Environment
|
||||
|
||||
- OS: [e.g. Linux / Windows / macOS]
|
||||
- FastAPI Version [e.g. 0.3.0], get it with:
|
||||
|
||||
```bash
|
||||
python -c "import fastapi; print(fastapi.__version__)"
|
||||
```
|
||||
|
||||
- Python version, get it with:
|
||||
|
||||
```bash
|
||||
python --version
|
||||
```
|
||||
|
||||
### Additional context
|
||||
|
||||
Add any other context about the problem here.
|
||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Security Contact
|
||||
about: Please report security vulnerabilities to security@tiangolo.com
|
||||
181
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
name: Feature Request
|
||||
description: Suggest an idea or ask for a feature that you would like to have in FastAPI
|
||||
labels: [enhancement]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for your interest in FastAPI! 🚀
|
||||
|
||||
Please follow these instructions, fill every question, and do every step. 🙏
|
||||
|
||||
I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time.
|
||||
|
||||
I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues.
|
||||
|
||||
All that, on top of all the incredible help provided by a bunch of community members, the [FastAPI Experts](https://fastapi.tiangolo.com/fastapi-people/#experts), that give a lot of their time to come here and help others.
|
||||
|
||||
That's a lot of work they are doing, but if more FastAPI users came to help others like them just a little bit more, it would be much less effort for them (and you and me 😅).
|
||||
|
||||
By asking questions in a structured way (following this) it will be much easier to help you.
|
||||
|
||||
And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎
|
||||
|
||||
As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: First Check
|
||||
description: Please confirm and check all the following options.
|
||||
options:
|
||||
- label: I added a very descriptive title to this issue.
|
||||
required: true
|
||||
- label: I used the GitHub search to find a similar issue and didn't find it.
|
||||
required: true
|
||||
- label: I searched the FastAPI documentation, with the integrated search.
|
||||
required: true
|
||||
- label: I already searched in Google "How to X in FastAPI" and didn't find any information.
|
||||
required: true
|
||||
- label: I already read and followed all the tutorial in the docs and didn't find an answer.
|
||||
required: true
|
||||
- label: I already checked if it is not related to FastAPI but to [Pydantic](https://github.com/samuelcolvin/pydantic).
|
||||
required: true
|
||||
- label: I already checked if it is not related to FastAPI but to [Swagger UI](https://github.com/swagger-api/swagger-ui).
|
||||
required: true
|
||||
- label: I already checked if it is not related to FastAPI but to [ReDoc](https://github.com/Redocly/redoc).
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: help
|
||||
attributes:
|
||||
label: Commit to Help
|
||||
description: |
|
||||
After submitting this, I commit to one of:
|
||||
|
||||
* Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
|
||||
* I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.
|
||||
* Implement a Pull Request for a confirmed bug.
|
||||
|
||||
options:
|
||||
- label: I commit to help with one of those options 👆
|
||||
required: true
|
||||
- type: textarea
|
||||
id: example
|
||||
attributes:
|
||||
label: Example Code
|
||||
description: |
|
||||
Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case.
|
||||
|
||||
If I (or someone) can copy it, run it, and see it right away, there's a much higher chance I (or someone) will be able to help you.
|
||||
|
||||
placeholder: |
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
render: python
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: |
|
||||
What is your feature request?
|
||||
|
||||
Write a short description telling me what you are trying to solve and what you are currently doing.
|
||||
placeholder: |
|
||||
* Open the browser and call the endpoint `/`.
|
||||
* It returns a JSON with `{"Hello": "World"}`.
|
||||
* I would like it to have an extra parameter to teleport me to the moon and back.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: wanted-solution
|
||||
attributes:
|
||||
label: Wanted Solution
|
||||
description: |
|
||||
Tell me what's the solution you would like.
|
||||
placeholder: |
|
||||
I would like it to have a `teleport_to_moon` parameter that defaults to `False`, and can be set to `True` to teleport me.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: wanted-code
|
||||
attributes:
|
||||
label: Wanted Code
|
||||
description: Show me an example of how you would want the code to look like.
|
||||
placeholder: |
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/", teleport_to_moon=True)
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
render: python
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Alternatives
|
||||
description: |
|
||||
Tell me about alternatives you've considered.
|
||||
placeholder: |
|
||||
To wait for Space X moon travel plans to drop down long after they release them. But I would rather teleport.
|
||||
- type: dropdown
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating System
|
||||
description: What operating system are you on?
|
||||
multiple: true
|
||||
options:
|
||||
- Linux
|
||||
- Windows
|
||||
- macOS
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: os-details
|
||||
attributes:
|
||||
label: Operating System Details
|
||||
description: You can add more details about your operating system here, in particular if you chose "Other".
|
||||
- type: input
|
||||
id: fastapi-version
|
||||
attributes:
|
||||
label: FastAPI Version
|
||||
description: |
|
||||
What FastAPI version are you using?
|
||||
|
||||
You can find the FastAPI version with:
|
||||
|
||||
```bash
|
||||
python -c "import fastapi; print(fastapi.__version__)"
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: python-version
|
||||
attributes:
|
||||
label: Python Version
|
||||
description: |
|
||||
What Python version are you using?
|
||||
|
||||
You can find the Python version with:
|
||||
|
||||
```bash
|
||||
python --version
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Add any additional context information or screenshots you think are useful.
|
||||
26
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,26 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: "[FEATURE]"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Is your feature request related to a problem
|
||||
|
||||
Is your feature request related to a problem?
|
||||
|
||||
Add a clear and concise description of what the problem is. Ex. I want to be able to [...] but I can't because [...]
|
||||
|
||||
### The solution you would like
|
||||
|
||||
Add a clear and concise description of what you want to happen.
|
||||
|
||||
### Describe alternatives you've considered
|
||||
|
||||
Add a clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
### Additional context
|
||||
|
||||
Add any other context or screenshots about the feature request here.
|
||||
24
.github/ISSUE_TEMPLATE/question.md
vendored
@@ -1,24 +0,0 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask a question
|
||||
title: "[QUESTION]"
|
||||
labels: question
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### First check
|
||||
|
||||
* [ ] I used the GitHub search to find a similar issue and didn't find it.
|
||||
* [ ] I searched the FastAPI documentation, with the integrated search.
|
||||
* [ ] I already searched in Google "How to X in FastAPI" and didn't find any information.
|
||||
|
||||
### Description
|
||||
|
||||
How can I [...]?
|
||||
|
||||
Is it possible to [...]?
|
||||
|
||||
### Additional context
|
||||
|
||||
Add any other context or screenshots about the feature request here.
|
||||
146
.github/ISSUE_TEMPLATE/question.yml
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
name: Question or Problem
|
||||
description: Ask a question or ask about a problem
|
||||
labels: [question]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for your interest in FastAPI! 🚀
|
||||
|
||||
Please follow these instructions, fill every question, and do every step. 🙏
|
||||
|
||||
I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time.
|
||||
|
||||
I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues.
|
||||
|
||||
All that, on top of all the incredible help provided by a bunch of community members, the [FastAPI Experts](https://fastapi.tiangolo.com/fastapi-people/#experts), that give a lot of their time to come here and help others.
|
||||
|
||||
That's a lot of work they are doing, but if more FastAPI users came to help others like them just a little bit more, it would be much less effort for them (and you and me 😅).
|
||||
|
||||
By asking questions in a structured way (following this) it will be much easier to help you.
|
||||
|
||||
And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎
|
||||
|
||||
As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: First Check
|
||||
description: Please confirm and check all the following options.
|
||||
options:
|
||||
- label: I added a very descriptive title to this issue.
|
||||
required: true
|
||||
- label: I used the GitHub search to find a similar issue and didn't find it.
|
||||
required: true
|
||||
- label: I searched the FastAPI documentation, with the integrated search.
|
||||
required: true
|
||||
- label: I already searched in Google "How to X in FastAPI" and didn't find any information.
|
||||
required: true
|
||||
- label: I already read and followed all the tutorial in the docs and didn't find an answer.
|
||||
required: true
|
||||
- label: I already checked if it is not related to FastAPI but to [Pydantic](https://github.com/samuelcolvin/pydantic).
|
||||
required: true
|
||||
- label: I already checked if it is not related to FastAPI but to [Swagger UI](https://github.com/swagger-api/swagger-ui).
|
||||
required: true
|
||||
- label: I already checked if it is not related to FastAPI but to [ReDoc](https://github.com/Redocly/redoc).
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: help
|
||||
attributes:
|
||||
label: Commit to Help
|
||||
description: |
|
||||
After submitting this, I commit to one of:
|
||||
|
||||
* Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
|
||||
* I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.
|
||||
* Implement a Pull Request for a confirmed bug.
|
||||
|
||||
options:
|
||||
- label: I commit to help with one of those options 👆
|
||||
required: true
|
||||
- type: textarea
|
||||
id: example
|
||||
attributes:
|
||||
label: Example Code
|
||||
description: |
|
||||
Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case.
|
||||
|
||||
If I (or someone) can copy it, run it, and see it right away, there's a much higher chance I (or someone) will be able to help you.
|
||||
|
||||
placeholder: |
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
render: python
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: |
|
||||
What is the problem, question, or error?
|
||||
|
||||
Write a short description telling me what you are doing, what you expect to happen, and what is currently happening.
|
||||
placeholder: |
|
||||
* Open the browser and call the endpoint `/`.
|
||||
* It returns a JSON with `{"Hello": "World"}`.
|
||||
* But I expected it to return `{"Hello": "Sara"}`.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating System
|
||||
description: What operating system are you on?
|
||||
multiple: true
|
||||
options:
|
||||
- Linux
|
||||
- Windows
|
||||
- macOS
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: os-details
|
||||
attributes:
|
||||
label: Operating System Details
|
||||
description: You can add more details about your operating system here, in particular if you chose "Other".
|
||||
- type: input
|
||||
id: fastapi-version
|
||||
attributes:
|
||||
label: FastAPI Version
|
||||
description: |
|
||||
What FastAPI version are you using?
|
||||
|
||||
You can find the FastAPI version with:
|
||||
|
||||
```bash
|
||||
python -c "import fastapi; print(fastapi.__version__)"
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: python-version
|
||||
attributes:
|
||||
label: Python Version
|
||||
description: |
|
||||
What Python version are you using?
|
||||
|
||||
You can find the Python version with:
|
||||
|
||||
```bash
|
||||
python --version
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Add any additional context information or screenshots you think are useful.
|
||||
7
.github/actions/comment-docs-preview-in-pr/Dockerfile
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM python:3.7
|
||||
|
||||
RUN pip install httpx "pydantic==1.5.1" pygithub
|
||||
|
||||
COPY ./app /app
|
||||
|
||||
CMD ["python", "/app/main.py"]
|
||||
13
.github/actions/comment-docs-preview-in-pr/action.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
name: Comment Docs Preview in PR
|
||||
description: Comment with the docs URL preview in the PR
|
||||
author: Sebastián Ramírez <tiangolo@gmail.com>
|
||||
inputs:
|
||||
token:
|
||||
description: Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }}
|
||||
required: true
|
||||
deploy_url:
|
||||
description: The deployment URL to comment in the PR
|
||||
required: true
|
||||
runs:
|
||||
using: docker
|
||||
image: Dockerfile
|
||||
70
.github/actions/comment-docs-preview-in-pr/app/main.py
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
import logging
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
import httpx
|
||||
from github import Github
|
||||
from github.PullRequest import PullRequest
|
||||
from pydantic import BaseModel, BaseSettings, SecretStr, ValidationError
|
||||
|
||||
github_api = "https://api.github.com"
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
github_repository: str
|
||||
github_event_path: Path
|
||||
github_event_name: Optional[str] = None
|
||||
input_token: SecretStr
|
||||
input_deploy_url: str
|
||||
|
||||
|
||||
class PartialGithubEventHeadCommit(BaseModel):
|
||||
id: str
|
||||
|
||||
|
||||
class PartialGithubEventWorkflowRun(BaseModel):
|
||||
head_commit: PartialGithubEventHeadCommit
|
||||
|
||||
|
||||
class PartialGithubEvent(BaseModel):
|
||||
workflow_run: PartialGithubEventWorkflowRun
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
settings = Settings()
|
||||
logging.info(f"Using config: {settings.json()}")
|
||||
g = Github(settings.input_token.get_secret_value())
|
||||
repo = g.get_repo(settings.github_repository)
|
||||
try:
|
||||
event = PartialGithubEvent.parse_file(settings.github_event_path)
|
||||
except ValidationError as e:
|
||||
logging.error(f"Error parsing event file: {e.errors()}")
|
||||
sys.exit(0)
|
||||
use_pr: Optional[PullRequest] = None
|
||||
for pr in repo.get_pulls():
|
||||
if pr.head.sha == event.workflow_run.head_commit.id:
|
||||
use_pr = pr
|
||||
break
|
||||
if not use_pr:
|
||||
logging.error(
|
||||
f"No PR found for hash: {event.workflow_run.head_commit.id}"
|
||||
)
|
||||
sys.exit(0)
|
||||
github_headers = {
|
||||
"Authorization": f"token {settings.input_token.get_secret_value()}"
|
||||
}
|
||||
url = f"{github_api}/repos/{settings.github_repository}/issues/{use_pr.number}/comments"
|
||||
logging.info(f"Using comments URL: {url}")
|
||||
response = httpx.post(
|
||||
url,
|
||||
headers=github_headers,
|
||||
json={
|
||||
"body": f"📝 Docs preview for commit {use_pr.head.sha} at: {settings.input_deploy_url}"
|
||||
},
|
||||
)
|
||||
if not (200 <= response.status_code <= 300):
|
||||
logging.error(f"Error posting comment: {response.text}")
|
||||
sys.exit(1)
|
||||
logging.info("Finished")
|
||||
7
.github/actions/people/Dockerfile
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM python:3.7
|
||||
|
||||
RUN pip install httpx PyGithub "pydantic==1.5.1" "pyyaml>=5.3.1,<6.0.0"
|
||||
|
||||
COPY ./app /app
|
||||
|
||||
CMD ["python", "/app/main.py"]
|
||||
13
.github/actions/people/action.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
name: "Generate FastAPI People"
|
||||
description: "Generate the data for the FastAPI People page"
|
||||
author: "Sebastián Ramírez <tiangolo@gmail.com>"
|
||||
inputs:
|
||||
token:
|
||||
description: 'User token, to read the GitHub API. Can be passed in using {{ secrets.ACTION_TOKEN }}'
|
||||
required: true
|
||||
standard_token:
|
||||
description: 'Default GitHub Action token, used for the PR. Can be passed in using {{ secrets.GITHUB_TOKEN }}'
|
||||
required: true
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
||||
529
.github/actions/people/app/main.py
vendored
Normal file
@@ -0,0 +1,529 @@
|
||||
import logging
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import Counter, defaultdict
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
from typing import Container, DefaultDict, Dict, List, Optional, Set
|
||||
|
||||
import httpx
|
||||
import yaml
|
||||
from github import Github
|
||||
from pydantic import BaseModel, BaseSettings, SecretStr
|
||||
|
||||
github_graphql_url = "https://api.github.com/graphql"
|
||||
|
||||
issues_query = """
|
||||
query Q($after: String) {
|
||||
repository(name: "fastapi", owner: "tiangolo") {
|
||||
issues(first: 100, after: $after) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
number
|
||||
author {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
title
|
||||
createdAt
|
||||
state
|
||||
comments(first: 100) {
|
||||
nodes {
|
||||
createdAt
|
||||
author {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
prs_query = """
|
||||
query Q($after: String) {
|
||||
repository(name: "fastapi", owner: "tiangolo") {
|
||||
pullRequests(first: 100, after: $after) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
number
|
||||
labels(first: 100) {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
author {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
title
|
||||
createdAt
|
||||
state
|
||||
comments(first: 100) {
|
||||
nodes {
|
||||
createdAt
|
||||
author {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
reviews(first:100) {
|
||||
nodes {
|
||||
author {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
sponsors_query = """
|
||||
query Q($after: String) {
|
||||
user(login: "tiangolo") {
|
||||
sponsorshipsAsMaintainer(first: 100, after: $after) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
sponsorEntity {
|
||||
... on Organization {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
... on User {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
}
|
||||
tier {
|
||||
name
|
||||
monthlyPriceInDollars
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class Author(BaseModel):
|
||||
login: str
|
||||
avatarUrl: str
|
||||
url: str
|
||||
|
||||
|
||||
class CommentsNode(BaseModel):
|
||||
createdAt: datetime
|
||||
author: Optional[Author] = None
|
||||
|
||||
|
||||
class Comments(BaseModel):
|
||||
nodes: List[CommentsNode]
|
||||
|
||||
|
||||
class IssuesNode(BaseModel):
|
||||
number: int
|
||||
author: Optional[Author] = None
|
||||
title: str
|
||||
createdAt: datetime
|
||||
state: str
|
||||
comments: Comments
|
||||
|
||||
|
||||
class IssuesEdge(BaseModel):
|
||||
cursor: str
|
||||
node: IssuesNode
|
||||
|
||||
|
||||
class Issues(BaseModel):
|
||||
edges: List[IssuesEdge]
|
||||
|
||||
|
||||
class IssuesRepository(BaseModel):
|
||||
issues: Issues
|
||||
|
||||
|
||||
class IssuesResponseData(BaseModel):
|
||||
repository: IssuesRepository
|
||||
|
||||
|
||||
class IssuesResponse(BaseModel):
|
||||
data: IssuesResponseData
|
||||
|
||||
|
||||
class LabelNode(BaseModel):
|
||||
name: str
|
||||
|
||||
|
||||
class Labels(BaseModel):
|
||||
nodes: List[LabelNode]
|
||||
|
||||
|
||||
class ReviewNode(BaseModel):
|
||||
author: Optional[Author] = None
|
||||
state: str
|
||||
|
||||
|
||||
class Reviews(BaseModel):
|
||||
nodes: List[ReviewNode]
|
||||
|
||||
|
||||
class PullRequestNode(BaseModel):
|
||||
number: int
|
||||
labels: Labels
|
||||
author: Optional[Author] = None
|
||||
title: str
|
||||
createdAt: datetime
|
||||
state: str
|
||||
comments: Comments
|
||||
reviews: Reviews
|
||||
|
||||
|
||||
class PullRequestEdge(BaseModel):
|
||||
cursor: str
|
||||
node: PullRequestNode
|
||||
|
||||
|
||||
class PullRequests(BaseModel):
|
||||
edges: List[PullRequestEdge]
|
||||
|
||||
|
||||
class PRsRepository(BaseModel):
|
||||
pullRequests: PullRequests
|
||||
|
||||
|
||||
class PRsResponseData(BaseModel):
|
||||
repository: PRsRepository
|
||||
|
||||
|
||||
class PRsResponse(BaseModel):
|
||||
data: PRsResponseData
|
||||
|
||||
|
||||
class SponsorEntity(BaseModel):
|
||||
login: str
|
||||
avatarUrl: str
|
||||
url: str
|
||||
|
||||
|
||||
class Tier(BaseModel):
|
||||
name: str
|
||||
monthlyPriceInDollars: float
|
||||
|
||||
|
||||
class SponsorshipAsMaintainerNode(BaseModel):
|
||||
sponsorEntity: SponsorEntity
|
||||
tier: Tier
|
||||
|
||||
|
||||
class SponsorshipAsMaintainerEdge(BaseModel):
|
||||
cursor: str
|
||||
node: SponsorshipAsMaintainerNode
|
||||
|
||||
|
||||
class SponsorshipAsMaintainer(BaseModel):
|
||||
edges: List[SponsorshipAsMaintainerEdge]
|
||||
|
||||
|
||||
class SponsorsUser(BaseModel):
|
||||
sponsorshipsAsMaintainer: SponsorshipAsMaintainer
|
||||
|
||||
|
||||
class SponsorsResponseData(BaseModel):
|
||||
user: SponsorsUser
|
||||
|
||||
|
||||
class SponsorsResponse(BaseModel):
|
||||
data: SponsorsResponseData
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
input_token: SecretStr
|
||||
input_standard_token: SecretStr
|
||||
github_repository: str
|
||||
|
||||
|
||||
def get_graphql_response(
|
||||
*, settings: Settings, query: str, after: Optional[str] = None
|
||||
):
|
||||
headers = {"Authorization": f"token {settings.input_token.get_secret_value()}"}
|
||||
variables = {"after": after}
|
||||
response = httpx.post(
|
||||
github_graphql_url,
|
||||
headers=headers,
|
||||
json={"query": query, "variables": variables, "operationName": "Q"},
|
||||
)
|
||||
if not response.status_code == 200:
|
||||
logging.error(f"Response was not 200, after: {after}")
|
||||
logging.error(response.text)
|
||||
raise RuntimeError(response.text)
|
||||
data = response.json()
|
||||
return data
|
||||
|
||||
|
||||
def get_graphql_issue_edges(*, settings: Settings, after: Optional[str] = None):
|
||||
data = get_graphql_response(settings=settings, query=issues_query, after=after)
|
||||
graphql_response = IssuesResponse.parse_obj(data)
|
||||
return graphql_response.data.repository.issues.edges
|
||||
|
||||
|
||||
def get_graphql_pr_edges(*, settings: Settings, after: Optional[str] = None):
|
||||
data = get_graphql_response(settings=settings, query=prs_query, after=after)
|
||||
graphql_response = PRsResponse.parse_obj(data)
|
||||
return graphql_response.data.repository.pullRequests.edges
|
||||
|
||||
|
||||
def get_graphql_sponsor_edges(*, settings: Settings, after: Optional[str] = None):
|
||||
data = get_graphql_response(settings=settings, query=sponsors_query, after=after)
|
||||
graphql_response = SponsorsResponse.parse_obj(data)
|
||||
return graphql_response.data.user.sponsorshipsAsMaintainer.edges
|
||||
|
||||
|
||||
def get_experts(settings: Settings):
|
||||
issue_nodes: List[IssuesNode] = []
|
||||
issue_edges = get_graphql_issue_edges(settings=settings)
|
||||
|
||||
while issue_edges:
|
||||
for edge in issue_edges:
|
||||
issue_nodes.append(edge.node)
|
||||
last_edge = issue_edges[-1]
|
||||
issue_edges = get_graphql_issue_edges(settings=settings, after=last_edge.cursor)
|
||||
|
||||
commentors = Counter()
|
||||
last_month_commentors = Counter()
|
||||
authors: Dict[str, Author] = {}
|
||||
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
one_month_ago = now - timedelta(days=30)
|
||||
|
||||
for issue in issue_nodes:
|
||||
issue_author_name = None
|
||||
if issue.author:
|
||||
authors[issue.author.login] = issue.author
|
||||
issue_author_name = issue.author.login
|
||||
issue_commentors = set()
|
||||
for comment in issue.comments.nodes:
|
||||
if comment.author:
|
||||
authors[comment.author.login] = comment.author
|
||||
if comment.author.login == issue_author_name:
|
||||
continue
|
||||
issue_commentors.add(comment.author.login)
|
||||
for author_name in issue_commentors:
|
||||
commentors[author_name] += 1
|
||||
if issue.createdAt > one_month_ago:
|
||||
last_month_commentors[author_name] += 1
|
||||
return commentors, last_month_commentors, authors
|
||||
|
||||
|
||||
def get_contributors(settings: Settings):
|
||||
pr_nodes: List[PullRequestNode] = []
|
||||
pr_edges = get_graphql_pr_edges(settings=settings)
|
||||
|
||||
while pr_edges:
|
||||
for edge in pr_edges:
|
||||
pr_nodes.append(edge.node)
|
||||
last_edge = pr_edges[-1]
|
||||
pr_edges = get_graphql_pr_edges(settings=settings, after=last_edge.cursor)
|
||||
|
||||
contributors = Counter()
|
||||
commentors = Counter()
|
||||
reviewers = Counter()
|
||||
authors: Dict[str, Author] = {}
|
||||
|
||||
for pr in pr_nodes:
|
||||
author_name = None
|
||||
if pr.author:
|
||||
authors[pr.author.login] = pr.author
|
||||
author_name = pr.author.login
|
||||
pr_commentors: Set[str] = set()
|
||||
pr_reviewers: Set[str] = set()
|
||||
for comment in pr.comments.nodes:
|
||||
if comment.author:
|
||||
authors[comment.author.login] = comment.author
|
||||
if comment.author.login == author_name:
|
||||
continue
|
||||
pr_commentors.add(comment.author.login)
|
||||
for author_name in pr_commentors:
|
||||
commentors[author_name] += 1
|
||||
for review in pr.reviews.nodes:
|
||||
if review.author:
|
||||
authors[review.author.login] = review.author
|
||||
pr_reviewers.add(review.author.login)
|
||||
for reviewer in pr_reviewers:
|
||||
reviewers[reviewer] += 1
|
||||
if pr.state == "MERGED" and pr.author:
|
||||
contributors[pr.author.login] += 1
|
||||
return contributors, commentors, reviewers, authors
|
||||
|
||||
|
||||
def get_individual_sponsors(settings: Settings):
|
||||
nodes: List[SponsorshipAsMaintainerNode] = []
|
||||
edges = get_graphql_sponsor_edges(settings=settings)
|
||||
|
||||
while edges:
|
||||
for edge in edges:
|
||||
nodes.append(edge.node)
|
||||
last_edge = edges[-1]
|
||||
edges = get_graphql_sponsor_edges(settings=settings, after=last_edge.cursor)
|
||||
|
||||
tiers: DefaultDict[float, Dict[str, SponsorEntity]] = defaultdict(dict)
|
||||
for node in nodes:
|
||||
tiers[node.tier.monthlyPriceInDollars][
|
||||
node.sponsorEntity.login
|
||||
] = node.sponsorEntity
|
||||
return tiers
|
||||
|
||||
|
||||
def get_top_users(
|
||||
*,
|
||||
counter: Counter,
|
||||
min_count: int,
|
||||
authors: Dict[str, Author],
|
||||
skip_users: Container[str],
|
||||
):
|
||||
users = []
|
||||
for commentor, count in counter.most_common(50):
|
||||
if commentor in skip_users:
|
||||
continue
|
||||
if count >= min_count:
|
||||
author = authors[commentor]
|
||||
users.append(
|
||||
{
|
||||
"login": commentor,
|
||||
"count": count,
|
||||
"avatarUrl": author.avatarUrl,
|
||||
"url": author.url,
|
||||
}
|
||||
)
|
||||
return users
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
settings = Settings()
|
||||
logging.info(f"Using config: {settings.json()}")
|
||||
g = Github(settings.input_standard_token.get_secret_value())
|
||||
repo = g.get_repo(settings.github_repository)
|
||||
issue_commentors, issue_last_month_commentors, issue_authors = get_experts(
|
||||
settings=settings
|
||||
)
|
||||
contributors, pr_commentors, reviewers, pr_authors = get_contributors(
|
||||
settings=settings
|
||||
)
|
||||
authors = {**issue_authors, **pr_authors}
|
||||
maintainers_logins = {"tiangolo"}
|
||||
bot_names = {"codecov", "github-actions"}
|
||||
maintainers = []
|
||||
for login in maintainers_logins:
|
||||
user = authors[login]
|
||||
maintainers.append(
|
||||
{
|
||||
"login": login,
|
||||
"answers": issue_commentors[login],
|
||||
"prs": contributors[login],
|
||||
"avatarUrl": user.avatarUrl,
|
||||
"url": user.url,
|
||||
}
|
||||
)
|
||||
|
||||
min_count_expert = 10
|
||||
min_count_last_month = 3
|
||||
min_count_contributor = 4
|
||||
min_count_reviewer = 4
|
||||
skip_users = maintainers_logins | bot_names
|
||||
experts = get_top_users(
|
||||
counter=issue_commentors,
|
||||
min_count=min_count_expert,
|
||||
authors=authors,
|
||||
skip_users=skip_users,
|
||||
)
|
||||
last_month_active = get_top_users(
|
||||
counter=issue_last_month_commentors,
|
||||
min_count=min_count_last_month,
|
||||
authors=authors,
|
||||
skip_users=skip_users,
|
||||
)
|
||||
top_contributors = get_top_users(
|
||||
counter=contributors,
|
||||
min_count=min_count_contributor,
|
||||
authors=authors,
|
||||
skip_users=skip_users,
|
||||
)
|
||||
top_reviewers = get_top_users(
|
||||
counter=reviewers,
|
||||
min_count=min_count_reviewer,
|
||||
authors=authors,
|
||||
skip_users=skip_users,
|
||||
)
|
||||
|
||||
tiers = get_individual_sponsors(settings=settings)
|
||||
sponsors_50 = []
|
||||
for login, sponsor in tiers[50].items():
|
||||
sponsors_50.append(
|
||||
{"login": login, "avatarUrl": sponsor.avatarUrl, "url": sponsor.url}
|
||||
)
|
||||
keys = list(tiers.keys())
|
||||
keys.sort(reverse=True)
|
||||
sponsors = []
|
||||
for key in keys:
|
||||
if key >= 50:
|
||||
continue
|
||||
for login, sponsor in tiers[key].items():
|
||||
sponsors.append(
|
||||
{"login": login, "avatarUrl": sponsor.avatarUrl, "url": sponsor.url}
|
||||
)
|
||||
|
||||
people = {
|
||||
"maintainers": maintainers,
|
||||
"experts": experts,
|
||||
"last_month_active": last_month_active,
|
||||
"top_contributors": top_contributors,
|
||||
"top_reviewers": top_reviewers,
|
||||
"sponsors_50": sponsors_50,
|
||||
"sponsors": sponsors,
|
||||
}
|
||||
people_path = Path("./docs/en/data/people.yml")
|
||||
people_old_content = people_path.read_text(encoding="utf-8")
|
||||
new_content = yaml.dump(people, sort_keys=False, width=200, allow_unicode=True)
|
||||
if people_old_content == new_content:
|
||||
logging.info("The FastAPI People data hasn't changed, finishing.")
|
||||
sys.exit(0)
|
||||
people_path.write_text(new_content, encoding="utf-8")
|
||||
logging.info("Setting up GitHub Actions git user")
|
||||
subprocess.run(["git", "config", "user.name", "github-actions"], check=True)
|
||||
subprocess.run(
|
||||
["git", "config", "user.email", "github-actions@github.com"], check=True
|
||||
)
|
||||
branch_name = "fastapi-people"
|
||||
logging.info(f"Creating a new branch {branch_name}")
|
||||
subprocess.run(["git", "checkout", "-b", branch_name], check=True)
|
||||
logging.info("Adding updated file")
|
||||
subprocess.run(["git", "add", str(people_path)], check=True)
|
||||
logging.info("Committing updated file")
|
||||
message = "👥 Update FastAPI People"
|
||||
result = subprocess.run(["git", "commit", "-m", message], check=True)
|
||||
logging.info("Pushing branch")
|
||||
subprocess.run(["git", "push", "origin", branch_name], check=True)
|
||||
logging.info("Creating PR")
|
||||
pr = repo.create_pull(title=message, body=message, base="master", head=branch_name)
|
||||
logging.info(f"Created PR: {pr.number}")
|
||||
logging.info("Finished")
|
||||
7
.github/actions/watch-previews/Dockerfile
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM python:3.7
|
||||
|
||||
RUN pip install httpx PyGithub "pydantic==1.5.1"
|
||||
|
||||
COPY ./app /app
|
||||
|
||||
CMD ["python", "/app/main.py"]
|
||||
10
.github/actions/watch-previews/action.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
name: "Watch docs previews in PRs"
|
||||
description: "Check PRs and trigger new docs deploys"
|
||||
author: "Sebastián Ramírez <tiangolo@gmail.com>"
|
||||
inputs:
|
||||
token:
|
||||
description: 'Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }}'
|
||||
required: true
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
||||
101
.github/actions/watch-previews/app/main.py
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
import httpx
|
||||
from github import Github
|
||||
from github.NamedUser import NamedUser
|
||||
from pydantic import BaseModel, BaseSettings, SecretStr
|
||||
|
||||
github_api = "https://api.github.com"
|
||||
netlify_api = "https://api.netlify.com"
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
input_token: SecretStr
|
||||
github_repository: str
|
||||
github_event_path: Path
|
||||
github_event_name: Optional[str] = None
|
||||
|
||||
|
||||
class Artifact(BaseModel):
|
||||
id: int
|
||||
node_id: str
|
||||
name: str
|
||||
size_in_bytes: int
|
||||
url: str
|
||||
archive_download_url: str
|
||||
expired: bool
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
|
||||
class ArtifactResponse(BaseModel):
|
||||
total_count: int
|
||||
artifacts: List[Artifact]
|
||||
|
||||
|
||||
def get_message(commit: str) -> str:
|
||||
return f"Docs preview for commit {commit} at"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
settings = Settings()
|
||||
logging.info(f"Using config: {settings.json()}")
|
||||
g = Github(settings.input_token.get_secret_value())
|
||||
repo = g.get_repo(settings.github_repository)
|
||||
owner: NamedUser = repo.owner
|
||||
headers = {"Authorization": f"token {settings.input_token.get_secret_value()}"}
|
||||
prs = list(repo.get_pulls(state="open"))
|
||||
response = httpx.get(
|
||||
f"{github_api}/repos/{settings.github_repository}/actions/artifacts",
|
||||
headers=headers,
|
||||
)
|
||||
data = response.json()
|
||||
artifacts_response = ArtifactResponse.parse_obj(data)
|
||||
for pr in prs:
|
||||
logging.info("-----")
|
||||
logging.info(f"Processing PR #{pr.number}: {pr.title}")
|
||||
pr_comments = list(pr.get_issue_comments())
|
||||
pr_commits = list(pr.get_commits())
|
||||
last_commit = pr_commits[0]
|
||||
for pr_commit in pr_commits:
|
||||
if pr_commit.commit.author.date > last_commit.commit.author.date:
|
||||
last_commit = pr_commit
|
||||
commit = last_commit.commit.sha
|
||||
logging.info(f"Last commit: {commit}")
|
||||
message = get_message(commit)
|
||||
notified = False
|
||||
for pr_comment in pr_comments:
|
||||
if message in pr_comment.body:
|
||||
notified = True
|
||||
logging.info(f"Docs preview was notified: {notified}")
|
||||
if not notified:
|
||||
artifact_name = f"docs-zip-{commit}"
|
||||
use_artifact: Optional[Artifact] = None
|
||||
for artifact in artifacts_response.artifacts:
|
||||
if artifact.name == artifact_name:
|
||||
use_artifact = artifact
|
||||
break
|
||||
if not use_artifact:
|
||||
logging.info("Artifact not available")
|
||||
else:
|
||||
logging.info(f"Existing artifact: {use_artifact.name}")
|
||||
response = httpx.post(
|
||||
"https://api.github.com/repos/tiangolo/fastapi/actions/workflows/preview-docs.yml/dispatches",
|
||||
headers=headers,
|
||||
json={
|
||||
"ref": "master",
|
||||
"inputs": {
|
||||
"pr": f"{pr.number}",
|
||||
"name": artifact_name,
|
||||
"commit": commit,
|
||||
},
|
||||
},
|
||||
)
|
||||
logging.info(
|
||||
f"Trigger sent, response status: {response.status_code} - content: {response.content}"
|
||||
)
|
||||
logging.info("Finished")
|
||||
50
.github/workflows/build-docs.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Build Docs
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
jobs:
|
||||
build-docs:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.7"
|
||||
- uses: actions/cache@v2
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-docs
|
||||
- name: Install Flit
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: python3.7 -m pip install flit
|
||||
- name: Install docs extras
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: python3.7 -m flit install --deps production --extras doc
|
||||
- name: Install Material for MkDocs Insiders
|
||||
if: github.event.pull_request.head.repo.fork == false && steps.cache.outputs.cache-hit != 'true'
|
||||
run: pip install git+https://${{ secrets.ACTIONS_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git
|
||||
- name: Build Docs
|
||||
run: python3.7 ./scripts/docs.py build-all
|
||||
- name: Zip docs
|
||||
run: bash ./scripts/zip-docs.sh
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: docs-zip
|
||||
path: ./docs.zip
|
||||
- name: Deploy to Netlify
|
||||
uses: nwtgck/actions-netlify@v1.1.5
|
||||
with:
|
||||
publish-dir: './site'
|
||||
production-branch: master
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
enable-commit-comment: false
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
||||
29
.github/workflows/deploy-docs.yml
vendored
@@ -1,29 +0,0 @@
|
||||
name: Build and Deploy to Netlify
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: "3.7"
|
||||
- name: Install Flit
|
||||
run: python3.7 -m pip install flit
|
||||
- name: Install docs extras
|
||||
run: python3.7 -m flit install --extras doc
|
||||
- name: Build Docs
|
||||
run: python3.7 ./scripts/docs.py build-all
|
||||
- name: Deploy to Netlify
|
||||
uses: nwtgck/actions-netlify@v1.0.3
|
||||
with:
|
||||
publish-dir: './site'
|
||||
production-branch: master
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
||||
30
.github/workflows/issue-manager.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Issue Manager
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
issue_comment:
|
||||
types:
|
||||
- created
|
||||
issues:
|
||||
types:
|
||||
- labeled
|
||||
pull_request_target:
|
||||
types:
|
||||
- labeled
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
issue-manager:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: tiangolo/issue-manager@0.4.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
config: >
|
||||
{
|
||||
"answered": {
|
||||
"delay": 864000,
|
||||
"message": "Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs."
|
||||
}
|
||||
}
|
||||
13
.github/workflows/label-approved.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
name: Label Approved
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 12 * * *"
|
||||
|
||||
jobs:
|
||||
label-approved:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: docker://tiangolo/label-approved:0.0.2
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
40
.github/workflows/latest-changes.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Latest Changes
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
branches:
|
||||
- master
|
||||
types:
|
||||
- closed
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
number:
|
||||
description: PR number
|
||||
required: true
|
||||
debug_enabled:
|
||||
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
|
||||
required: false
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
latest-changes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
# To allow latest-changes to commit to master
|
||||
token: ${{ secrets.ACTIONS_TOKEN }}
|
||||
# Allow debugging with tmate
|
||||
- name: Setup tmate session
|
||||
uses: mxschmitt/action-tmate@v3
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
|
||||
with:
|
||||
limit-access-to-actor: true
|
||||
token: ${{ secrets.ACTIONS_TOKEN }}
|
||||
standard_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: docker://tiangolo/latest-changes:0.0.3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
latest_changes_file: docs/en/docs/release-notes.md
|
||||
latest_changes_header: '## Latest Changes\n\n'
|
||||
debug_logs: true
|
||||
19
.github/workflows/main.yml
vendored
@@ -1,19 +0,0 @@
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
issue-manager:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: tiangolo/issue-manager@master
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
config: >
|
||||
{
|
||||
"answered": {
|
||||
"users": ["tiangolo", "dmontagu"],
|
||||
"delay": 864000,
|
||||
"message": "Assuming the original issue was solved, it will be automatically closed now. But feel free to add more comments or create new issues."
|
||||
}
|
||||
}
|
||||
29
.github/workflows/people.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
name: FastAPI People
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 14 1 * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
debug_enabled:
|
||||
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
|
||||
required: false
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
fastapi-people:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
# Allow debugging with tmate
|
||||
- name: Setup tmate session
|
||||
uses: mxschmitt/action-tmate@v3
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
|
||||
with:
|
||||
limit-access-to-actor: true
|
||||
token: ${{ secrets.ACTIONS_TOKEN }}
|
||||
standard_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: ./.github/actions/people
|
||||
with:
|
||||
token: ${{ secrets.ACTIONS_TOKEN }}
|
||||
standard_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
41
.github/workflows/preview-docs.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Preview Docs
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- Build Docs
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
preview-docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Download Artifact Docs
|
||||
uses: dawidd6/action-download-artifact@v2.9.0
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
workflow: build-docs.yml
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
name: docs-zip
|
||||
- name: Unzip docs
|
||||
run: |
|
||||
rm -rf ./site
|
||||
unzip docs.zip
|
||||
rm -f docs.zip
|
||||
- name: Deploy to Netlify
|
||||
id: netlify
|
||||
uses: nwtgck/actions-netlify@v1.1.5
|
||||
with:
|
||||
publish-dir: './site'
|
||||
production-deploy: false
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
enable-commit-comment: false
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
||||
- name: Comment Deploy
|
||||
uses: ./.github/actions/comment-docs-preview-in-pr
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
deploy_url: "${{ steps.netlify.outputs.deploy-url }}"
|
||||
46
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
name: Publish
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.6"
|
||||
- uses: actions/cache@v2
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-publish
|
||||
- name: Install Flit
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: pip install flit
|
||||
- name: Install Dependencies
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: flit install --symlink
|
||||
- name: Publish
|
||||
env:
|
||||
FLIT_USERNAME: ${{ secrets.FLIT_USERNAME }}
|
||||
FLIT_PASSWORD: ${{ secrets.FLIT_PASSWORD }}
|
||||
run: bash scripts/publish.sh
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
# - name: Notify
|
||||
# env:
|
||||
# GITTER_TOKEN: ${{ secrets.GITTER_TOKEN }}
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# TAG: ${{ github.event.release.name }}
|
||||
# run: bash scripts/notify.sh
|
||||
36
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.6, 3.7, 3.8]
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- uses: actions/cache@v2
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-test
|
||||
- name: Install Flit
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: pip install flit
|
||||
- name: Install Dependencies
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: flit install --symlink
|
||||
- name: Test
|
||||
run: bash scripts/test.sh
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
7
.gitignore
vendored
@@ -16,3 +16,10 @@ Pipfile.lock
|
||||
env3.*
|
||||
env
|
||||
docs_build
|
||||
venv
|
||||
docs.zip
|
||||
archive.zip
|
||||
|
||||
# vim temporary files
|
||||
*~
|
||||
.*.sw?
|
||||
|
||||
32
.travis.yml
@@ -1,32 +0,0 @@
|
||||
dist: xenial
|
||||
|
||||
language: python
|
||||
|
||||
cache: pip
|
||||
|
||||
python:
|
||||
- "3.6"
|
||||
- "3.7"
|
||||
- "3.8"
|
||||
- "nightly"
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- python: "nightly"
|
||||
|
||||
install:
|
||||
- pip install flit
|
||||
- flit install --symlink
|
||||
|
||||
script:
|
||||
- bash scripts/test.sh
|
||||
|
||||
after_script:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
deploy:
|
||||
provider: script
|
||||
script: bash scripts/deploy.sh
|
||||
on:
|
||||
tags: true
|
||||
python: "3.6"
|
||||
87
README.md
@@ -5,17 +5,14 @@
|
||||
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.com/tiangolo/fastapi" target="_blank">
|
||||
<img src="https://travis-ci.com/tiangolo/fastapi.svg?branch=master" alt="Build Status">
|
||||
<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" alt="Coverage">
|
||||
<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://badge.fury.io/py/fastapi.svg" alt="Package version">
|
||||
</a>
|
||||
<a href="https://gitter.im/tiangolo/fastapi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge" target="_blank">
|
||||
<img src="https://badges.gitter.im/tiangolo/fastapi.svg" alt="Join the chat at https://gitter.im/tiangolo/fastapi">
|
||||
<img src="https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package" alt="Package version">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -33,50 +30,70 @@ 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% *.
|
||||
* **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>.
|
||||
* **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>
|
||||
|
||||
## Sponsors
|
||||
|
||||
<!-- 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://bit.ly/2QSouzH" target="_blank" title="Jina: build neural search-as-a-service for any kind of data in just minutes."><img src="https://fastapi.tiangolo.com/img/sponsors/jina.svg"></a>
|
||||
<a href="https://www.investsuite.com/jobs" target="_blank" title="Wealthtech jobs with FastAPI"><img src="https://fastapi.tiangolo.com/img/sponsors/investsuite.svg"></a>
|
||||
<a href="https://www.vim.so/?utm_source=FastAPI" target="_blank" title="We help you master vim with interactive exercises"><img src="https://fastapi.tiangolo.com/img/sponsors/vimso.png"></a>
|
||||
<a href="https://talkpython.fm/fastapi-sponsor" target="_blank" title="FastAPI video courses on demand from people you trust"><img src="https://fastapi.tiangolo.com/img/sponsors/talkpython.png"></a>
|
||||
|
||||
<!-- /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.*"
|
||||
"_[...] 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>
|
||||
|
||||
---
|
||||
|
||||
"*I’m over the moon excited about **FastAPI**. It’s so fun!*"
|
||||
"_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.*"
|
||||
"_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="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="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 [...]*"
|
||||
"_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 [...]*"
|
||||
"_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>
|
||||
|
||||
---
|
||||
|
||||
"*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>
|
||||
|
||||
---
|
||||
|
||||
## **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>
|
||||
@@ -106,12 +123,12 @@ $ 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>.
|
||||
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
|
||||
$ pip install uvicorn[standard]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
@@ -125,6 +142,8 @@ $ pip install uvicorn
|
||||
* Create a file `main.py` with:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -136,7 +155,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -145,7 +164,9 @@ def read_item(item_id: int, q: str = None):
|
||||
|
||||
If your code uses `async` / `await`, use `async def`:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -157,7 +178,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str = None):
|
||||
async def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -235,7 +256,9 @@ 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="2 7 8 9 10 23 24 25"
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -245,7 +268,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool = None
|
||||
is_offer: Optional[bool] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -254,7 +277,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
@@ -416,9 +439,9 @@ Used by Pydantic:
|
||||
|
||||
Used by 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://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="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||
* <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).
|
||||
@@ -427,7 +450,7 @@ Used by Starlette:
|
||||
|
||||
Used by 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://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]`.
|
||||
|
||||
31
SECURITY.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Security Policy
|
||||
|
||||
Security is very important for FastAPI and its community. 🔒
|
||||
|
||||
Learn more about it below. 👇
|
||||
|
||||
## Versions
|
||||
|
||||
The latest versions of FastAPI are supported.
|
||||
|
||||
You are encouraged to [write tests](https://fastapi.tiangolo.com/tutorial/testing/) for your application and update your FastAPI version frequently after ensuring that your tests are passing. This way you will benefit from the latest features, bug fixes, and **security fixes**.
|
||||
|
||||
You can learn more about [FastAPI versions and how to pin and upgrade them](https://fastapi.tiangolo.com/deployment/versions/) for your project in the docs.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you think you found a vulnerability, and even if you are not sure about it, please report it right away by sending an email to: security@tiangolo.com. Please try to be as explicit as possible, describing all the steps and example code to reproduce the security issue.
|
||||
|
||||
I (the author, [@tiangolo](https://twitter.com/tiangolo)) will review it thoroughly and get back to you.
|
||||
|
||||
## Public Discussions
|
||||
|
||||
Please restrain from publicly discussing a potential security vulnerability. 🙊
|
||||
|
||||
It's better to discuss privately and try to find a solution first, to limit the potential impact as much as possible.
|
||||
|
||||
---
|
||||
|
||||
Thanks for your help!
|
||||
|
||||
The FastAPI community and I thank you for that. 🙇
|
||||
467
docs/de/docs/index.md
Normal file
@@ -0,0 +1,467 @@
|
||||
|
||||
{!../../../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>
|
||||
|
||||
## Sponsors
|
||||
|
||||
<!-- sponsors -->
|
||||
|
||||
{% if sponsors %}
|
||||
{% for sponsor in sponsors.gold -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor -%}
|
||||
{%- for sponsor in sponsors.silver -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">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.
|
||||
125
docs/de/mkdocs.yml
Normal file
@@ -0,0 +1,125 @@
|
||||
site_name: FastAPI
|
||||
site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
|
||||
site_url: https://fastapi.tiangolo.com/de/
|
||||
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: de
|
||||
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: /
|
||||
- de: /de/
|
||||
- es: /es/
|
||||
- fr: /fr/
|
||||
- id: /id/
|
||||
- it: /it/
|
||||
- ja: /ja/
|
||||
- ko: /ko/
|
||||
- pl: /pl/
|
||||
- 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/fastapi
|
||||
- icon: fontawesome/brands/discord
|
||||
link: https://discord.gg/VQjSZaeJmf
|
||||
- icon: fontawesome/brands/twitter
|
||||
link: https://twitter.com/fastapi
|
||||
- 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: /de/
|
||||
name: de
|
||||
- link: /es/
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /id/
|
||||
name: id
|
||||
- link: /it/
|
||||
name: it - italiano
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pl/
|
||||
name: pl
|
||||
- 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/de/overrides/.gitignore
vendored
Normal file
278
docs/en/data/external_links.yml
Normal file
@@ -0,0 +1,278 @@
|
||||
articles:
|
||||
english:
|
||||
- author: "@pystar"
|
||||
author_link: https://pystar.substack.com/
|
||||
link: https://pystar.substack.com/p/how-to-create-a-fake-certificate
|
||||
title: How to Create A Fake Certificate Authority And Generate TLS Certs for FastAPI
|
||||
- author: Shahriyar(Shako) Rzayev
|
||||
author_link: https://www.linkedin.com/in/shahriyar-rzayev/
|
||||
link: https://www.azepug.az/posts/fastapi/#building-simple-e-commerce-with-nuxtjs-and-fastapi-series
|
||||
title: Building simple E-Commerce with NuxtJS and FastAPI
|
||||
- author: Rodrigo Arenas
|
||||
author_link: https://rodrigo-arenas.medium.com/
|
||||
link: https://medium.com/analytics-vidhya/serve-a-machine-learning-model-using-sklearn-fastapi-and-docker-85aabf96729b
|
||||
title: "Serve a machine learning model using Sklearn, FastAPI and Docker"
|
||||
- author: Navule Pavan Kumar Rao
|
||||
author_link: https://www.linkedin.com/in/navule/
|
||||
link: https://www.tutlinks.com/deploy-fastapi-on-ubuntu-gunicorn-caddy-2/
|
||||
title: Deploy FastAPI on Ubuntu and Serve using Caddy 2 Web Server
|
||||
- author: Patrick Ladon
|
||||
author_link: https://dev.to/factorlive
|
||||
link: https://dev.to/factorlive/python-facebook-messenger-webhook-with-fastapi-on-glitch-4n90
|
||||
title: Python Facebook messenger webhook with FastAPI on Glitch
|
||||
- author: Dom Patmore
|
||||
author_link: https://twitter.com/dompatmore
|
||||
link: https://dompatmore.com/blog/authenticate-your-fastapi-app-with-auth0
|
||||
title: Authenticate Your FastAPI App with auth0
|
||||
- author: Valon Januzaj
|
||||
author_link: https://www.linkedin.com/in/valon-januzaj-b02692187/
|
||||
link: https://valonjanuzaj.medium.com/deploy-a-dockerized-fastapi-application-to-aws-cc757830ba1b
|
||||
title: Deploy a dockerized FastAPI application to AWS
|
||||
- author: Amit Chaudhary
|
||||
author_link: https://twitter.com/amitness
|
||||
link: https://amitness.com/2020/06/fastapi-vs-flask/
|
||||
title: FastAPI for Flask Users
|
||||
- author: Louis Guitton
|
||||
author_link: https://twitter.com/louis_guitton
|
||||
link: https://guitton.co/posts/fastapi-monitoring/
|
||||
title: How to monitor your FastAPI service
|
||||
- author: Julien Harbulot
|
||||
author_link: https://julienharbulot.com/
|
||||
link: https://julienharbulot.com/notification-server.html
|
||||
title: HTTP server to display desktop notifications
|
||||
- author: Precious Ndubueze
|
||||
author_link: https://medium.com/@gabbyprecious2000
|
||||
link: https://medium.com/@gabbyprecious2000/creating-a-crud-app-with-fastapi-part-one-7c049292ad37
|
||||
title: Creating a CRUD App with FastAPI (Part one)
|
||||
- author: Farhad Malik
|
||||
author_link: https://medium.com/@farhadmalik
|
||||
link: https://towardsdatascience.com/build-and-host-fast-data-science-applications-using-fastapi-823be8a1d6a0
|
||||
title: Build And Host Fast Data Science Applications Using FastAPI
|
||||
- author: Navule Pavan Kumar Rao
|
||||
author_link: https://www.linkedin.com/in/navule/
|
||||
link: https://www.tutlinks.com/deploy-fastapi-on-azure/
|
||||
title: Deploy FastAPI on Azure App Service
|
||||
- author: Davide Fiocco
|
||||
author_link: https://github.com/davidefiocco
|
||||
link: https://davidefiocco.github.io/streamlit-fastapi-ml-serving/
|
||||
title: Machine learning model serving in Python using FastAPI and streamlit
|
||||
- author: Netflix
|
||||
author_link: https://netflixtechblog.com/
|
||||
link: https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072
|
||||
title: Introducing Dispatch
|
||||
- author: Stavros Korokithakis
|
||||
author_link: https://twitter.com/Stavros
|
||||
link: https://www.stavros.io/posts/fastapi-with-django/
|
||||
title: Using FastAPI with Django
|
||||
- author: Twilio
|
||||
author_link: https://www.twilio.com
|
||||
link: https://www.twilio.com/blog/build-secure-twilio-webhook-python-fastapi
|
||||
title: Build a Secure Twilio Webhook with Python and FastAPI
|
||||
- author: Sebastián Ramírez (tiangolo)
|
||||
author_link: https://twitter.com/tiangolo
|
||||
link: https://dev.to/tiangolo/build-a-web-api-from-scratch-with-fastapi-the-workshop-2ehe
|
||||
title: Build a web API from scratch with FastAPI - the workshop
|
||||
- author: Paul Sec
|
||||
author_link: https://twitter.com/PaulWebSec
|
||||
link: https://paulsec.github.io/posts/fastapi_plus_zeit_serverless_fu/
|
||||
title: FastAPI + Zeit.co = 🚀
|
||||
- author: cuongld2
|
||||
author_link: https://dev.to/cuongld2
|
||||
link: https://dev.to/cuongld2/build-simple-api-service-with-python-fastapi-part-1-581o
|
||||
title: Build simple API service with Python FastAPI — Part 1
|
||||
- author: Paurakh Sharma Humagain
|
||||
author_link: https://twitter.com/PaurakhSharma
|
||||
link: https://dev.to/paurakhsharma/microservice-in-python-using-fastapi-24cc
|
||||
title: Microservice in Python using FastAPI
|
||||
- author: Guillermo Cruz
|
||||
author_link: https://wuilly.com/
|
||||
link: https://wuilly.com/2019/10/real-time-notifications-with-python-and-postgres/
|
||||
title: Real-time Notifications with Python and Postgres
|
||||
- author: Benjamin Ramser
|
||||
author_link: https://iwpnd.pw
|
||||
link: https://iwpnd.pw/articles/2020-03/apache-kafka-fastapi-geostream
|
||||
title: Apache Kafka producer and consumer with FastAPI and aiokafka
|
||||
- author: Navule Pavan Kumar Rao
|
||||
author_link: https://www.linkedin.com/in/navule/
|
||||
link: https://www.tutlinks.com/create-and-deploy-fastapi-app-to-heroku/
|
||||
title: Create and Deploy FastAPI app to Heroku without using Docker
|
||||
- author: Benjamin Ramser
|
||||
author_link: https://iwpnd.pw
|
||||
link: https://iwpnd.pw/articles/2020-01/deploy-fastapi-to-aws-lambda
|
||||
title: How to continuously deploy a FastAPI to AWS Lambda with AWS SAM
|
||||
- author: Arthur Henrique
|
||||
author_link: https://twitter.com/arthurheinrique
|
||||
link: https://medium.com/@arthur393/another-boilerplate-to-fastapi-azure-pipeline-ci-pytest-3c8d9a4be0bb
|
||||
title: 'Another Boilerplate to FastAPI: Azure Pipeline CI + Pytest'
|
||||
- author: Shane Soh
|
||||
author_link: https://medium.com/@shane.soh
|
||||
link: https://medium.com/analytics-vidhya/deploy-machine-learning-models-with-keras-fastapi-redis-and-docker-4940df614ece
|
||||
title: Deploy Machine Learning Models with Keras, FastAPI, Redis and Docker
|
||||
- author: Mandy Gu
|
||||
author_link: https://towardsdatascience.com/@mandygu
|
||||
link: https://towardsdatascience.com/deploying-iris-classifications-with-fastapi-and-docker-7c9b83fdec3a
|
||||
title: 'Towards Data Science: Deploying Iris Classifications with FastAPI and Docker'
|
||||
- author: Michael Herman
|
||||
author_link: https://testdriven.io/authors/herman
|
||||
link: https://testdriven.io/blog/fastapi-crud/
|
||||
title: 'TestDriven.io: Developing and Testing an Asynchronous API with FastAPI and Pytest'
|
||||
- author: Bernard Brenyah
|
||||
author_link: https://medium.com/@bbrenyah
|
||||
link: https://medium.com/python-data/how-to-deploy-tensorflow-2-0-models-as-an-api-service-with-fastapi-docker-128b177e81f3
|
||||
title: How To Deploy Tensorflow 2.0 Models As An API Service With FastAPI & Docker
|
||||
- author: Dylan Anthony
|
||||
author_link: https://dev.to/dbanty
|
||||
link: https://dev.to/dbanty/why-i-m-leaving-flask-3ki6
|
||||
title: Why I'm Leaving Flask
|
||||
- author: Rob Wagner
|
||||
author_link: https://robwagner.dev/
|
||||
link: https://robwagner.dev/tortoise-fastapi-setup/
|
||||
title: Setting up Tortoise ORM with FastAPI
|
||||
- author: Mike Moritz
|
||||
author_link: https://medium.com/@mike.p.moritz
|
||||
link: https://medium.com/@mike.p.moritz/using-docker-compose-to-deploy-a-lightweight-python-rest-api-with-a-job-queue-37e6072a209b
|
||||
title: Using Docker Compose to deploy a lightweight Python REST API with a job queue
|
||||
- author: '@euri10'
|
||||
author_link: https://gitlab.com/euri10
|
||||
link: https://gitlab.com/euri10/fastapi_cheatsheet
|
||||
title: A FastAPI and Swagger UI visual cheatsheet
|
||||
- author: Uber Engineering
|
||||
author_link: https://eng.uber.com
|
||||
link: https://eng.uber.com/ludwig-v0-2/
|
||||
title: 'Uber: Ludwig v0.2 Adds New Features and Other Improvements to its Deep Learning Toolbox [including a FastAPI server]'
|
||||
- author: Maarten Grootendorst
|
||||
author_link: https://www.linkedin.com/in/mgrootendorst/
|
||||
link: https://towardsdatascience.com/how-to-deploy-a-machine-learning-model-dc51200fe8cf
|
||||
title: How to Deploy a Machine Learning Model
|
||||
- author: Johannes Gontrum
|
||||
author_link: https://twitter.com/gntrm
|
||||
link: https://medium.com/@gntrm/jwt-authentication-with-fastapi-and-aws-cognito-1333f7f2729e
|
||||
title: JWT Authentication with FastAPI and AWS Cognito
|
||||
- author: Ankush Thakur
|
||||
author_link: https://geekflare.com/author/ankush/
|
||||
link: https://geekflare.com/python-asynchronous-web-frameworks/
|
||||
title: Top 5 Asynchronous Web Frameworks for Python
|
||||
- author: Nico Axtmann
|
||||
author_link: https://www.linkedin.com/in/nico-axtmann
|
||||
link: https://medium.com/@nico.axtmann95/deploying-a-scikit-learn-model-with-onnx-und-fastapi-1af398268915
|
||||
title: Deploying a scikit-learn model with ONNX and FastAPI
|
||||
- author: Nils de Bruin
|
||||
author_link: https://medium.com/@nilsdebruin
|
||||
link: https://medium.com/data-rebels/fastapi-authentication-revisited-enabling-api-key-authentication-122dc5975680
|
||||
title: 'FastAPI authentication revisited: Enabling API key authentication'
|
||||
- author: Nick Cortale
|
||||
author_link: https://nickc1.github.io/
|
||||
link: https://nickc1.github.io/api,/scikit-learn/2019/01/10/scikit-fastapi.html
|
||||
title: 'FastAPI and Scikit-Learn: Easily Deploy Models'
|
||||
- author: Errieta Kostala
|
||||
author_link: https://dev.to/errietta
|
||||
link: https://dev.to/errietta/introduction-to-the-fastapi-python-framework-2n10
|
||||
title: Introduction to the fastapi python framework
|
||||
- author: Nils de Bruin
|
||||
author_link: https://medium.com/@nilsdebruin
|
||||
link: https://medium.com/data-rebels/fastapi-how-to-add-basic-and-cookie-authentication-a45c85ef47d3
|
||||
title: FastAPI — How to add basic and cookie authentication
|
||||
- author: Nils de Bruin
|
||||
author_link: https://medium.com/@nilsdebruin
|
||||
link: https://medium.com/data-rebels/fastapi-google-as-an-external-authentication-provider-3a527672cf33
|
||||
title: FastAPI — Google as an external authentication provider
|
||||
- author: William Hayes
|
||||
author_link: https://medium.com/@williamhayes
|
||||
link: https://medium.com/@williamhayes/fastapi-starlette-debug-vs-prod-5f7561db3a59
|
||||
title: FastAPI/Starlette debug vs prod
|
||||
german:
|
||||
- author: Nico Axtmann
|
||||
author_link: https://twitter.com/_nicoax
|
||||
link: https://blog.codecentric.de/2019/08/inbetriebnahme-eines-scikit-learn-modells-mit-onnx-und-fastapi/
|
||||
title: Inbetriebnahme eines scikit-learn-Modells mit ONNX und FastAPI
|
||||
japanese:
|
||||
- author: '@bee2'
|
||||
author_link: https://qiita.com/bee2
|
||||
link: https://qiita.com/bee2/items/75d9c0d7ba20e7a4a0e9
|
||||
title: '[FastAPI] Python製のASGI Web フレームワーク FastAPIに入門する'
|
||||
- author: '@bee2'
|
||||
author_link: https://qiita.com/bee2
|
||||
link: https://qiita.com/bee2/items/0ad260ab9835a2087dae
|
||||
title: PythonのWeb frameworkのパフォーマンス比較 (Django, Flask, responder, FastAPI, japronto)
|
||||
- author: ライトコードメディア編集部
|
||||
author_link: https://rightcode.co.jp/author/jun
|
||||
link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-admin-page-improvement
|
||||
title: '【第4回】FastAPIチュートリアル: toDoアプリを作ってみよう【管理者ページ改良編】'
|
||||
- author: ライトコードメディア編集部
|
||||
author_link: https://rightcode.co.jp/author/jun
|
||||
link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-authentication-user-registration
|
||||
title: '【第3回】FastAPIチュートリアル: toDoアプリを作ってみよう【認証・ユーザ登録編】'
|
||||
- author: ライトコードメディア編集部
|
||||
author_link: https://rightcode.co.jp/author/jun
|
||||
link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-model-building
|
||||
title: '【第2回】FastAPIチュートリアル: ToDoアプリを作ってみよう【モデル構築編】'
|
||||
- author: ライトコードメディア編集部
|
||||
author_link: https://rightcode.co.jp/author/jun
|
||||
link: https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-environment
|
||||
title: '【第1回】FastAPIチュートリアル: ToDoアプリを作ってみよう【環境構築編】'
|
||||
- author: Hikaru Takahashi
|
||||
author_link: https://qiita.com/hikarut
|
||||
link: https://qiita.com/hikarut/items/b178af2e2440c67c6ac4
|
||||
title: フロントエンド開発者向けのDockerによるPython開発環境構築
|
||||
- author: '@angel_katayoku'
|
||||
author_link: https://qiita.com/angel_katayoku
|
||||
link: https://qiita.com/angel_katayoku/items/8a458a8952f50b73f420
|
||||
title: FastAPIでPOSTされたJSONのレスポンスbodyを受け取る
|
||||
- author: '@angel_katayoku'
|
||||
author_link: https://qiita.com/angel_katayoku
|
||||
link: https://qiita.com/angel_katayoku/items/4fbc1a4e2b33fa2237d2
|
||||
title: FastAPIをMySQLと接続してDockerで管理してみる
|
||||
- author: '@angel_katayoku'
|
||||
author_link: https://qiita.com/angel_katayoku
|
||||
link: https://qiita.com/angel_katayoku/items/0e1f5dbbe62efc612a78
|
||||
title: FastAPIでCORSを回避
|
||||
- author: '@ryoryomaru'
|
||||
author_link: https://qiita.com/ryoryomaru
|
||||
link: https://qiita.com/ryoryomaru/items/59958ed385b3571d50de
|
||||
title: python製の最新APIフレームワーク FastAPI を触ってみた
|
||||
- author: '@mtitg'
|
||||
author_link: https://qiita.com/mtitg
|
||||
link: https://qiita.com/mtitg/items/47770e9a562dd150631d
|
||||
title: FastAPI|DB接続してCRUDするPython製APIサーバーを構築
|
||||
russian:
|
||||
- author: Troy Köhler
|
||||
author_link: https://www.linkedin.com/in/trkohler/
|
||||
link: https://trkohler.com/fast-api-introduction-to-framework
|
||||
title: 'FastAPI: знакомимся с фреймворком'
|
||||
- author: prostomarkeloff
|
||||
author_link: https://github.com/prostomarkeloff
|
||||
link: https://habr.com/ru/post/478620/
|
||||
title: Почему Вы должны попробовать FastAPI?
|
||||
- author: Andrey Korchak
|
||||
author_link: https://habr.com/ru/users/57uff3r/
|
||||
link: https://habr.com/ru/post/454440/
|
||||
title: 'Мелкая питонячая радость #2: Starlette - Солидная примочка – FastAPI'
|
||||
vietnamese:
|
||||
- author: Nguyễn Nhân
|
||||
author_link: https://fullstackstation.com/author/figonking/
|
||||
link: https://fullstackstation.com/fastapi-trien-khai-bang-docker/
|
||||
title: 'FASTAPI: TRIỂN KHAI BẰNG DOCKER'
|
||||
podcasts:
|
||||
english:
|
||||
- author: Podcast.`__init__`
|
||||
author_link: https://www.pythonpodcast.com/
|
||||
link: https://www.pythonpodcast.com/fastapi-web-application-framework-episode-259/
|
||||
title: Build The Next Generation Of Python Web Applications With FastAPI - Episode 259 - interview to Sebastían Ramírez (tiangolo)
|
||||
- author: Python Bytes FM
|
||||
author_link: https://pythonbytes.fm/
|
||||
link: https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855
|
||||
title: FastAPI on PythonBytes
|
||||
talks:
|
||||
english:
|
||||
- author: Sebastián Ramírez (tiangolo)
|
||||
author_link: https://twitter.com/tiangolo
|
||||
link: https://www.youtube.com/watch?v=PnpTY1f4k2U
|
||||
title: '[VIRTUAL] Py.Amsterdam''s flying Software Circus: Intro to FastAPI'
|
||||
- author: Sebastián Ramírez (tiangolo)
|
||||
author_link: https://twitter.com/tiangolo
|
||||
link: https://www.youtube.com/watch?v=z9K5pwb0rt8
|
||||
title: 'PyConBY 2020: Serve ML models easily with FastAPI'
|
||||
- author: Chris Withers
|
||||
author_link: https://twitter.com/chriswithers13
|
||||
link: https://www.youtube.com/watch?v=3DLwPcrE5mA
|
||||
title: 'PyCon UK 2019: FastAPI from the ground up'
|
||||
752
docs/en/data/people.yml
Normal file
@@ -0,0 +1,752 @@
|
||||
maintainers:
|
||||
- login: tiangolo
|
||||
answers: 1225
|
||||
prs: 232
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=05f95ca7fdead36edd9c86be46b4ef6c3c71f876&v=4
|
||||
url: https://github.com/tiangolo
|
||||
experts:
|
||||
- login: Kludex
|
||||
count: 267
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: dmontagu
|
||||
count: 262
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
|
||||
url: https://github.com/dmontagu
|
||||
- login: ycd
|
||||
count: 216
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: Mause
|
||||
count: 182
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4
|
||||
url: https://github.com/Mause
|
||||
- login: euri10
|
||||
count: 166
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
|
||||
url: https://github.com/euri10
|
||||
- login: phy25
|
||||
count: 130
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4
|
||||
url: https://github.com/phy25
|
||||
- login: ArcLightSlavik
|
||||
count: 64
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4
|
||||
url: https://github.com/ArcLightSlavik
|
||||
- login: falkben
|
||||
count: 56
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4
|
||||
url: https://github.com/falkben
|
||||
- login: raphaelauv
|
||||
count: 47
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
url: https://github.com/raphaelauv
|
||||
- login: sm-Fifteen
|
||||
count: 46
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4
|
||||
url: https://github.com/sm-Fifteen
|
||||
- login: includeamin
|
||||
count: 38
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4
|
||||
url: https://github.com/includeamin
|
||||
- login: prostomarkeloff
|
||||
count: 33
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4
|
||||
url: https://github.com/prostomarkeloff
|
||||
- login: Dustyposa
|
||||
count: 32
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4
|
||||
url: https://github.com/Dustyposa
|
||||
- login: krishnardt
|
||||
count: 30
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4
|
||||
url: https://github.com/krishnardt
|
||||
- login: insomnes
|
||||
count: 30
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4
|
||||
url: https://github.com/insomnes
|
||||
- login: wshayes
|
||||
count: 29
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
|
||||
url: https://github.com/wshayes
|
||||
- login: dbanty
|
||||
count: 25
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=0cf33e4f40efc2ea206a1189fd63a11344eb88ed&v=4
|
||||
url: https://github.com/dbanty
|
||||
- login: SirTelemak
|
||||
count: 24
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4
|
||||
url: https://github.com/SirTelemak
|
||||
- login: chbndrhnns
|
||||
count: 22
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4
|
||||
url: https://github.com/chbndrhnns
|
||||
- login: acnebs
|
||||
count: 22
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=bfd127b3e6200f4d00afd714f0fc95c2512df19b&v=4
|
||||
url: https://github.com/acnebs
|
||||
- login: nsidnev
|
||||
count: 22
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4
|
||||
url: https://github.com/nsidnev
|
||||
- login: frankie567
|
||||
count: 21
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=72adf1cb1d29787305c99700d669561952cea0af&v=4
|
||||
url: https://github.com/frankie567
|
||||
- login: chris-allnutt
|
||||
count: 21
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4
|
||||
url: https://github.com/chris-allnutt
|
||||
- login: retnikt
|
||||
count: 19
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4
|
||||
url: https://github.com/retnikt
|
||||
- login: Hultner
|
||||
count: 18
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4
|
||||
url: https://github.com/Hultner
|
||||
- login: jorgerpo
|
||||
count: 17
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4
|
||||
url: https://github.com/jorgerpo
|
||||
- login: nkhitrov
|
||||
count: 17
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/28262306?u=66ee21316275ef356081c2efc4ed7a4572e690dc&v=4
|
||||
url: https://github.com/nkhitrov
|
||||
- login: waynerv
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
- login: haizaar
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/58201?u=4f1f9843d69433ca0d380d95146cfe119e5fdac4&v=4
|
||||
url: https://github.com/haizaar
|
||||
- login: acidjunk
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
|
||||
url: https://github.com/acidjunk
|
||||
- login: zamiramir
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/40475662?u=e58ef61034e8d0d6a312cc956fb09b9c3332b449&v=4
|
||||
url: https://github.com/zamiramir
|
||||
- login: juntatalor
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8134632?v=4
|
||||
url: https://github.com/juntatalor
|
||||
- login: valentin994
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/42819267?u=fdeeaa9242a59b243f8603496b00994f6951d5a2&v=4
|
||||
url: https://github.com/valentin994
|
||||
- login: aalifadv
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/78442260?v=4
|
||||
url: https://github.com/aalifadv
|
||||
- login: stefanondisponibile
|
||||
count: 10
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/20441825?u=ee1e59446b98f8ec2363caeda4c17164d0d9cc7d&v=4
|
||||
url: https://github.com/stefanondisponibile
|
||||
last_month_active:
|
||||
- login: Kludex
|
||||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: frankie567
|
||||
count: 9
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=72adf1cb1d29787305c99700d669561952cea0af&v=4
|
||||
url: https://github.com/frankie567
|
||||
- login: Mause
|
||||
count: 6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4
|
||||
url: https://github.com/Mause
|
||||
- login: ArcLightSlavik
|
||||
count: 6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4
|
||||
url: https://github.com/ArcLightSlavik
|
||||
- login: gyKa
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1000842?v=4
|
||||
url: https://github.com/gyKa
|
||||
- login: ricky-sb
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10700079?v=4
|
||||
url: https://github.com/ricky-sb
|
||||
- login: captainCapitalism
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/32553875?v=4
|
||||
url: https://github.com/captainCapitalism
|
||||
- login: acidjunk
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
|
||||
url: https://github.com/acidjunk
|
||||
top_contributors:
|
||||
- login: waynerv
|
||||
count: 25
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
- login: tokusumi
|
||||
count: 22
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
|
||||
url: https://github.com/tokusumi
|
||||
- login: dmontagu
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
|
||||
url: https://github.com/dmontagu
|
||||
- login: euri10
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
|
||||
url: https://github.com/euri10
|
||||
- login: mariacamilagl
|
||||
count: 9
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
|
||||
url: https://github.com/mariacamilagl
|
||||
- login: RunningIkkyu
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4
|
||||
url: https://github.com/RunningIkkyu
|
||||
- login: Serrones
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4
|
||||
url: https://github.com/Serrones
|
||||
- login: hard-coders
|
||||
count: 6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4
|
||||
url: https://github.com/hard-coders
|
||||
- login: wshayes
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
|
||||
url: https://github.com/wshayes
|
||||
- login: SwftAlpc
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4
|
||||
url: https://github.com/SwftAlpc
|
||||
- login: Attsun1031
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1175560?v=4
|
||||
url: https://github.com/Attsun1031
|
||||
- login: jekirl
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2546697?v=4
|
||||
url: https://github.com/jekirl
|
||||
- login: komtaki
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=5a44657c0544111ee3c132d9bb9951c2804f7969&v=4
|
||||
url: https://github.com/komtaki
|
||||
- login: Smlep
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4
|
||||
url: https://github.com/Smlep
|
||||
top_reviewers:
|
||||
- login: Kludex
|
||||
count: 80
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: tokusumi
|
||||
count: 44
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
|
||||
url: https://github.com/tokusumi
|
||||
- login: Laineyzhang55
|
||||
count: 42
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4
|
||||
url: https://github.com/Laineyzhang55
|
||||
- login: ycd
|
||||
count: 41
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=826f228edf0bab0d19ad1d5c4ba4df1047ccffef&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: waynerv
|
||||
count: 38
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
- login: AdrianDeAnda
|
||||
count: 28
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=bb7f8a0d6c9de4e9d0320a9f271210206e202250&v=4
|
||||
url: https://github.com/AdrianDeAnda
|
||||
- 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=5a44657c0544111ee3c132d9bb9951c2804f7969&v=4
|
||||
url: https://github.com/komtaki
|
||||
- login: ArcLightSlavik
|
||||
count: 20
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=81a84af39c89b898b0fbc5a04e8834f60f23e55a&v=4
|
||||
url: https://github.com/ArcLightSlavik
|
||||
- login: cassiobotaro
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4
|
||||
url: https://github.com/cassiobotaro
|
||||
- login: yanever
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/21978760?v=4
|
||||
url: https://github.com/yanever
|
||||
- login: SwftAlpc
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4
|
||||
url: https://github.com/SwftAlpc
|
||||
- login: pedabraham
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16860088?u=abf922a7b920bf8fdb7867d8b43e091f1e796178&v=4
|
||||
url: https://github.com/pedabraham
|
||||
- login: delhi09
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4
|
||||
url: https://github.com/delhi09
|
||||
- login: RunningIkkyu
|
||||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=706e1ee3f248245f2d68b976d149d06fd5a2010d&v=4
|
||||
url: https://github.com/RunningIkkyu
|
||||
- login: hard-coders
|
||||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4
|
||||
url: https://github.com/hard-coders
|
||||
- login: sh0nk
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4
|
||||
url: https://github.com/sh0nk
|
||||
- login: mariacamilagl
|
||||
count: 10
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
|
||||
url: https://github.com/mariacamilagl
|
||||
- login: Attsun1031
|
||||
count: 10
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1175560?v=4
|
||||
url: https://github.com/Attsun1031
|
||||
- login: maoyibo
|
||||
count: 10
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7887703?v=4
|
||||
url: https://github.com/maoyibo
|
||||
- login: PandaHun
|
||||
count: 9
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/13096845?u=646eba44db720e37d0dbe8e98e77ab534ea78a20&v=4
|
||||
url: https://github.com/PandaHun
|
||||
- login: bezaca
|
||||
count: 9
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4
|
||||
url: https://github.com/bezaca
|
||||
- login: lsglucas
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
|
||||
url: https://github.com/lsglucas
|
||||
- login: rjNemo
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
|
||||
url: https://github.com/rjNemo
|
||||
- login: blt232018
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43393471?u=172b0e0391db1aa6c1706498d6dfcb003c8a4857&v=4
|
||||
url: https://github.com/blt232018
|
||||
- login: Serrones
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4
|
||||
url: https://github.com/Serrones
|
||||
- login: ryuckel
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/36391432?u=094eec0cfddd5013f76f31e55e56147d78b19553&v=4
|
||||
url: https://github.com/ryuckel
|
||||
- login: raphaelauv
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
url: https://github.com/raphaelauv
|
||||
- login: NastasiaSaby
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8245071?u=b3afd005f9e4bf080c219ef61a592b3a8004b764&v=4
|
||||
url: https://github.com/NastasiaSaby
|
||||
- login: Smlep
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4
|
||||
url: https://github.com/Smlep
|
||||
- login: jovicon
|
||||
count: 6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4
|
||||
url: https://github.com/jovicon
|
||||
- login: Mause
|
||||
count: 6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4
|
||||
url: https://github.com/Mause
|
||||
- login: nimctl
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/49960770?u=e39b11d47188744ee07b2a1c7ce1a1bdf3c80760&v=4
|
||||
url: https://github.com/nimctl
|
||||
- login: juntatalor
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8134632?v=4
|
||||
url: https://github.com/juntatalor
|
||||
- login: SnkSynthesis
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/63564282?u=0078826509dbecb2fdb543f4e881c9cd06157893&v=4
|
||||
url: https://github.com/SnkSynthesis
|
||||
- login: anthonycepeda
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4
|
||||
url: https://github.com/anthonycepeda
|
||||
- login: euri10
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
|
||||
url: https://github.com/euri10
|
||||
- login: rkbeatss
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/23391143?u=56ab6bff50be950fa8cae5cf736f2ae66e319ff3&v=4
|
||||
url: https://github.com/rkbeatss
|
||||
- login: aviramha
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/41201924?u=6883cc4fc13a7b2e60d4deddd4be06f9c5287880&v=4
|
||||
url: https://github.com/aviramha
|
||||
- login: Zxilly
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31370133?v=4
|
||||
url: https://github.com/Zxilly
|
||||
- login: Bluenix2
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/38372706?u=c9d28aff15958d6ebf1971148bfb3154ff943c4f&v=4
|
||||
url: https://github.com/Bluenix2
|
||||
sponsors_50:
|
||||
- login: johnadjei
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/767860?v=4
|
||||
url: https://github.com/johnadjei
|
||||
- login: wdwinslow
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4
|
||||
url: https://github.com/wdwinslow
|
||||
- login: bingwu-chime
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/67026650?u=603a6b345f25c20c6706a8a6c7f71ae688d649a5&v=4
|
||||
url: https://github.com/bingwu-chime
|
||||
sponsors:
|
||||
- login: kamalgill
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/133923?u=0df9181d97436ce330e9acf90ab8a54b7022efe7&v=4
|
||||
url: https://github.com/kamalgill
|
||||
- login: grillazz
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3415861?u=16d7d0ffa5dfb99f8834f8f76d90e138ba09b94a&v=4
|
||||
url: https://github.com/grillazz
|
||||
- login: tizz98
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5739698?u=f095a3659e3a8e7c69ccd822696990b521ea25f9&v=4
|
||||
url: https://github.com/tizz98
|
||||
- login: jmaralc
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4
|
||||
url: https://github.com/jmaralc
|
||||
- login: psgandalf
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8134158?v=4
|
||||
url: https://github.com/psgandalf
|
||||
- login: samuelcolvin
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=807390ba9cfe23906c3bf8a0d56aaca3cf2bfa0d&v=4
|
||||
url: https://github.com/samuelcolvin
|
||||
- login: jokull
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/701?u=0532b62166893d5160ef795c4c8b7512d971af05&v=4
|
||||
url: https://github.com/jokull
|
||||
- login: wshayes
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
|
||||
url: https://github.com/wshayes
|
||||
- login: koxudaxi
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/630670?u=507d8577b4b3670546b449c4c2ccbc5af40d72f7&v=4
|
||||
url: https://github.com/koxudaxi
|
||||
- login: falkben
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4
|
||||
url: https://github.com/falkben
|
||||
- login: jqueguiner
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/690878?u=e4835b2a985a0f2d52018e4926cb5a58c26a62e8&v=4
|
||||
url: https://github.com/jqueguiner
|
||||
- login: Mazyod
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/860511?v=4
|
||||
url: https://github.com/Mazyod
|
||||
- login: ltieman
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1084689?u=e69b17de17cb3ca141a17daa7ccbe173ceb1eb17&v=4
|
||||
url: https://github.com/ltieman
|
||||
- login: mrmattwright
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1277725?v=4
|
||||
url: https://github.com/mrmattwright
|
||||
- login: westonsteimel
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1593939?u=0f2c0e3647f916fe295d62fa70da7a4c177115e3&v=4
|
||||
url: https://github.com/westonsteimel
|
||||
- login: timdrijvers
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1694939?v=4
|
||||
url: https://github.com/timdrijvers
|
||||
- login: mrgnw
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2504532?u=7ec43837a6d0afa80f96f0788744ea6341b89f97&v=4
|
||||
url: https://github.com/mrgnw
|
||||
- login: madisonmay
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2645393?u=f22b93c6ea345a4d26a90a3834dfc7f0789fcb63&v=4
|
||||
url: https://github.com/madisonmay
|
||||
- login: saivarunk
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2976867?u=71f4385e781e9a9e871a52f2d4686f9a8d69ba2f&v=4
|
||||
url: https://github.com/saivarunk
|
||||
- login: andre1sk
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3148093?v=4
|
||||
url: https://github.com/andre1sk
|
||||
- login: Shark009
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3163309?v=4
|
||||
url: https://github.com/Shark009
|
||||
- login: peterHoburg
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3860655?u=f55f47eb2d6a9b495e806ac5a044e3ae01ccc1fa&v=4
|
||||
url: https://github.com/peterHoburg
|
||||
- login: dudil
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4785835?u=58b7ea39123e0507f3b2996448a27256b16fd697&v=4
|
||||
url: https://github.com/dudil
|
||||
- login: ennui93
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5300907?u=5b5452725ddb391b2caaebf34e05aba873591c3a&v=4
|
||||
url: https://github.com/ennui93
|
||||
- login: sco1
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5323929?u=2b8434060d0c9d93de80a2a945baed94a412c31e&v=4
|
||||
url: https://github.com/sco1
|
||||
- login: MacroPower
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5648814?u=b2730000c9f9a471282b9849d2cc85711d7973d4&v=4
|
||||
url: https://github.com/MacroPower
|
||||
- login: ginomempin
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6091865?v=4
|
||||
url: https://github.com/ginomempin
|
||||
- login: iwpnd
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6152183?u=b2286006daafff5f991557344fee20b5da59639a&v=4
|
||||
url: https://github.com/iwpnd
|
||||
- login: s3ich4n
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6926298?u=ba3025d698e1c986655e776ae383a3d60d9d578e&v=4
|
||||
url: https://github.com/s3ich4n
|
||||
- login: Rehket
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7015688?u=3afb0ba200feebbc7f958950e92db34df2a3c172&v=4
|
||||
url: https://github.com/Rehket
|
||||
- login: christippett
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7218120?u=434b9d29287d7de25772d94ddc74a9bd6d969284&v=4
|
||||
url: https://github.com/christippett
|
||||
- login: Kludex
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=cf8455cb899806b774a3a71073f88583adec99f6&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: Shackelford-Arden
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4
|
||||
url: https://github.com/Shackelford-Arden
|
||||
- login: macleodmac
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8996312?u=e39c68c3e0b1d264dcba4850134a291680f46355&v=4
|
||||
url: https://github.com/macleodmac
|
||||
- login: cristeaadrian
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9112724?v=4
|
||||
url: https://github.com/cristeaadrian
|
||||
- login: otivvormes
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11317418?u=6de1edefb6afd0108c0ad2816bd6efc4464a9c44&v=4
|
||||
url: https://github.com/otivvormes
|
||||
- login: iambobmae
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/12390270?u=c9a35c2ee5092a9b4135ebb1f91b7f521c467031&v=4
|
||||
url: https://github.com/iambobmae
|
||||
- login: ronaldnwilliams
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/13632749?u=ac41a086d0728bf66a9d2bee9e5e377041ff44a4&v=4
|
||||
url: https://github.com/ronaldnwilliams
|
||||
- login: uselessscat
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/15332878?u=8485a1b7383c274b28f383370ee2d5f9a6cd423b&v=4
|
||||
url: https://github.com/uselessscat
|
||||
- login: natenka
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/15850513?u=00d1083c980d0b4ce32835dc07eee7f43f34fd2f&v=4
|
||||
url: https://github.com/natenka
|
||||
- login: la-mar
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16618300?u=7755c0521d2bb0d704f35a51464b15c1e2e6c4da&v=4
|
||||
url: https://github.com/la-mar
|
||||
- login: robintully
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/17059673?u=862b9bb01513f5acd30df97433cb97a24dbfb772&v=4
|
||||
url: https://github.com/robintully
|
||||
- login: ShaulAb
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/18129076?u=2c8d48e47f2dbee15c3f89c3d17d4c356504386c&v=4
|
||||
url: https://github.com/ShaulAb
|
||||
- login: wedwardbeck
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/19333237?u=1de4ae2bf8d59eb4c013f21d863cbe0f2010575f&v=4
|
||||
url: https://github.com/wedwardbeck
|
||||
- login: linusg
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/19366641?u=125e390abef8fff3b3b0d370c369cba5d7fd4c67&v=4
|
||||
url: https://github.com/linusg
|
||||
- login: RedCarpetUp
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/20360440?v=4
|
||||
url: https://github.com/RedCarpetUp
|
||||
- login: daddycocoaman
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/21189155?u=756f6a17c71c538b11470f70839baacab43807ef&v=4
|
||||
url: https://github.com/daddycocoaman
|
||||
- login: Filimoa
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=75e02d102d2ee3e3d793e555fa5c63045913ccb0&v=4
|
||||
url: https://github.com/Filimoa
|
||||
- login: raminsj13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24259406?u=d51f2a526312ebba150a06936ed187ca0727d329&v=4
|
||||
url: https://github.com/raminsj13
|
||||
- login: comoelcometa
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/25950317?u=c6751efa038561b9bc5fa56d1033d5174e10cd65&v=4
|
||||
url: https://github.com/comoelcometa
|
||||
- login: veprimk
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/29689749?u=f8cb5a15a286e522e5b189bc572d5a1a90217fb2&v=4
|
||||
url: https://github.com/veprimk
|
||||
- login: orihomie
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/29889683?u=6bc2135a52fcb3a49e69e7d50190796618185fda&v=4
|
||||
url: https://github.com/orihomie
|
||||
- login: SaltyCoco
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31451104?u=6ee4e17c07d21b7054f54a12fa9cc377a1b24ff9&v=4
|
||||
url: https://github.com/SaltyCoco
|
||||
- login: mauroalejandrojm
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31569442?u=cdada990a1527926a36e95f62c30a8b48bbc49a1&v=4
|
||||
url: https://github.com/mauroalejandrojm
|
||||
- login: public-daniel
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/32238294?u=0377e38dd023395c9643d5388b4e9489a24b4d34&v=4
|
||||
url: https://github.com/public-daniel
|
||||
- login: ybressler
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=6621dc9ab53b697912ab2a32211bb29ae90a9112&v=4
|
||||
url: https://github.com/ybressler
|
||||
- login: dbanty
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=0cf33e4f40efc2ea206a1189fd63a11344eb88ed&v=4
|
||||
url: https://github.com/dbanty
|
||||
- login: dudikbender
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=494f85229115076121b3639a3806bbac1c6ae7f6&v=4
|
||||
url: https://github.com/dudikbender
|
||||
- login: primer-io
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4
|
||||
url: https://github.com/primer-io
|
||||
- login: tkrestiankova
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/67013045?v=4
|
||||
url: https://github.com/tkrestiankova
|
||||
- login: daverin
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/70378377?u=6d1814195c0de7162820eaad95a25b423a3869c0&v=4
|
||||
url: https://github.com/daverin
|
||||
- login: anthonycepeda
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=892f700c79f9732211bd5221bf16eec32356a732&v=4
|
||||
url: https://github.com/anthonycepeda
|
||||
- login: linux-china
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/46711?v=4
|
||||
url: https://github.com/linux-china
|
||||
- login: jhb
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/142217?v=4
|
||||
url: https://github.com/jhb
|
||||
- login: yourkin
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/178984?v=4
|
||||
url: https://github.com/yourkin
|
||||
- login: jmagnusson
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/190835?v=4
|
||||
url: https://github.com/jmagnusson
|
||||
- login: slafs
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4
|
||||
url: https://github.com/slafs
|
||||
- login: adamghill
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/317045?u=f1349d5ffe84a19f324e204777859fbf69ddf633&v=4
|
||||
url: https://github.com/adamghill
|
||||
- login: eteq
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/346587?v=4
|
||||
url: https://github.com/eteq
|
||||
- login: dmig
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/388564?v=4
|
||||
url: https://github.com/dmig
|
||||
- login: hongqn
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/405587?u=470b4c04832e45141fd5264d3354845cc9fc6466&v=4
|
||||
url: https://github.com/hongqn
|
||||
- login: rinckd
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/546002?u=1fcc7e664dc86524a0af6837a0c222829c3fd4e5&v=4
|
||||
url: https://github.com/rinckd
|
||||
- login: Pytlicek
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1430522?u=169dba3bfbc04ed214a914640ff435969f19ddb3&v=4
|
||||
url: https://github.com/Pytlicek
|
||||
- login: okken
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1568356?u=0a991a21bdc62e2bea9ad311652f2c45f453dc84&v=4
|
||||
url: https://github.com/okken
|
||||
- login: leogregianin
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1684053?u=94ddd387601bd1805034dbe83e6eba0491c15323&v=4
|
||||
url: https://github.com/leogregianin
|
||||
- login: cbonoz
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2351087?u=fd3e8030b2cc9fbfbb54a65e9890c548a016f58b&v=4
|
||||
url: https://github.com/cbonoz
|
||||
- login: rglsk
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2768101?u=e349c88673f2155fe021331377c656a9d74bcc25&v=4
|
||||
url: https://github.com/rglsk
|
||||
- login: Atem18
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2875254?v=4
|
||||
url: https://github.com/Atem18
|
||||
- login: paul121
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3116995?u=6e2d8691cc345e63ee02e4eb4d7cef82b1fcbedc&v=4
|
||||
url: https://github.com/paul121
|
||||
- login: igorcorrea
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3438238?u=c57605077c31a8f7b2341fc4912507f91b4a5621&v=4
|
||||
url: https://github.com/igorcorrea
|
||||
- login: zsinx6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4
|
||||
url: https://github.com/zsinx6
|
||||
- login: pawamoy
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4
|
||||
url: https://github.com/pawamoy
|
||||
- login: spyker77
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4953435?u=568baae6469628e020fe0bab16e395b7ae10c7d3&v=4
|
||||
url: https://github.com/spyker77
|
||||
- login: serfer2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5196592?u=e8798d87120952ed41876778f0cc8a1ddb47f901&v=4
|
||||
url: https://github.com/serfer2
|
||||
- login: JonasKs
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5310116?u=98a049f3e1491bffb91e1feb7e93def6881a9389&v=4
|
||||
url: https://github.com/JonasKs
|
||||
- login: holec
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6438041?u=f5af71ec85b3a9d7b8139cb5af0512b02fa9ab1e&v=4
|
||||
url: https://github.com/holec
|
||||
- login: BartlomiejRasztabiga
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8852711?u=ed213d60f7a423df31ceb1004aa3ec60e612cb98&v=4
|
||||
url: https://github.com/BartlomiejRasztabiga
|
||||
- login: davanstrien
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8995957?u=fb2aad2b52bb4e7b56db6d7c8ecc9ae1eac1b984&v=4
|
||||
url: https://github.com/davanstrien
|
||||
- login: and-semakin
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9129071?u=ea77ddf7de4bc375d546bf2825ed420eaddb7666&v=4
|
||||
url: https://github.com/and-semakin
|
||||
- login: VivianSolide
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9358572?u=ffb2e2ec522a15dcd3f0af1f9fd1df4afe418afa&v=4
|
||||
url: https://github.com/VivianSolide
|
||||
- login: hard-coders
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=f2d3d2038c55d86d7f9348f4e6c5e30191e4ee8b&v=4
|
||||
url: https://github.com/hard-coders
|
||||
- login: satwikkansal
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10217535?u=b12d6ef74ea297de9e46da6933b1a5b7ba9e6a61&v=4
|
||||
url: https://github.com/satwikkansal
|
||||
- login: pheanex
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10408624?u=5b6bab6ee174aa6e991333e06eb29f628741013d&v=4
|
||||
url: https://github.com/pheanex
|
||||
- login: wotori
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10486621?u=0044c295b91694b8c9bccc0a805681f794250f7b&v=4
|
||||
url: https://github.com/wotori
|
||||
- login: JimFawkes
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/12075115?u=dc58ecfd064d72887c34bf500ddfd52592509acd&v=4
|
||||
url: https://github.com/JimFawkes
|
||||
- login: logan-connolly
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16244943?u=8ae66dfbba936463cc8aa0dd7a6d2b4c0cc757eb&v=4
|
||||
url: https://github.com/logan-connolly
|
||||
- login: iPr0ger
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/19322290?v=4
|
||||
url: https://github.com/iPr0ger
|
||||
- login: sadikkuzu
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=765ed469c44c004560079210ccdad5b29938eaa9&v=4
|
||||
url: https://github.com/sadikkuzu
|
||||
- login: ghandic
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
|
||||
url: https://github.com/ghandic
|
||||
- login: MoronVV
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24293616?v=4
|
||||
url: https://github.com/MoronVV
|
||||
- login: AngusWG
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/26385612?u=f4d4c8bd2097cdd58eb9e385932b83c78777f3c0&v=4
|
||||
url: https://github.com/AngusWG
|
||||
- login: mertguvencli
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4
|
||||
url: https://github.com/mertguvencli
|
||||
- login: rgreen32
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/35779241?u=c9d64ad1ab364b6a1ec8e3d859da9ca802d681d8&v=4
|
||||
url: https://github.com/rgreen32
|
||||
- login: askurihin
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37978981?v=4
|
||||
url: https://github.com/askurihin
|
||||
- login: berrysauce
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/38889179?u=758ed15a5be8bbd03855f5a74f42c19f7946ee32&v=4
|
||||
url: https://github.com/berrysauce
|
||||
- login: JitPackJoyride
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/40203625?u=9638bfeacfa5940358188f8205ce662bba022b53&v=4
|
||||
url: https://github.com/JitPackJoyride
|
||||
- login: es3n1n
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/40367813?u=e881a3880f1e342d19a1ea7c8e1b6d76c52dc294&v=4
|
||||
url: https://github.com/es3n1n
|
||||
- login: ilias-ant
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4
|
||||
url: https://github.com/ilias-ant
|
||||
- login: kbhatiya999
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/47816034?v=4
|
||||
url: https://github.com/kbhatiya999
|
||||
- login: akanz1
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/51492342?u=2280f57134118714645e16b535c1a37adf6b369b&v=4
|
||||
url: https://github.com/akanz1
|
||||
- login: rychardvale
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/54805553?u=3d20ab05301d05f9ac3500fb79a2bfee3842b753&v=4
|
||||
url: https://github.com/rychardvale
|
||||
- login: athemeart
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/61623624?v=4
|
||||
url: https://github.com/athemeart
|
||||
- login: Rhythmicc
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/29839231?u=2100781089a259707c475c4547bd7995b0fc18ee&v=4
|
||||
url: https://github.com/Rhythmicc
|
||||
21
docs/en/data/sponsors.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
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://bit.ly/2QSouzH
|
||||
title: "Jina: build neural search-as-a-service for any kind of data in just minutes."
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/jina.svg
|
||||
silver:
|
||||
- url: https://www.investsuite.com/jobs
|
||||
title: Wealthtech jobs with FastAPI
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/investsuite.svg
|
||||
- url: https://www.vim.so/?utm_source=FastAPI
|
||||
title: We help you master vim with interactive exercises
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/vimso.png
|
||||
- url: https://talkpython.fm/fastapi-sponsor
|
||||
title: FastAPI video courses on demand from people you trust
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/talkpython.png
|
||||
bronze:
|
||||
- url: https://testdriven.io/courses/tdd-fastapi/
|
||||
title: Learn to build high-quality web apps with best practices
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/testdriven.svg
|
||||
@@ -23,7 +23,7 @@ Each of those response `dict`s can have a key `model`, containing a Pydantic mod
|
||||
|
||||
For example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write:
|
||||
|
||||
```Python hl_lines="18 23"
|
||||
```Python hl_lines="18 23"
|
||||
{!../../../docs_src/additional_responses/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -44,7 +44,7 @@ For example, to declare another response with a status code `404` and a Pydantic
|
||||
|
||||
The generated responses in the OpenAPI for this *path operation* will be:
|
||||
|
||||
```JSON hl_lines="3 4 5 6 7 8 9 10 11 12"
|
||||
```JSON hl_lines="3-12"
|
||||
{
|
||||
"responses": {
|
||||
"404": {
|
||||
@@ -83,7 +83,7 @@ The generated responses in the OpenAPI for this *path operation* will be:
|
||||
|
||||
The schemas are referenced to another place inside the OpenAPI schema:
|
||||
|
||||
```JSON hl_lines="4 5 6 7 8 9 10 11 12 13 14 15 16"
|
||||
```JSON hl_lines="4-16"
|
||||
{
|
||||
"components": {
|
||||
"schemas": {
|
||||
@@ -168,7 +168,7 @@ You can use this same `responses` parameter to add different media types for the
|
||||
|
||||
For example, you can add an additional media type of `image/png`, declaring that your *path operation* can return a JSON object (with media type `application/json`) or a PNG image:
|
||||
|
||||
```Python hl_lines="17 18 19 20 21 22 23 24 28"
|
||||
```Python hl_lines="19-24 28"
|
||||
{!../../../docs_src/additional_responses/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -192,7 +192,7 @@ For example, you can declare a response with a status code `404` that uses a Pyd
|
||||
|
||||
And a response with a status code `200` that uses your `response_model`, but includes a custom `example`:
|
||||
|
||||
```Python hl_lines="20 21 22 23 24 25 26 27 28 29 30 31"
|
||||
```Python hl_lines="20-31"
|
||||
{!../../../docs_src/additional_responses/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -228,7 +228,7 @@ You can use that technique to re-use some predefined responses in your *path ope
|
||||
|
||||
For example:
|
||||
|
||||
```Python hl_lines="11 12 13 14 15 24"
|
||||
```Python hl_lines="13-17 26"
|
||||
{!../../../docs_src/additional_responses/tutorial004.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ But you also want it to accept new items. And when the items didn't exist before
|
||||
|
||||
To achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want:
|
||||
|
||||
```Python hl_lines="2 19"
|
||||
```Python hl_lines="4 23"
|
||||
{!../../../docs_src/additional_status_codes/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ Later, for your production application, you might want to use a database server
|
||||
* Create a `metadata` object.
|
||||
* Create a table `notes` using the `metadata` object.
|
||||
|
||||
```Python hl_lines="4 14 16 17 18 19 20 21 22"
|
||||
```Python hl_lines="4 14 16-22"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -38,7 +38,7 @@ Later, for your production application, you might want to use a database server
|
||||
* Create a `DATABASE_URL`.
|
||||
* Create a `database` object.
|
||||
|
||||
```Python hl_lines="3 9 12"
|
||||
```Python hl_lines="3 9 12"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -54,7 +54,7 @@ Here, this section would run directly, right before starting your **FastAPI** ap
|
||||
* Create an `engine`.
|
||||
* Create all the tables from the `metadata` object.
|
||||
|
||||
```Python hl_lines="25 26 27 28"
|
||||
```Python hl_lines="25-28"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -65,7 +65,7 @@ Create Pydantic models for:
|
||||
* Notes to be created (`NoteIn`).
|
||||
* Notes to be returned (`Note`).
|
||||
|
||||
```Python hl_lines="31 32 33 36 37 38 39"
|
||||
```Python hl_lines="31-33 36-39"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -78,7 +78,7 @@ So, you will be able to see it all in the interactive API docs.
|
||||
* Create your `FastAPI` application.
|
||||
* Create event handlers to connect and disconnect from the database.
|
||||
|
||||
```Python hl_lines="42 45 46 47 50 51 52"
|
||||
```Python hl_lines="42 45-47 50-52"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -86,7 +86,7 @@ So, you will be able to see it all in the interactive API docs.
|
||||
|
||||
Create the *path operation function* to read notes:
|
||||
|
||||
```Python hl_lines="55 56 57 58"
|
||||
```Python hl_lines="55-58"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -103,7 +103,7 @@ That documents (and validates, serializes, filters) the output data, as a `list`
|
||||
|
||||
Create the *path operation function* to create notes:
|
||||
|
||||
```Python hl_lines="61 62 63 64 65"
|
||||
```Python hl_lines="61-65"
|
||||
{!../../../docs_src/async_sql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
100
docs/en/docs/advanced/async-tests.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Async Tests
|
||||
|
||||
You have already seen how to test your **FastAPI** applications using the provided `TestClient`, but with it, you can't test or run any other `async` function in your (synchronous) pytest functions.
|
||||
|
||||
Being able to use asynchronous functions in your tests could be useful, for example, when you're querying your database asynchronously. Imagine you want to test sending requests to your FastAPI application and then verify that your backend successfully wrote the correct data in the database, while using an async database library.
|
||||
|
||||
Let's look at how we can make that work.
|
||||
|
||||
## pytest-asyncio
|
||||
|
||||
If we want to call asynchronous functions in our tests, our test functions have to be asynchronous. Pytest provides a neat library for this, called `pytest-asyncio`, that allows us to specify that some test functions are to be called asynchronously.
|
||||
|
||||
You can install it via:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install pytest-asyncio
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## HTTPX
|
||||
|
||||
Even if your **FastAPI** application uses normal `def` functions instead of `async def`, it is still an `async` application underneath.
|
||||
|
||||
The `TestClient` does some magic inside to call the asynchronous FastAPI application in your normal `def` test functions, using standard pytest. But that magic doesn't work anymore when we're using it inside asynchronous functions. By running our tests asynchronously, we can no longer use the `TestClient` inside our test functions.
|
||||
|
||||
Luckily there's a nice alternative, called <a href="https://www.python-httpx.org/" class="external-link" target="_blank">HTTPX</a>.
|
||||
|
||||
HTTPX is an HTTP client for Python 3 that allows us to query our FastAPI application similarly to how we did it with the `TestClient`.
|
||||
|
||||
If you're familiar with the <a href="https://requests.readthedocs.io/en/master/" class="external-link" target="_blank">Requests</a> library, you'll find that the API of HTTPX is almost identical.
|
||||
|
||||
The important difference for us is that with HTTPX we are not limited to synchronous, but can also make asynchronous requests.
|
||||
|
||||
## Example
|
||||
|
||||
For a simple example, let's consider the following `main.py` module:
|
||||
|
||||
```Python
|
||||
{!../../../docs_src/async_tests/main.py!}
|
||||
```
|
||||
|
||||
The `test_main.py` module that contains the tests for `main.py` could look like this now:
|
||||
|
||||
```Python
|
||||
{!../../../docs_src/async_tests/test_main.py!}
|
||||
```
|
||||
|
||||
## Run it
|
||||
|
||||
You can run your tests as usual via:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pytest
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## In Detail
|
||||
|
||||
The marker `@pytest.mark.asyncio` tells pytest that this test function should be called asynchronously:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!../../../docs_src/async_tests/test_main.py!}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Note that the test function is now `async def` instead of just `def` as before when using the `TestClient`.
|
||||
|
||||
Then we can create an `AsyncClient` with the app, and send async requests to it, using `await`.
|
||||
|
||||
```Python hl_lines="9-10"
|
||||
{!../../../docs_src/async_tests/test_main.py!}
|
||||
```
|
||||
|
||||
This is the equivalent to:
|
||||
|
||||
```Python
|
||||
response = client.get('/')
|
||||
```
|
||||
|
||||
that we used to make our requests with the `TestClient`.
|
||||
|
||||
!!! tip
|
||||
Note that we're using async/await with the new `AsyncClient` - the request is asynchronous.
|
||||
|
||||
## Other Asynchronous Function Calls
|
||||
|
||||
As the testing function is now asynchronous, you can now also call (and `await`) other `async` functions apart from sending requests to your FastAPI application in your tests, exactly as you would call them anywhere else in your code.
|
||||
|
||||
!!! tip
|
||||
If you encounter a `RuntimeError: Task attached to a different loop` when integrating asynchronous function calls in your tests (e.g. when using <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">MongoDB's MotorClient</a>) check out <a href="https://github.com/pytest-dev/pytest-asyncio/issues/38#issuecomment-264418154" class="external-link" target="_blank">this issue</a> in the pytest-asyncio repository.
|
||||
346
docs/en/docs/advanced/behind-a-proxy.md
Normal file
@@ -0,0 +1,346 @@
|
||||
# Behind a Proxy
|
||||
|
||||
In some situations, you might need to use a **proxy** server like Traefik or Nginx with a configuration that adds an extra path prefix that is not seen by your application.
|
||||
|
||||
In these cases you can use `root_path` to configure your application.
|
||||
|
||||
The `root_path` is a mechanism provided by the ASGI specification (that FastAPI is built on, through Starlette).
|
||||
|
||||
The `root_path` is used to handle these specific cases.
|
||||
|
||||
And it's also used internally when mounting sub-applications.
|
||||
|
||||
## Proxy with a stripped path prefix
|
||||
|
||||
Having a proxy with a stripped path prefix, in this case, means that you could declare a path at `/app` in your code, but then, you add a layer on top (the proxy) that would put your **FastAPI** application under a path like `/api/v1`.
|
||||
|
||||
In this case, the original path `/app` would actually be served at `/api/v1/app`.
|
||||
|
||||
Even though all your code is written assuming there's just `/app`.
|
||||
|
||||
And the proxy would be **"stripping"** the **path prefix** on the fly before transmitting the request to Uvicorn, keep your application convinced that it is serving at `/app`, so that you don't have to update all your code to include the prefix `/api/v1`.
|
||||
|
||||
Up to here, everything would work as normally.
|
||||
|
||||
But then, when you open the integrated docs UI (the frontend), it would expect to get the OpenAPI schema at `/openapi.json`, instead of `/api/v1/openapi.json`.
|
||||
|
||||
So, the frontend (that runs in the browser) would try to reach `/openapi.json` and wouldn't be able to get the OpenAPI schema.
|
||||
|
||||
Because we have a proxy with a path prefix of `/api/v1` for our app, the frontend needs to fetch the OpenAPI schema at `/api/v1/openapi.json`.
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
|
||||
browser("Browser")
|
||||
proxy["Proxy on http://0.0.0.0:9999/api/v1/app"]
|
||||
server["Server on http://127.0.0.1:8000/app"]
|
||||
|
||||
browser --> proxy
|
||||
proxy --> server
|
||||
```
|
||||
|
||||
!!! tip
|
||||
The IP `0.0.0.0` is commonly used to mean that the program listens on all the IPs available in that machine/server.
|
||||
|
||||
The docs UI would also need the OpenAPI schema to declare that this API `server` is located at `/api/v1` (behind the proxy). For example:
|
||||
|
||||
```JSON hl_lines="4-8"
|
||||
{
|
||||
"openapi": "3.0.2",
|
||||
// More stuff here
|
||||
"servers": [
|
||||
{
|
||||
"url": "/api/v1"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
// More stuff here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the "Proxy" could be something like **Traefik**. And the server would be something like **Uvicorn**, running your FastAPI application.
|
||||
|
||||
### Providing the `root_path`
|
||||
|
||||
To achieve this, you can use the command line option `--root-path` like:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
If you use Hypercorn, it also has the option `--root-path`.
|
||||
|
||||
!!! note "Technical Details"
|
||||
The ASGI specification defines a `root_path` for this use case.
|
||||
|
||||
And the `--root-path` command line option provides that `root_path`.
|
||||
|
||||
### Checking the current `root_path`
|
||||
|
||||
You can get the current `root_path` used by your application for each request, it is part of the `scope` dictionary (that's part of the ASGI spec).
|
||||
|
||||
Here we are including it in the message just for demonstration purposes.
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!../../../docs_src/behind_a_proxy/tutorial001.py!}
|
||||
```
|
||||
|
||||
Then, if you start Uvicorn with:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
The response would be something like:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
### Setting the `root_path` in the FastAPI app
|
||||
|
||||
Alternatively, if you don't have a way to provide a command line option like `--root-path` or equivalent, you can set the `root_path` parameter when creating your FastAPI app:
|
||||
|
||||
```Python hl_lines="3"
|
||||
{!../../../docs_src/behind_a_proxy/tutorial002.py!}
|
||||
```
|
||||
|
||||
Passing the `root_path` to `FastAPI` would be the equivalent of passing the `--root-path` command line option to Uvicorn or Hypercorn.
|
||||
|
||||
### About `root_path`
|
||||
|
||||
Have in mind that the server (Uvicorn) won't use that `root_path` for anything else than passing it to the app.
|
||||
|
||||
But if you go with your browser to <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000/app</a> you will see the normal response:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
So, it won't expect to be accessed at `http://127.0.0.1:8000/api/v1/app`.
|
||||
|
||||
Uvicorn will expect the proxy to access Uvicorn at `http://127.0.0.1:8000/app`, and then it would be the proxy's responsibility to add the extra `/api/v1` prefix on top.
|
||||
|
||||
## About proxies with a stripped path prefix
|
||||
|
||||
Have in mind that a proxy with stripped path prefix is only one of the ways to configure it.
|
||||
|
||||
Probably in many cases the default will be that the proxy doesn't have a stripped path prefix.
|
||||
|
||||
In a case like that (without a stripped path prefix), the proxy would listen on something like `https://myawesomeapp.com`, and then if the browser goes to `https://myawesomeapp.com/api/v1/app` and your server (e.g. Uvicorn) listens on `http://127.0.0.1:8000` the proxy (without a stripped path prefix) would access Uvicorn at the same path: `http://127.0.0.1:8000/api/v1/app`.
|
||||
|
||||
## Testing locally with Traefik
|
||||
|
||||
You can easily run the experiment locally with a stripped path prefix using <a href="https://docs.traefik.io/" class="external-link" target="_blank">Traefik</a>.
|
||||
|
||||
<a href="https://github.com/containous/traefik/releases" class="external-link" target="_blank">Download Traefik</a>, it's a single binary, you can extract the compressed file and run it directly from the terminal.
|
||||
|
||||
Then create a file `traefik.toml` with:
|
||||
|
||||
```TOML hl_lines="3"
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":9999"
|
||||
|
||||
[providers]
|
||||
[providers.file]
|
||||
filename = "routes.toml"
|
||||
```
|
||||
|
||||
This tells Traefik to listen on port 9999 and to use another file `routes.toml`.
|
||||
|
||||
!!! tip
|
||||
We are using port 9999 instead of the standard HTTP port 80 so that you don't have to run it with admin (`sudo`) privileges.
|
||||
|
||||
Now create that other file `routes.toml`:
|
||||
|
||||
```TOML hl_lines="5 12 20"
|
||||
[http]
|
||||
[http.middlewares]
|
||||
|
||||
[http.middlewares.api-stripprefix.stripPrefix]
|
||||
prefixes = ["/api/v1"]
|
||||
|
||||
[http.routers]
|
||||
|
||||
[http.routers.app-http]
|
||||
entryPoints = ["http"]
|
||||
service = "app"
|
||||
rule = "PathPrefix(`/api/v1`)"
|
||||
middlewares = ["api-stripprefix"]
|
||||
|
||||
[http.services]
|
||||
|
||||
[http.services.app]
|
||||
[http.services.app.loadBalancer]
|
||||
[[http.services.app.loadBalancer.servers]]
|
||||
url = "http://127.0.0.1:8000"
|
||||
```
|
||||
|
||||
This file configures Traefik to use the path prefix `/api/v1`.
|
||||
|
||||
And then it will redirect its requests to your Uvicorn running on `http://127.0.0.1:8000`.
|
||||
|
||||
Now start Traefik:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ ./traefik --configFile=traefik.toml
|
||||
|
||||
INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
And now start your app with Uvicorn, using the `--root-path` option:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Check the responses
|
||||
|
||||
Now, if you go to the URL with the port for Uvicorn: <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a>, you will see the normal response:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Notice that even though you are accessing it at `http://127.0.0.1:8000/app` it shows the `root_path` of `/api/v1`, taken from the option `--root-path`.
|
||||
|
||||
And now open the URL with the port for Traefik, including the path prefix: <a href="http://127.0.0.1:9999/api/v1/app" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/app</a>.
|
||||
|
||||
We get the same response:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
but this time at the URL with the prefix path provided by the proxy: `/api/v1`.
|
||||
|
||||
Of course, the idea here is that everyone would access the app through the proxy, so the version with the path prefix `/app/v1` is the "correct" one.
|
||||
|
||||
And the version without the path prefix (`http://127.0.0.1:8000/app`), provided by Uvicorn directly, would be exclusively for the _proxy_ (Traefik) to access it.
|
||||
|
||||
That demonstrates how the Proxy (Traefik) uses the path prefix and how the server (Uvicorn) uses the `root_path` from the option `--root-path`.
|
||||
|
||||
### Check the docs UI
|
||||
|
||||
But here's the fun part. ✨
|
||||
|
||||
The "official" way to access the app would be through the proxy with the path prefix that we defined. So, as we would expect, if you try the docs UI served by Uvicorn directly, without the path prefix in the URL, it won't work, because it expects to be accessed through the proxy.
|
||||
|
||||
You can check it at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image01.png">
|
||||
|
||||
But if we access the docs UI at the "official" URL using the proxy with port `9999`, at `/api/v1/docs`, it works correctly! 🎉
|
||||
|
||||
You can check it at <a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a>:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image02.png">
|
||||
|
||||
Right as we wanted it. ✔️
|
||||
|
||||
This is because FastAPI uses this `root_path` to create the default `server` in OpenAPI with the URL provided by `root_path`.
|
||||
|
||||
## Additional servers
|
||||
|
||||
!!! warning
|
||||
This is a more advanced use case. Feel free to skip it.
|
||||
|
||||
By default, **FastAPI** will create a `server` in the OpenAPI schema with the URL for the `root_path`.
|
||||
|
||||
But you can also provide other alternative `servers`, for example if you want *the same* docs UI to interact with a staging and production environments.
|
||||
|
||||
If you pass a custom list of `servers` and there's a `root_path` (because your API lives behind a proxy), **FastAPI** will insert a "server" with this `root_path` at the beginning of the list.
|
||||
|
||||
For example:
|
||||
|
||||
```Python hl_lines="4-7"
|
||||
{!../../../docs_src/behind_a_proxy/tutorial003.py!}
|
||||
```
|
||||
|
||||
Will generate an OpenAPI schema like:
|
||||
|
||||
```JSON hl_lines="5-7"
|
||||
{
|
||||
"openapi": "3.0.2",
|
||||
// More stuff here
|
||||
"servers": [
|
||||
{
|
||||
"url": "/api/v1"
|
||||
},
|
||||
{
|
||||
"url": "https://stag.example.com",
|
||||
"description": "Staging environment"
|
||||
},
|
||||
{
|
||||
"url": "https://prod.example.com",
|
||||
"description": "Production environment"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
// More stuff here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Notice the auto-generated server with a `url` value of `/api/v1`, taken from the `root_path`.
|
||||
|
||||
In the docs UI at <a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a> it would look like:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image03.png">
|
||||
|
||||
!!! tip
|
||||
The docs UI will interact with the server that you select.
|
||||
|
||||
### Disable automatic server from `root_path`
|
||||
|
||||
If you don't want **FastAPI** to include an automatic server using the `root_path`, you can use the parameter `root_path_in_servers=False`:
|
||||
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/behind_a_proxy/tutorial004.py!}
|
||||
```
|
||||
|
||||
and then it won't include it in the OpenAPI schema.
|
||||
|
||||
## Mounting a sub-application
|
||||
|
||||
If you need to mount a sub-application (as described in [Sub Applications - Mounts](./sub-applications.md){.internal-link target=_blank}) while also using a proxy with `root_path`, you can do it normally, as you would expect.
|
||||
|
||||
FastAPI will internally use the `root_path` smartly, so it will just work. ✨
|
||||
@@ -36,7 +36,7 @@ If there's no `gzip` in the header, it will not try to decompress the body.
|
||||
|
||||
That way, the same route class can handle gzip compressed or uncompressed requests.
|
||||
|
||||
```Python hl_lines="8 9 10 11 12 13 14 15"
|
||||
```Python hl_lines="8-15"
|
||||
{!../../../docs_src/custom_request_and_route/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -50,7 +50,7 @@ This method returns a function. And that function is what will receive a request
|
||||
|
||||
Here we use it to create a `GzipRequest` from the original request.
|
||||
|
||||
```Python hl_lines="18 19 20 21 22 23 24 25 26"
|
||||
```Python hl_lines="18-26"
|
||||
{!../../../docs_src/custom_request_and_route/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -84,13 +84,13 @@ We can also use this same approach to access the request body in an exception ha
|
||||
|
||||
All we need to do is handle the request inside a `try`/`except` block:
|
||||
|
||||
```Python hl_lines="13 15"
|
||||
```Python hl_lines="13 15"
|
||||
{!../../../docs_src/custom_request_and_route/tutorial002.py!}
|
||||
```
|
||||
|
||||
If an exception occurs, the`Request` instance will still be in scope, so we can read and make use of the request body when handling the error:
|
||||
|
||||
```Python hl_lines="16 17 18"
|
||||
```Python hl_lines="16-18"
|
||||
{!../../../docs_src/custom_request_and_route/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -104,6 +104,6 @@ You can also set the `route_class` parameter of an `APIRouter`:
|
||||
|
||||
In this example, the *path operations* under the `router` will use the custom `TimedRoute` class, and will have an extra `X-Response-Time` header in the response with the time it took to generate the response:
|
||||
|
||||
```Python hl_lines="13 14 15 16 17 18 19 20"
|
||||
```Python hl_lines="13-20"
|
||||
{!../../../docs_src/custom_request_and_route/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -21,7 +21,7 @@ For example, if you are squeezing performance, you can install and use <a href="
|
||||
|
||||
Import the `Response` class (sub-class) you want to use and declare it in the *path operation decorator*.
|
||||
|
||||
```Python hl_lines="2 7"
|
||||
```Python hl_lines="2 7"
|
||||
{!../../../docs_src/custom_response/tutorial001b.py!}
|
||||
```
|
||||
|
||||
@@ -40,9 +40,9 @@ Import the `Response` class (sub-class) you want to use and declare it in the *p
|
||||
To return a response with HTML directly from **FastAPI**, use `HTMLResponse`.
|
||||
|
||||
* Import `HTMLResponse`.
|
||||
* Pass `HTMLResponse` as the parameter `content_type` of your *path operation*.
|
||||
* Pass `HTMLResponse` as the parameter `response_class` of your *path operation decorator*.
|
||||
|
||||
```Python hl_lines="2 7"
|
||||
```Python hl_lines="2 7"
|
||||
{!../../../docs_src/custom_response/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -59,7 +59,7 @@ As seen in [Return a Response directly](response-directly.md){.internal-link tar
|
||||
|
||||
The same example from above, returning an `HTMLResponse`, could look like:
|
||||
|
||||
```Python hl_lines="2 7 19"
|
||||
```Python hl_lines="2 7 19"
|
||||
{!../../../docs_src/custom_response/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -79,7 +79,7 @@ The `response_class` will then be used only to document the OpenAPI *path operat
|
||||
|
||||
For example, it could be something like:
|
||||
|
||||
```Python hl_lines="7 23 21"
|
||||
```Python hl_lines="7 21 23"
|
||||
{!../../../docs_src/custom_response/tutorial004.py!}
|
||||
```
|
||||
|
||||
@@ -150,7 +150,7 @@ An alternative JSON response using <a href="https://github.com/ultrajson/ultrajs
|
||||
!!! warning
|
||||
`ujson` is less careful than Python's built-in implementation in how it handles some edge-cases.
|
||||
|
||||
```Python hl_lines="2 7"
|
||||
```Python hl_lines="2 7"
|
||||
{!../../../docs_src/custom_response/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -161,10 +161,33 @@ An alternative JSON response using <a href="https://github.com/ultrajson/ultrajs
|
||||
|
||||
Returns an HTTP redirect. Uses a 307 status code (Temporary Redirect) by default.
|
||||
|
||||
You can return a `RedirectResponse` directly:
|
||||
|
||||
```Python hl_lines="2 9"
|
||||
{!../../../docs_src/custom_response/tutorial006.py!}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Or you can use it in the `response_class` parameter:
|
||||
|
||||
|
||||
```Python hl_lines="2 7 9"
|
||||
{!../../../docs_src/custom_response/tutorial006b.py!}
|
||||
```
|
||||
|
||||
If you do that, then you can return the URL directly from your *path operation* function.
|
||||
|
||||
In this case, the `status_code` used will be the default one for the `RedirectResponse`, which is `307`.
|
||||
|
||||
---
|
||||
|
||||
You can also use the `status_code` parameter combined with the `response_class` parameter:
|
||||
|
||||
```Python hl_lines="2 7 9"
|
||||
{!../../../docs_src/custom_response/tutorial006c.py!}
|
||||
```
|
||||
|
||||
### `StreamingResponse`
|
||||
|
||||
Takes an async generator or a normal generator/iterator and streams the response body.
|
||||
@@ -175,14 +198,24 @@ Takes an async generator or a normal generator/iterator and streams the response
|
||||
|
||||
#### Using `StreamingResponse` with file-like objects
|
||||
|
||||
If you have a file-like object (e.g. the object returned by `open()`), you can return it in a `StreamingResponse`.
|
||||
If you have a file-like object (e.g. the object returned by `open()`), you can create a generator function to iterate over that file-like object.
|
||||
|
||||
That way, you don't have to read it all first in memory, and you can pass that generator function to the `StreamingResponse`, and return it.
|
||||
|
||||
This includes many libraries to interact with cloud storage, video processing, and others.
|
||||
|
||||
```Python hl_lines="2 10 11"
|
||||
```{ .python .annotate hl_lines="2 10-12 14" }
|
||||
{!../../../docs_src/custom_response/tutorial008.py!}
|
||||
```
|
||||
|
||||
1. This is the generator function. It's a "generator function" because it contains `yield` statements inside.
|
||||
2. By using a `with` block, we make sure that the file-like object is closed after the generator function is done. So, after it finishes sending the response.
|
||||
3. This `yield from` tells the function to iterate over that thing named `file_like`. And then, for each part iterated, yield that part as coming from this generator function.
|
||||
|
||||
So, it is a generator function that transfers the "generating" work to something else internally.
|
||||
|
||||
By doing it this way, we can put it in a `with` block, and that way, ensure that it is closed after finishing.
|
||||
|
||||
!!! tip
|
||||
Notice that here as we are using standard `open()` that doesn't support `async` and `await`, we declare the path operation with normal `def`.
|
||||
|
||||
@@ -203,6 +236,29 @@ File responses will include appropriate `Content-Length`, `Last-Modified` and `E
|
||||
{!../../../docs_src/custom_response/tutorial009.py!}
|
||||
```
|
||||
|
||||
You can also use the `response_class` parameter:
|
||||
|
||||
```Python hl_lines="2 8 10"
|
||||
{!../../../docs_src/custom_response/tutorial009b.py!}
|
||||
```
|
||||
|
||||
In this case, you can return the file path directly from your *path operation* function.
|
||||
|
||||
## Default response class
|
||||
|
||||
When creating a **FastAPI** class instance or an `APIRouter` you can specify which response class to use by default.
|
||||
|
||||
The parameter that defines this is `default_response_class`.
|
||||
|
||||
In the example below, **FastAPI** will use `ORJSONResponse` by default, in all *path operations*, instead of `JSONResponse`.
|
||||
|
||||
```Python hl_lines="2 4"
|
||||
{!../../../docs_src/custom_response/tutorial010.py!}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
You can still override `response_class` in *path operations* as before.
|
||||
|
||||
## Additional documentation
|
||||
|
||||
You can also declare the media type and many other details in OpenAPI using `responses`: [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
|
||||
98
docs/en/docs/advanced/dataclasses.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Using Dataclasses
|
||||
|
||||
FastAPI is built on top of **Pydantic**, and I have been showing you how to use Pydantic models to declare requests and responses.
|
||||
|
||||
But FastAPI also supports using <a href="https://docs.python.org/3/library/dataclasses.html" class="external-link" target="_blank">`dataclasses`</a> the same way:
|
||||
|
||||
```Python hl_lines="1 7-12 19-20"
|
||||
{!../../../docs_src/dataclasses/tutorial001.py!}
|
||||
```
|
||||
|
||||
This is still thanks to **Pydantic**, as it has <a href="https://pydantic-docs.helpmanual.io/usage/dataclasses/#use-of-stdlib-dataclasses-with-basemodel" class="external-link" target="_blank">internal support for `dataclasses`</a>.
|
||||
|
||||
So, even with the code above that doesn't use Pydantic explicitly, FastAPI is using Pydantic to convert those standard dataclasses to Pydantic's own flavor of dataclasses.
|
||||
|
||||
And of course, it supports the same:
|
||||
|
||||
* data validation
|
||||
* data serialization
|
||||
* data documentation, etc.
|
||||
|
||||
This works the same way as with Pydantic models. And it is actually achieved in the same way underneath, using Pydantic.
|
||||
|
||||
!!! info
|
||||
Have in mind that dataclasses can't do everything Pydantic models can do.
|
||||
|
||||
So, you might still need to use Pydantic models.
|
||||
|
||||
But if you have a bunch of dataclasses laying around, this is a nice trick to use them to power a web API using FastAPI. 🤓
|
||||
|
||||
## Dataclasses in `response_model`
|
||||
|
||||
You can also use `dataclasses` in the `response_model` parameter:
|
||||
|
||||
```Python hl_lines="1 7-13 19"
|
||||
{!../../../docs_src/dataclasses/tutorial002.py!}
|
||||
```
|
||||
|
||||
The dataclass will be automatically converted to a Pydantic dataclass.
|
||||
|
||||
This way, its schema will show up in the API docs user interface:
|
||||
|
||||
<img src="/img/tutorial/dataclasses/image01.png">
|
||||
|
||||
## Dataclasses in Nested Data Structures
|
||||
|
||||
You can also combine `dataclasses` with other type annotations to make nested data structures.
|
||||
|
||||
In some cases, you might still have to use Pydantic's version of `dataclasses`. For example, if you have errors with the automatically generated API documentation.
|
||||
|
||||
In that case, you can simply swap the standard `dataclasses` with `pydantic.dataclasses`, which is a drop-in replacement:
|
||||
|
||||
```{ .python .annotate hl_lines="1 5 8-11 14-17 23-25 28" }
|
||||
{!../../../docs_src/dataclasses/tutorial003.py!}
|
||||
```
|
||||
|
||||
1. We still import `field` from standard `dataclasses`.
|
||||
|
||||
2. `pydantic.dataclasses` is a drop-in replacement for `dataclasses`.
|
||||
|
||||
3. The `Author` dataclass includes a list of `Item` dataclasses.
|
||||
|
||||
4. The `Author` dataclass is used as the `response_model` parameter.
|
||||
|
||||
5. You can use other standard type annotations with dataclasses as the request body.
|
||||
|
||||
In this case, it's a list of `Item` dataclasses.
|
||||
|
||||
6. Here we are returning a dictionary that contains `items` which is a list of dataclasses.
|
||||
|
||||
FastAPI is still capable of <abbr title="converting the data to a format that can be transmitted">serializing</abbr> the data to JSON.
|
||||
|
||||
7. Here the `response_model` is using a type annotation of a list of `Author` dataclasses.
|
||||
|
||||
Again, you can combine `dataclasses` with standard type annotations.
|
||||
|
||||
8. Notice that this *path operation function* uses regular `def` instead of `async def`.
|
||||
|
||||
As always, in FastAPI you can combine `def` and `async def` as needed.
|
||||
|
||||
If you need a refresher about when to use which, check out the section _"In a hurry?"_ in the docs about <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank" class="internal-link">`async` and `await`</a>.
|
||||
|
||||
9. This *path operation function* is not returning dataclasses (although it could), but a list of dictionaries with internal data.
|
||||
|
||||
FastAPI will use the `response_model` parameter (that includes dataclasses) to convert the response.
|
||||
|
||||
You can combine `dataclasses` with other type annotations in many different combinations to form complex data structures.
|
||||
|
||||
Check the in-code annotation tips above to see more specific details.
|
||||
|
||||
## Learn More
|
||||
|
||||
You can also combine `dataclasses` with other Pydantic models, inherit from them, include them in your own models, etc.
|
||||
|
||||
To learn more, check the <a href="https://pydantic-docs.helpmanual.io/usage/dataclasses/" class="external-link" target="_blank">Pydantic docs about dataclasses</a>.
|
||||
|
||||
## Version
|
||||
|
||||
This is available since FastAPI version `0.67.0`. 🔖
|
||||
@@ -4,6 +4,9 @@ You can define event handlers (functions) that need to be executed before the ap
|
||||
|
||||
These functions can be declared with `async def` or normal `def`.
|
||||
|
||||
!!! warning
|
||||
Only event handlers for the main application will be executed, not for [Sub Applications - Mounts](./sub-applications.md){.internal-link target=_blank}.
|
||||
|
||||
## `startup` event
|
||||
|
||||
To add a function that should be run before the application starts, declare it with the event `"startup"`:
|
||||
@@ -41,4 +44,4 @@ Here, the `shutdown` event handler function will write a text line `"Application
|
||||
So, we declare the event handler function with standard `def` instead of `async def`.
|
||||
|
||||
!!! info
|
||||
You can read more about these event handlers in <a href="https://www.starlette.io/events/" class="external-link" target="_blank">Starlette's Events' docs</a>.
|
||||
You can read more about these event handlers in <a href="https://www.starlette.io/events/" class="external-link" target="_blank">Starlette's Events' docs</a>.
|
||||
|
||||
@@ -32,7 +32,6 @@ And that function `get_openapi()` receives as parameters:
|
||||
* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.0.2`.
|
||||
* `description`: The description of your API.
|
||||
* `routes`: A list of routes, these are each of the registered *path operations*. They are taken from `app.routes`.
|
||||
* `openapi_prefix`: The URL prefix to be used in your OpenAPI.
|
||||
|
||||
## Overriding the defaults
|
||||
|
||||
@@ -44,7 +43,7 @@ For example, let's add <a href="https://github.com/Rebilly/ReDoc/blob/master/doc
|
||||
|
||||
First, write all your **FastAPI** application as normally:
|
||||
|
||||
```Python hl_lines="1 4 7 8 9"
|
||||
```Python hl_lines="1 4 7-9"
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -52,7 +51,7 @@ First, write all your **FastAPI** application as normally:
|
||||
|
||||
Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function:
|
||||
|
||||
```Python hl_lines="2 15 16 17 18 19 20"
|
||||
```Python hl_lines="2 15-20"
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -60,7 +59,7 @@ Then, use the same utility function to generate the OpenAPI schema, inside a `cu
|
||||
|
||||
Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema:
|
||||
|
||||
```Python hl_lines="21 22 23"
|
||||
```Python hl_lines="21-23"
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -72,7 +71,7 @@ That way, your application won't have to generate the schema every time a user o
|
||||
|
||||
It will be generated only once, and then the same cached schema will be used for the next requests.
|
||||
|
||||
```Python hl_lines="13 14 24 25"
|
||||
```Python hl_lines="13-14 24-25"
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -173,7 +172,7 @@ $ pip install aiofiles
|
||||
* Import `StaticFiles`.
|
||||
* "Mount" a `StaticFiles()` instance in a specific path.
|
||||
|
||||
```Python hl_lines="7 11"
|
||||
```Python hl_lines="7 11"
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -225,7 +224,7 @@ You can re-use FastAPI's internal functions to create the HTML pages for the doc
|
||||
|
||||
And similarly for ReDoc...
|
||||
|
||||
```Python hl_lines="2 3 4 5 6 14 15 16 17 18 19 20 21 22 25 26 27 30 31 32 33 34 35 36"
|
||||
```Python hl_lines="2-6 14-22 25-27 30-36"
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -240,7 +239,7 @@ And similarly for ReDoc...
|
||||
|
||||
Now, to be able to test that everything works, create a *path operation*:
|
||||
|
||||
```Python hl_lines="39 40 41"
|
||||
```Python hl_lines="39-41"
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ GraphQL is implemented with Graphene, you can check <a href="https://docs.graphe
|
||||
|
||||
Import `graphene` and define your GraphQL data:
|
||||
|
||||
```Python hl_lines="1 6 7 8 9 10"
|
||||
```Python hl_lines="1 6-10"
|
||||
{!../../../docs_src/graphql/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -18,7 +18,7 @@ Import `graphene` and define your GraphQL data:
|
||||
|
||||
Then import and add Starlette's `GraphQLApp`:
|
||||
|
||||
```Python hl_lines="3 14"
|
||||
```Python hl_lines="3 14"
|
||||
{!../../../docs_src/graphql/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -16,3 +16,9 @@ In the next sections you will see other options, configurations, and additional
|
||||
You could still use most of the features in **FastAPI** with the knowledge from the main [Tutorial - User Guide](../tutorial/){.internal-link target=_blank}.
|
||||
|
||||
And the next sections assume you already read it, and assume that you know those main ideas.
|
||||
|
||||
## TestDriven.io course
|
||||
|
||||
If you would like to take an advanced-beginner course to complement this section of the docs, you might want to check: <a href="https://testdriven.io/courses/tdd-fastapi/" class="external-link" target="_blank">Test-Driven Development with FastAPI and Docker</a> by **TestDriven.io**.
|
||||
|
||||
They are currently donating 10% of all profits to the development of **FastAPI**. 🎉 😄
|
||||
|
||||
@@ -62,7 +62,7 @@ Any incoming requests to `http` or `ws` will be redirected to the secure scheme
|
||||
|
||||
Enforces that all incoming requests have a correctly set `Host` header, in order to guard against HTTP Host Header attacks.
|
||||
|
||||
```Python hl_lines="2 6 7 8"
|
||||
```Python hl_lines="2 6-8"
|
||||
{!../../../docs_src/advanced_middleware/tutorial002.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ You can adapt it to any other NoSQL database like:
|
||||
|
||||
For now, don't pay attention to the rest, only the imports:
|
||||
|
||||
```Python hl_lines="6 7 8"
|
||||
```Python hl_lines="3-5"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -29,7 +29,7 @@ We will use it later as a fixed field `type` in our documents.
|
||||
|
||||
This is not required by Couchbase, but is a good practice that will help you afterwards.
|
||||
|
||||
```Python hl_lines="10"
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -54,7 +54,7 @@ This utility function will:
|
||||
* Set defaults for timeouts.
|
||||
* Return it.
|
||||
|
||||
```Python hl_lines="13 14 15 16 17 18 19 20 21 22"
|
||||
```Python hl_lines="12-21"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -66,7 +66,7 @@ As **Couchbase** "documents" are actually just "JSON objects", we can model them
|
||||
|
||||
First, let's create a `User` model:
|
||||
|
||||
```Python hl_lines="25 26 27 28 29"
|
||||
```Python hl_lines="24-28"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -80,7 +80,7 @@ This will have the data that is actually stored in the database.
|
||||
|
||||
We don't create it as a subclass of Pydantic's `BaseModel` but as a subclass of our own `User`, because it will have all the attributes in `User` plus a couple more:
|
||||
|
||||
```Python hl_lines="32 33 34"
|
||||
```Python hl_lines="31-33"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -100,7 +100,7 @@ Now create a function that will:
|
||||
|
||||
By creating a function that is only dedicated to getting your user from a `username` (or any other parameter) independent of your *path operation function*, you can more easily re-use it in multiple parts and also add <abbr title="Automated test, written in code, that checks if another piece of code is working correctly.">unit tests</abbr> for it:
|
||||
|
||||
```Python hl_lines="37 38 39 40 41 42 43"
|
||||
```Python hl_lines="36-42"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -135,7 +135,7 @@ UserInDB(username="johndoe", hashed_password="some_hash")
|
||||
|
||||
### Create the `FastAPI` app
|
||||
|
||||
```Python hl_lines="47"
|
||||
```Python hl_lines="46"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -143,9 +143,9 @@ UserInDB(username="johndoe", hashed_password="some_hash")
|
||||
|
||||
As our code is calling Couchbase and we are not using the <a href="https://docs.couchbase.com/python-sdk/2.5/async-programming.html#asyncio-python-3-5" class="external-link" target="_blank">experimental Python <code>await</code> support</a>, we should declare our function with normal `def` instead of `async def`.
|
||||
|
||||
Also, Couchbase recommends not using a single `Bucket` object in multiple "<abbr title="A sequence of code being executed by the program, while at the same time, or at intervals, there can be others being executed too.">thread</abbr>s", so, we can get just get the bucket directly and pass it to our utility functions:
|
||||
Also, Couchbase recommends not using a single `Bucket` object in multiple "<abbr title="A sequence of code being executed by the program, while at the same time, or at intervals, there can be others being executed too.">thread</abbr>s", so, we can just get the bucket directly and pass it to our utility functions:
|
||||
|
||||
```Python hl_lines="50 51 52 53 54"
|
||||
```Python hl_lines="49-53"
|
||||
{!../../../docs_src/nosql_databases/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ It will have a *path operation* that will receive an `Invoice` body, and a query
|
||||
|
||||
This part is pretty normal, most of the code is probably already familiar to you:
|
||||
|
||||
```Python hl_lines="8 9 10 11 12 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53"
|
||||
```Python hl_lines="10-14 37-54"
|
||||
{!../../../docs_src/openapi_callbacks/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -83,16 +83,7 @@ So we are going to use that same knowledge to document how the *external API* sh
|
||||
|
||||
First create a new `APIRouter` that will contain one or more callbacks.
|
||||
|
||||
This router will never be added to an actual `FastAPI` app (i.e. it will never be passed to `app.include_router(...)`).
|
||||
|
||||
Because of that, you need to declare what will be the `default_response_class`, and set it to `JSONResponse`.
|
||||
|
||||
!!! Note "Technical Details"
|
||||
The `response_class` is normally set by the `FastAPI` app during the call to `app.include_router(some_router)`.
|
||||
|
||||
But as we are never calling `app.include_router(some_router)`, we need to set the `default_response_class` during creation of the `APIRouter`.
|
||||
|
||||
```Python hl_lines="3 24"
|
||||
```Python hl_lines="5 26"
|
||||
{!../../../docs_src/openapi_callbacks/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -105,7 +96,7 @@ It should look just like a normal FastAPI *path operation*:
|
||||
* It should probably have a declaration of the body it should receive, e.g. `body: InvoiceEvent`.
|
||||
* And it could also have a declaration of the response it should return, e.g. `response_model=InvoiceEventReceived`.
|
||||
|
||||
```Python hl_lines="15 16 17 20 21 27 28 29 30 31"
|
||||
```Python hl_lines="17-19 22-23 29-33"
|
||||
{!../../../docs_src/openapi_callbacks/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -172,7 +163,7 @@ At this point you have the *callback path operation(s)* needed (the one(s) that
|
||||
|
||||
Now use the parameter `callbacks` in *your API's path operation decorator* to pass the attribute `.routes` (that's actually just a `list` of routes/*path operations*) from that callback router:
|
||||
|
||||
```Python hl_lines="34"
|
||||
```Python hl_lines="36"
|
||||
{!../../../docs_src/openapi_callbacks/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ If you want to use your APIs' function names as `operationId`s, you can iterate
|
||||
|
||||
You should do it after adding all your *path operations*.
|
||||
|
||||
```Python hl_lines="2 12 13 14 15 16 17 18 19 20 21 24"
|
||||
```Python hl_lines="2 12-21 24"
|
||||
{!../../../docs_src/path_operation_advanced_configuration/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -33,7 +33,7 @@ You should do it after adding all your *path operations*.
|
||||
|
||||
## Exclude from OpenAPI
|
||||
|
||||
To exclude a *path operation* from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`;
|
||||
To exclude a *path operation* from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`:
|
||||
|
||||
```Python hl_lines="6"
|
||||
{!../../../docs_src/path_operation_advanced_configuration/tutorial003.py!}
|
||||
@@ -47,6 +47,124 @@ Adding an `\f` (an escaped "form feed" character) causes **FastAPI** to truncate
|
||||
|
||||
It won't show up in the documentation, but other tools (such as Sphinx) will be able to use the rest.
|
||||
|
||||
```Python hl_lines="19 20 21 22 23 24 25 26 27 28 29"
|
||||
```Python hl_lines="19-29"
|
||||
{!../../../docs_src/path_operation_advanced_configuration/tutorial004.py!}
|
||||
```
|
||||
|
||||
## Additional Responses
|
||||
|
||||
You probably have seen how to declare the `response_model` and `status_code` for a *path operation*.
|
||||
|
||||
That defines the metadata about the main response of a *path operation*.
|
||||
|
||||
You can also declare additional responses with their models, status codes, etc.
|
||||
|
||||
There's a whole chapter here in the documentation about it, you can read it at [Additional Responses in OpenAPI](./additional-responses.md){.internal-link target=_blank}.
|
||||
|
||||
## OpenAPI Extra
|
||||
|
||||
When you declare a *path operation* in your application, **FastAPI** automatically generates the relevant metadata about that *path operation* to be included in the OpenAPI schema.
|
||||
|
||||
!!! note "Technical details"
|
||||
In the OpenAPI specification it is called the <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">Operation Object</a>.
|
||||
|
||||
It has all the information about the *path operation* and is used to generate the automatic documentation.
|
||||
|
||||
It includes the `tags`, `parameters`, `requestBody`, `responses`, etc.
|
||||
|
||||
This *path operation*-specific OpenAPI schema is normally generated automatically by **FastAPI**, but you can also extend it.
|
||||
|
||||
!!! tip
|
||||
This is a low level extension point.
|
||||
|
||||
If you only need to declare additonal responses, a more convenient way to do it is with [Additional Responses in OpenAPI](./additional-responses.md){.internal-link target=_blank}.
|
||||
|
||||
You can extend the OpenAPI schema for a *path operation* using the parameter `openapi_extra`.
|
||||
|
||||
### OpenAPI Extensions
|
||||
|
||||
This `openapi_extra` can be helpful, for example, to declare [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):
|
||||
|
||||
```Python hl_lines="6"
|
||||
{!../../../docs_src/path_operation_advanced_configuration/tutorial005.py!}
|
||||
```
|
||||
|
||||
If you open the automatic API docs, your extension will show up at the bottom of the specific *path operation*.
|
||||
|
||||
<img src="/img/tutorial/path-operation-advanced-configuration/image01.png">
|
||||
|
||||
And if you see the resulting OpenAPI (at `/openapi.json` in your API), you will see your extension as part of the specific *path operation* too:
|
||||
|
||||
```JSON hl_lines="22"
|
||||
{
|
||||
"openapi": "3.0.2",
|
||||
"info": {
|
||||
"title": "FastAPI",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"paths": {
|
||||
"/items/": {
|
||||
"get": {
|
||||
"summary": "Read Items",
|
||||
"operationId": "read_items_items__get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-aperture-labs-portal": "blue"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Custom OpenAPI *path operation* schema
|
||||
|
||||
The dictionary in `openapi_extra` will be deeply merged with the automatically generated OpenAPI schema for the *path operation*.
|
||||
|
||||
So, you could add additional data to the automatically generated schema.
|
||||
|
||||
For example, you could decide to read and validate the request with your own code, without using the automatic features of FastAPI with Pydantic, but you could still want to define the request in the OpenAPI schema.
|
||||
|
||||
You could do that with `openapi_extra`:
|
||||
|
||||
```Python hl_lines="20-37 39-40"
|
||||
{!../../../docs_src/path_operation_advanced_configuration/tutorial006.py!}
|
||||
```
|
||||
|
||||
In this example, we didn't declare any Pydantic model. In fact, the request body is not even <abbr title="converted from some plain format, like bytes, into Python objects">parsed</abbr> as JSON, it is read directly as `bytes`, and the function `magic_data_reader()` would be in charge of parsing it in some way.
|
||||
|
||||
Nevertheless, we can declare the expected schema for the request body.
|
||||
|
||||
### Custom OpenAPI content type
|
||||
|
||||
Using this same trick, you could use a Pydantic model to define the JSON Schema that is then included in the custom OpenAPI schema section for the *path operation*.
|
||||
|
||||
And you could do this even if the data type in the request is not JSON.
|
||||
|
||||
For example, in this application we don't use FastAPI's integrated functionality to extract the JSON Schema from Pydantic models nor the automatic validation for JSON. In fact, we are declaring the request content type as YAML, not JSON:
|
||||
|
||||
```Python hl_lines="17-22 24"
|
||||
{!../../../docs_src/path_operation_advanced_configuration/tutorial007.py!}
|
||||
```
|
||||
|
||||
Nevertheless, although we are not using the default integrated functionality, we are still using a Pydantic model to manually generate the JSON Schema for the data that we want to receive in YAML.
|
||||
|
||||
Then we use the request directly, and extract the body as `bytes`. This means that FastAPI won't even try to parse the request payload as JSON.
|
||||
|
||||
And then in our code, we parse that YAML content directly, and then we are again using the same Pydantic model to validate the YAML content:
|
||||
|
||||
```Python hl_lines="26-33"
|
||||
{!../../../docs_src/path_operation_advanced_configuration/tutorial007.py!}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Here we re-use the same Pydantic model.
|
||||
|
||||
But the same way, we could have validated it in some other way.
|
||||
|
||||
@@ -6,7 +6,7 @@ You can declare a parameter of type `Response` in your *path operation function*
|
||||
|
||||
And then you can set cookies in that *temporal* response object.
|
||||
|
||||
```Python hl_lines="1 8 9"
|
||||
```Python hl_lines="1 8-9"
|
||||
{!../../../docs_src/response_cookies/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -26,7 +26,7 @@ To do that, you can create a response as described in [Return a Response Directl
|
||||
|
||||
Then set Cookies in it, and then return it:
|
||||
|
||||
```Python hl_lines="10 11 12"
|
||||
```Python hl_lines="10-12"
|
||||
{!../../../docs_src/response_cookies/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ For example, you cannot put a Pydantic model in a `JSONResponse` without first c
|
||||
|
||||
For those cases, you can use the `jsonable_encoder` to convert your data before passing it to a response:
|
||||
|
||||
```Python hl_lines="4 6 20 21"
|
||||
```Python hl_lines="6-7 21-22"
|
||||
{!../../../docs_src/response_directly/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ You can declare a parameter of type `Response` in your *path operation function*
|
||||
|
||||
And then you can set headers in that *temporal* response object.
|
||||
|
||||
```Python hl_lines="1 7 8"
|
||||
```Python hl_lines="1 7-8"
|
||||
{!../../../docs_src/response_headers/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -24,7 +24,7 @@ You can also add headers when you return a `Response` directly.
|
||||
|
||||
Create a response as described in [Return a Response Directly](response-directly.md){.internal-link target=_blank} and pass the headers as an additional parameter:
|
||||
|
||||
```Python hl_lines="10 11 12"
|
||||
```Python hl_lines="10-12"
|
||||
{!../../../docs_src/response_headers/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Then, when you type that username and password, the browser sends them in the he
|
||||
* It returns an object of type `HTTPBasicCredentials`:
|
||||
* It contains the `username` and `password` sent.
|
||||
|
||||
```Python hl_lines="2 6 10"
|
||||
```Python hl_lines="2 6 10"
|
||||
{!../../../docs_src/security/tutorial006.py!}
|
||||
```
|
||||
|
||||
@@ -36,7 +36,7 @@ Use a dependency to check if the username and password are correct.
|
||||
|
||||
For this, use the Python standard module <a href="https://docs.python.org/3/library/secrets.html" class="external-link" target="_blank">`secrets`</a> to check the username and password:
|
||||
|
||||
```Python hl_lines="1 11 12 13"
|
||||
```Python hl_lines="1 11-13"
|
||||
{!../../../docs_src/security/tutorial007.py!}
|
||||
```
|
||||
|
||||
@@ -54,9 +54,9 @@ But by using the `secrets.compare_digest()` it will be secure against a type of
|
||||
|
||||
But what's a "timing attack"?
|
||||
|
||||
Let's imagine an attacker is trying to guess the username and password.
|
||||
Let's imagine some attackers are trying to guess the username and password.
|
||||
|
||||
And that attacker sends a request with a username `johndoe` and a password `love123`.
|
||||
And they send a request with a username `johndoe` and a password `love123`.
|
||||
|
||||
Then the Python code in your application would be equivalent to something like:
|
||||
|
||||
@@ -67,7 +67,7 @@ if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
|
||||
|
||||
But right at the moment Python compares the first `j` in `johndoe` to the first `s` in `stanleyjobson`, it will return `False`, because it already knows that those two strings are not the same, thinking that "there's no need to waste more computation comparing the rest of the letters". And your application will say "incorrect user or password".
|
||||
|
||||
But then the attacker tries with username `stanleyjobsox` and password `love123`.
|
||||
But then the attackers try with username `stanleyjobsox` and password `love123`.
|
||||
|
||||
And your application code does something like:
|
||||
|
||||
@@ -78,17 +78,17 @@ if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
|
||||
|
||||
Python will have to compare the whole `stanleyjobso` in both `stanleyjobsox` and `stanleyjobson` before realizing that both strings are not the same. So it will take some extra microseconds to reply back "incorrect user or password".
|
||||
|
||||
#### The time to answer helps the attacker
|
||||
#### The time to answer helps the attackers
|
||||
|
||||
At that point, by noticing that the server took some microseconds longer to send the "incorrect user or password" response, the attacker will know that she/he got _something_ right, some of the initial letters were right.
|
||||
At that point, by noticing that the server took some microseconds longer to send the "incorrect user or password" response, the attackers will know that they got _something_ right, some of the initial letters were right.
|
||||
|
||||
And then she/he can try again knowing that it's probably something more similar to `stanleyjobsox` than to `johndoe`.
|
||||
And then they can try again knowing that it's probably something more similar to `stanleyjobsox` than to `johndoe`.
|
||||
|
||||
#### A "professional" attack
|
||||
|
||||
Of course, the attacker would not try all this by hand, she/he would write a program to do it, possibly with thousands or millions of tests per second. And would get just one extra correct letter at a time.
|
||||
Of course, the attackers would not try all this by hand, they would write a program to do it, possibly with thousands or millions of tests per second. And would get just one extra correct letter at a time.
|
||||
|
||||
But doing that, in some minutes or hours the attacker would have guessed the correct username and password, with the "help" of our application, just using the time taken to answer.
|
||||
But doing that, in some minutes or hours the attackers would have guessed the correct username and password, with the "help" of our application, just using the time taken to answer.
|
||||
|
||||
#### Fix it with `secrets.compare_digest()`
|
||||
|
||||
@@ -102,6 +102,6 @@ That way, using `secrets.compare_digest()` in your application code, it will be
|
||||
|
||||
After detecting that the credentials are incorrect, return an `HTTPException` with a status code 401 (the same returned when no credentials are provided) and add the header `WWW-Authenticate` to make the browser show the login prompt again:
|
||||
|
||||
```Python hl_lines="15 16 17 18 19"
|
||||
```Python hl_lines="15-19"
|
||||
{!../../../docs_src/security/tutorial007.py!}
|
||||
```
|
||||
|
||||
@@ -56,7 +56,7 @@ They are normally used to declare specific security permissions, for example:
|
||||
|
||||
First, let's quickly see the parts that change from the examples in the main **Tutorial - User Guide** for [OAuth2 with Password (and hashing), Bearer with JWT tokens](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. Now using OAuth2 scopes:
|
||||
|
||||
```Python hl_lines="2 5 9 13 47 65 106 108 109 110 111 112 113 114 115 116 122 123 124 125 129 130 131 132 133 134 135 140 154"
|
||||
```Python hl_lines="2 4 8 12 46 64 105 107-115 121-124 128-134 139 153"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -68,7 +68,7 @@ The first change is that now we are declaring the OAuth2 security scheme with tw
|
||||
|
||||
The `scopes` parameter receives a `dict` with each scope as a key and the description as the value:
|
||||
|
||||
```Python hl_lines="63 64 65 66"
|
||||
```Python hl_lines="62-65"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -93,7 +93,7 @@ And we return the scopes as part of the JWT token.
|
||||
|
||||
But in your application, for security, you should make sure you only add the scopes that the user is actually able to have, or the ones you have predefined.
|
||||
|
||||
```Python hl_lines="155"
|
||||
```Python hl_lines="153"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -118,7 +118,7 @@ In this case, it requires the scope `me` (it could require more than one scope).
|
||||
|
||||
We are doing it here to demonstrate how **FastAPI** handles scopes declared at different levels.
|
||||
|
||||
```Python hl_lines="5 140 167"
|
||||
```Python hl_lines="4 139 166"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -143,7 +143,7 @@ We also declare a special parameter of type `SecurityScopes`, imported from `fas
|
||||
|
||||
This `SecurityScopes` class is similar to `Request` (`Request` was used to get the request object directly).
|
||||
|
||||
```Python hl_lines="9 106"
|
||||
```Python hl_lines="8 105"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -157,9 +157,9 @@ The `security_scopes` object (of class `SecurityScopes`) also provides a `scope_
|
||||
|
||||
We create an `HTTPException` that we can re-use (`raise`) later at several points.
|
||||
|
||||
In this exception, we include the scopes required (if any) as a string separated by spaces (using `scope_str`). We put that string containing the scopes in in the `WWW-Authenticate` header (this is part of the spec).
|
||||
In this exception, we include the scopes required (if any) as a string separated by spaces (using `scope_str`). We put that string containing the scopes in the `WWW-Authenticate` header (this is part of the spec).
|
||||
|
||||
```Python hl_lines="106 108 109 110 111 112 113 114 115 116"
|
||||
```Python hl_lines="105 107-115"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -177,7 +177,7 @@ Instead of, for example, a `dict`, or something else, as it could break the appl
|
||||
|
||||
We also verify that we have a user with that username, and if not, we raise that same exception we created before.
|
||||
|
||||
```Python hl_lines="47 117 118 119 120 121 122 123 124 125 126 127 128"
|
||||
```Python hl_lines="46 116-127"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -187,7 +187,7 @@ We now verify that all the scopes required, by this dependency and all the depen
|
||||
|
||||
For this, we use `security_scopes.scopes`, that contains a `list` with all these scopes as `str`.
|
||||
|
||||
```Python hl_lines="129 130 131 132 133 134 135"
|
||||
```Python hl_lines="128-134"
|
||||
{!../../../docs_src/security/tutorial005.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ The same way as with Pydantic models, you declare class attributes with type ann
|
||||
|
||||
You can use all the same validation features and tools you use for Pydantic models, like different data types and additional validations with `Field()`.
|
||||
|
||||
```Python hl_lines="2 5 6 7 8 11"
|
||||
```Python hl_lines="2 5-8 11"
|
||||
{!../../../docs_src/settings/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -150,7 +150,7 @@ Next it will convert and validate the data. So, when you use that `settings` obj
|
||||
|
||||
Then you can use the new `settings` object in your application:
|
||||
|
||||
```Python hl_lines="18 19 20"
|
||||
```Python hl_lines="18-20"
|
||||
{!../../../docs_src/settings/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -189,7 +189,7 @@ For example, you could have a file `config.py` with:
|
||||
|
||||
And then use it in a file `main.py`:
|
||||
|
||||
```Python hl_lines="3 11 12 13"
|
||||
```Python hl_lines="3 11-13"
|
||||
{!../../../docs_src/settings/app01/main.py!}
|
||||
```
|
||||
|
||||
@@ -216,7 +216,7 @@ Notice that now we don't create a default instance `settings = Settings()`.
|
||||
|
||||
Now we create a dependency that returns a new `config.Settings()`.
|
||||
|
||||
```Python hl_lines="5 11 12"
|
||||
```Python hl_lines="5 11-12"
|
||||
{!../../../docs_src/settings/app02/main.py!}
|
||||
```
|
||||
|
||||
@@ -227,7 +227,7 @@ Now we create a dependency that returns a new `config.Settings()`.
|
||||
|
||||
And then we can require it from the *path operation function* as a dependency and use it anywhere we need it.
|
||||
|
||||
```Python hl_lines="16 18 19 20"
|
||||
```Python hl_lines="16 18-20"
|
||||
{!../../../docs_src/settings/app02/main.py!}
|
||||
```
|
||||
|
||||
@@ -235,7 +235,7 @@ And then we can require it from the *path operation function* as a dependency an
|
||||
|
||||
Then it would be very easy to provide a different settings object during testing by creating a dependency override for `get_settings`:
|
||||
|
||||
```Python hl_lines="8 9 12 21"
|
||||
```Python hl_lines="9-10 13 21"
|
||||
{!../../../docs_src/settings/app02/test_main.py!}
|
||||
```
|
||||
|
||||
@@ -272,7 +272,7 @@ APP_NAME="ChimichangApp"
|
||||
|
||||
And then update your `config.py` with:
|
||||
|
||||
```Python hl_lines="9 10"
|
||||
```Python hl_lines="9-10"
|
||||
{!../../../docs_src/settings/app03/config.py!}
|
||||
```
|
||||
|
||||
@@ -288,7 +288,7 @@ Reading a file from disk is normally a costly (slow) operation, so you probably
|
||||
But every time we do:
|
||||
|
||||
```Python
|
||||
config.Settings()
|
||||
Settings()
|
||||
```
|
||||
|
||||
a new `Settings` object would be created, and at creation it would read the `.env` file again.
|
||||
@@ -297,7 +297,7 @@ If the dependency function was just like:
|
||||
|
||||
```Python
|
||||
def get_settings():
|
||||
return config.Settings()
|
||||
return Settings()
|
||||
```
|
||||
|
||||
we would create that object for each request, and we would be reading the `.env` file for each request. ⚠️
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
If you are starting a project from scratch, you are probably better off with SQLAlchemy ORM ([SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank}), or any other async ORM.
|
||||
|
||||
If you already have a code base that uses <a href="http://docs.peewee-orm.com/en/latest/" class="external-link" target="_blank">Peewee ORM</a>, you can check here how to use it with **FastAPI**.
|
||||
If you already have a code base that uses <a href="https://docs.peewee-orm.com/en/latest/" class="external-link" target="_blank">Peewee ORM</a>, you can check here how to use it with **FastAPI**.
|
||||
|
||||
!!! warning "Python 3.7+ required"
|
||||
You will need Python 3.7 or above to safely use Peewee with FastAPI.
|
||||
@@ -25,7 +25,7 @@ But if you need to change some of the defaults, support more than one predefined
|
||||
Nevertheless, it's possible to do it, and here you'll see exactly what code you have to add to be able to use Peewee with FastAPI.
|
||||
|
||||
!!! note "Technical Details"
|
||||
You can read more about Peewee's stand about async in Python <a href="http://docs.peewee-orm.com/en/latest/peewee/database.html#async-with-gevent" class="external-link" target="_blank">in the docs</a>, <a href="https://github.com/coleifer/peewee/issues/263#issuecomment-517347032" class="external-link" target="_blank">an issue</a>, <a href="https://github.com/coleifer/peewee/pull/2072#issuecomment-563215132" class="external-link" target="_blank">a PR</a>.
|
||||
You can read more about Peewee's stand about async in Python <a href="https://docs.peewee-orm.com/en/latest/peewee/database.html#async-with-gevent" class="external-link" target="_blank">in the docs</a>, <a href="https://github.com/coleifer/peewee/issues/263#issuecomment-517347032" class="external-link" target="_blank">an issue</a>, <a href="https://github.com/coleifer/peewee/pull/2072#issuecomment-563215132" class="external-link" target="_blank">a PR</a>.
|
||||
|
||||
## The same app
|
||||
|
||||
@@ -113,7 +113,7 @@ This might seem a bit complex (and it actually is), you don't really need to com
|
||||
|
||||
We will create a `PeeweeConnectionState`:
|
||||
|
||||
```Python hl_lines="10 11 12 13 14 15 16 17 18 19"
|
||||
```Python hl_lines="10-19"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/database.py!}
|
||||
```
|
||||
|
||||
@@ -161,7 +161,7 @@ This is the same you would do if you followed the Peewee tutorial and updated th
|
||||
|
||||
Import `db` from `database` (the file `database.py` from above) and use it here.
|
||||
|
||||
```Python hl_lines="3 6 7 8 9 10 11 12 15 16 17 18 19 20 21"
|
||||
```Python hl_lines="3 6-12 15-21"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/models.py!}
|
||||
```
|
||||
|
||||
@@ -189,7 +189,7 @@ Now let's check the file `sql_app/schemas.py`.
|
||||
|
||||
Create all the same Pydantic models as in the SQLAlchemy tutorial:
|
||||
|
||||
```Python hl_lines="16 17 18 21 22 25 26 27 28 29 30 34 35 38 39 42 43 44 45 46 47 48"
|
||||
```Python hl_lines="16-18 21-22 25-30 34-35 38-39 42-48"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/schemas.py!}
|
||||
```
|
||||
|
||||
@@ -214,7 +214,7 @@ But recent versions of Pydantic allow providing a custom class that inherits fro
|
||||
|
||||
We are going to create a custom `PeeweeGetterDict` class and use it in all the same Pydantic *models* / schemas that use `orm_mode`:
|
||||
|
||||
```Python hl_lines="3 8 9 10 11 12 13 31 49"
|
||||
```Python hl_lines="3 8-13 31 49"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/schemas.py!}
|
||||
```
|
||||
|
||||
@@ -235,7 +235,7 @@ Now let's see the file `sql_app/crud.py`.
|
||||
|
||||
Create all the same CRUD utils as in the SQLAlchemy tutorial, all the code is very similar:
|
||||
|
||||
```Python hl_lines="1 4 5 8 9 12 13 16 17 18 19 20 23 24 27 28 29 30"
|
||||
```Python hl_lines="1 4-5 8-9 12-13 16-20 23-24 27-30"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/crud.py!}
|
||||
```
|
||||
|
||||
@@ -259,7 +259,7 @@ And now in the file `sql_app/main.py` let's integrate and use all the other part
|
||||
|
||||
In a very simplistic way create the database tables:
|
||||
|
||||
```Python hl_lines="9 10 11"
|
||||
```Python hl_lines="9-11"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
|
||||
```
|
||||
|
||||
@@ -267,7 +267,7 @@ In a very simplistic way create the database tables:
|
||||
|
||||
Create a dependency that will connect the database right at the beginning of a request and disconnect it at the end:
|
||||
|
||||
```Python hl_lines="23 24 25 26 27 28 29"
|
||||
```Python hl_lines="23-29"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
|
||||
```
|
||||
|
||||
@@ -291,7 +291,7 @@ For all the `contextvars` parts to work, we need to make sure we have an indepen
|
||||
|
||||
For that, we need to create another `async` dependency `reset_db_state()` that is used as a sub-dependency in `get_db()`. It will set the value for the context variable (with just a default `dict`) that will be used as the database state for the whole request. And then the dependency `get_db()` will store in it the database state (connection, transactions, etc).
|
||||
|
||||
```Python hl_lines="18 19 20"
|
||||
```Python hl_lines="18-20"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
|
||||
```
|
||||
|
||||
@@ -306,11 +306,11 @@ For the **next request**, as we will reset that context variable again in the `a
|
||||
|
||||
#### Peewee Proxy
|
||||
|
||||
If you are using a <a href="http://docs.peewee-orm.com/en/latest/peewee/database.html#dynamically-defining-a-database" class="external-link" target="_blank">Peewee Proxy</a>, the actual database is at `db.obj`.
|
||||
If you are using a <a href="https://docs.peewee-orm.com/en/latest/peewee/database.html#dynamically-defining-a-database" class="external-link" target="_blank">Peewee Proxy</a>, the actual database is at `db.obj`.
|
||||
|
||||
So, you would reset it with:
|
||||
|
||||
```Python hl_lines="3 4"
|
||||
```Python hl_lines="3-4"
|
||||
async def reset_db_state():
|
||||
database.db.obj._state._state.set(db_state_default.copy())
|
||||
database.db.obj._state.reset()
|
||||
@@ -320,7 +320,7 @@ async def reset_db_state():
|
||||
|
||||
Now, finally, here's the standard **FastAPI** *path operations* code.
|
||||
|
||||
```Python hl_lines="32 33 34 35 36 37 40 41 42 43 46 47 48 49 50 51 52 53 56 57 58 59 60 61 62 65 66 67 68 71 72 73 74 75 76 77 78 79"
|
||||
```Python hl_lines="32-37 40-43 46-53 56-62 65-68 71-79"
|
||||
{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
# Sub Applications - Behind a Proxy, Mounts
|
||||
|
||||
There are at least two situations where you could need to create your **FastAPI** application using some specific paths.
|
||||
|
||||
But then you need to set them up to be served with a path prefix.
|
||||
|
||||
It could happen if you have a:
|
||||
|
||||
* **Proxy** server.
|
||||
* You are "**mounting**" a FastAPI application inside another FastAPI application (or inside another ASGI application, like Starlette).
|
||||
|
||||
## Proxy
|
||||
|
||||
Having a proxy in this case means that you could declare a path at `/app`, but then, you could need to add a layer on top (the Proxy) that would put your **FastAPI** application under a path like `/api/v1`.
|
||||
|
||||
In this case, the original path `/app` will actually be served at `/api/v1/app`.
|
||||
|
||||
Even though your application "thinks" it is serving at `/app`.
|
||||
|
||||
And the Proxy could be re-writing the path "on the fly" to keep your application convinced that it is serving at `/app`.
|
||||
|
||||
Up to here, everything would work as normally.
|
||||
|
||||
But then, when you open the integrated docs, they would expect to get the OpenAPI schema at `/openapi.json`, instead of `/api/v1/openapi.json`.
|
||||
|
||||
So, the frontend (that runs in the browser) would try to reach `/openapi.json` and wouldn't be able to get the OpenAPI schema.
|
||||
|
||||
So, it's needed that the frontend looks for the OpenAPI schema at `/api/v1/openapi.json`.
|
||||
|
||||
And it's also needed that the returned JSON OpenAPI schema has the defined path at `/api/v1/app` (behind the proxy) instead of `/app`.
|
||||
|
||||
---
|
||||
|
||||
For these cases, you can declare an `openapi_prefix` parameter in your `FastAPI` application.
|
||||
|
||||
See the section below, about "mounting", for an example.
|
||||
|
||||
## Mounting a **FastAPI** application
|
||||
|
||||
"Mounting" means adding a complete "independent" application in a specific path, that then takes care of handling all the sub-paths.
|
||||
|
||||
You could want to do this if you have several "independent" applications that you want to separate, having their own independent OpenAPI schema and user interfaces.
|
||||
|
||||
### Top-level application
|
||||
|
||||
First, create the main, top-level, **FastAPI** application, and its *path operations*:
|
||||
|
||||
```Python hl_lines="3 6 7 8"
|
||||
{!../../../docs_src/sub_applications/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Sub-application
|
||||
|
||||
Then, create your sub-application, and its *path operations*.
|
||||
|
||||
This sub-application is just another standard FastAPI application, but this is the one that will be "mounted".
|
||||
|
||||
When creating the sub-application, use the parameter `openapi_prefix`. In this case, with a prefix of `/subapi`:
|
||||
|
||||
```Python hl_lines="11 14 15 16"
|
||||
{!../../../docs_src/sub_applications/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Mount the sub-application
|
||||
|
||||
In your top-level application, `app`, mount the sub-application, `subapi`.
|
||||
|
||||
Here you need to make sure you use the same path that you used for the `openapi_prefix`, in this case, `/subapi`:
|
||||
|
||||
```Python hl_lines="11 19"
|
||||
{!../../../docs_src/sub_applications/tutorial001.py!}
|
||||
```
|
||||
|
||||
## Check the automatic API docs
|
||||
|
||||
Now, run `uvicorn`, if your file is at `main.py`, it would be:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
And open the docs at <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 API docs for the main app, including only its own paths:
|
||||
|
||||
<img src="/img/tutorial/sub-applications/image01.png">
|
||||
|
||||
And then, open the docs for the sub-application, at <a href="http://127.0.0.1:8000/subapi/docs" class="external-link" target="_blank">http://127.0.0.1:8000/subapi/docs</a>.
|
||||
|
||||
You will see the automatic API docs for the sub-application, including only its own sub-paths, with their correct prefix:
|
||||
|
||||
<img src="/img/tutorial/sub-applications/image02.png">
|
||||
|
||||
If you try interacting with any of the two user interfaces, they will work, because the browser will be able to talk to the correct path (or sub-path).
|
||||
73
docs/en/docs/advanced/sub-applications.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Sub Applications - Mounts
|
||||
|
||||
If you need to have two independent FastAPI applications, with their own independent OpenAPI and their own docs UIs, you can have a main app and "mount" one (or more) sub-application(s).
|
||||
|
||||
## Mounting a **FastAPI** application
|
||||
|
||||
"Mounting" means adding a completely "independent" application in a specific path, that then takes care of handling everything under that path, with the _path operations_ declared in that sub-application.
|
||||
|
||||
### Top-level application
|
||||
|
||||
First, create the main, top-level, **FastAPI** application, and its *path operations*:
|
||||
|
||||
```Python hl_lines="3 6-8"
|
||||
{!../../../docs_src/sub_applications/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Sub-application
|
||||
|
||||
Then, create your sub-application, and its *path operations*.
|
||||
|
||||
This sub-application is just another standard FastAPI application, but this is the one that will be "mounted":
|
||||
|
||||
```Python hl_lines="11 14-16"
|
||||
{!../../../docs_src/sub_applications/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Mount the sub-application
|
||||
|
||||
In your top-level application, `app`, mount the sub-application, `subapi`.
|
||||
|
||||
In this case, it will be mounted at the path `/subapi`:
|
||||
|
||||
```Python hl_lines="11 19"
|
||||
{!../../../docs_src/sub_applications/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Check the automatic API docs
|
||||
|
||||
Now, run `uvicorn` with the main app, if your file is `main.py`, it would be:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
And open the docs at <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 API docs for the main app, including only its own _path operations_:
|
||||
|
||||
<img src="/img/tutorial/sub-applications/image01.png">
|
||||
|
||||
And then, open the docs for the sub-application, at <a href="http://127.0.0.1:8000/subapi/docs" class="external-link" target="_blank">http://127.0.0.1:8000/subapi/docs</a>.
|
||||
|
||||
You will see the automatic API docs for the sub-application, including only its own _path operations_, all under the correct sub-path prefix `/subapi`:
|
||||
|
||||
<img src="/img/tutorial/sub-applications/image02.png">
|
||||
|
||||
If you try interacting with any of the two user interfaces, they will work correctly, because the browser will be able to talk to each specific app or sub-app.
|
||||
|
||||
### Technical Details: `root_path`
|
||||
|
||||
When you mount a sub-application as described above, FastAPI will take care of communicating the mount path for the sub-application using a mechanism from the ASGI specification called a `root_path`.
|
||||
|
||||
That way, the sub-application will know to use that path prefix for the docs UI.
|
||||
|
||||
And the sub-application could also have its own mounted sub-applications and everything would work correctly, because FastAPI handles all these `root_path`s automatically.
|
||||
|
||||
You will learn more about the `root_path` and how to use it explicitly in the section about [Behind a Proxy](./behind-a-proxy.md){.internal-link target=_blank}.
|
||||
@@ -39,13 +39,16 @@ $ pip install aiofiles
|
||||
* Declare a `Request` parameter in the *path operation* that will return a template.
|
||||
* Use the `templates` you created to render and return a `TemplateResponse`, passing the `request` as one of the key-value pairs in the Jinja2 "context".
|
||||
|
||||
```Python hl_lines="3 10 14 15"
|
||||
```Python hl_lines="4 11 15-16"
|
||||
{!../../../docs_src/templates/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
Notice that you have to pass the `request` as part of the key-value pairs in the context for Jinja2. So, you also have to declare it in your *path operation*.
|
||||
|
||||
!!! tip
|
||||
By declaring `response_class=HTMLResponse` the docs UI will be able to know that the response will be HTML.
|
||||
|
||||
!!! note "Technical Details"
|
||||
You could also use `from starlette.templating import Jinja2Templates`.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ We create a new file at `sql_app/tests/test_sql_app.py`.
|
||||
|
||||
So the new file structure looks like:
|
||||
|
||||
``` hl_lines="9 10 11"
|
||||
``` hl_lines="9-11"
|
||||
.
|
||||
└── sql_app
|
||||
├── __init__.py
|
||||
@@ -48,7 +48,7 @@ For the tests we'll use a file `test.db` instead of `sql_app.db`.
|
||||
|
||||
But the rest of the session code is more or less the same, we just copy it.
|
||||
|
||||
```Python hl_lines="8 9 10 11 12 13"
|
||||
```Python hl_lines="8-13"
|
||||
{!../../../docs_src/sql_databases/sql_app/tests/test_sql_app.py!}
|
||||
```
|
||||
|
||||
@@ -77,7 +77,7 @@ So we add that line here, with the new file.
|
||||
|
||||
Now we create the dependency override and add it to the overrides for our app.
|
||||
|
||||
```Python hl_lines="19 20 21 22 23 24 27"
|
||||
```Python hl_lines="19-24 27"
|
||||
{!../../../docs_src/sql_databases/sql_app/tests/test_sql_app.py!}
|
||||
```
|
||||
|
||||
@@ -88,7 +88,7 @@ Now we create the dependency override and add it to the overrides for our app.
|
||||
|
||||
Then we can just test the app as normally.
|
||||
|
||||
```Python hl_lines="32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47"
|
||||
```Python hl_lines="32-47"
|
||||
{!../../../docs_src/sql_databases/sql_app/tests/test_sql_app.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ To override a dependency for testing, you put as a key the original dependency (
|
||||
|
||||
And then **FastAPI** will call that override instead of the original dependency.
|
||||
|
||||
```Python hl_lines="24 25 28"
|
||||
```Python hl_lines="26-27 30"
|
||||
{!../../../docs_src/dependency_testing/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
When you need your event handlers (`startup` and `shutdown`) to run in your tests, you can use the `TestClient` with a `with` statement:
|
||||
|
||||
```Python hl_lines="9 10 11 12 20 21 22 23 24"
|
||||
```Python hl_lines="9-12 20-24"
|
||||
{!../../../docs_src/app_testing/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -4,6 +4,9 @@ You can use the same `TestClient` to test WebSockets.
|
||||
|
||||
For this, you use the `TestClient` in a `with` statement, connecting to the WebSocket:
|
||||
|
||||
```Python hl_lines="27 28 29 30 31"
|
||||
```Python hl_lines="27-31"
|
||||
{!../../../docs_src/app_testing/tutorial002.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
For more details, check Starlette's documentation for <a href="https://www.starlette.io/testclient/#testing-websocket-sessions" class="external-link" target="_blank">testing WebSockets</a>.
|
||||
|
||||
@@ -29,7 +29,7 @@ Let's imagine you want to get the client's IP address/host inside of your *path
|
||||
|
||||
For that you need to access the request directly.
|
||||
|
||||
```Python hl_lines="1 7 8"
|
||||
```Python hl_lines="1 7-8"
|
||||
{!../../../docs_src/using_request_directly/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ In production you would have one of the options above.
|
||||
|
||||
But it's the simplest way to focus on the server-side of WebSockets and have a working example:
|
||||
|
||||
```Python hl_lines="2 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 41 42 43"
|
||||
```Python hl_lines="2 6-38 41-43"
|
||||
{!../../../docs_src/websockets/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -32,7 +32,7 @@ But it's the simplest way to focus on the server-side of WebSockets and have a w
|
||||
|
||||
In your **FastAPI** application, create a `websocket`:
|
||||
|
||||
```Python hl_lines="1 46 47"
|
||||
```Python hl_lines="1 46-47"
|
||||
{!../../../docs_src/websockets/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -45,44 +45,13 @@ In your **FastAPI** application, create a `websocket`:
|
||||
|
||||
In your WebSocket route you can `await` for messages and send messages.
|
||||
|
||||
```Python hl_lines="48 49 50 51 52"
|
||||
```Python hl_lines="48-52"
|
||||
{!../../../docs_src/websockets/tutorial001.py!}
|
||||
```
|
||||
|
||||
You can receive and send binary, text, and JSON data.
|
||||
|
||||
## Using `Depends` and others
|
||||
|
||||
In WebSocket endpoints you can import from `fastapi` and use:
|
||||
|
||||
* `Depends`
|
||||
* `Security`
|
||||
* `Cookie`
|
||||
* `Header`
|
||||
* `Path`
|
||||
* `Query`
|
||||
|
||||
They work the same way as for other FastAPI endpoints/*path operations*:
|
||||
|
||||
```Python hl_lines="53 54 55 56 57 58 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76"
|
||||
{!../../../docs_src/websockets/tutorial002.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
In a WebSocket it doesn't really make sense to raise an `HTTPException`. So it's better to close the WebSocket connection directly.
|
||||
|
||||
You can use a closing code from the <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">valid codes defined in the specification</a>.
|
||||
|
||||
In the future, there will be a `WebSocketException` that you will be able to `raise` from anywhere, and add exception handlers for it. It depends on the <a href="https://github.com/encode/starlette/pull/527" class="external-link" target="_blank">PR #527</a> in Starlette.
|
||||
|
||||
## More info
|
||||
|
||||
To learn more about the options, check Starlette's documentation for:
|
||||
|
||||
* <a href="https://www.starlette.io/websockets/" class="external-link" target="_blank">The `WebSocket` class</a>.
|
||||
* <a href="https://www.starlette.io/endpoints/#websocketendpoint" class="external-link" target="_blank">Class-based WebSocket handling</a>.
|
||||
|
||||
## Test it
|
||||
## Try it
|
||||
|
||||
If your file is named `main.py`, run your application with:
|
||||
|
||||
@@ -115,3 +84,89 @@ You can send (and receive) many messages:
|
||||
<img src="/img/tutorial/websockets/image04.png">
|
||||
|
||||
And all of them will use the same WebSocket connection.
|
||||
|
||||
## Using `Depends` and others
|
||||
|
||||
In WebSocket endpoints you can import from `fastapi` and use:
|
||||
|
||||
* `Depends`
|
||||
* `Security`
|
||||
* `Cookie`
|
||||
* `Header`
|
||||
* `Path`
|
||||
* `Query`
|
||||
|
||||
They work the same way as for other FastAPI endpoints/*path operations*:
|
||||
|
||||
```Python hl_lines="58-65 68-83"
|
||||
{!../../../docs_src/websockets/tutorial002.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
In a WebSocket it doesn't really make sense to raise an `HTTPException`. So it's better to close the WebSocket connection directly.
|
||||
|
||||
You can use a closing code from the <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">valid codes defined in the specification</a>.
|
||||
|
||||
In the future, there will be a `WebSocketException` that you will be able to `raise` from anywhere, and add exception handlers for it. It depends on the <a href="https://github.com/encode/starlette/pull/527" class="external-link" target="_blank">PR #527</a> in Starlette.
|
||||
|
||||
### Try the WebSockets with dependencies
|
||||
|
||||
If your file is named `main.py`, run your application with:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Open your browser at <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
|
||||
|
||||
There you can set:
|
||||
|
||||
* The "Item ID", used in the path.
|
||||
* The "Token" used as a query parameter.
|
||||
|
||||
!!! tip
|
||||
Notice that the query `token` will be handled by a dependency.
|
||||
|
||||
With that you can connect the WebSocket and then send and receive messages:
|
||||
|
||||
<img src="/img/tutorial/websockets/image05.png">
|
||||
|
||||
## Handling disconnections and multiple clients
|
||||
|
||||
When a WebSocket connection is closed, the `await websocket.receive_text()` will raise a `WebSocketDisconnect` exception, which you can then catch and handle like in this example.
|
||||
|
||||
```Python hl_lines="81-83"
|
||||
{!../../../docs_src/websockets/tutorial003.py!}
|
||||
```
|
||||
|
||||
To try it out:
|
||||
|
||||
* Open the app with several browser tabs.
|
||||
* Write messages from them.
|
||||
* Then close one of the tabs.
|
||||
|
||||
That will raise the `WebSocketDisconnect` exception, and all the other clients will receive a message like:
|
||||
|
||||
```
|
||||
Client #1596980209979 left the chat
|
||||
```
|
||||
|
||||
!!! tip
|
||||
The app above is a minimal and simple example to demonstrate how to handle and broadcast messages to several WebSocket connections.
|
||||
|
||||
But have in mind that, as everything is handled in memory, in a single list, it will only work while the process is running, and will only work with a single process.
|
||||
|
||||
If you need something easy to integrate with FastAPI but that is more robust, supported by Redis, PostgreSQL or others, check <a href="https://github.com/encode/broadcaster" class="external-link" target="_blank">encode/broadcaster</a>.
|
||||
|
||||
## More info
|
||||
|
||||
To learn more about the options, check Starlette's documentation for:
|
||||
|
||||
* <a href="https://www.starlette.io/websockets/" class="external-link" target="_blank">The `WebSocket` class</a>.
|
||||
* <a href="https://www.starlette.io/endpoints/#websocketendpoint" class="external-link" target="_blank">Class-based WebSocket handling</a>.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Including WSGI - Flask, Django, others
|
||||
|
||||
You can mount WSGI applications as you saw with [Sub Applications - Behind a Proxy, Mounts](./sub-applications-proxy.md){.internal-link target=_blank}.
|
||||
You can mount WSGI applications as you saw with [Sub Applications - Mounts](./sub-applications.md){.internal-link target=_blank}, [Behind a Proxy](./behind-a-proxy.md){.internal-link target=_blank}.
|
||||
|
||||
For that, you can use the `WSGIMiddleware` and use it to wrap your WSGI application, for example, Flask, Django, etc.
|
||||
|
||||
@@ -12,7 +12,7 @@ Then wrap the WSGI (e.g. Flask) app with the middleware.
|
||||
|
||||
And then mount that under a path.
|
||||
|
||||
```Python hl_lines="2 3 22"
|
||||
```Python hl_lines="2-3 22"
|
||||
{!../../../docs_src/wsgi/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ It was one of the first examples of **automatic API documentation**, and this wa
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
Have an automatic API documentation web user interface.
|
||||
|
||||
### <a href="http://flask.pocoo.org/" class="external-link" target="_blank">Flask</a>
|
||||
### <a href="https://flask.palletsprojects.com" class="external-link" target="_blank">Flask</a>
|
||||
|
||||
Flask is a "microframework", it doesn't include database integrations nor many of the things that come by default in Django.
|
||||
|
||||
@@ -57,7 +57,7 @@ Given the simplicity of Flask, it seemed like a good match for building APIs. Th
|
||||
Have a simple and easy to use routing system.
|
||||
|
||||
|
||||
### <a href="http://docs.python-requests.org" class="external-link" target="_blank">Requests</a>
|
||||
### <a href="https://requests.readthedocs.io" class="external-link" target="_blank">Requests</a>
|
||||
|
||||
**FastAPI** is not actually an alternative to **Requests**. Their scope is very different.
|
||||
|
||||
@@ -276,7 +276,7 @@ Routes are declared in a single place, using functions declared in other places
|
||||
|
||||
This actually inspired updating parts of Pydantic, to support the same validation declaration style (all this functionality is now already available in Pydantic).
|
||||
|
||||
### <a href="http://www.hug.rest/" class="external-link" target="_blank">Hug</a>
|
||||
### <a href="https://www.hug.rest/" class="external-link" target="_blank">Hug</a>
|
||||
|
||||
Hug was one of the first frameworks to implement the declaration of API parameter types using Python type hints. This was a great idea that inspired other tools to do the same.
|
||||
|
||||
@@ -410,7 +410,7 @@ It is the recommended server for Starlette and **FastAPI**.
|
||||
|
||||
You can combine it with Gunicorn, to have an asynchronous multi-process server.
|
||||
|
||||
Check more details in the [Deployment](deployment.md){.internal-link target=_blank} section.
|
||||
Check more details in the [Deployment](deployment/index.md){.internal-link target=_blank} section.
|
||||
|
||||
## Benchmarks and speed
|
||||
|
||||
|
||||
@@ -102,13 +102,15 @@ To see the difference, imagine the following story about burgers:
|
||||
|
||||
### Concurrent Burgers
|
||||
|
||||
<!-- The gender neutral cook emoji "🧑🍳" does not render well in browsers. In the meantime, I'm using a mix of male "👨🍳" and female "👩🍳" cooks. -->
|
||||
|
||||
You go with your crush 😍 to get fast food 🍔, you stand in line while the cashier 💁 takes the orders from the people in front of you.
|
||||
|
||||
Then it's your turn, you place your order of 2 very fancy burgers 🍔 for your crush 😍 and you.
|
||||
|
||||
You pay 💸.
|
||||
|
||||
The cashier 💁 says something to the guy in the kitchen 👨🍳 so he knows he has to prepare your burgers 🍔 (even though he is currently preparing the ones for the previous clients).
|
||||
The cashier 💁 says something to the cook in the kitchen 👨🍳 so they know they have to prepare your burgers 🍔 (even though they are currently preparing the ones for the previous clients).
|
||||
|
||||
The cashier 💁 gives you the number of your turn.
|
||||
|
||||
@@ -146,9 +148,9 @@ Now let's imagine these aren't "Concurrent Burgers", but "Parallel Burgers".
|
||||
|
||||
You go with your crush 😍 to get parallel fast food 🍔.
|
||||
|
||||
You stand in line while several (let's say 8) cashiers that at the same time are cooks 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳 take the orders from the people in front of you.
|
||||
You stand in line while several (let's say 8) cashiers that at the same time are cooks 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 take the orders from the people in front of you.
|
||||
|
||||
Everyone before you is waiting 🕙 for their burgers 🍔 to be ready before leaving the counter because each of the 8 cashiers goes himself and prepares the burger right away before getting the next order.
|
||||
Everyone before you is waiting 🕙 for their burgers 🍔 to be ready before leaving the counter because each of the 8 cashiers goes and prepares the burger right away before getting the next order.
|
||||
|
||||
Then it's finally your turn, you place your order of 2 very fancy burgers 🍔 for your crush 😍 and you.
|
||||
|
||||
@@ -174,7 +176,7 @@ There was not much talk or flirting as most of the time was spent waiting 🕙 i
|
||||
|
||||
In this scenario of the parallel burgers, you are a computer / program 🤖 with two processors (you and your crush 😍), both waiting 🕙 and dedicating their attention ⏯ to be "waiting on the counter" 🕙 for a long time.
|
||||
|
||||
The fast food store has 8 processors (cashiers/cooks) 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳. While the concurrent burgers store might have had only 2 (one cashier and one cook) 💁 👨🍳.
|
||||
The fast food store has 8 processors (cashiers/cooks) 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳. While the concurrent burgers store might have had only 2 (one cashier and one cook) 💁 👨🍳.
|
||||
|
||||
But still, the final experience is not the best 😞.
|
||||
|
||||
@@ -210,7 +212,7 @@ Most of the existing popular Python frameworks (including Flask and Django) were
|
||||
|
||||
Even though the main specification for asynchronous web Python (ASGI) was developed at Django, to add support for WebSockets.
|
||||
|
||||
That kind of asynchronicity is what made NodeJS popular (even though NodeJS is not parallel) and that's the strength of Go as a programing language.
|
||||
That kind of asynchronicity is what made NodeJS popular (even though NodeJS is not parallel) and that's the strength of Go as a programming language.
|
||||
|
||||
And that's the same level of performance you get with **FastAPI**.
|
||||
|
||||
@@ -236,7 +238,7 @@ You could have turns as in the burgers example, first the living room, then the
|
||||
|
||||
It would take the same amount of time to finish with or without turns (concurrency) and you would have done the same amount of work.
|
||||
|
||||
But in this case, if you could bring the 8 ex-cashier/cooks/now-cleaners 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳, and each one of them (plus you) could take a zone of the house to clean it, you could do all the work in **parallel**, with the extra help, and finish much sooner.
|
||||
But in this case, if you could bring the 8 ex-cashier/cooks/now-cleaners 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳, and each one of them (plus you) could take a zone of the house to clean it, you could do all the work in **parallel**, with the extra help, and finish much sooner.
|
||||
|
||||
In this scenario, each one of the cleaners (including you) would be a processor, doing their part of the job.
|
||||
|
||||
@@ -261,11 +263,11 @@ But you can also exploit the benefits of parallelism and multiprocessing (having
|
||||
|
||||
That, plus the simple fact that Python is the main language for **Data Science**, Machine Learning and especially Deep Learning, make FastAPI a very good match for Data Science / Machine Learning web APIs and applications (among many others).
|
||||
|
||||
To see how to achieve this parallelism in production see the section about [Deployment](deployment.md){.internal-link target=_blank}.
|
||||
To see how to achieve this parallelism in production see the section about [Deployment](deployment/index.md){.internal-link target=_blank}.
|
||||
|
||||
## `async` and `await`
|
||||
|
||||
Modern versions of python have a very intuitive way to define asynchronous code. This makes it look just like normal "sequential" code and do the "awaiting" for you at the right moments.
|
||||
Modern versions of Python have a very intuitive way to define asynchronous code. This makes it look just like normal "sequential" code and do the "awaiting" for you at the right moments.
|
||||
|
||||
When there is an operation that will require waiting before giving the results and has support for these new Python features, you can code it like:
|
||||
|
||||
@@ -305,7 +307,7 @@ burgers = get_burgers(2)
|
||||
|
||||
So, if you are using a library that tells you that you can call it with `await`, you need to create the *path operation functions* that uses it with `async def`, like in:
|
||||
|
||||
```Python hl_lines="2 3"
|
||||
```Python hl_lines="2-3"
|
||||
@app.get('/burgers')
|
||||
async def read_burgers():
|
||||
burgers = await get_burgers(2)
|
||||
@@ -334,9 +336,9 @@ This same syntax (or almost identical) was also included recently in modern vers
|
||||
|
||||
But before that, handling asynchronous code was quite more complex and difficult.
|
||||
|
||||
In previous versions of Python, you could have used threads or <a href="http://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. But the code is way more complex to understand, debug, and think about.
|
||||
In previous versions of Python, you could have used threads or <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. But the code is way more complex to understand, debug, and think about.
|
||||
|
||||
In previous versions of NodeJS / Browser JavaScript, you would have used "callbacks". Which lead to <a href="http://callbackhell.com/" class="external-link" target="_blank">callback hell</a>.
|
||||
In previous versions of NodeJS / Browser JavaScript, you would have used "callbacks". Which leads to <a href="http://callbackhell.com/" class="external-link" target="_blank">callback hell</a>.
|
||||
|
||||
## Coroutines
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ When you check the benchmarks, it is common to see several tools of different ty
|
||||
|
||||
Specifically, to see Uvicorn, Starlette and FastAPI compared together (among many other tools).
|
||||
|
||||
The simplest the problem solved by the tool, the better performance it will get. And most of the benchmarks don't test the additional features provided by the tool.
|
||||
The simpler the problem solved by the tool, the better performance it will get. And most of the benchmarks don't test the additional features provided by the tool.
|
||||
|
||||
The hierarchy is like:
|
||||
|
||||
|
||||
@@ -499,13 +499,3 @@ $ bash scripts/test-cov-html.sh
|
||||
</div>
|
||||
|
||||
This command generates a directory `./htmlcov/`, if you open the file `./htmlcov/index.html` in your browser, you can explore interactively the regions of code that are covered by the tests, and notice if there is any region missing.
|
||||
|
||||
### Tests in your editor
|
||||
|
||||
If you want to use the integrated tests in your editor add `./docs_src` to your `PYTHONPATH` variable.
|
||||
|
||||
For example, in VS Code you can create a file `.env` with:
|
||||
|
||||
```env
|
||||
PYTHONPATH=./docs_src
|
||||
```
|
||||
|
||||
@@ -1,13 +1,105 @@
|
||||
a.external-link::after {
|
||||
/* \00A0 is a non-breaking space
|
||||
/* \00A0 is a non-breaking space
|
||||
to make the mark be on the same line as the link
|
||||
*/
|
||||
content: "\00A0[↪]";
|
||||
content: "\00A0[↪]";
|
||||
}
|
||||
|
||||
a.internal-link::after {
|
||||
/* \00A0 is a non-breaking space
|
||||
/* \00A0 is a non-breaking space
|
||||
to make the mark be on the same line as the link
|
||||
*/
|
||||
content: "\00A0↪";
|
||||
content: "\00A0↪";
|
||||
}
|
||||
|
||||
/* Give space to lower icons so Gitter chat doesn't get on top of them */
|
||||
.md-footer-meta {
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
|
||||
.user-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.user-list-center {
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.user {
|
||||
margin: 1em;
|
||||
min-width: 7em;
|
||||
}
|
||||
|
||||
.user .avatar-wrapper {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: 10px auto;
|
||||
overflow: hidden;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.user .avatar-wrapper img {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.user .title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.user .count {
|
||||
font-size: 80%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
a.announce-link:link,
|
||||
a.announce-link:visited {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
a.announce-link:hover {
|
||||
color: var(--md-accent-fg-color);
|
||||
}
|
||||
|
||||
.announce-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.announce-wrapper div.item {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.announce-wrapper .sponsor-badge {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
right: 0;
|
||||
font-size: 0.5rem;
|
||||
color: #999;
|
||||
background-color: #666;
|
||||
border-radius: 10px;
|
||||
padding: 0 10px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.announce-wrapper .sponsor-image {
|
||||
display: block;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.announce-wrapper>div {
|
||||
min-height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.twitter {
|
||||
color: #00acee;
|
||||
}
|
||||
|
||||
@@ -1,394 +0,0 @@
|
||||
# Deployment
|
||||
|
||||
Deploying a **FastAPI** application is relatively easy.
|
||||
|
||||
There are several ways to do it depending on your specific use case and the tools that you use.
|
||||
|
||||
You will see more about some of the ways to do it in the next sections.
|
||||
|
||||
## FastAPI versions
|
||||
|
||||
**FastAPI** is already being used in production in many applications and systems. And the test coverage is kept at 100%. But its development is still moving quickly.
|
||||
|
||||
New features are added frequently, bugs are fixed regularly, and the code is still continuously improving.
|
||||
|
||||
That's why the current versions are still `0.x.x`, this reflects that each version could potentially have breaking changes. This follows the <a href="https://semver.org/" class="external-link" target="_blank">Semantic Versioning</a> conventions.
|
||||
|
||||
You can create production applications with **FastAPI** right now (and you have probably been doing it for some time), you just have to make sure that you use a version that works correctly with the rest of your code.
|
||||
|
||||
### Pin your `fastapi` version
|
||||
|
||||
The first thing you should do is to "pin" the version of **FastAPI** you are using to the specific latest version that you know works correctly for your application.
|
||||
|
||||
For example, let's say you are using version `0.45.0` in your app.
|
||||
|
||||
If you use a `requirements.txt` file you could specify the version with:
|
||||
|
||||
```txt
|
||||
fastapi==0.45.0
|
||||
```
|
||||
|
||||
that would mean that you would use exactly the version `0.45.0`.
|
||||
|
||||
Or you could also pin it with:
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
that would mean that you would use the versions `0.45.0` or above, but less than `0.46.0`, for example, a version `0.45.2` would still be accepted.
|
||||
|
||||
If you use any other tool to manage your installations, like Poetry, Pipenv, or others, they all have a way that you can use to define specific versions for your packages.
|
||||
|
||||
### Available versions
|
||||
|
||||
You can see the available versions (e.g. to check what is the current latest) in the [Release Notes](release-notes.md){.internal-link target=_blank}.
|
||||
|
||||
### About versions
|
||||
|
||||
Following the Semantic Versioning conventions, any version below `1.0.0` could potentially add breaking changes.
|
||||
|
||||
FastAPI also follows the convention that any "PATCH" version change is for bug fixes and non-breaking changes.
|
||||
|
||||
!!! tip
|
||||
The "PATCH" is the last number, for example, in `0.2.3`, the PATCH version is `3`.
|
||||
|
||||
So, you should be able to pin to a version like:
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
Breaking changes and new features are added in "MINOR" versions.
|
||||
|
||||
!!! tip
|
||||
The "MINOR" is the number in the middle, for example, in `0.2.3`, the MINOR version is `2`.
|
||||
|
||||
### Upgrading the FastAPI versions
|
||||
|
||||
You should add tests for your app.
|
||||
|
||||
With **FastAPI** it's very easy (thanks to Starlette), check the docs: [Testing](tutorial/testing.md){.internal-link target=_blank}
|
||||
|
||||
After you have tests, then you can upgrade the **FastAPI** version to a more recent one, and make sure that all your code is working correctly by running your tests.
|
||||
|
||||
If everything is working, or after you make the necessary changes, and all your tests are passing, then you can pin your `fastapi` to that new recent version.
|
||||
|
||||
### About Starlette
|
||||
|
||||
You shouldn't pin the version of `starlette`.
|
||||
|
||||
Different versions of **FastAPI** will use a specific newer version of Starlette.
|
||||
|
||||
So, you can just let **FastAPI** use the correct Starlette version.
|
||||
|
||||
### About Pydantic
|
||||
|
||||
Pydantic includes the tests for **FastAPI** with its own tests, so new versions of Pydantic (above `1.0.0`) are always compatible with FastAPI.
|
||||
|
||||
You can pin Pydantic to any version above `1.0.0` that works for you and below `2.0.0`.
|
||||
|
||||
For example:
|
||||
|
||||
```txt
|
||||
pydantic>=1.2.0,<2.0.0
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
In this section you'll see instructions and links to guides to know how to:
|
||||
|
||||
* Make your **FastAPI** application a Docker image/container with maximum performance. In about **5 min**.
|
||||
* (Optionally) understand what you, as a developer, need to know about HTTPS.
|
||||
* Set up a Docker Swarm mode cluster with automatic HTTPS, even on a simple $5 USD/month server. In about **20 min**.
|
||||
* Generate and deploy a full **FastAPI** application, using your Docker Swarm cluster, with HTTPS, etc. In about **10 min**.
|
||||
|
||||
You can use <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a> for deployment. It has several advantages like security, replicability, development simplicity, etc.
|
||||
|
||||
If you are using Docker, you can use the official Docker image:
|
||||
|
||||
### <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>
|
||||
|
||||
This image has an "auto-tuning" mechanism included, so that you can just add your code and get very high performance automatically. And without making sacrifices.
|
||||
|
||||
But you can still change and update all the configurations with environment variables or configuration files.
|
||||
|
||||
!!! tip
|
||||
To see all the configurations and options, go to the Docker image page: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
|
||||
|
||||
### Create a `Dockerfile`
|
||||
|
||||
* Go to your project directory.
|
||||
* Create a `Dockerfile` with:
|
||||
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||
|
||||
COPY ./app /app
|
||||
```
|
||||
|
||||
#### Bigger Applications
|
||||
|
||||
If you followed the section about creating [Bigger Applications with Multiple Files](tutorial/bigger-applications.md){.internal-link target=_blank}, your `Dockerfile` might instead look like:
|
||||
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||
|
||||
COPY ./app /app/app
|
||||
```
|
||||
|
||||
#### Raspberry Pi and other architectures
|
||||
|
||||
If you are running Docker in a Raspberry Pi (that has an ARM processor) or any other architecture, you can create a `Dockerfile` from scratch, based on a Python base image (that is multi-architecture) and use Uvicorn alone.
|
||||
|
||||
In this case, your `Dockerfile` could look like:
|
||||
|
||||
```Dockerfile
|
||||
FROM python:3.7
|
||||
|
||||
RUN pip install fastapi uvicorn
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
COPY ./app /app
|
||||
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
### Create the **FastAPI** Code
|
||||
|
||||
* Create an `app` directory and enter in it.
|
||||
* Create a `main.py` file with:
|
||||
|
||||
```Python
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
* You should now have a directory structure like:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ └── main.py
|
||||
└── Dockerfile
|
||||
```
|
||||
|
||||
### Build the Docker image
|
||||
|
||||
* Go to the project directory (in where your `Dockerfile` is, containing your `app` directory).
|
||||
* Build your FastAPI image:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ docker build -t myimage .
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Start the Docker container
|
||||
|
||||
* Run a container based on your image:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ docker run -d --name mycontainer -p 80:80 myimage
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Now you have an optimized FastAPI server in a Docker container. Auto-tuned for your current server (and number of CPU cores).
|
||||
|
||||
### Check it
|
||||
|
||||
You should be able to check it in your Docker container's URL, for example: <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> or <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> (or equivalent, using your Docker host).
|
||||
|
||||
You will see something like:
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
### Interactive API docs
|
||||
|
||||
Now you can go to <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> or <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (or equivalent, using your Docker host).
|
||||
|
||||
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 you can also go to <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> or <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (or equivalent, using your Docker host).
|
||||
|
||||
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
|
||||
|
||||

|
||||
|
||||
## HTTPS
|
||||
|
||||
### About HTTPS
|
||||
|
||||
It is easy to assume that HTTPS is something that is just "enabled" or not.
|
||||
|
||||
But it is way more complex than that.
|
||||
|
||||
!!! tip
|
||||
If you are in a hurry or don't care, continue with the next section for step by step instructions to set everything up.
|
||||
|
||||
To learn the basics of HTTPS, from a consumer perspective, check <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a>.
|
||||
|
||||
Now, from a developer's perspective, here are several things to have in mind while thinking about HTTPS:
|
||||
|
||||
* For HTTPS, the server needs to have "certificates" generated by a third party.
|
||||
* Those certificates are actually acquired from the third-party, not "generated".
|
||||
* Certificates have a lifetime.
|
||||
* They expire.
|
||||
* And then they need to be renewed, acquired again from the third party.
|
||||
* The encryption of the connection happens at the TCP level.
|
||||
* That's one layer below HTTP.
|
||||
* So, the certificate and encryption handling is done before HTTP.
|
||||
* TCP doesn't know about "domains". Only about IP addresses.
|
||||
* The information about the specific domain requested goes in the HTTP data.
|
||||
* The HTTPS certificates "certify" a certain domain, but the protocol and encryption happen at the TCP level, before knowing which domain is being dealt with.
|
||||
* By default, that would mean that you can only have one HTTPS certificate per IP address.
|
||||
* No matter how big your server is or how small each application you have on it might be.
|
||||
* There is a solution to this, however.
|
||||
* There's an extension to the TLS protocol (the one handling the encryption at the TCP level, before HTTP) called <a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication">SNI</abbr></a>.
|
||||
* This SNI extension allows one single server (with a single IP address) to have several HTTPS certificates and serve multiple HTTPS domains/applications.
|
||||
* For this to work, a single component (program) running on the server, listening on the public IP address, must have all the HTTPS certificates in the server.
|
||||
* After obtaining a secure connection, the communication protocol is still HTTP.
|
||||
* The contents are encrypted, even though they are being sent with the HTTP protocol.
|
||||
|
||||
It is a common practice to have one program/HTTP server running on the server (the machine, host, etc.) and managing all the HTTPS parts : sending the decrypted HTTP requests to the actual HTTP application running in the same server (the **FastAPI** application, in this case), take the HTTP response from the application, encrypt it using the appropriate certificate and sending it back to the client using HTTPS. This server is often called a <a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">TLS Termination Proxy</a>.
|
||||
|
||||
### Let's Encrypt
|
||||
|
||||
Before Let's Encrypt, these HTTPS certificates were sold by trusted third-parties.
|
||||
|
||||
The process to acquire one of these certificates used to be cumbersome, require quite some paperwork and the certificates were quite expensive.
|
||||
|
||||
But then <a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a> was created.
|
||||
|
||||
It is a project from the Linux Foundation. It provides HTTPS certificates for free. In an automated way. These certificates use all the standard cryptographic security, and are short lived (about 3 months), so the security is actually better because of their reduced lifespan.
|
||||
|
||||
The domains are securely verified and the certificates are generated automatically. This also allows automating the renewal of these certificates.
|
||||
|
||||
The idea is to automate the acquisition and renewal of these certificates, so that you can have secure HTTPS, for free, forever.
|
||||
|
||||
### Traefik
|
||||
|
||||
<a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a> is a high performance reverse proxy / load balancer. It can do the "TLS Termination Proxy" job (apart from other features).
|
||||
|
||||
It has integration with Let's Encrypt. So, it can handle all the HTTPS parts, including certificate acquisition and renewal.
|
||||
|
||||
It also has integrations with Docker. So, you can declare your domains in each application configurations and have it read those configurations, generate the HTTPS certificates and serve HTTPS to your application automatically, without requiring any change in its configuration.
|
||||
|
||||
---
|
||||
|
||||
With this information and tools, continue with the next section to combine everything.
|
||||
|
||||
## Docker Swarm mode cluster with Traefik and HTTPS
|
||||
|
||||
You can have a Docker Swarm mode cluster set up in minutes (about 20 min) with a main Traefik handling HTTPS (including certificate acquisition and renewal).
|
||||
|
||||
By using Docker Swarm mode, you can start with a "cluster" of a single machine (it can even be a $5 USD / month server) and then you can grow as much as you need adding more servers.
|
||||
|
||||
To set up a Docker Swarm Mode cluster with Traefik and HTTPS handling, follow this guide:
|
||||
|
||||
### <a href="https://medium.com/@tiangolo/docker-swarm-mode-and-traefik-for-a-https-cluster-20328dba6232" class="external-link" target="_blank">Docker Swarm Mode and Traefik for an HTTPS cluster</a>
|
||||
|
||||
### Deploy a FastAPI application
|
||||
|
||||
The easiest way to set everything up, would be using the [**FastAPI** Project Generators](project-generation.md){.internal-link target=_blank}.
|
||||
|
||||
It is designed to be integrated with this Docker Swarm cluster with Traefik and HTTPS described above.
|
||||
|
||||
You can generate a project in about 2 min.
|
||||
|
||||
The generated project has instructions to deploy it, doing it takes another 2 min.
|
||||
|
||||
## Alternatively, deploy **FastAPI** without Docker
|
||||
|
||||
You can deploy **FastAPI** directly without Docker too.
|
||||
|
||||
You just need to install an ASGI compatible server like:
|
||||
|
||||
=== "Uvicorn"
|
||||
|
||||
* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>, a lightning-fast ASGI server, built on uvloop and httptools.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install uvicorn
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
=== "Hypercorn"
|
||||
|
||||
* <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>, an ASGI server also compatible with HTTP/2.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install hypercorn
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
...or any other ASGI server.
|
||||
|
||||
And run your application the same way you have done in the tutorials, but without the `--reload` option, e.g.:
|
||||
|
||||
=== "Uvicorn"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --host 0.0.0.0 --port 80
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
=== "Hypercorn"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ hypercorn main:app --bind 0.0.0.0:80
|
||||
|
||||
Running on 0.0.0.0:8080 over http (CTRL + C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
You might want to set up some tooling to make sure it is restarted automatically if it stops.
|
||||
|
||||
You might also want to install <a href="https://gunicorn.org/" class="external-link" target="_blank">Gunicorn</a> and <a href="https://www.uvicorn.org/#running-with-gunicorn" class="external-link" target="_blank">use it as a manager for Uvicorn</a>, or use Hypercorn with multiple workers.
|
||||
|
||||
Making sure to fine-tune the number of workers, etc.
|
||||
|
||||
But if you are doing all that, you might just use the Docker image that does it automatically.
|
||||
240
docs/en/docs/deployment/deta.md
Normal file
@@ -0,0 +1,240 @@
|
||||
# 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. 🎁
|
||||
|
||||
It will take you about **10 minutes**.
|
||||
|
||||
!!! info
|
||||
<a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> is a **FastAPI** sponsor. 🎉
|
||||
|
||||
## A basic **FastAPI** app
|
||||
|
||||
* Create a directory for your app, for example `./fastapideta/` and enter in it.
|
||||
|
||||
### FastAPI code
|
||||
|
||||
* Create a `main.py` file with:
|
||||
|
||||
```Python
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int):
|
||||
return {"item_id": item_id}
|
||||
```
|
||||
|
||||
### Requirements
|
||||
|
||||
Now, in the same directory create a file `requirements.txt` with:
|
||||
|
||||
```text
|
||||
fastapi
|
||||
```
|
||||
|
||||
!!! tip
|
||||
You don't need to install Uvicorn to deploy on Deta, although you would probably want to install it locally to test your app.
|
||||
|
||||
### Directory structure
|
||||
|
||||
You will now have one directory `./fastapideta/` with two files:
|
||||
|
||||
```
|
||||
.
|
||||
└── main.py
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
## Create a free Deta account
|
||||
|
||||
Now create a <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">free account on Deta</a>, you just need an email and password.
|
||||
|
||||
You don't even need a credit card.
|
||||
|
||||
## Install the CLI
|
||||
|
||||
Once you have your account, install the Deta <abbr title="Command Line Interface application">CLI</abbr>:
|
||||
|
||||
=== "Linux, macOS"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ curl -fsSL https://get.deta.dev/cli.sh | sh
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
=== "Windows PowerShell"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ iwr https://get.deta.dev/cli.ps1 -useb | iex
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
After installing it, open a new terminal so that the installed CLI is detected.
|
||||
|
||||
In a new terminal, confirm that it was correctly installed with:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ deta --help
|
||||
|
||||
Deta command line interface for managing deta micros.
|
||||
Complete documentation available at https://docs.deta.sh
|
||||
|
||||
Usage:
|
||||
deta [flags]
|
||||
deta [command]
|
||||
|
||||
Available Commands:
|
||||
auth Change auth settings for a deta micro
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
!!! tip
|
||||
If you have problems installing the CLI, check the <a href="https://docs.deta.sh/docs/micros/getting_started?ref=fastapi" class="external-link" target="_blank">official Deta docs</a>.
|
||||
|
||||
## Login with the CLI
|
||||
|
||||
Now login to Deta from the CLI with:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ deta login
|
||||
|
||||
Please, log in from the web page. Waiting..
|
||||
Logged in successfully.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
This will open a web browser and authenticate automatically.
|
||||
|
||||
## Deploy with Deta
|
||||
|
||||
Next, deploy your application with the Deta CLI:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ deta new
|
||||
|
||||
Successfully created a new micro
|
||||
|
||||
// Notice the "endpoint" 🔍
|
||||
|
||||
{
|
||||
"name": "fastapideta",
|
||||
"runtime": "python3.7",
|
||||
"endpoint": "https://qltnci.deta.dev",
|
||||
"visor": "enabled",
|
||||
"http_auth": "enabled"
|
||||
}
|
||||
|
||||
Adding dependencies...
|
||||
|
||||
|
||||
---> 100%
|
||||
|
||||
|
||||
Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
You will see a JSON message similar to:
|
||||
|
||||
```JSON hl_lines="4"
|
||||
{
|
||||
"name": "fastapideta",
|
||||
"runtime": "python3.7",
|
||||
"endpoint": "https://qltnci.deta.dev",
|
||||
"visor": "enabled",
|
||||
"http_auth": "enabled"
|
||||
}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Your deployment will have a different `"endpoint"` URL.
|
||||
|
||||
## Check it
|
||||
|
||||
Now open your browser in your `endpoint` URL. In the example above it was `https://qltnci.deta.dev`, but yours will be different.
|
||||
|
||||
You will see the JSON response from your FastAPI app:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"Hello": "World"
|
||||
}
|
||||
```
|
||||
|
||||
And now go to the `/docs` for your API, in the example above it would be `https://qltnci.deta.dev/docs`.
|
||||
|
||||
It will show your docs like:
|
||||
|
||||
<img src="/img/deployment/deta/image01.png">
|
||||
|
||||
## Enable public access
|
||||
|
||||
By default, Deta will handle authentication using cookies for your account.
|
||||
|
||||
But once you are ready, you can make it public with:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ deta auth disable
|
||||
|
||||
Successfully disabled http auth
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Now you can share that URL with anyone and they will be able to access your API. 🚀
|
||||
|
||||
## HTTPS
|
||||
|
||||
Congrats! You deployed your FastAPI app to Deta! 🎉 🍰
|
||||
|
||||
Also notice that Deta correctly handles HTTPS for you, so you don't have to take care of that and can be sure that your clients will have a secure encrypted connection. ✅ 🔒
|
||||
|
||||
## Check the Visor
|
||||
|
||||
From your docs UI (they will be in a URL like `https://qltnci.deta.dev/docs`) send a request to your *path operation* `/items/{item_id}`.
|
||||
|
||||
For example with ID `5`.
|
||||
|
||||
Now go to <a href="https://web.deta.sh/" class="external-link" target="_blank">https://web.deta.sh</a>.
|
||||
|
||||
You will see there's a section to the left called <abbr title="it comes from Micro(server)">"Micros"</abbr> with each of your apps.
|
||||
|
||||
You will see a tab with "Details", and also a tab "Visor", go to the tab "Visor".
|
||||
|
||||
In there you can inspect the recent requests sent to your app.
|
||||
|
||||
You can also edit them and re-play them.
|
||||
|
||||
<img src="/img/deployment/deta/image02.png">
|
||||
|
||||
## Learn more
|
||||
|
||||
At some point you will probably want to store some data for your app in a way that persists through time. For that you can use <a href="https://docs.deta.sh/docs/base/py_tutorial?ref=fastapi" class="external-link" target="_blank">Deta Base</a>, it also has a generous **free tier**.
|
||||
|
||||
You can also read more in the <a href="https://docs.deta.sh?ref=fastapi" class="external-link" target="_blank">Deta Docs</a>.
|
||||
179
docs/en/docs/deployment/docker.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# Deploy with Docker
|
||||
|
||||
In this section you'll see instructions and links to guides to know how to:
|
||||
|
||||
* Make your **FastAPI** application a Docker image/container with maximum performance. In about **5 min**.
|
||||
* (Optionally) understand what you, as a developer, need to know about HTTPS.
|
||||
* Set up a Docker Swarm mode cluster with automatic HTTPS, even on a simple $5 USD/month server. In about **20 min**.
|
||||
* Generate and deploy a full **FastAPI** application, using your Docker Swarm cluster, with HTTPS, etc. In about **10 min**.
|
||||
|
||||
You can use <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a> for deployment. It has several advantages like security, replicability, development simplicity, etc.
|
||||
|
||||
If you are using Docker, you can use the official Docker image:
|
||||
|
||||
## <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>
|
||||
|
||||
This image has an "auto-tuning" mechanism included, so that you can just add your code and get very high performance automatically. And without making sacrifices.
|
||||
|
||||
But you can still change and update all the configurations with environment variables or configuration files.
|
||||
|
||||
!!! tip
|
||||
To see all the configurations and options, go to the Docker image page: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
|
||||
|
||||
## Create a `Dockerfile`
|
||||
|
||||
* Go to your project directory.
|
||||
* Create a `Dockerfile` with:
|
||||
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||
|
||||
COPY ./app /app
|
||||
```
|
||||
|
||||
### Bigger Applications
|
||||
|
||||
If you followed the section about creating [Bigger Applications with Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}, your `Dockerfile` might instead look like:
|
||||
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||
|
||||
COPY ./app /app/app
|
||||
```
|
||||
|
||||
### Raspberry Pi and other architectures
|
||||
|
||||
If you are running Docker in a Raspberry Pi (that has an ARM processor) or any other architecture, you can create a `Dockerfile` from scratch, based on a Python base image (that is multi-architecture) and use Uvicorn alone.
|
||||
|
||||
In this case, your `Dockerfile` could look like:
|
||||
|
||||
```Dockerfile
|
||||
FROM python:3.7
|
||||
|
||||
RUN pip install fastapi uvicorn
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
COPY ./app /app
|
||||
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
## Create the **FastAPI** Code
|
||||
|
||||
* Create an `app` directory and enter in it.
|
||||
* Create a `main.py` file 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}
|
||||
```
|
||||
|
||||
* You should now have a directory structure like:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ └── main.py
|
||||
└── Dockerfile
|
||||
```
|
||||
|
||||
## Build the Docker image
|
||||
|
||||
* Go to the project directory (in where your `Dockerfile` is, containing your `app` directory).
|
||||
* Build your FastAPI image:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ docker build -t myimage .
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Start the Docker container
|
||||
|
||||
* Run a container based on your image:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ docker run -d --name mycontainer -p 80:80 myimage
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Now you have an optimized FastAPI server in a Docker container. Auto-tuned for your current server (and number of CPU cores).
|
||||
|
||||
## Check it
|
||||
|
||||
You should be able to check it in your Docker container's URL, for example: <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> or <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> (or equivalent, using your Docker host).
|
||||
|
||||
You will see something like:
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
## Interactive API docs
|
||||
|
||||
Now you can go to <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> or <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (or equivalent, using your Docker host).
|
||||
|
||||
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 you can also go to <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> or <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (or equivalent, using your Docker host).
|
||||
|
||||
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
|
||||
|
||||

|
||||
|
||||
## Traefik
|
||||
|
||||
<a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a> is a high performance reverse proxy / load balancer. It can do the "TLS Termination Proxy" job (apart from other features).
|
||||
|
||||
It has integration with Let's Encrypt. So, it can handle all the HTTPS parts, including certificate acquisition and renewal.
|
||||
|
||||
It also has integrations with Docker. So, you can declare your domains in each application configurations and have it read those configurations, generate the HTTPS certificates and serve HTTPS to your application automatically, without requiring any change in its configuration.
|
||||
|
||||
---
|
||||
|
||||
With this information and tools, continue with the next section to combine everything.
|
||||
|
||||
## Docker Swarm mode cluster with Traefik and HTTPS
|
||||
|
||||
You can have a Docker Swarm mode cluster set up in minutes (about 20 min) with a main Traefik handling HTTPS (including certificate acquisition and renewal).
|
||||
|
||||
By using Docker Swarm mode, you can start with a "cluster" of a single machine (it can even be a $5 USD / month server) and then you can grow as much as you need adding more servers.
|
||||
|
||||
To set up a Docker Swarm Mode cluster with Traefik and HTTPS handling, follow this guide:
|
||||
|
||||
### <a href="https://medium.com/@tiangolo/docker-swarm-mode-and-traefik-for-a-https-cluster-20328dba6232" class="external-link" target="_blank">Docker Swarm Mode and Traefik for an HTTPS cluster</a>
|
||||
|
||||
### Deploy a FastAPI application
|
||||
|
||||
The easiest way to set everything up, would be using the [**FastAPI** Project Generators](../project-generation.md){.internal-link target=_blank}.
|
||||
|
||||
It is designed to be integrated with this Docker Swarm cluster with Traefik and HTTPS described above.
|
||||
|
||||
You can generate a project in about 2 min.
|
||||
|
||||
The generated project has instructions to deploy it, doing it takes another 2 min.
|
||||
48
docs/en/docs/deployment/https.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# About HTTPS
|
||||
|
||||
It is easy to assume that HTTPS is something that is just "enabled" or not.
|
||||
|
||||
But it is way more complex than that.
|
||||
|
||||
!!! tip
|
||||
If you are in a hurry or don't care, continue with the next sections for step by step instructions to set everything up with different techniques.
|
||||
|
||||
To learn the basics of HTTPS, from a consumer perspective, check <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a>.
|
||||
|
||||
Now, from a developer's perspective, here are several things to have in mind while thinking about HTTPS:
|
||||
|
||||
* For HTTPS, the server needs to have "certificates" generated by a third party.
|
||||
* Those certificates are actually acquired from the third-party, not "generated".
|
||||
* Certificates have a lifetime.
|
||||
* They expire.
|
||||
* And then they need to be renewed, acquired again from the third party.
|
||||
* The encryption of the connection happens at the TCP level.
|
||||
* That's one layer below HTTP.
|
||||
* So, the certificate and encryption handling is done before HTTP.
|
||||
* TCP doesn't know about "domains". Only about IP addresses.
|
||||
* The information about the specific domain requested goes in the HTTP data.
|
||||
* The HTTPS certificates "certify" a certain domain, but the protocol and encryption happen at the TCP level, before knowing which domain is being dealt with.
|
||||
* By default, that would mean that you can only have one HTTPS certificate per IP address.
|
||||
* No matter how big your server is or how small each application you have on it might be.
|
||||
* There is a solution to this, however.
|
||||
* There's an extension to the TLS protocol (the one handling the encryption at the TCP level, before HTTP) called <a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication">SNI</abbr></a>.
|
||||
* This SNI extension allows one single server (with a single IP address) to have several HTTPS certificates and serve multiple HTTPS domains/applications.
|
||||
* For this to work, a single component (program) running on the server, listening on the public IP address, must have all the HTTPS certificates in the server.
|
||||
* After obtaining a secure connection, the communication protocol is still HTTP.
|
||||
* The contents are encrypted, even though they are being sent with the HTTP protocol.
|
||||
|
||||
It is a common practice to have one program/HTTP server running on the server (the machine, host, etc.) and managing all the HTTPS parts : sending the decrypted HTTP requests to the actual HTTP application running in the same server (the **FastAPI** application, in this case), take the HTTP response from the application, encrypt it using the appropriate certificate and sending it back to the client using HTTPS. This server is often called a <a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">TLS Termination Proxy</a>.
|
||||
|
||||
## Let's Encrypt
|
||||
|
||||
Before Let's Encrypt, these HTTPS certificates were sold by trusted third-parties.
|
||||
|
||||
The process to acquire one of these certificates used to be cumbersome, require quite some paperwork and the certificates were quite expensive.
|
||||
|
||||
But then <a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a> was created.
|
||||
|
||||
It is a project from the Linux Foundation. It provides HTTPS certificates for free. In an automated way. These certificates use all the standard cryptographic security, and are short lived (about 3 months), so the security is actually better because of their reduced lifespan.
|
||||
|
||||
The domains are securely verified and the certificates are generated automatically. This also allows automating the renewal of these certificates.
|
||||
|
||||
The idea is to automate the acquisition and renewal of these certificates, so that you can have secure HTTPS, for free, forever.
|
||||
7
docs/en/docs/deployment/index.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Deployment - Intro
|
||||
|
||||
Deploying a **FastAPI** application is relatively easy.
|
||||
|
||||
There are several ways to do it depending on your specific use case and the tools that you use.
|
||||
|
||||
You will see more details to have in mind and some of the techniques to do it in the next sections.
|
||||
74
docs/en/docs/deployment/manually.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Deploy manually
|
||||
|
||||
You can deploy **FastAPI** manually as well.
|
||||
|
||||
You just need to install an ASGI compatible server like:
|
||||
|
||||
=== "Uvicorn"
|
||||
|
||||
* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>, a lightning-fast ASGI server, built on uvloop and httptools.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ 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.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install hypercorn
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
...or any other ASGI server.
|
||||
|
||||
And run your application the same way you have done in the tutorials, but without the `--reload` option, e.g.:
|
||||
|
||||
=== "Uvicorn"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --host 0.0.0.0 --port 80
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
=== "Hypercorn"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ hypercorn main:app --bind 0.0.0.0:80
|
||||
|
||||
Running on 0.0.0.0:8080 over http (CTRL + C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
You might want to set up some tooling to make sure it is restarted automatically if it stops.
|
||||
|
||||
You might also want to install <a href="https://gunicorn.org/" class="external-link" target="_blank">Gunicorn</a> and <a href="https://www.uvicorn.org/#running-with-gunicorn" class="external-link" target="_blank">use it as a manager for Uvicorn</a>, or use Hypercorn with multiple workers.
|
||||
|
||||
Making sure to fine-tune the number of workers, etc.
|
||||
|
||||
But if you are doing all that, you might just use the Docker image that does it automatically.
|
||||
87
docs/en/docs/deployment/versions.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# About FastAPI versions
|
||||
|
||||
**FastAPI** is already being used in production in many applications and systems. And the test coverage is kept at 100%. But its development is still moving quickly.
|
||||
|
||||
New features are added frequently, bugs are fixed regularly, and the code is still continuously improving.
|
||||
|
||||
That's why the current versions are still `0.x.x`, this reflects that each version could potentially have breaking changes. This follows the <a href="https://semver.org/" class="external-link" target="_blank">Semantic Versioning</a> conventions.
|
||||
|
||||
You can create production applications with **FastAPI** right now (and you have probably been doing it for some time), you just have to make sure that you use a version that works correctly with the rest of your code.
|
||||
|
||||
## Pin your `fastapi` version
|
||||
|
||||
The first thing you should do is to "pin" the version of **FastAPI** you are using to the specific latest version that you know works correctly for your application.
|
||||
|
||||
For example, let's say you are using version `0.45.0` in your app.
|
||||
|
||||
If you use a `requirements.txt` file you could specify the version with:
|
||||
|
||||
```txt
|
||||
fastapi==0.45.0
|
||||
```
|
||||
|
||||
that would mean that you would use exactly the version `0.45.0`.
|
||||
|
||||
Or you could also pin it with:
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
that would mean that you would use the versions `0.45.0` or above, but less than `0.46.0`, for example, a version `0.45.2` would still be accepted.
|
||||
|
||||
If you use any other tool to manage your installations, like Poetry, Pipenv, or others, they all have a way that you can use to define specific versions for your packages.
|
||||
|
||||
## Available versions
|
||||
|
||||
You can see the available versions (e.g. to check what is the current latest) in the [Release Notes](../release-notes.md){.internal-link target=_blank}.
|
||||
|
||||
## About versions
|
||||
|
||||
Following the Semantic Versioning conventions, any version below `1.0.0` could potentially add breaking changes.
|
||||
|
||||
FastAPI also follows the convention that any "PATCH" version change is for bug fixes and non-breaking changes.
|
||||
|
||||
!!! tip
|
||||
The "PATCH" is the last number, for example, in `0.2.3`, the PATCH version is `3`.
|
||||
|
||||
So, you should be able to pin to a version like:
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
Breaking changes and new features are added in "MINOR" versions.
|
||||
|
||||
!!! tip
|
||||
The "MINOR" is the number in the middle, for example, in `0.2.3`, the MINOR version is `2`.
|
||||
|
||||
## Upgrading the FastAPI versions
|
||||
|
||||
You should add tests for your app.
|
||||
|
||||
With **FastAPI** it's very easy (thanks to Starlette), check the docs: [Testing](../tutorial/testing.md){.internal-link target=_blank}
|
||||
|
||||
After you have tests, then you can upgrade the **FastAPI** version to a more recent one, and make sure that all your code is working correctly by running your tests.
|
||||
|
||||
If everything is working, or after you make the necessary changes, and all your tests are passing, then you can pin your `fastapi` to that new recent version.
|
||||
|
||||
## About Starlette
|
||||
|
||||
You shouldn't pin the version of `starlette`.
|
||||
|
||||
Different versions of **FastAPI** will use a specific newer version of Starlette.
|
||||
|
||||
So, you can just let **FastAPI** use the correct Starlette version.
|
||||
|
||||
## About Pydantic
|
||||
|
||||
Pydantic includes the tests for **FastAPI** with its own tests, so new versions of Pydantic (above `1.0.0`) are always compatible with FastAPI.
|
||||
|
||||
You can pin Pydantic to any version above `1.0.0` that works for you and below `2.0.0`.
|
||||
|
||||
For example:
|
||||
|
||||
```txt
|
||||
pydantic>=1.2.0,<2.0.0
|
||||
```
|
||||
@@ -7,113 +7,72 @@ There are many posts, articles, tools, and projects, related to **FastAPI**.
|
||||
Here's an incomplete list of some of them.
|
||||
|
||||
!!! tip
|
||||
If you have an article, project, tool, or anything related to **FastAPI** that is not yet listed here, create a <a href="https://github.com/tiangolo/fastapi/edit/master/docs/external-links.md" class="external-link" target="_blank">Pull Request adding it</a>.
|
||||
If you have an article, project, tool, or anything related to **FastAPI** that is not yet listed here, create a <a href="https://github.com/tiangolo/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">Pull Request adding it</a>.
|
||||
|
||||
## Articles
|
||||
|
||||
### English
|
||||
|
||||
* <a href="https://medium.com/@williamhayes/fastapi-starlette-debug-vs-prod-5f7561db3a59" class="external-link" target="_blank">FastAPI/Starlette debug vs prod</a> by <a href="https://medium.com/@williamhayes" class="external-link" target="_blank">William Hayes</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.english %}
|
||||
|
||||
* <a href="https://medium.com/data-rebels/fastapi-google-as-an-external-authentication-provider-3a527672cf33" class="external-link" target="_blank">FastAPI — Google as an external authentication provider</a> by <a href="https://medium.com/@nils_29588" class="external-link" target="_blank">Nils de Bruin</a>.
|
||||
|
||||
* <a href="https://medium.com/data-rebels/fastapi-how-to-add-basic-and-cookie-authentication-a45c85ef47d3" class="external-link" target="_blank">FastAPI — How to add basic and cookie authentication</a> by <a href="https://medium.com/@nils_29588" class="external-link" target="_blank">Nils de Bruin</a>.
|
||||
|
||||
* <a href="https://dev.to/errietta/introduction-to-the-fastapi-python-framework-2n10" class="external-link" target="_blank">Introduction to the fastapi python framework</a> by <a href="https://dev.to/errietta" class="external-link" target="_blank">Errieta Kostala</a>.
|
||||
|
||||
* <a href="http://nickc1.github.io/api,/scikit-learn/2019/01/10/scikit-fastapi.html" class="external-link" target="_blank">FastAPI and Scikit-Learn: Easily Deploy Models</a> by <a href="http://nickc1.github.io/" class="external-link" target="_blank">Nick Cortale</a>.
|
||||
|
||||
* <a href="https://medium.com/data-rebels/fastapi-authentication-revisited-enabling-api-key-authentication-122dc5975680" class="external-link" target="_blank">FastAPI authentication revisited: Enabling API key authentication</a> by <a href="https://medium.com/@nils_29588" class="external-link" target="_blank">Nils de Bruin</a>.
|
||||
|
||||
* <a href="https://blog.bartab.fr/fastapi-logging-on-the-fly/" class="external-link" target="_blank">FastAPI, a simple use case on logging</a> by <a href="https://blog.bartab.fr/" class="external-link" target="_blank">@euri10</a>.
|
||||
|
||||
* <a href="https://medium.com/@nico.axtmann95/deploying-a-scikit-learn-model-with-onnx-und-fastapi-1af398268915" class="external-link" target="_blank">Deploying a scikit-learn model with ONNX and FastAPI</a> by <a href="https://www.linkedin.com/in/nico-axtmann" class="external-link" target="_blank">Nico Axtmann</a>.
|
||||
|
||||
* <a href="https://geekflare.com/python-asynchronous-web-frameworks/" class="external-link" target="_blank">Top 5 Asynchronous Web Frameworks for Python</a> by <a href="https://geekflare.com/author/ankush/" class="external-link" target="_blank">Ankush Thakur</a> on <a href="https://geekflare.com" class="external-link" target="_blank">GeekFlare</a>.
|
||||
|
||||
* <a href="https://medium.com/@gntrm/jwt-authentication-with-fastapi-and-aws-cognito-1333f7f2729e" class="external-link" target="_blank">JWT Authentication with FastAPI and AWS Cognito</a> by <a href="https://twitter.com/gntrm" class="external-link" target="_blank">Johannes Gontrum</a>.
|
||||
|
||||
* <a href="https://towardsdatascience.com/how-to-deploy-a-machine-learning-model-dc51200fe8cf" class="external-link" target="_blank">How to Deploy a Machine Learning Model</a> by <a href="https://www.linkedin.com/in/mgrootendorst/" class="external-link" target="_blank">Maarten Grootendorst</a> on <a href="https://towardsdatascience.com/" class="external-link" target="_blank">Towards Data Science</a>.
|
||||
|
||||
* [Uber: Ludwig v0.2 Adds New Features and Other Improvements to its Deep Learning Toolbox [including a FastAPI server]](https://eng.uber.com/ludwig-v0-2/){.external-link target=_blank} on <a href="https://eng.uber.com" class="external-link" target="_blank">Uber Engineering</a>.
|
||||
|
||||
* <a href="https://gitlab.com/euri10/fastapi_cheatsheet" class="external-link" target="_blank">A FastAPI and Swagger UI visual cheatsheet</a> by <a href="https://gitlab.com/euri10" class="external-link" target="_blank">@euri10</a>
|
||||
|
||||
* <a href="https://medium.com/@mike.p.moritz/using-docker-compose-to-deploy-a-lightweight-python-rest-api-with-a-job-queue-37e6072a209b" class="external-link" target="_blank">Using Docker Compose to deploy a lightweight Python REST API with a job queue</a> by <a href="https://medium.com/@mike.p.moritz" class="external-link" target="_blank">Mike Moritz</a>.
|
||||
|
||||
* <a href="https://robwagner.dev/tortoise-fastapi-setup/" class="external-link" target="_blank">Setting up Tortoise ORM with FastAPI</a> by <a href="https://robwagner.dev/" class="external-link" target="_blank">Rob Wagner</a>.
|
||||
|
||||
* <a href="https://dev.to/dbanty/why-i-m-leaving-flask-3ki6" class="external-link" target="_blank">Why I'm Leaving Flask</a> by <a href="https://dev.to/dbanty" class="external-link" target="_blank">Dylan Anthony</a>.
|
||||
|
||||
* <a href="https://medium.com/python-data/how-to-deploy-tensorflow-2-0-models-as-an-api-service-with-fastapi-docker-128b177e81f3" class="external-link" target="_blank">How To Deploy Tensorflow 2.0 Models As An API Service With FastAPI & Docker</a> by <a href="https://medium.com/@bbrenyah" class="external-link" target="_blank">Bernard Brenyah</a>.
|
||||
|
||||
* <a href="https://testdriven.io/blog/fastapi-crud/" class="external-link" target="_blank">TestDriven.io: Developing and Testing an Asynchronous API with FastAPI and Pytest</a> by <a href="https://testdriven.io/authors/herman/" class="external-link" target="_blank">Michael Herman</a>.
|
||||
|
||||
* <a href="https://towardsdatascience.com/deploying-iris-classifications-with-fastapi-and-docker-7c9b83fdec3a" class="external-link" target="_blank">Towards Data Science: Deploying Iris Classifications with FastAPI and Docker</a> by <a href="https://towardsdatascience.com/@mandygu" class="external-link" target="_blank">Mandy Gu</a>.
|
||||
|
||||
* <a href="https://medium.com/analytics-vidhya/deploy-machine-learning-models-with-keras-fastapi-redis-and-docker-4940df614ece" class="external-link" target="_blank">Deploy Machine Learning Models with Keras, FastAPI, Redis and Docker</a> by <a href="https://medium.com/@shane.soh" class="external-link" target="_blank">Shane Soh</a>.
|
||||
|
||||
* <a href="https://medium.com/@arthur393/another-boilerplate-to-fastapi-azure-pipeline-ci-pytest-3c8d9a4be0bb" class="external-link" target="_blank">Another Boilerplate to FastAPI: Azure Pipeline CI + Pytest</a> by <a href="https://twitter.com/arthurheinrique" class="external-link" target="_blank">Arthur Henrique</a>.
|
||||
|
||||
* <a href="https://iwpnd.pw/articles/2020-01/deploy-fastapi-to-aws-lambda" class="external-link" target="_blank">How to continuously deploy a FastAPI to AWS Lambda with AWS SAM</a> by <a href="https://iwpnd.pw" class="external-link" target="_blank">Benjamin Ramser</a>.
|
||||
|
||||
* <a href="https://www.tutlinks.com/create-and-deploy-fastapi-app-to-heroku/" class="external-link" target="_blank">Create and Deploy FastAPI app to Heroku without using Docker</a> by <a href="https://www.linkedin.com/in/navule/" class="external-link" target="_blank">Navule Pavan Kumar Rao</a>.
|
||||
|
||||
* <a href="https://iwpnd.pw/articles/2020-03/apache-kafka-fastapi-geostream" class="external-link" target="_blank">Apache Kafka producer and consumer with FastAPI and aiokafka</a> by <a href="https://iwpnd.pw" class="external-link" target="_blank">Benjamin Ramser</a>.
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Japanese
|
||||
|
||||
* <a href="https://qiita.com/mtitg/items/47770e9a562dd150631d" class="external-link" target="_blank">FastAPI|DB接続してCRUDするPython製APIサーバーを構築</a> by <a href="https://qiita.com/mtitg" class="external-link" target="_blank">@mtitg</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.japanese %}
|
||||
|
||||
* <a href="https://qiita.com/ryoryomaru/items/59958ed385b3571d50de" class="external-link" target="_blank">python製の最新APIフレームワーク FastAPI を触ってみた</a> by <a href="https://qiita.com/ryoryomaru" class="external-link" target="_blank">@ryoryomaru</a>.
|
||||
|
||||
* <a href="https://qiita.com/angel_katayoku/items/0e1f5dbbe62efc612a78" class="external-link" target="_blank">FastAPIでCORSを回避</a> by <a href="https://qiita.com/angel_katayoku" class="external-link" target="_blank">@angel_katayoku</a>.
|
||||
|
||||
* <a href="https://qiita.com/angel_katayoku/items/4fbc1a4e2b33fa2237d2" class="external-link" target="_blank">FastAPIをMySQLと接続してDockerで管理してみる</a> by <a href="https://qiita.com/angel_katayoku" class="external-link" target="_blank">@angel_katayoku</a>.
|
||||
|
||||
* <a href="https://qiita.com/angel_katayoku/items/8a458a8952f50b73f420" class="external-link" target="_blank">FastAPIでPOSTされたJSONのレスポンスbodyを受け取る</a> by <a href="https://qiita.com/angel_katayoku" class="external-link" target="_blank">@angel_katayoku</a>.
|
||||
|
||||
* <a href="https://qiita.com/hikarut/items/b178af2e2440c67c6ac4" class="external-link" target="_blank">フロントエンド開発者向けのDockerによるPython開発環境構築</a> by <a href="https://qiita.com/hikarut" class="external-link" target="_blank">Hikaru Takahashi</a>.
|
||||
|
||||
* <a href="https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-environment" class="external-link" target="_blank">【第1回】FastAPIチュートリアル: ToDoアプリを作ってみよう【環境構築編】</a> by <a href="https://rightcode.co.jp/author/jun" class="external-link" target="_blank">ライトコードメディア編集部</a>
|
||||
|
||||
* <a href="https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-model-building" class="external-link" target="_blank">【第2回】FastAPIチュートリアル: ToDoアプリを作ってみよう【モデル構築編】</a> by <a href="https://rightcode.co.jp/author/jun" class="external-link" target="_blank">ライトコードメディア編集部</a>
|
||||
|
||||
* <a href="https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-authentication-user-registration" class="external-link" target="_blank">【第3回】FastAPIチュートリアル: toDoアプリを作ってみよう【認証・ユーザ登録編】</a> by <a href="https://rightcode.co.jp/author/jun" class="external-link" target="_blank">ライトコードメディア編集部</a>
|
||||
|
||||
* <a href="https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-admin-page-improvement" class="external-link" target="_blank">【第4回】FastAPIチュートリアル: toDoアプリを作ってみよう【管理者ページ改良編】</a> by <a href="https://rightcode.co.jp/author/jun" class="external-link" target="_blank">ライトコードメディア編集部</a>
|
||||
|
||||
* <a href="https://qiita.com/bee2/items/0ad260ab9835a2087dae" class="external-link" target="_blank">PythonのWeb frameworkのパフォーマンス比較 (Django, Flask, responder, FastAPI, japronto)</a> by <a href="https://qiita.com/bee2" class="external-link" target="_blank">@bee2</a>.
|
||||
|
||||
* <a href="https://qiita.com/bee2/items/75d9c0d7ba20e7a4a0e9" class="external-link" target="_blank">[FastAPI] Python製のASGI Web フレームワーク FastAPIに入門する</a> by <a href="https://qiita.com/bee2" class="external-link" target="_blank">@bee2</a>.
|
||||
|
||||
### Chinese
|
||||
|
||||
* <a href="https://cloud.tencent.com/developer/article/1431448" class="external-link" target="_blank">使用FastAPI框架快速构建高性能的api服务</a> by <a href="https://cloud.tencent.com/developer/user/5471722" class="external-link" target="_blank">逍遥散人</a>.
|
||||
|
||||
* <a href="https://wxq0309.github.io/" class="external-link" target="_blank">FastAPI框架中文文档</a> by <a href="https://wxq0309.github.io/" class="external-link" target="_blank">何大仙</a>.
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Vietnamese
|
||||
|
||||
* <a href="https://fullstackstation.com/fastapi-trien-khai-bang-docker/" class="external-link" target="_blank">FASTAPI: TRIỂN KHAI BẰNG DOCKER</a> by <a href="https://fullstackstation.com/author/figonking/" class="external-link" target="_blank">Nguyễn Nhân</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.vietnamese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Russian
|
||||
|
||||
* <a href="https://habr.com/ru/post/454440/" class="external-link" target="_blank">Мелкая питонячая радость #2: Starlette - Солидная примочка – FastAPI</a> by <a href="https://habr.com/ru/users/57uff3r/" class="external-link" target="_blank">Andrey Korchak</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.russian %}
|
||||
|
||||
* <a href="https://habr.com/ru/post/478620/" class="external-link" target="_blank">Почему Вы должны попробовать FastAPI?</a> by <a href="https://github.com/prostomarkeloff" class="external-link" target="_blank">prostomarkeloff</a>.
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### German
|
||||
|
||||
* <a href="https://blog.codecentric.de/2019/08/inbetriebnahme-eines-scikit-learn-modells-mit-onnx-und-fastapi/" class="external-link" target="_blank">Inbetriebnahme eines scikit-learn-Modells mit ONNX und FastAPI</a> by <a href="https://twitter.com/_nicoax" class="external-link" target="_blank">Nico Axtmann</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.german %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Podcasts
|
||||
|
||||
* <a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" class="external-link" target="_blank">FastAPI on PythonBytes</a> by <a href="https://pythonbytes.fm/" class="external-link" target="_blank">Python Bytes FM</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.podcasts.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Talks
|
||||
|
||||
* <a href="https://www.youtube.com/watch?v=3DLwPcrE5mA" class="external-link" target="_blank">PyCon UK 2019: FastAPI from the ground up</a> by <a href="https://twitter.com/chriswithers13" class="external-link" target="_blank">Chris Withers</a>.
|
||||
{% if external_links %}
|
||||
{% for article in external_links.talks.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Projects
|
||||
|
||||
|
||||
177
docs/en/docs/fastapi-people.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# FastAPI People
|
||||
|
||||
FastAPI has an amazing community that welcomes people from all backgrounds.
|
||||
|
||||
## Creator - Maintainer
|
||||
|
||||
Hey! 👋
|
||||
|
||||
This is me:
|
||||
|
||||
{% if people %}
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.maintainers %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Answers: {{ user.answers }}</div><div class="count">Pull Requests: {{ user.prs }}</div></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
I'm the creator and maintainer of **FastAPI**. You can read more about that in [Help FastAPI - Get Help - Connect with the author](help-fastapi.md#connect-with-the-author){.internal-link target=_blank}.
|
||||
|
||||
...But here I want to show you the community.
|
||||
|
||||
---
|
||||
|
||||
**FastAPI** receives a lot of support from the community. And I want to highlight their contributions.
|
||||
|
||||
These are the people that:
|
||||
|
||||
* [Help others with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank}.
|
||||
* [Create Pull Requests](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}.
|
||||
* Review Pull Requests, [especially important for translations](contributing.md#translations){.internal-link target=_blank}.
|
||||
|
||||
A round of applause to them. 👏 🙇
|
||||
|
||||
## Most active users last month
|
||||
|
||||
These are the users that have been [helping others the most with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} during the last month. ☕
|
||||
|
||||
{% if people %}
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.last_month_active %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Issues replied: {{ user.count }}</div></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
## Experts
|
||||
|
||||
Here are the **FastAPI Experts**. 🤓
|
||||
|
||||
These are the users that have [helped others the most with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} through *all time*.
|
||||
|
||||
They have proven to be experts by helping many others. ✨
|
||||
|
||||
{% if people %}
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.experts %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Issues replied: {{ user.count }}</div></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
## Top Contributors
|
||||
|
||||
Here are the **Top Contributors**. 👷
|
||||
|
||||
These users have [created the most Pull Requests](help-fastapi.md#create-a-pull-request){.internal-link target=_blank} that have been *merged*.
|
||||
|
||||
They have contributed source code, documentation, translations, etc. 📦
|
||||
|
||||
{% if people %}
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.top_contributors %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Pull Requests: {{ user.count }}</div></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
There are many other contributors (more than a hundred), you can see them all in the <a href="https://github.com/tiangolo/fastapi/graphs/contributors" class="external-link" target="_blank">FastAPI GitHub Contributors page</a>. 👷
|
||||
|
||||
## Top Reviewers
|
||||
|
||||
These users are the **Top Reviewers**. 🕵️
|
||||
|
||||
### Reviews for Translations
|
||||
|
||||
I only speak a few languages (and not very well 😅). So, the reviewers are the ones that have the [**power to approve translations**](contributing.md#translations){.internal-link target=_blank} of the documentation. Without them, there wouldn't be documentation in several other languages.
|
||||
|
||||
---
|
||||
|
||||
The **Top Reviewers** 🕵️ have reviewed the most Pull Requests from others, ensuring the quality of the code, documentation, and especially, the **translations**.
|
||||
|
||||
{% if people %}
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.top_reviewers %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Reviews: {{ user.count }}</div></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
## Sponsors
|
||||
|
||||
These are the **Sponsors**. 😎
|
||||
|
||||
They are supporting my work with **FastAPI** (and others), mainly through <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub Sponsors</a>.
|
||||
|
||||
### Gold Sponsors
|
||||
|
||||
{% if sponsors %}
|
||||
{% for sponsor in sponsors.gold -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Silver Sponsors
|
||||
|
||||
{% if sponsors %}
|
||||
{% for sponsor in sponsors.silver -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Bronze Sponsors
|
||||
|
||||
{% if sponsors %}
|
||||
{% for sponsor in sponsors.bronze -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Individual Sponsors
|
||||
|
||||
{% if people %}
|
||||
{% if people.sponsors_50 %}
|
||||
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.sponsors_50 %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if people %}
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.sponsors %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
## About the data - technical details
|
||||
|
||||
The main intention of this page is to highlight the effort of the community to help others.
|
||||
|
||||
Especially including efforts that are normally less visible, and in many cases more arduous, like helping others with issues and reviewing Pull Requests with translations.
|
||||
|
||||
The data is calculated each month, you can read the <a href="https://github.com/tiangolo/fastapi/blob/master/.github/actions/people/app/main.py" class="external-link" target="_blank">source code here</a>.
|
||||
|
||||
Here I'm also highlighting contributions from sponsors.
|
||||
|
||||
I also reserve the right to update the algorithm, sections, thresholds, etc (just in case 🤷).
|
||||
@@ -7,7 +7,7 @@
|
||||
### Based on open standards
|
||||
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> for API creation, including declarations of <abbr title="also known as: endpoints, routes">path</abbr> <abbr title="also known as HTTP methods, as POST, GET, PUT, DELETE">operations</abbr>, parameters, body requests, security, etc.
|
||||
* Automatic data model documentation with <a href="http://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (as OpenAPI itself is based on JSON Schema).
|
||||
* Automatic data model documentation with <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (as OpenAPI itself is based on JSON Schema).
|
||||
* Designed around these standards, after a meticulous study. Instead of an afterthought layer on top.
|
||||
* This also allows using automatic **client code generation** in many languages.
|
||||
|
||||
@@ -71,7 +71,7 @@ my_second_user: User = User(**second_user_data)
|
||||
|
||||
### Editor support
|
||||
|
||||
All the framework was designed to be easy and intuitive to use, all the decisions where tested on multiple editors even before starting development, to ensure the best development experience.
|
||||
All the framework was designed to be easy and intuitive to use, all the decisions were tested on multiple editors even before starting development, to ensure the best development experience.
|
||||
|
||||
In the last Python developer survey it was clear <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">that the most used feature is "autocompletion"</a>.
|
||||
|
||||
|
||||
@@ -10,29 +10,33 @@ 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 ✅
|
||||
|
||||
## Follow FastAPI on Twitter
|
||||
|
||||
<a href="https://twitter.com/fastapi" class="external-link" target="_blank">Follow @fastapi on **Twitter**</a> to get the latest news about **FastAPI**. 🐦
|
||||
|
||||
## 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>.
|
||||
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>. ⭐️
|
||||
|
||||
By adding a star, other users will be able to find it more easily and see that it has been already useful for others.
|
||||
|
||||
## Watch the GitHub repository for releases
|
||||
|
||||
You can "watch" FastAPI in GitHub (clicking the "watch" button at the top right): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>.
|
||||
You can "watch" FastAPI in GitHub (clicking the "watch" button at the top right): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. 👀
|
||||
|
||||
There you can select "Releases only".
|
||||
|
||||
Doing it, you will receive notifications (in your email) whenever there's a new release (a new version) of **FastAPI** with bug fixes and new features.
|
||||
|
||||
## Join the chat
|
||||
|
||||
<a href="https://gitter.im/tiangolo/fastapi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge" target="_blank">
|
||||
<img src="https://badges.gitter.im/tiangolo/fastapi.svg" alt="Join the chat at https://gitter.im/tiangolo/fastapi">
|
||||
</a>
|
||||
|
||||
Join the chat on Gitter: <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">https://gitter.im/tiangolo/fastapi</a>.
|
||||
|
||||
There you can ask quick questions, help others, share ideas, etc.
|
||||
By doing it, you will receive notifications (in your email) whenever there's a new release (a new version) of **FastAPI** with bug fixes and new features.
|
||||
|
||||
## Connect with the author
|
||||
|
||||
@@ -45,61 +49,99 @@ You can:
|
||||
* Follow me to see when I create a new Open Source project.
|
||||
* <a href="https://twitter.com/tiangolo" class="external-link" target="_blank">Follow me on **Twitter**</a>.
|
||||
* Tell me how you use FastAPI (I love to hear that).
|
||||
* Ask questions.
|
||||
* Hear when I make announcements or release new tools.
|
||||
* You can also <a href="https://twitter.com/fastapi" class="external-link" target="_blank">follow @fastapi on Twitter</a> (a separate account).
|
||||
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Connect with me on **Linkedin**</a>.
|
||||
* Talk to me.
|
||||
* Endorse me or recommend me :)
|
||||
* <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">Read what I write (or follow me) on **Medium**</a>.
|
||||
* Read other ideas, articles and tools I have created.
|
||||
* Follow me to see when I publish something new.
|
||||
* Hear when I make announcements or release new tools (although I use Twitter more often 🤷♂).
|
||||
* Read what I write (or follow me) on <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> or <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a>.
|
||||
* Read other ideas, articles, and read about tools I have created.
|
||||
* Follow me to read when I publish something new.
|
||||
|
||||
## Tweet about **FastAPI**
|
||||
|
||||
<a href="https://twitter.com/compose/tweet?text=I'm loving FastAPI because... https://github.com/tiangolo/fastapi cc @tiangolo" class="external-link" target="_blank">Tweet about **FastAPI**</a> and let me and others know why you like it.
|
||||
<a href="https://twitter.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/tiangolo/fastapi" class="external-link" target="_blank">Tweet about **FastAPI**</a> and let me and others know why you like it. 🎉
|
||||
|
||||
## Let me know how are you using **FastAPI**
|
||||
|
||||
I love to hear about how **FastAPI** is being used, what have you liked in it, in which project/company are you using it, etc.
|
||||
|
||||
You can let me know:
|
||||
|
||||
* <a href="https://twitter.com/compose/tweet?text=Hey @tiangolo, I'm using FastAPI at..." class="external-link" target="_blank">On **Twitter**</a>.
|
||||
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">On **Linkedin**</a>.
|
||||
* <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">On **Medium**</a>.
|
||||
I love to hear about how **FastAPI** is being used, what you have liked in it, in which project/company are you using it, etc.
|
||||
|
||||
## Vote for FastAPI
|
||||
|
||||
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Vote for **FastAPI** in Slant</a>.
|
||||
* <a href="https://alternativeto.net/software/fastapi/" class="external-link" target="_blank">Vote for **FastAPI** in AlternativeTo</a>.
|
||||
|
||||
## Help others with issues in GitHub
|
||||
|
||||
You can see <a href="https://github.com/tiangolo/fastapi/issues" class="external-link" target="_blank">existing issues</a> and try and help others.
|
||||
You can see <a href="https://github.com/tiangolo/fastapi/issues" class="external-link" target="_blank">existing issues</a> and try and help others, most of the times they are questions that you might already know the answer for. 🤓
|
||||
|
||||
If you are helping a lot of people with issues, you might become an official [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}. 🎉
|
||||
|
||||
## Watch the GitHub repository
|
||||
|
||||
You can "watch" FastAPI in GitHub (clicking the "watch" button at the top right): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>.
|
||||
You can "watch" FastAPI in GitHub (clicking the "watch" button at the top right): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. 👀
|
||||
|
||||
If you select "Watching" instead of "Releases only", you will receive notifications when someone creates a new issue.
|
||||
If you select "Watching" instead of "Releases only" you will receive notifications when someone creates a new issue.
|
||||
|
||||
Then you can try and help them solving those issues.
|
||||
Then you can try and help them solve those issues.
|
||||
|
||||
## Create issues
|
||||
|
||||
You can <a href="https://github.com/tiangolo/fastapi/issues/new/choose" class="external-link" target="_blank">create a new issue</a> in the GitHub repository, for example to:
|
||||
|
||||
* Report a bug/issue.
|
||||
* Suggest a new feature.
|
||||
* Ask a question.
|
||||
* Ask a **question** or ask about a **problem**.
|
||||
* Suggest a new **feature**.
|
||||
|
||||
**Note**: if you create an issue, then I'm going to ask you to also help others. 😉
|
||||
|
||||
## Create a Pull Request
|
||||
|
||||
You can <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">create a Pull Request</a>, for example:
|
||||
You can [contribute](contributing.md){.internal-link target=_blank} to the source code with Pull Requests, for example:
|
||||
|
||||
* To fix a typo you found on the documentation.
|
||||
* To share an article, video, or podcast you created or found about FastAPI by <a href="https://github.com/tiangolo/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">editing this file</a>.
|
||||
* Make sure you add your link to the start of the corresponding section.
|
||||
* To help [translate the documentation](contributing.md#translations){.internal-link target=_blank} to your language.
|
||||
* You can also help to review the translations created by others.
|
||||
* To propose new documentation sections.
|
||||
* To fix an existing issue/bug.
|
||||
* To add a new feature.
|
||||
|
||||
## Join the chat
|
||||
|
||||
Join the 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank">Discord chat server</a> 👥 and hang out with others in the FastAPI community.
|
||||
|
||||
!!! tip
|
||||
For questions, ask them in <a href="https://github.com/tiangolo/fastapi/issues/new/choose" class="external-link" target="_blank">GitHub issues</a>, there's a much better chance you will receive help by the [FastAPI Experts](fastapi-people.md#experts){.internal-link target=_blank}.
|
||||
|
||||
Use the chat only for other general conversations.
|
||||
|
||||
There is also the previous <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">Gitter chat</a>, but as it doesn't have channels and advanced features, conversations are more difficult, so Discord is now the recommended system.
|
||||
|
||||
### Don't use the chat for questions
|
||||
|
||||
Have in mind that as chats allow more "free conversation", it's easy to ask questions that are too general and more difficult to answer, so, you might not receive answers.
|
||||
|
||||
In GitHub issues the template will guide you to write the right question so that you can more easily get a good answer, or even solve the problem yourself even before asking. And in GitHub I can make sure I always answer everything, even if it takes some time. I can't personally do that with the chat systems. 😅
|
||||
|
||||
Conversations in the chat systems are also not as easily searchable as in GitHub, so questions and answers might get lost in the conversation. And only the ones in GitHub issues count to become a [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}, so you will most probably receive more attention in GitHub isssues.
|
||||
|
||||
On the other side, there are thousands of users in the chat systems, so there's a high chance you'll find someone to talk to there, almost all the time. 😄
|
||||
|
||||
## Sponsor the author
|
||||
|
||||
You can also financially support the author (me) through <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub sponsors</a>.
|
||||
|
||||
There you could buy me a coffee ☕️ to say thanks. 😄
|
||||
|
||||
And you can also become a Silver or Gold sponsor for FastAPI. 🏅🎉
|
||||
|
||||
## Sponsor the tools that power FastAPI
|
||||
|
||||
As you have seen in the documentation, FastAPI stands on the shoulders of giants, Starlette and Pydantic.
|
||||
|
||||
You can also sponsor:
|
||||
|
||||
* <a href="https://github.com/sponsors/samuelcolvin" class="external-link" target="_blank">Samuel Colvin (Pydantic)</a>
|
||||
* <a href="https://github.com/sponsors/encode" class="external-link" target="_blank">Encode (Starlette, Uvicorn)</a>
|
||||
|
||||
---
|
||||
|
||||
Thanks!
|
||||
Thanks! 🚀
|
||||
|
||||
BIN
docs/en/docs/img/deployment/deta/image01.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
docs/en/docs/img/deployment/deta/image02.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
125
docs/en/docs/img/sponsors/deta-banner.svg
Normal file
|
After Width: | Height: | Size: 37 KiB |
65
docs/en/docs/img/sponsors/deta.svg
Normal file
|
After Width: | Height: | Size: 55 KiB |
293
docs/en/docs/img/sponsors/fastapi-course-bundle-banner.svg
Normal file
@@ -0,0 +1,293 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="429.96896"
|
||||
height="40"
|
||||
viewBox="0 0 113.76262 10.583333"
|
||||
version="1.1"
|
||||
id="svg853"
|
||||
inkscape:version="1.0.2 (1.0.2+r75+1)"
|
||||
sodipodi:docname="fastapi-course-bundle-banner.svg">
|
||||
<defs
|
||||
id="defs847" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.8"
|
||||
inkscape:cx="222.91167"
|
||||
inkscape:cy="33.521565"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="g3355"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-center="true"
|
||||
inkscape:snap-page="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1025"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
units="px" />
|
||||
<metadata
|
||||
id="metadata850">
|
||||
<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>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-80.634914,-82.650791)">
|
||||
<g
|
||||
id="g3355"
|
||||
transform="matrix(1.4999999,0,0,1.4999999,-40.317455,-41.325393)">
|
||||
<rect
|
||||
style="fill:#ffffff;stroke-width:0.197707;stop-color:#000000"
|
||||
id="rect1784"
|
||||
width="75.841751"
|
||||
height="7.0555558"
|
||||
x="80.634918"
|
||||
y="82.650795" />
|
||||
<g
|
||||
aria-label="FastAPI Course Bundle. Get 3 in-depth courses. Save 10%!"
|
||||
transform="scale(1.0561291,0.94685395)"
|
||||
id="text871"
|
||||
style="font-size:2.43444px;line-height:1.25;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;letter-spacing:0px;word-spacing:0px;stroke-width:0.0608608">
|
||||
<path
|
||||
d="m 84.413426,90.970748 h -0.72629 v 0.764329 h -0.228229 v -1.730735 h 1.0722 v 0.187814 h -0.843971 v 0.591968 h 0.72629 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3922" />
|
||||
<path
|
||||
d="m 85.526042,91.735077 q -0.01902,-0.03804 -0.03091,-0.135511 -0.153342,0.159285 -0.366117,0.159285 -0.190191,0 -0.312626,-0.106982 -0.121247,-0.108171 -0.121247,-0.2734 0,-0.200888 0.152153,-0.311437 0.153341,-0.111737 0.430306,-0.111737 h 0.213965 v -0.101038 q 0,-0.115303 -0.06894,-0.183059 -0.06894,-0.06894 -0.203266,-0.06894 -0.11768,0 -0.197323,0.05943 -0.07964,0.05943 -0.07964,0.143831 h -0.221096 q 0,-0.09628 0.06775,-0.185436 0.06894,-0.09034 0.185436,-0.142643 0.11768,-0.0523 0.257946,-0.0523 0.222285,0 0.348286,0.111737 0.126002,0.110548 0.130756,0.305494 v 0.591968 q 0,0.177115 0.04517,0.28172 v 0.01902 z m -0.364929,-0.167606 q 0.103416,0 0.196134,-0.05349 0.09272,-0.05349 0.134323,-0.139077 v -0.263889 h -0.172361 q -0.404155,0 -0.404155,0.23655 0,0.103416 0.06894,0.161662 0.06894,0.05824 0.177115,0.05824 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3924" />
|
||||
<path
|
||||
d="m 86.807451,91.393922 q 0,-0.08915 -0.06776,-0.137888 -0.06657,-0.04993 -0.234172,-0.08558 -0.166417,-0.03566 -0.265078,-0.08559 -0.09747,-0.04993 -0.14502,-0.118869 -0.04636,-0.06894 -0.04636,-0.16404 0,-0.158096 0.133133,-0.267455 0.134322,-0.10936 0.342343,-0.10936 0.21872,0 0.35423,0.112926 0.1367,0.112925 0.1367,0.288852 h -0.221097 q 0,-0.09034 -0.07726,-0.155719 -0.07608,-0.06538 -0.192568,-0.06538 -0.120058,0 -0.187813,0.0523 -0.06776,0.0523 -0.06776,0.136699 0,0.07964 0.063,0.120058 0.063,0.04042 0.22704,0.07726 0.165228,0.03685 0.267456,0.08796 0.102227,0.05111 0.150964,0.123624 0.04993,0.07132 0.04993,0.174737 0,0.172361 -0.137888,0.276966 -0.137889,0.103416 -0.357797,0.103416 -0.154529,0 -0.273399,-0.05468 -0.118869,-0.05468 -0.186624,-0.152153 -0.06657,-0.09866 -0.06657,-0.212775 h 0.219908 q 0.0059,0.110548 0.08796,0.175926 0.08321,0.06419 0.218719,0.06419 0.124813,0 0.199701,-0.04993 0.07608,-0.05111 0.07608,-0.135511 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3926" />
|
||||
<path
|
||||
d="m 87.612195,90.137476 v 0.311437 h 0.240116 v 0.169983 h -0.240116 v 0.797612 q 0,0.07727 0.03209,0.116491 0.03209,0.03804 0.109359,0.03804 0.03804,0 0.104605,-0.01426 v 0.178304 q -0.08677,0.02377 -0.168794,0.02377 -0.147398,0 -0.222285,-0.08915 -0.07489,-0.08915 -0.07489,-0.253191 v -0.797612 h -0.234172 v -0.169983 h 0.234172 v -0.311437 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3928" />
|
||||
<path
|
||||
d="m 89.098059,91.283374 h -0.725102 l -0.16285,0.451703 h -0.235361 l 0.660912,-1.730735 h 0.1997 l 0.662102,1.730735 h -0.234173 z m -0.656157,-0.187813 h 0.588402 l -0.294796,-0.809499 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3930" />
|
||||
<path
|
||||
d="m 89.958671,91.057523 v 0.677554 h -0.228228 v -1.730735 h 0.638327 q 0.284097,0 0.444571,0.145021 0.161662,0.14502 0.161662,0.383947 0,0.252003 -0.158096,0.388702 -0.156908,0.135511 -0.450514,0.135511 z m 0,-0.186625 h 0.410099 q 0.183058,0 0.280531,-0.08558 0.09747,-0.08678 0.09747,-0.249626 0,-0.15453 -0.09747,-0.247247 -0.09747,-0.09272 -0.267455,-0.09628 h -0.423175 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3932" />
|
||||
<path
|
||||
d="m 91.511103,91.735077 h -0.228229 v -1.730735 h 0.228229 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3934" />
|
||||
<path
|
||||
d="m 93.843315,91.158562 q -0.02021,0.279342 -0.206833,0.439815 -0.185436,0.160474 -0.48974,0.160474 -0.332834,0 -0.524213,-0.223474 -0.190191,-0.224663 -0.190191,-0.615742 v -0.105794 q 0,-0.249625 0.08796,-0.439816 0.08796,-0.19019 0.250814,-0.291229 0.164039,-0.102228 0.380381,-0.102228 0.29955,0 0.482609,0.160474 0.183058,0.160473 0.211587,0.450514 h -0.356607 q -0.01308,-0.167606 -0.09391,-0.242493 -0.07964,-0.07608 -0.243682,-0.07608 -0.178303,0 -0.267455,0.128378 -0.08796,0.12719 -0.09034,0.395834 v 0.130756 q 0,0.280532 0.0844,0.410099 0.08559,0.129567 0.268645,0.129567 0.165228,0 0.246059,-0.07489 0.08202,-0.07608 0.09391,-0.234172 z"
|
||||
style="font-weight:bold"
|
||||
id="path3936" />
|
||||
<path
|
||||
d="m 94.001411,91.080108 q 0,-0.191379 0.0737,-0.341154 0.0737,-0.149776 0.211587,-0.231795 0.139077,-0.08202 0.322135,-0.08202 0.260324,0 0.424363,0.159285 0.165228,0.159284 0.184247,0.432683 l 0.0024,0.08796 q 0,0.295985 -0.165228,0.475477 -0.165229,0.178304 -0.443382,0.178304 -0.278154,0 -0.444571,-0.178304 -0.165228,-0.178304 -0.165228,-0.484986 z m 0.343532,0.02496 q 0,0.183059 0.06894,0.280532 0.06894,0.09628 0.197323,0.09628 0.124812,0 0.194945,-0.0951 0.07013,-0.09628 0.07013,-0.306682 0,-0.179492 -0.07013,-0.278154 -0.07013,-0.09866 -0.197323,-0.09866 -0.126001,0 -0.194945,0.09866 -0.06894,0.09747 -0.06894,0.303116 z"
|
||||
style="font-weight:bold"
|
||||
id="path3938" />
|
||||
<path
|
||||
d="m 96.204056,91.604321 q -0.12719,0.15453 -0.351853,0.15453 -0.206832,0 -0.316192,-0.118869 -0.108171,-0.11887 -0.110548,-0.348287 v -0.842782 h 0.343532 v 0.830895 q 0,0.200889 0.183058,0.200889 0.174738,0 0.240116,-0.121247 v -0.910537 h 0.34472 v 1.286164 h -0.323324 z"
|
||||
style="font-weight:bold"
|
||||
id="path3940" />
|
||||
<path
|
||||
d="m 97.521126,90.771048 q -0.07013,-0.0095 -0.123624,-0.0095 -0.194945,0 -0.255568,0.131944 v 0.841594 h -0.343532 v -1.286164 h 0.324513 l 0.0095,0.153341 q 0.103416,-0.177115 0.286475,-0.177115 0.05706,0 0.106982,0.01545 z"
|
||||
style="font-weight:bold"
|
||||
id="path3942" />
|
||||
<path
|
||||
d="m 98.384116,91.379658 q 0,-0.063 -0.063,-0.09866 -0.06181,-0.03685 -0.1997,-0.06538 -0.458835,-0.09628 -0.458835,-0.389891 0,-0.171172 0.141455,-0.285286 0.142643,-0.115303 0.37206,-0.115303 0.244871,0 0.39108,0.115303 0.147397,0.115303 0.147397,0.29955 h -0.343531 q 0,-0.0737 -0.04755,-0.121246 -0.04755,-0.04874 -0.148587,-0.04874 -0.08677,0 -0.134322,0.03923 -0.04755,0.03923 -0.04755,0.09985 0,0.05706 0.05349,0.09272 0.05468,0.03447 0.183058,0.06062 0.128379,0.02496 0.216342,0.05706 0.27221,0.09985 0.27221,0.345909 0,0.175926 -0.150963,0.285286 -0.150964,0.108171 -0.389891,0.108171 -0.161662,0 -0.287663,-0.05706 -0.124813,-0.05825 -0.196135,-0.158096 -0.07132,-0.101039 -0.07132,-0.217531 h 0.325701 q 0.0048,0.09153 0.06776,0.140266 0.063,0.04874 0.168794,0.04874 0.09866,0 0.148586,-0.03685 0.05111,-0.03804 0.05111,-0.09866 z"
|
||||
style="font-weight:bold"
|
||||
id="path3944" />
|
||||
<path
|
||||
d="m 99.530014,91.758851 q -0.282909,0 -0.461212,-0.173549 -0.177115,-0.173549 -0.177115,-0.462401 v -0.03328 q 0,-0.193756 0.07489,-0.345909 0.07489,-0.153341 0.211587,-0.235361 0.137888,-0.08321 0.313815,-0.08321 0.263889,0 0.414853,0.166417 0.152151,0.166417 0.152151,0.47191 v 0.140266 h -0.819007 q 0.01664,0.126001 0.09985,0.202077 0.0844,0.07608 0.212776,0.07608 0.198511,0 0.310248,-0.143832 l 0.168793,0.189002 q -0.07726,0.10936 -0.209208,0.171171 -0.131945,0.06062 -0.292418,0.06062 z m -0.03923,-1.055558 q -0.102227,0 -0.166417,0.06894 -0.063,0.06894 -0.08083,0.197323 h 0.477854 v -0.02734 q -0.0024,-0.114115 -0.06181,-0.175927 -0.05943,-0.063 -0.168794,-0.063 z"
|
||||
style="font-weight:bold"
|
||||
id="path3946" />
|
||||
<path
|
||||
d="m 100.88631,91.735077 v -1.730735 h 0.60623 q 0.31501,0 0.47786,0.121247 0.16285,0.120058 0.16285,0.353041 0,0.12719 -0.0654,0.224663 -0.0654,0.09628 -0.18187,0.141454 0.13313,0.03328 0.20921,0.134322 0.0773,0.101039 0.0773,0.247248 0,0.249625 -0.15928,0.378004 -0.15928,0.128379 -0.45408,0.130756 z m 0.35661,-0.75363 v 0.467155 h 0.30549 q 0.126,0 0.19614,-0.05943 0.0713,-0.06062 0.0713,-0.166417 0,-0.237738 -0.24606,-0.241304 z m 0,-0.252003 h 0.26389 q 0.26983,-0.0048 0.26983,-0.215153 0,-0.117681 -0.0689,-0.168794 -0.0678,-0.0523 -0.21516,-0.0523 h -0.24962 z"
|
||||
style="font-weight:bold"
|
||||
id="path3948" />
|
||||
<path
|
||||
d="m 103.18881,91.604321 q -0.12719,0.15453 -0.35186,0.15453 -0.20683,0 -0.31619,-0.118869 -0.10817,-0.11887 -0.11055,-0.348287 v -0.842782 h 0.34353 v 0.830895 q 0,0.200889 0.18306,0.200889 0.17474,0 0.24012,-0.121247 v -0.910537 h 0.34472 v 1.286164 h -0.32333 z"
|
||||
style="font-weight:bold"
|
||||
id="path3950" />
|
||||
<path
|
||||
d="m 104.09934,90.448913 0.0107,0.148586 q 0.13789,-0.17236 0.36968,-0.17236 0.20446,0 0.30431,0.120058 0.0999,0.120058 0.10223,0.358985 v 0.830895 h -0.34353 v -0.822575 q 0,-0.109359 -0.0476,-0.158095 -0.0476,-0.04993 -0.1581,-0.04993 -0.14502,0 -0.21753,0.123624 v 0.906972 h -0.34353 v -1.286164 z"
|
||||
style="font-weight:bold"
|
||||
id="path3952" />
|
||||
<path
|
||||
d="m 105.09428,91.082485 q 0,-0.300739 0.13432,-0.479042 0.13551,-0.178304 0.36968,-0.178304 0.18782,0 0.31025,0.140266 v -0.656158 h 0.34472 v 1.82583 H 105.943 l -0.0166,-0.1367 q -0.12838,0.160474 -0.33045,0.160474 -0.22704,0 -0.36493,-0.178304 -0.1367,-0.179492 -0.1367,-0.498062 z m 0.34353,0.02496 q 0,0.180681 0.063,0.276965 0.063,0.09628 0.18306,0.09628 0.15928,0 0.22466,-0.134322 v -0.507571 q -0.0642,-0.134323 -0.22228,-0.134323 -0.24844,0 -0.24844,0.402967 z"
|
||||
style="font-weight:bold"
|
||||
id="path3954" />
|
||||
<path
|
||||
d="m 106.88445,91.735077 h -0.34472 v -1.82583 h 0.34472 z"
|
||||
style="font-weight:bold"
|
||||
id="path3956" />
|
||||
<path
|
||||
d="m 107.76051,91.758851 q -0.28291,0 -0.46121,-0.173549 -0.17711,-0.173549 -0.17711,-0.462401 v -0.03328 q 0,-0.193756 0.0749,-0.345909 0.0749,-0.153341 0.21159,-0.235361 0.13789,-0.08321 0.31382,-0.08321 0.26388,0 0.41485,0.166417 0.15215,0.166417 0.15215,0.47191 v 0.140266 h -0.81901 q 0.0166,0.126001 0.0998,0.202077 0.0844,0.07608 0.21278,0.07608 0.19851,0 0.31025,-0.143832 l 0.16879,0.189002 q -0.0773,0.10936 -0.20921,0.171171 -0.13194,0.06062 -0.29242,0.06062 z m -0.0392,-1.055558 q -0.10223,0 -0.16642,0.06894 -0.063,0.06894 -0.0808,0.197323 h 0.47785 v -0.02734 q -0.002,-0.114115 -0.0618,-0.175927 -0.0594,-0.063 -0.16879,-0.063 z"
|
||||
style="font-weight:bold"
|
||||
id="path3958" />
|
||||
<path
|
||||
d="m 108.52484,91.619774 q 0,-0.05706 0.0333,-0.0951 0.0345,-0.03804 0.10222,-0.03804 0.0678,0 0.10223,0.03804 0.0357,0.03804 0.0357,0.0951 0,0.05468 -0.0357,0.09153 -0.0345,0.03685 -0.10223,0.03685 -0.0677,0 -0.10222,-0.03685 -0.0333,-0.03685 -0.0333,-0.09153 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3960" />
|
||||
<path
|
||||
d="m 111.07815,91.508037 q -0.088,0.126001 -0.24606,0.189002 -0.15691,0.06181 -0.36612,0.06181 -0.21158,0 -0.37562,-0.09866 -0.16404,-0.09985 -0.25438,-0.282908 -0.0892,-0.183059 -0.0915,-0.424363 v -0.150964 q 0,-0.391079 0.18187,-0.606232 0.18306,-0.215154 0.51351,-0.215154 0.27103,0 0.43625,0.139077 0.16523,0.137889 0.20208,0.392268 h -0.22823 q -0.0642,-0.343531 -0.40891,-0.343531 -0.22942,0 -0.34828,0.161662 -0.11768,0.160473 -0.11887,0.465967 v 0.141454 q 0,0.291229 0.13313,0.46359 0.13313,0.171171 0.36017,0.171171 0.12838,0 0.22467,-0.02853 0.0963,-0.02853 0.15928,-0.09628 v -0.388702 h -0.40059 v -0.185436 h 0.62763 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3962" />
|
||||
<path
|
||||
d="m 111.95897,91.758851 q -0.26151,0 -0.42555,-0.171172 -0.16404,-0.17236 -0.16404,-0.460023 v -0.04042 q 0,-0.191379 0.0725,-0.341154 0.0737,-0.150964 0.20445,-0.235361 0.13195,-0.08559 0.28529,-0.08559 0.25081,0 0.38989,0.165228 0.13908,0.165228 0.13908,0.473099 v 0.09153 h -0.87131 q 0.005,0.19019 0.11055,0.307871 0.10698,0.116491 0.27102,0.116491 0.11649,0 0.19732,-0.04755 0.0808,-0.04755 0.14145,-0.126002 l 0.13433,0.104605 q -0.16167,0.248437 -0.48499,0.248437 z m -0.0273,-1.153031 q -0.13313,0 -0.22347,0.09747 -0.0903,0.09628 -0.11174,0.271021 h 0.64427 v -0.01664 q -0.01,-0.167606 -0.0903,-0.259135 -0.0808,-0.09272 -0.21872,-0.09272 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3964" />
|
||||
<path
|
||||
d="m 113.01215,90.137476 v 0.311437 h 0.24012 v 0.169983 h -0.24012 v 0.797612 q 0,0.07727 0.0321,0.116491 0.0321,0.03804 0.10936,0.03804 0.038,0 0.1046,-0.01426 v 0.178304 q -0.0868,0.02377 -0.16879,0.02377 -0.1474,0 -0.22229,-0.08915 -0.0749,-0.08915 -0.0749,-0.253191 v -0.797612 h -0.23417 v -0.169983 h 0.23417 v -0.311437 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3966" />
|
||||
<path
|
||||
d="m 114.40886,90.762727 h 0.16523 q 0.15572,-0.0024 0.24487,-0.08202 0.0891,-0.07964 0.0891,-0.215153 0,-0.304305 -0.30311,-0.304305 -0.14264,0 -0.22823,0.08202 -0.0844,0.08083 -0.0844,0.215153 h -0.21991 q 0,-0.205643 0.14978,-0.341154 0.15096,-0.1367 0.38276,-0.1367 0.24487,0 0.38395,0.129568 0.13907,0.129567 0.13907,0.360173 0,0.112926 -0.0737,0.21872 -0.0725,0.105793 -0.19851,0.158095 0.14264,0.04517 0.21991,0.149776 0.0784,0.104604 0.0784,0.255568 0,0.232984 -0.15215,0.369683 -0.15215,0.1367 -0.39583,0.1367 -0.24368,0 -0.39703,-0.131945 -0.15215,-0.131945 -0.15215,-0.348287 h 0.2211 q 0,0.1367 0.0892,0.21872 0.0892,0.08202 0.23893,0.08202 0.15928,0 0.24368,-0.08321 0.0844,-0.08321 0.0844,-0.238927 0,-0.150964 -0.0927,-0.231795 -0.0927,-0.08083 -0.26746,-0.08321 h -0.16523 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3968" />
|
||||
<path
|
||||
d="m 116.32385,91.735077 h -0.21991 v -1.286164 h 0.21991 z m -0.23774,-1.627319 q 0,-0.05349 0.0321,-0.09034 0.0333,-0.03685 0.0975,-0.03685 0.0642,0 0.0975,0.03685 0.0333,0.03685 0.0333,0.09034 0,0.05349 -0.0333,0.08915 -0.0333,0.03566 -0.0975,0.03566 -0.0642,0 -0.0975,-0.03566 -0.0321,-0.03566 -0.0321,-0.08915 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3970" />
|
||||
<path
|
||||
d="m 116.88253,90.448913 0.007,0.161662 q 0.1474,-0.185436 0.38514,-0.185436 0.40772,0 0.41129,0.460024 v 0.849914 h -0.21991 v -0.851103 q -0.001,-0.139077 -0.0642,-0.205644 -0.0618,-0.06657 -0.19376,-0.06657 -0.10698,0 -0.18781,0.05706 -0.0808,0.05706 -0.126,0.149775 v 0.916481 h -0.21991 v -1.286164 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3972" />
|
||||
<path
|
||||
d="m 118.47775,91.089617 h -0.58008 v -0.179492 h 0.58008 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3974" />
|
||||
<path
|
||||
d="m 118.63704,91.081297 q 0,-0.295984 0.14026,-0.475477 0.14027,-0.180681 0.36731,-0.180681 0.22585,0 0.3578,0.15453 v -0.670422 h 0.2199 v 1.82583 h -0.20207 l -0.0107,-0.137888 q -0.13195,0.161662 -0.36731,0.161662 -0.22347,0 -0.36493,-0.183059 -0.14026,-0.183058 -0.14026,-0.477854 z m 0.21991,0.02496 q 0,0.218719 0.0903,0.342343 0.0903,0.123624 0.24962,0.123624 0.20921,0 0.3055,-0.187813 v -0.59078 q -0.0987,-0.181869 -0.30312,-0.181869 -0.16166,0 -0.252,0.124812 -0.0903,0.124813 -0.0903,0.369683 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3976" />
|
||||
<path
|
||||
d="m 120.59838,91.758851 q -0.26151,0 -0.42555,-0.171172 -0.16404,-0.17236 -0.16404,-0.460023 v -0.04042 q 0,-0.191379 0.0725,-0.341154 0.0737,-0.150964 0.20445,-0.235361 0.13195,-0.08559 0.28529,-0.08559 0.25081,0 0.38989,0.165228 0.13908,0.165228 0.13908,0.473099 v 0.09153 h -0.87131 q 0.005,0.19019 0.11054,0.307871 0.10699,0.116491 0.27103,0.116491 0.11649,0 0.19732,-0.04755 0.0808,-0.04755 0.14145,-0.126002 l 0.13432,0.104605 q -0.16166,0.248437 -0.48498,0.248437 z m -0.0273,-1.153031 q -0.13313,0 -0.22348,0.09747 -0.0903,0.09628 -0.11173,0.271021 h 0.64427 v -0.01664 q -0.01,-0.167606 -0.0903,-0.259135 -0.0808,-0.09272 -0.21872,-0.09272 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3978" />
|
||||
<path
|
||||
d="m 122.43966,91.106259 q 0,0.293607 -0.13432,0.473099 -0.13432,0.179493 -0.36374,0.179493 -0.23417,0 -0.36849,-0.148587 v 0.619309 h -0.21991 v -1.78066 h 0.20089 l 0.0107,0.142643 q 0.13432,-0.166417 0.37325,-0.166417 0.23179,0 0.36611,0.174738 0.13551,0.174737 0.13551,0.486174 z m -0.2199,-0.02496 q 0,-0.217531 -0.0927,-0.343532 -0.0927,-0.126001 -0.25438,-0.126001 -0.1997,0 -0.29955,0.177115 v 0.614553 q 0.0987,0.175926 0.30193,0.175926 0.15809,0 0.25081,-0.124812 0.0939,-0.126002 0.0939,-0.373249 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3980" />
|
||||
<path
|
||||
d="m 123.01618,90.137476 v 0.311437 h 0.24011 v 0.169983 h -0.24011 v 0.797612 q 0,0.07727 0.0321,0.116491 0.0321,0.03804 0.10936,0.03804 0.038,0 0.10461,-0.01426 v 0.178304 q -0.0868,0.02377 -0.1688,0.02377 -0.1474,0 -0.22228,-0.08915 -0.0749,-0.08915 -0.0749,-0.253191 v -0.797612 h -0.23417 v -0.169983 h 0.23417 v -0.311437 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3982" />
|
||||
<path
|
||||
d="m 123.73177,90.604631 q 0.14621,-0.179492 0.38038,-0.179492 0.40772,0 0.41129,0.460024 v 0.849914 h -0.21991 v -0.851103 q -0.001,-0.139077 -0.0642,-0.205644 -0.0618,-0.06657 -0.19376,-0.06657 -0.10698,0 -0.18781,0.05706 -0.0808,0.05706 -0.126,0.149775 v 0.916481 h -0.21991 v -1.82583 h 0.21991 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3984" />
|
||||
<path
|
||||
d="m 125.97245,91.579358 q 0.11769,0 0.20565,-0.07132 0.088,-0.07132 0.0975,-0.178304 h 0.20802 q -0.006,0.110548 -0.0761,0.210399 -0.0701,0.09985 -0.18782,0.159284 -0.11649,0.05944 -0.24725,0.05944 -0.2627,0 -0.41841,-0.174738 -0.15453,-0.175926 -0.15453,-0.480231 v -0.03685 q 0,-0.187813 0.0689,-0.334022 0.0689,-0.146209 0.19732,-0.22704 0.12957,-0.08083 0.3055,-0.08083 0.21634,0 0.35898,0.129567 0.14383,0.129568 0.15334,0.3364 h -0.20802 q -0.01,-0.124813 -0.0951,-0.204455 -0.0844,-0.08083 -0.20921,-0.08083 -0.16761,0 -0.26033,0.121247 -0.0915,0.120057 -0.0915,0.348286 v 0.0416 q 0,0.222286 0.0915,0.342344 0.0915,0.120057 0.26151,0.120057 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3986" />
|
||||
<path
|
||||
d="m 126.67259,91.080108 q 0,-0.189002 0.0737,-0.339966 0.0749,-0.150964 0.20683,-0.232983 0.13314,-0.08202 0.30312,-0.08202 0.2627,0 0.42436,0.18187 0.16285,0.18187 0.16285,0.483797 v 0.01545 q 0,0.187813 -0.0725,0.337589 -0.0713,0.148586 -0.20564,0.231794 -0.13313,0.08321 -0.30668,0.08321 -0.26151,0 -0.42436,-0.18187 -0.16167,-0.18187 -0.16167,-0.48142 z m 0.2211,0.02615 q 0,0.213965 0.0987,0.343532 0.0999,0.129567 0.26627,0.129567 0.1676,0 0.26627,-0.130756 0.0987,-0.131944 0.0987,-0.368494 0,-0.211587 -0.10104,-0.342343 -0.0999,-0.131945 -0.26627,-0.131945 -0.16285,0 -0.2627,0.129567 -0.0998,0.129568 -0.0998,0.370872 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3988" />
|
||||
<path
|
||||
d="m 128.91327,91.607887 q -0.12837,0.150964 -0.37681,0.150964 -0.20564,0 -0.31381,-0.118869 -0.10699,-0.120058 -0.10818,-0.35423 v -0.836839 h 0.21991 v 0.830895 q 0,0.292418 0.23774,0.292418 0.252,0 0.33521,-0.187813 v -0.9355 h 0.21991 v 1.286164 h -0.20921 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3990" />
|
||||
<path
|
||||
d="m 130.08176,90.646236 q -0.0499,-0.0083 -0.10817,-0.0083 -0.21634,0 -0.29361,0.184247 v 0.912915 h -0.21991 v -1.286164 h 0.21397 l 0.004,0.148586 q 0.10817,-0.17236 0.30669,-0.17236 0.0642,0 0.0975,0.01664 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3992" />
|
||||
<path
|
||||
d="m 131.03152,91.393922 q 0,-0.08915 -0.0677,-0.137888 -0.0666,-0.04993 -0.23418,-0.08558 -0.16641,-0.03566 -0.26507,-0.08559 -0.0975,-0.04993 -0.14502,-0.118869 -0.0464,-0.06894 -0.0464,-0.16404 0,-0.158096 0.13313,-0.267455 0.13432,-0.10936 0.34234,-0.10936 0.21872,0 0.35423,0.112926 0.1367,0.112925 0.1367,0.288852 h -0.22109 q 0,-0.09034 -0.0773,-0.155719 -0.0761,-0.06538 -0.19257,-0.06538 -0.12005,0 -0.18781,0.0523 -0.0677,0.0523 -0.0677,0.136699 0,0.07964 0.063,0.120058 0.063,0.04042 0.22704,0.07726 0.16522,0.03685 0.26745,0.08796 0.10223,0.05111 0.15097,0.123624 0.0499,0.07132 0.0499,0.174737 0,0.172361 -0.13789,0.276966 -0.13789,0.103416 -0.35779,0.103416 -0.15453,0 -0.2734,-0.05468 -0.11887,-0.05468 -0.18663,-0.152153 -0.0666,-0.09866 -0.0666,-0.212775 h 0.2199 q 0.006,0.110548 0.088,0.175926 0.0832,0.06419 0.21872,0.06419 0.12481,0 0.1997,-0.04993 0.0761,-0.05111 0.0761,-0.135511 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3994" />
|
||||
<path
|
||||
d="m 132.07163,91.758851 q -0.26151,0 -0.42555,-0.171172 -0.16404,-0.17236 -0.16404,-0.460023 v -0.04042 q 0,-0.191379 0.0725,-0.341154 0.0737,-0.150964 0.20445,-0.235361 0.13195,-0.08559 0.28529,-0.08559 0.25081,0 0.38989,0.165228 0.13908,0.165228 0.13908,0.473099 v 0.09153 h -0.87131 q 0.005,0.19019 0.11054,0.307871 0.10699,0.116491 0.27103,0.116491 0.11649,0 0.19732,-0.04755 0.0808,-0.04755 0.14145,-0.126002 l 0.13433,0.104605 q -0.16167,0.248437 -0.48499,0.248437 z m -0.0273,-1.153031 q -0.13313,0 -0.22347,0.09747 -0.0903,0.09628 -0.11174,0.271021 h 0.64427 v -0.01664 q -0.01,-0.167606 -0.0903,-0.259135 -0.0808,-0.09272 -0.21872,-0.09272 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3996" />
|
||||
<path
|
||||
d="m 133.57532,91.393922 q 0,-0.08915 -0.0678,-0.137888 -0.0666,-0.04993 -0.23417,-0.08558 -0.16642,-0.03566 -0.26508,-0.08559 -0.0975,-0.04993 -0.14502,-0.118869 -0.0464,-0.06894 -0.0464,-0.16404 0,-0.158096 0.13313,-0.267455 0.13432,-0.10936 0.34234,-0.10936 0.21872,0 0.35423,0.112926 0.1367,0.112925 0.1367,0.288852 h -0.22109 q 0,-0.09034 -0.0773,-0.155719 -0.0761,-0.06538 -0.19257,-0.06538 -0.12005,0 -0.18781,0.0523 -0.0678,0.0523 -0.0678,0.136699 0,0.07964 0.063,0.120058 0.063,0.04042 0.22704,0.07726 0.16522,0.03685 0.26745,0.08796 0.10223,0.05111 0.15097,0.123624 0.0499,0.07132 0.0499,0.174737 0,0.172361 -0.13789,0.276966 -0.13789,0.103416 -0.35779,0.103416 -0.15453,0 -0.2734,-0.05468 -0.11887,-0.05468 -0.18663,-0.152153 -0.0666,-0.09866 -0.0666,-0.212775 h 0.2199 q 0.006,0.110548 0.088,0.175926 0.0832,0.06419 0.21872,0.06419 0.12481,0 0.1997,-0.04993 0.0761,-0.05111 0.0761,-0.135511 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path3998" />
|
||||
<path
|
||||
d="m 134.08646,91.619774 q 0,-0.05706 0.0333,-0.0951 0.0345,-0.03804 0.10223,-0.03804 0.0677,0 0.10223,0.03804 0.0357,0.03804 0.0357,0.0951 0,0.05468 -0.0357,0.09153 -0.0345,0.03685 -0.10223,0.03685 -0.0678,0 -0.10223,-0.03685 -0.0333,-0.03685 -0.0333,-0.09153 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;stroke-width:0.0608608"
|
||||
id="path4000" />
|
||||
<path
|
||||
d="m 136.21303,91.280997 q 0,-0.101039 -0.0713,-0.15453 -0.0713,-0.05468 -0.25676,-0.114114 -0.18544,-0.06062 -0.29361,-0.11887 -0.29479,-0.159284 -0.29479,-0.429117 0,-0.140266 0.0785,-0.249625 0.0796,-0.110549 0.22704,-0.172361 0.14859,-0.06181 0.33284,-0.06181 0.18543,0 0.33045,0.06776 0.14502,0.06657 0.22466,0.189002 0.0808,0.122435 0.0808,0.278154 h -0.35661 q 0,-0.11887 -0.0749,-0.184248 -0.0749,-0.06657 -0.2104,-0.06657 -0.13075,0 -0.20326,0.05587 -0.0725,0.05468 -0.0725,0.145021 0,0.0844 0.0844,0.141454 0.0856,0.05706 0.25082,0.106982 0.3043,0.09153 0.44338,0.22704 0.13908,0.135511 0.13908,0.337588 0,0.224663 -0.16999,0.353042 -0.16998,0.12719 -0.45764,0.12719 -0.1997,0 -0.36374,-0.07251 -0.16404,-0.0737 -0.25082,-0.200889 -0.0856,-0.12719 -0.0856,-0.294796 h 0.35779 q 0,0.286475 0.34235,0.286475 0.12719,0 0.19851,-0.05111 0.0713,-0.0523 0.0713,-0.14502 z"
|
||||
style="font-weight:bold"
|
||||
id="path4002" />
|
||||
<path
|
||||
d="m 137.53604,91.735077 q -0.0238,-0.04636 -0.0345,-0.115303 -0.12481,0.139077 -0.32451,0.139077 -0.18901,0 -0.31382,-0.10936 -0.12362,-0.109359 -0.12362,-0.275776 0,-0.204455 0.15096,-0.313815 0.15215,-0.109359 0.43863,-0.110548 h 0.15809 v -0.0737 q 0,-0.08915 -0.0464,-0.142643 -0.0452,-0.05349 -0.14384,-0.05349 -0.0868,0 -0.1367,0.0416 -0.0487,0.0416 -0.0487,0.114115 h -0.34353 q 0,-0.111737 0.0689,-0.206833 0.0689,-0.0951 0.19495,-0.148586 0.126,-0.05468 0.2829,-0.05468 0.23774,0 0.37682,0.120058 0.14027,0.118869 0.14027,0.335211 v 0.557496 q 0.001,0.183059 0.0511,0.276965 v 0.02021 z m -0.2841,-0.238927 q 0.0761,0 0.14027,-0.03328 0.0642,-0.03447 0.0951,-0.09153 v -0.221096 h -0.12837 q -0.25795,0 -0.27459,0.178303 l -0.001,0.02021 q 0,0.06419 0.0452,0.105794 0.0452,0.0416 0.12362,0.0416 z"
|
||||
style="font-weight:bold"
|
||||
id="path4004" />
|
||||
<path
|
||||
d="m 138.5607,91.315469 0.23892,-0.866556 h 0.35899 l -0.43388,1.286164 h -0.32807 l -0.43388,-1.286164 h 0.35899 z"
|
||||
style="font-weight:bold"
|
||||
id="path4006" />
|
||||
<path
|
||||
d="m 139.88846,91.758851 q -0.2829,0 -0.46121,-0.173549 -0.17711,-0.173549 -0.17711,-0.462401 v -0.03328 q 0,-0.193756 0.0749,-0.345909 0.0749,-0.153341 0.21159,-0.235361 0.13789,-0.08321 0.31382,-0.08321 0.26389,0 0.41485,0.166417 0.15215,0.166417 0.15215,0.47191 v 0.140266 h -0.81901 q 0.0166,0.126001 0.0999,0.202077 0.0844,0.07608 0.21278,0.07608 0.19851,0 0.31025,-0.143832 l 0.16879,0.189002 q -0.0773,0.10936 -0.20921,0.171171 -0.13194,0.06062 -0.29242,0.06062 z m -0.0392,-1.055558 q -0.10223,0 -0.16642,0.06894 -0.063,0.06894 -0.0808,0.197323 h 0.47785 v -0.02734 q -0.002,-0.114115 -0.0618,-0.175927 -0.0594,-0.063 -0.16879,-0.063 z"
|
||||
style="font-weight:bold"
|
||||
id="path4008" />
|
||||
<path
|
||||
d="m 142.04237,91.735077 h -0.34353 v -1.324202 l -0.4101,0.12719 v -0.279343 l 0.71678,-0.256757 h 0.0369 z"
|
||||
style="font-weight:bold"
|
||||
id="path4010" />
|
||||
<path
|
||||
d="m 143.77073,91.019485 q 0,0.358984 -0.14859,0.549175 -0.14858,0.190191 -0.43506,0.190191 -0.28291,0 -0.43268,-0.186625 -0.14978,-0.186624 -0.15334,-0.534911 v -0.318569 q 0,-0.362551 0.14977,-0.550364 0.15097,-0.187814 0.43388,-0.187814 0.2829,0 0.43268,0.186625 0.14977,0.185436 0.15334,0.533722 z m -0.34353,-0.349476 q 0,-0.215153 -0.0594,-0.312625 -0.0582,-0.09866 -0.18305,-0.09866 -0.12125,0 -0.1795,0.09391 -0.0571,0.09272 -0.0606,0.291229 v 0.420797 q 0,0.211587 0.0571,0.315003 0.0582,0.102228 0.18543,0.102228 0.126,0 0.18187,-0.09866 0.0559,-0.09866 0.0582,-0.301927 z"
|
||||
style="font-weight:bold"
|
||||
id="path4012" />
|
||||
<path
|
||||
d="m 143.99896,90.337176 q 0,-0.159285 0.10341,-0.257946 0.10342,-0.09985 0.27103,-0.09985 0.16998,0 0.27339,0.09866 0.10342,0.09747 0.10342,0.265078 v 0.08559 q 0,0.160473 -0.10342,0.257946 -0.10341,0.09747 -0.27102,0.09747 -0.16879,0 -0.2734,-0.09747 -0.10341,-0.09866 -0.10341,-0.265078 z m 0.22823,0.09153 q 0,0.07132 0.0404,0.115303 0.0416,0.04279 0.10817,0.04279 0.0666,0 0.1058,-0.04398 0.0392,-0.04398 0.0392,-0.11768 v -0.08796 q 0,-0.07132 -0.0392,-0.115303 -0.0392,-0.04398 -0.10817,-0.04398 -0.0654,0 -0.1058,0.04398 -0.0404,0.04279 -0.0404,0.120058 z m 0.5991,0.882009 q 0,-0.160473 0.1046,-0.257946 0.10461,-0.09866 0.27102,-0.09866 0.1688,0 0.27221,0.09747 0.10461,0.09628 0.10461,0.266267 v 0.08559 q 0,0.159285 -0.10223,0.257946 -0.10223,0.09747 -0.27221,0.09747 -0.17117,0 -0.27459,-0.09866 -0.10341,-0.09866 -0.10341,-0.261512 z m 0.22823,0.09272 q 0,0.06538 0.0428,0.111737 0.0428,0.04636 0.10698,0.04636 0.14502,0 0.14502,-0.160473 v -0.09034 q 0,-0.07132 -0.0404,-0.114114 -0.0404,-0.04398 -0.10699,-0.04398 -0.0666,0 -0.10698,0.04398 -0.0404,0.04279 -0.0404,0.11768 z m -0.61099,0.202078 -0.16761,-0.09034 0.84516,-1.352731 0.16761,0.09034 z"
|
||||
style="font-weight:bold"
|
||||
id="path4014" />
|
||||
<path
|
||||
d="m 146.16475,91.203732 h -0.28528 l -0.0404,-1.19939 h 0.36612 z m -0.14264,0.187813 q 0.0868,0 0.13908,0.05111 0.0535,0.05111 0.0535,0.130756 0,0.07845 -0.0535,0.129567 -0.0523,0.05111 -0.13908,0.05111 -0.0856,0 -0.13908,-0.05111 -0.0523,-0.05111 -0.0523,-0.129567 0,-0.07845 0.0523,-0.129567 0.0535,-0.0523 0.13908,-0.0523 z"
|
||||
style="font-weight:bold"
|
||||
id="path4016" />
|
||||
</g>
|
||||
<g
|
||||
id="g896"
|
||||
transform="matrix(0.11457918,0,0,0.11457918,82.917314,84.127369)">
|
||||
<path
|
||||
fill="#fdd888"
|
||||
d="m 33,31 c 0,2.2 -1.8,4 -4,4 H 7 C 4.8,35 3,33.2 3,31 V 14 c 0,-2.2 1.8,-4 4,-4 h 22 c 2.2,0 4,1.8 4,4 z"
|
||||
id="path873" />
|
||||
<path
|
||||
fill="#fdd888"
|
||||
d="m 36,11 c 0,2.2 -1.8,4 -4,4 H 4 C 1.8,15 0,13.2 0,11 0,8.8 1.8,7 4,7 h 28 c 2.2,0 4,1.8 4,4 z"
|
||||
id="path875" />
|
||||
<path
|
||||
fill="#fcab40"
|
||||
d="m 3,15 h 30 v 2 H 3 Z"
|
||||
id="path877" />
|
||||
<path
|
||||
fill="#da2f47"
|
||||
d="m 19,3 h -2 c -1.657,0 -3,1.343 -3,3 v 29 h 8 V 6 C 22,4.344 20.657,3 19,3 Z"
|
||||
id="path879" />
|
||||
<path
|
||||
fill="#da2f47"
|
||||
d="m 16,7 c 1.1,0 1.263,-0.516 0.361,-1.147 L 9.639,1.147 C 8.737,0.516 7.554,0.781 7.008,1.736 L 4.992,5.264 C 4.446,6.219 4.9,7 6,7 Z m 4,0 C 18.9,7 18.737,6.484 19.639,5.853 l 6.723,-4.706 c 0.901,-0.631 2.085,-0.366 2.631,0.589 l 2.016,3.527 C 31.554,6.219 31.1,7 30,7 Z"
|
||||
id="path881" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 34 KiB |
124
docs/en/docs/img/sponsors/investsuite.svg
Normal file
@@ -0,0 +1,124 @@
|
||||
<?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>
|
||||
<clipPath
|
||||
id="clip0-3">
|
||||
<rect
|
||||
width="770"
|
||||
height="222.03999"
|
||||
fill="#ffffff"
|
||||
id="rect14-6"
|
||||
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.23333px;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.874025"
|
||||
y="21.589594"
|
||||
id="text959"><tspan
|
||||
id="tspan957"
|
||||
x="31.874023"
|
||||
y="21.589594"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333px;font-family:Roboto, sans-serif;-inkscape-font-specification:'Roboto, sans-serif';text-align:center;text-anchor:middle;stroke-width:0.116313">Wealthtech jobs with FastAPI</tspan></text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.8 KiB |
233
docs/en/docs/img/sponsors/jina-banner.svg
Normal file
|
After Width: | Height: | Size: 41 KiB |
1981
docs/en/docs/img/sponsors/jina.svg
Normal file
|
After Width: | Height: | Size: 215 KiB |
BIN
docs/en/docs/img/sponsors/talkpython.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
1
docs/en/docs/img/sponsors/testdriven.svg
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
docs/en/docs/img/sponsors/vimso.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
118
docs/en/docs/img/sponsors/wetransfer.svg
Normal file
@@ -0,0 +1,118 @@
|
||||
<?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>
|
||||
</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>
|
||||
<g
|
||||
id="layer1"
|
||||
transform="translate(-75.455132,-135.96141)">
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.364576;stop-color:#000000"
|
||||
id="rect901"
|
||||
width="63.5"
|
||||
height="26.458334"
|
||||
x="75.455132"
|
||||
y="135.96141" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.404023;stop-color:#000000"
|
||||
id="rect1758"
|
||||
width="60.854168"
|
||||
height="23.8125"
|
||||
x="76.778053"
|
||||
y="137.28433" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:4.23333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;stroke-width:0.133861"
|
||||
x="107.22684"
|
||||
y="154.45795"
|
||||
id="text1712"><tspan
|
||||
x="107.22684"
|
||||
y="154.45795"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333px;font-family:Roboto;-inkscape-font-specification:Roboto;text-align:center;text-anchor:middle;fill:#000000;stroke-width:0.133861"
|
||||
id="tspan2004">We deal in big ideas. You in?</tspan><tspan
|
||||
x="107.22684"
|
||||
y="159.79095"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333px;font-family:Roboto;-inkscape-font-specification:Roboto;text-align:center;text-anchor:middle;fill:#000000;stroke-width:0.133861"
|
||||
id="tspan874" /></text>
|
||||
<g
|
||||
id="g1003"
|
||||
transform="matrix(0.02061785,0,0,0.02061785,70.802235,134.33866)">
|
||||
<g
|
||||
id="g1015"
|
||||
transform="translate(4.0510205)">
|
||||
<path
|
||||
d="m 900.5,226.1 c -21.9,23 -28.6,35.3 -44.3,70.1 L 710.9,630 608.2,396.1 506.6,630 360.2,296.2 c -15.2,-34.8 -21.9,-46 -44.3,-70.1 h 185.7 c -14,11.8 -21.3,26.9 -21.3,46 0,13.4 2.3,23 9.5,40.4 l 55.5,132.4 41,-98.7 -23,-53.3 c -13.5,-30.8 -23,-49.9 -36.5,-66.7 h 185.7 c -18,11.8 -26.9,26.9 -26.9,46 0,13.4 2.3,23 9.5,40.4 L 751.8,445 807.9,312.6 c 7.3,-17.4 10.1,-26.9 10.1,-39.8 0,-16.8 -11.8,-37 -25.3,-46.5 z"
|
||||
id="path966" />
|
||||
<path
|
||||
d="m 1093.5,523.4 c -18,78 -61.2,103.8 -124,103.8 -71.8,0 -139.2,-52.2 -139.2,-150.3 0,-94.2 59.5,-161 137.5,-161 51.1,0 122.9,26.4 122.9,137.4 H 921.3 c 11.8,59.4 50.5,90.3 104.4,90.3 27.4,0 46.5,-5 67.8,-20.2 z M 917.9,414.6 v 7.3 H 992 c 0,-56.1 -12.4,-73.5 -35.9,-73.5 -24.2,0 -38.2,24.1 -38.2,66.2 z"
|
||||
id="path968" />
|
||||
<path
|
||||
d="M 1433.6,327.6 C 1387,283.3 1341,260.3 1305.7,260.3 v 247.4 c 0,49.9 12.9,80.2 47.1,111.1 h -212.1 c 34.2,-30.8 47.1,-61.1 47.1,-111.1 V 260.3 c -35.4,0 -83.6,23 -127.9,67.3 l 22.5,-118.4 c 15.2,11.8 43.2,16.8 74.6,16.8 h 179.6 c 31.4,0 59.5,-5.1 74.6,-16.8 z"
|
||||
id="path970" />
|
||||
<path
|
||||
d="m 1562.6,618.8 h -178.4 c 21.9,-25.8 31.4,-42.6 31.4,-83.6 v -90.9 c 0,-32 -4.5,-47.1 -25.8,-66.7 l -12.3,-11.2 134.7,-50.5 V 386 c 12.9,-40.4 33.1,-70.1 66.2,-70.1 26.9,0 44.3,19.1 44.3,47.1 0,29.7 -18.5,50.5 -44.3,50.5 -5.6,-12.9 -19.1,-19.1 -31.4,-19.1 -10.1,0 -19.6,2.8 -24.7,7.9 v 129.6 c -0.1,43.1 7.2,54.9 40.3,86.9 z"
|
||||
id="path972" />
|
||||
<path
|
||||
d="m 1931.3,567.2 c -6.7,35.3 -35.9,60 -75.8,60 -33.7,0 -59.5,-20.2 -67.3,-43.2 -16.8,30.3 -48.3,43.2 -81.9,43.2 -46.6,0 -78,-30.8 -78,-72.9 0,-49.4 35.4,-83.6 116.7,-103.2 l 37.6,-9 v -50.5 c 0,-31.4 -10.7,-44.3 -29.7,-44.3 -17.9,0 -29.7,11.8 -29.7,28 0,14 6.7,23 18.5,34.2 0,17.9 -28.1,36.4 -57.2,36.4 -28.6,0 -48.8,-21.9 -48.8,-48.8 0,-47.7 52.7,-81.3 130.2,-81.3 80.8,0 123.4,34.2 123.4,110.5 v 120.6 c 0,15.1 9,25.2 23,25.2 8.3,0.1 14.5,-1.6 19,-4.9 z m -148.7,-8.4 v -90.3 l -7.3,2.2 c -24.1,7.3 -40.4,23 -40.4,54.4 0,26.9 10.7,43.2 28.1,43.2 8.9,0 16.2,-2.8 19.6,-9.5 z"
|
||||
id="path974" />
|
||||
<path
|
||||
d="m 2083.3,618.8 h -150.9 c 15.7,-15.1 25.8,-37.6 25.8,-83.6 v -90.9 c 0,-30.8 -3.9,-46.5 -22.4,-63.9 l -12.9,-11.8 139.2,-52.7 v 43.7 c 16.3,-26.9 50.5,-43.7 84.7,-43.7 53.9,0 83.6,29.2 83.6,81.3 v 157.1 c 0,32 8.4,51.6 21.9,64.5 h -147 c 14.6,-14 18.5,-33.1 18.5,-48.2 V 410.1 c 0,-23.5 -7.8,-35.3 -29.7,-35.3 -12.3,0 -22.5,4.5 -29.2,11.2 v 184.5 c -0.1,15.2 3.8,33.7 18.4,48.3 z"
|
||||
id="path976" />
|
||||
<path
|
||||
d="m 2279.7,602.5 v -95.9 c 40.4,52.7 82.5,81.9 121.8,81.9 19.1,0 28.1,-10.1 28.1,-24.1 0,-13.5 -7.3,-21.3 -20.2,-26.4 l -65.1,-24.1 c -49.9,-18.5 -72.4,-49.4 -72.4,-95.3 0,-59.4 48.8,-102.6 118.4,-102.6 37.6,0 79.1,10.6 99.9,25.8 v 81.9 c -25.8,-45.4 -67.9,-70.7 -108.9,-70.7 -20.8,0 -31.4,6.7 -31.4,19.6 0,12.9 7.9,17.9 25.2,25.2 l 76.9,31.4 c 38.7,15.7 56.1,48.8 56.1,88.6 0,65.6 -47.7,109.4 -119.5,109.4 -36,0 -73,-7.9 -108.9,-24.7 z"
|
||||
id="path978" />
|
||||
<path
|
||||
d="m 2519.3,352.3 32.5,-49.9 c 41.5,-62.8 74.7,-93.1 130.8,-93.1 43.8,0 71.8,19.1 71.8,47.7 0,24.7 -20.2,42.6 -62.9,42.6 0,-34.8 -19.6,-47.7 -39.3,-47.7 -19.6,0 -34.8,14 -34.8,37 0,15.7 8.4,31.4 34.2,35.3 h 62.3 l -22.5,28 h -38.2 v 166.6 c 0,31.4 5.1,59.4 37.6,88.1 l 13.5,11.8 h -193.6 c 22.5,-22.4 35.9,-49.9 35.9,-90.3 V 352.3 Z"
|
||||
id="path980" />
|
||||
<path
|
||||
d="m 2959.2,523.4 c -18,78 -61.2,103.8 -124,103.8 -71.8,0 -139.2,-52.2 -139.2,-150.3 0,-94.2 59.5,-161 137.5,-161 51.1,0 122.9,26.4 122.9,137.4 H 2787 c 11.8,59.4 50.5,90.3 104.4,90.3 27.4,0 46.5,-5 67.8,-20.2 z M 2783.6,414.6 v 7.3 h 74.1 c 0,-56.1 -12.4,-73.5 -35.9,-73.5 -24.2,0 -38.2,24.1 -38.2,66.2 z"
|
||||
id="path982" />
|
||||
<path
|
||||
d="m 3147.2,618.8 h -178.4 c 21.9,-25.8 31.4,-42.6 31.4,-83.6 v -90.9 c 0,-32 -4.5,-47.1 -25.8,-66.7 L 2962,366.4 3096.7,315.9 V 386 c 12.9,-40.4 33.1,-70.1 66.2,-70.1 26.9,0 44.3,19.1 44.3,47.1 0,29.7 -18.5,50.5 -44.3,50.5 -5.6,-12.9 -19.1,-19.1 -31.4,-19.1 -10.1,0 -19.6,2.8 -24.7,7.9 v 129.6 c 0,43.1 7.3,54.9 40.4,86.9 z"
|
||||
id="path984" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 71 KiB |