Compare commits
106 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92c825be6a | ||
|
|
32438c85f6 | ||
|
|
02e53fde90 | ||
|
|
902cdaf010 | ||
|
|
04d77bb1c4 | ||
|
|
6d9fc08a7e | ||
|
|
5c9c088a2a | ||
|
|
014c7df142 | ||
|
|
9259dc228a | ||
|
|
de431d948d | ||
|
|
3d2c0993c1 | ||
|
|
37bc3614fd | ||
|
|
188da34529 | ||
|
|
d692c28f52 | ||
|
|
8568862a19 | ||
|
|
dfa067b061 | ||
|
|
0d1b97fb94 | ||
|
|
df1e754380 | ||
|
|
e5b341c7dd | ||
|
|
577c5a84db | ||
|
|
a5cfee434d | ||
|
|
9a8349bf96 | ||
|
|
a59408f68c | ||
|
|
3c08b05ea6 | ||
|
|
60599bad99 | ||
|
|
ccf30b5c2e | ||
|
|
ca0652aebf | ||
|
|
be957e7c99 | ||
|
|
90af868146 | ||
|
|
660f917d79 | ||
|
|
5278314f2f | ||
|
|
4a0316bcfe | ||
|
|
0393a093d3 | ||
|
|
27f530a7ff | ||
|
|
c3e5e65093 | ||
|
|
804ec460fc | ||
|
|
0125ea4f83 | ||
|
|
216770118a | ||
|
|
a935d66b10 | ||
|
|
dd2541bc97 | ||
|
|
098e629344 | ||
|
|
bbe5f28b77 | ||
|
|
4a0922ebab | ||
|
|
8f16868c6a | ||
|
|
bc3e7f2bbc | ||
|
|
58848be2de | ||
|
|
cfb65d0e15 | ||
|
|
855daa2e53 | ||
|
|
de54e85152 | ||
|
|
b8d3070daf | ||
|
|
471c9cfc2d | ||
|
|
b79c13baed | ||
|
|
332ee4aee1 | ||
|
|
ad40f4a457 | ||
|
|
6b9931f882 | ||
|
|
4c51bb6714 | ||
|
|
57ff677027 | ||
|
|
613c3f3e95 | ||
|
|
bf6d923ca8 | ||
|
|
252188c686 | ||
|
|
510fec9bee | ||
|
|
a73709507c | ||
|
|
75407b9295 | ||
|
|
3180f35bdd | ||
|
|
d498b7feb3 | ||
|
|
3269e6a95c | ||
|
|
f1808de18e | ||
|
|
748dc375db | ||
|
|
b38fb937b0 | ||
|
|
23ef570bf6 | ||
|
|
c25a71e352 | ||
|
|
0c5e684ff9 | ||
|
|
b097a538ab | ||
|
|
a0628f3f6f | ||
|
|
16f6dc66e2 | ||
|
|
07b68365f1 | ||
|
|
0a65c41909 | ||
|
|
d5e782074f | ||
|
|
b5a0c228e5 | ||
|
|
4b94da956c | ||
|
|
b59e8ffcf6 | ||
|
|
7f382127cc | ||
|
|
3513b039b9 | ||
|
|
4cf15503cb | ||
|
|
22dc7e9132 | ||
|
|
7ee32ea197 | ||
|
|
e6ca71523b | ||
|
|
7da9625505 | ||
|
|
ae50492735 | ||
|
|
bcb967f98a | ||
|
|
19c6a2b9bd | ||
|
|
01dd913634 | ||
|
|
343ecb7669 | ||
|
|
e9f2a3c291 | ||
|
|
00e2e544c7 | ||
|
|
dcb076b752 | ||
|
|
659b8ae8af | ||
|
|
2a48b10be3 | ||
|
|
5bd167e0e7 | ||
|
|
58b69493a9 | ||
|
|
786c392bd5 | ||
|
|
acc15230ea | ||
|
|
a84960b13d | ||
|
|
61779949f4 | ||
|
|
10134803a9 | ||
|
|
5085652479 |
11
Pipfile
@@ -5,10 +5,7 @@ verify_ssl = true
|
||||
|
||||
[dev-packages]
|
||||
mypy = "*"
|
||||
jedi = "*"
|
||||
black = "*"
|
||||
prospector = "*"
|
||||
rope = "*"
|
||||
jupyter = "*"
|
||||
better-exceptions = "*"
|
||||
pytest = "*"
|
||||
@@ -20,10 +17,14 @@ mkdocs = "*"
|
||||
mkdocs-material = "*"
|
||||
markdown-include = "*"
|
||||
autoflake = "*"
|
||||
email-validator = "*"
|
||||
ujson = "*"
|
||||
flake8 = "*"
|
||||
python-multipart = "*"
|
||||
|
||||
[packages]
|
||||
starlette = "*"
|
||||
pydantic = "*"
|
||||
starlette = "==0.10.1"
|
||||
pydantic = "==0.18.2"
|
||||
|
||||
[requires]
|
||||
python_version = "3.6"
|
||||
|
||||
348
Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "deb42eb176158abbd62d0af06fc60f571ae7da3012f7baafb1bcca08c363273b"
|
||||
"sha256": "20483e725e92e679c4c21ea3ff0043d759c74102b181f16b67908f979f854d5c"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@@ -26,18 +26,18 @@
|
||||
},
|
||||
"pydantic": {
|
||||
"hashes": [
|
||||
"sha256:51f879ca4b1d114c9f892737a0d65233251fb00fcd2b6da2be0d277b8ba7d28d",
|
||||
"sha256:c90c9e5ae2a6a3f59efdcb1505ddfb18be6dc5648b536bf33782269460954cc2"
|
||||
"sha256:9f023811b6cefd203c5fd8fd15a4152f04e79e531b8f676ab1244dfe06ce8024",
|
||||
"sha256:edbb08b561feda505374c0f25e4b54466a0a0c702ed6b2efaabdc3890d1a82e7"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.16.1"
|
||||
"version": "==0.18.2"
|
||||
},
|
||||
"starlette": {
|
||||
"hashes": [
|
||||
"sha256:a7b24496638b9e755bc31a72b0596939f3dd0e6eb1878ff55da5647be026a9e3"
|
||||
"sha256:7cc05c33d00db3b2ddfd7516a737544ed0a34c9dd0ced94076f29b581ce4f532"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.9.8"
|
||||
"version": "==0.10.1"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
@@ -48,13 +48,6 @@
|
||||
],
|
||||
"version": "==1.4.3"
|
||||
},
|
||||
"astroid": {
|
||||
"hashes": [
|
||||
"sha256:292fa429e69d60e4161e7612cb7cc8fa3609e2e309f80c224d93a76d5e7b58be",
|
||||
"sha256:c7013d119ec95eb626f7a2011f0b63d0c9a095df9ad06d8507b37084eada1a8d"
|
||||
],
|
||||
"version": "==2.0.4"
|
||||
},
|
||||
"atomicwrites": {
|
||||
"hashes": [
|
||||
"sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0",
|
||||
@@ -85,10 +78,11 @@
|
||||
},
|
||||
"better-exceptions": {
|
||||
"hashes": [
|
||||
"sha256:0a73efef96b48f867ea980227ac3b00d36a92754e6d316ad2ee472f136014580"
|
||||
"sha256:bf79c87659bc849989d726bf0e4a2100edefe7eded112d201f54fe08467fdf63",
|
||||
"sha256:c196cad849de615abb9f6eb67ca1b83f33b938818f0e2fe8fa157b22aeb7b992"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.2.1"
|
||||
"version": "==0.2.2"
|
||||
},
|
||||
"black": {
|
||||
"hashes": [
|
||||
@@ -100,10 +94,10 @@
|
||||
},
|
||||
"bleach": {
|
||||
"hashes": [
|
||||
"sha256:48d39675b80a75f6d1c3bdbffec791cf0bbbab665cf01e20da701c77de278718",
|
||||
"sha256:73d26f018af5d5adcdabf5c1c974add4361a9c76af215fe32fdec8a6fc5fb9b9"
|
||||
"sha256:213336e49e102af26d9cde77dd2d0397afabc5a6bf2fed985dc35b5d1e285a16",
|
||||
"sha256:3fdf7f77adcf649c9911387df51254b813185e32b2c6619f690b593a617e19fa"
|
||||
],
|
||||
"version": "==3.0.2"
|
||||
"version": "==3.1.0"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
@@ -162,10 +156,10 @@
|
||||
},
|
||||
"decorator": {
|
||||
"hashes": [
|
||||
"sha256:2c51dff8ef3c447388fe5e4453d24a2bf128d3a4c32af3fabef1f01c6851ab82",
|
||||
"sha256:c39efa13fbdeb4506c476c9b3babf6a718da943dab7811c206005a4a956c080c"
|
||||
"sha256:33cd704aea07b4c28b3eb2c97d288a06918275dac0ecebdaf1bc8a48d98adb9e",
|
||||
"sha256:cabb249f4710888a2fc0e13e9a16c343d932033718ff62e1e9bc93a9d3a9122b"
|
||||
],
|
||||
"version": "==4.3.0"
|
||||
"version": "==4.3.2"
|
||||
},
|
||||
"defusedxml": {
|
||||
"hashes": [
|
||||
@@ -174,6 +168,13 @@
|
||||
],
|
||||
"version": "==0.5.0"
|
||||
},
|
||||
"dnspython": {
|
||||
"hashes": [
|
||||
"sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01",
|
||||
"sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d"
|
||||
],
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"docutils": {
|
||||
"hashes": [
|
||||
"sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
|
||||
@@ -182,18 +183,27 @@
|
||||
],
|
||||
"version": "==0.14"
|
||||
},
|
||||
"dodgy": {
|
||||
"email-validator": {
|
||||
"hashes": [
|
||||
"sha256:65e13cf878d7aff129f1461c13cb5fd1bb6dfe66bb5327e09379c3877763280c"
|
||||
"sha256:ddc4b5b59fa699bb10127adcf7ad4de78fde4ec539a072b104b8bb16da666ae5"
|
||||
],
|
||||
"version": "==0.1.9"
|
||||
"index": "pypi",
|
||||
"version": "==1.0.3"
|
||||
},
|
||||
"entrypoints": {
|
||||
"hashes": [
|
||||
"sha256:10ad569bb245e7e2ba425285b9fa3e8178a0dc92fc53b1e1c553805e15a8825b",
|
||||
"sha256:d2d587dde06f99545fb13a383d2cd336a8ff1f359c5839ce3a64c917d10c029f"
|
||||
"sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19",
|
||||
"sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"
|
||||
],
|
||||
"version": "==0.2.3"
|
||||
"version": "==0.3"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
"sha256:09b9bb539920776da542e67a570a5df96ff933c9a08b62cfae920bcc789e4383",
|
||||
"sha256:e0f8cd519cfc0072c0ee31add5def09d2b3ef6040b34dc426445c3af9b02163c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.7.4"
|
||||
},
|
||||
"flit": {
|
||||
"hashes": [
|
||||
@@ -250,11 +260,10 @@
|
||||
},
|
||||
"jedi": {
|
||||
"hashes": [
|
||||
"sha256:0191c447165f798e6a730285f2eee783fff81b0d3df261945ecb80983b5c3ca7",
|
||||
"sha256:b7493f73a2febe0dc33d51c99b474547f7f6c0b2c8fb2b21f453eef204c12148"
|
||||
"sha256:571702b5bd167911fe9036e5039ba67f820d6502832285cde8c881ab2b2149fd",
|
||||
"sha256:c8481b5e59d34a5c7c42e98f6625e633f6ef59353abea6437472c7ec2093f191"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.13.1"
|
||||
"version": "==0.13.2"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
@@ -265,10 +274,10 @@
|
||||
},
|
||||
"jsonschema": {
|
||||
"hashes": [
|
||||
"sha256:3ae8afd6f4ca6417f14bf43ef61341311598f14234cdb4174fe43d42b236a3c8",
|
||||
"sha256:dfd8426040892c8d0ef6da574085f282569f189cb24b70091a66c21c12d6705e"
|
||||
"sha256:683fe7ed58763ea0be572de5aad47cd3cc1297640916f9a8ccd222b287da7d2f",
|
||||
"sha256:b42d7a292addb57370e6260bcbadb77e00a899fe6ec998c453f45893c41c658b"
|
||||
],
|
||||
"version": "==3.0.0a3"
|
||||
"version": "==3.0.0b3"
|
||||
},
|
||||
"jupyter": {
|
||||
"hashes": [
|
||||
@@ -300,40 +309,6 @@
|
||||
],
|
||||
"version": "==4.4.0"
|
||||
},
|
||||
"lazy-object-proxy": {
|
||||
"hashes": [
|
||||
"sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33",
|
||||
"sha256:1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39",
|
||||
"sha256:209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019",
|
||||
"sha256:27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088",
|
||||
"sha256:27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b",
|
||||
"sha256:2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e",
|
||||
"sha256:2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6",
|
||||
"sha256:320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b",
|
||||
"sha256:50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5",
|
||||
"sha256:5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff",
|
||||
"sha256:61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd",
|
||||
"sha256:6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7",
|
||||
"sha256:7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff",
|
||||
"sha256:7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d",
|
||||
"sha256:7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2",
|
||||
"sha256:7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35",
|
||||
"sha256:81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4",
|
||||
"sha256:933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514",
|
||||
"sha256:94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252",
|
||||
"sha256:ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109",
|
||||
"sha256:bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f",
|
||||
"sha256:cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c",
|
||||
"sha256:d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92",
|
||||
"sha256:ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577",
|
||||
"sha256:e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d",
|
||||
"sha256:e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d",
|
||||
"sha256:e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f",
|
||||
"sha256:eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a",
|
||||
"sha256:f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b"
|
||||
],
|
||||
"version": "==1.3.1"
|
||||
},
|
||||
"livereload": {
|
||||
"hashes": [
|
||||
"sha256:29cadfabcedd12eed792e0131991235b9d4764d4474bed75cf525f57109ec0a2",
|
||||
@@ -412,27 +387,27 @@
|
||||
},
|
||||
"mkdocs-material": {
|
||||
"hashes": [
|
||||
"sha256:037712dd7e2128a9b596943bcd92ebc9ad28800906dcee447e2fc008dd9dbbff",
|
||||
"sha256:52522c8553a6d6da8fca2afe43297e8f88acdcf8ccf752a118148f1328f761e2"
|
||||
"sha256:4b4af83c704d2bab41be3a5228e800a5e1157003368fbf548d95073ce19e0f61",
|
||||
"sha256:86c0042c803586985bf79c99962ebd4644c3f0ff095d5df541f09fa48f5b62cc"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.1.0"
|
||||
"version": "==3.3.0"
|
||||
},
|
||||
"more-itertools": {
|
||||
"hashes": [
|
||||
"sha256:c187a73da93e7a8acc0001572aebc7e3c69daf7bf6881a2cea10650bd4420092",
|
||||
"sha256:c476b5d3a34e12d40130bc2f935028b5f636df8f372dc2c1c01dc19681b2039e",
|
||||
"sha256:fcbfeaea0be121980e15bc97b3817b5202ca73d0eae185b4550cbfce2a3ebb3d"
|
||||
"sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4",
|
||||
"sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc",
|
||||
"sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9"
|
||||
],
|
||||
"version": "==4.3.0"
|
||||
"version": "==5.0.0"
|
||||
},
|
||||
"mypy": {
|
||||
"hashes": [
|
||||
"sha256:12d965c9c4e8a625673aec493162cf390e66de12ef176b1f4821ac00d55f3ab3",
|
||||
"sha256:38d5b5f835a81817dcc0af8d155bce4e9aefa03794fe32ed154d6612e83feafa"
|
||||
"sha256:986a7f97808a865405c5fd98fae5ebfa963c31520a56c783df159e9a81e41b3e",
|
||||
"sha256:cc5df73cc11d35655a8c364f45d07b13c8db82c000def4bd7721be13356533b4"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.650"
|
||||
"version": "==0.660"
|
||||
},
|
||||
"mypy-extensions": {
|
||||
"hashes": [
|
||||
@@ -457,10 +432,10 @@
|
||||
},
|
||||
"notebook": {
|
||||
"hashes": [
|
||||
"sha256:661341909008d1e7bfa1541904006f9789fa3de1cbec8379d2879819454cc04b",
|
||||
"sha256:91705b109fc785198faed892489cddb233265564d5e2dad5e4f7974af05ee8dd"
|
||||
"sha256:3ab2db8bc10e6edbd264c3c4b800bee276c99818386ee0c146d98d7e6bcf0a67",
|
||||
"sha256:d908673a4010787625c8952e91a22adf737db031f2aa0793ad92f6558918a74a"
|
||||
],
|
||||
"version": "==5.7.2"
|
||||
"version": "==5.7.4"
|
||||
},
|
||||
"pandocfilters": {
|
||||
"hashes": [
|
||||
@@ -470,17 +445,10 @@
|
||||
},
|
||||
"parso": {
|
||||
"hashes": [
|
||||
"sha256:35704a43a3c113cce4de228ddb39aab374b8004f4f2407d070b6a2ca784ce8a2",
|
||||
"sha256:895c63e93b94ac1e1690f5fdd40b65f07c8171e3e53cbd7793b5b96c0e0a7f24"
|
||||
"sha256:4b8f9ed80c3a4a3191aa3261505d868aa552dd25649cb13a7d73b6b7315edf2d",
|
||||
"sha256:5a120be2e8863993b597f1c0437efca799e90e0793c98ae5d4e34ebd00140e31"
|
||||
],
|
||||
"version": "==0.3.1"
|
||||
},
|
||||
"pep8-naming": {
|
||||
"hashes": [
|
||||
"sha256:1b419fa45b68b61cd8c5daf4e0c96d28915ad14d3d5f35fcc1e7e95324a33a2e",
|
||||
"sha256:4eedfd4c4b05e48796f74f5d8628c068ff788b9c2b08471ad408007fc6450e5a"
|
||||
],
|
||||
"version": "==0.4.1"
|
||||
"version": "==0.3.2"
|
||||
},
|
||||
"pexpect": {
|
||||
"hashes": [
|
||||
@@ -499,10 +467,10 @@
|
||||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:447ba94990e8014ee25ec853339faf7b0fc8050cdc3289d4d71f7f410fb90095",
|
||||
"sha256:bde19360a8ec4dfd8a20dcb811780a30998101f078fc7ded6162f0076f50508f"
|
||||
"sha256:8ddc32f03971bfdf900a81961a48ccf2fb677cf7715108f85295c67405798616",
|
||||
"sha256:980710797ff6a041e9a73a5787804f848996ecaa6f8a1b1e08224a5894f2074a"
|
||||
],
|
||||
"version": "==0.8.0"
|
||||
"version": "==0.8.1"
|
||||
},
|
||||
"prometheus-client": {
|
||||
"hashes": [
|
||||
@@ -512,18 +480,11 @@
|
||||
},
|
||||
"prompt-toolkit": {
|
||||
"hashes": [
|
||||
"sha256:c1d6aff5252ab2ef391c2fe498ed8c088066f66bc64a8d5c095bbf795d9fec34",
|
||||
"sha256:d4c47f79b635a0e70b84fdb97ebd9a274203706b1ee5ed44c10da62755cf3ec9",
|
||||
"sha256:fd17048d8335c1e6d5ee403c3569953ba3eb8555d710bfc548faf0712666ea39"
|
||||
"sha256:88002cc618cacfda8760c4539e76c3b3f148ecdb7035a3d422c7ecdc90c2a3ba",
|
||||
"sha256:c6655a12e9b08edb8cf5aeab4815fd1e1bdea4ad73d3bbf269cf2e0c4eb75d5e",
|
||||
"sha256:df5835fb8f417aa55e5cafadbaeb0cf630a1e824aad16989f9f0493e679ec010"
|
||||
],
|
||||
"version": "==2.0.7"
|
||||
},
|
||||
"prospector": {
|
||||
"hashes": [
|
||||
"sha256:877d8d361a5c0e04c8587718c22c5d671afcf814945c96b3e592836d772943fd"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.1.6.2"
|
||||
"version": "==2.0.8"
|
||||
},
|
||||
"ptyprocess": {
|
||||
"hashes": [
|
||||
@@ -542,64 +503,24 @@
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:cbc619d09254895b0d12c2c691e237b2e91e9b2ecf5e84c26b35400f93dcfb83",
|
||||
"sha256:cbfca99bd594a10f674d0cd97a3d802a1fdef635d4361e1a2658de47ed261e3a"
|
||||
"sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56",
|
||||
"sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"
|
||||
],
|
||||
"version": "==2.4.0"
|
||||
},
|
||||
"pydocstyle": {
|
||||
"hashes": [
|
||||
"sha256:2258f9b0df68b97bf3a6c29003edc5238ff8879f1efb6f1999988d934e432bd8",
|
||||
"sha256:5741c85e408f9e0ddf873611085e819b809fca90b619f5fd7f34bd4959da3dd4",
|
||||
"sha256:ed79d4ec5e92655eccc21eb0c6cf512e69512b4a97d215ace46d17e4990f2039"
|
||||
],
|
||||
"version": "==3.0.0"
|
||||
"version": "==2.5.0"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f",
|
||||
"sha256:8d616a382f243dbf19b54743f280b80198be0bca3a5396f1d2e1fca6223e8805"
|
||||
"sha256:5e8c00e30c464c99e0b501dc160b13a14af7f27d4dffb529c556e30a159e231d",
|
||||
"sha256:f277f9ca3e55de669fba45b7393a1449009cff5a37d1af10ebb76c52765269cd"
|
||||
],
|
||||
"version": "==1.6.0"
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:6301ecb0997a52d2d31385e62d0a4a4cf18d2f2da7054a5ddad5c366cd39cee7",
|
||||
"sha256:82666aac15622bd7bb685a4ee7f6625dd716da3ef7473620c192c0168aae64fc"
|
||||
"sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a",
|
||||
"sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d"
|
||||
],
|
||||
"version": "==2.3.0"
|
||||
},
|
||||
"pylint": {
|
||||
"hashes": [
|
||||
"sha256:1d6d3622c94b4887115fe5204982eee66fdd8a951cf98635ee5caee6ec98c3ec",
|
||||
"sha256:31142f764d2a7cd41df5196f9933b12b7ee55e73ef12204b648ad7e556c119fb"
|
||||
],
|
||||
"version": "==2.1.1"
|
||||
},
|
||||
"pylint-celery": {
|
||||
"hashes": [
|
||||
"sha256:41e32094e7408d15c044178ea828dd524beedbdbe6f83f712c5e35bde1de4beb"
|
||||
],
|
||||
"version": "==0.3"
|
||||
},
|
||||
"pylint-django": {
|
||||
"hashes": [
|
||||
"sha256:5dc5f85caef2c5f9e61622b9cbd89d94edd3dcf546939b2974d18de4fa90d676",
|
||||
"sha256:bf313f10b68ed915a34f0f475cc9ff8c7f574a95302beb48b79c5993f7efd84c"
|
||||
],
|
||||
"version": "==2.0.2"
|
||||
},
|
||||
"pylint-flask": {
|
||||
"hashes": [
|
||||
"sha256:8fcdbb7cbf13d8c2ac1f2230b2aa1c1b83bb3ca2bd8b76f95561cb8757a305ec"
|
||||
],
|
||||
"version": "==0.5"
|
||||
},
|
||||
"pylint-plugin-utils": {
|
||||
"hashes": [
|
||||
"sha256:8ad25a82bcce390d1d6b7c006c123e0cb18051839c9df7b8bdb7823c53fe676e"
|
||||
],
|
||||
"version": "==0.4"
|
||||
"version": "==2.3.1"
|
||||
},
|
||||
"pymdown-extensions": {
|
||||
"hashes": [
|
||||
@@ -610,25 +531,25 @@
|
||||
},
|
||||
"pyrsistent": {
|
||||
"hashes": [
|
||||
"sha256:05910b7ff43cec0a853c15da0bfaf2867faa95f29b08e71f5846a195f1f38c75"
|
||||
"sha256:5a3827d57ad3e46820e5ee4ed5b9e0ee7bc4686df6634a7368bc1863a5c48a77"
|
||||
],
|
||||
"version": "==0.14.7"
|
||||
"version": "==0.14.9"
|
||||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:1d131cc532be0023ef8ae265e2a779938d0619bb6c2510f52987ffcba7fa1ee4",
|
||||
"sha256:ca4761407f1acc85ffd1609f464ca20bb71a767803505bd4127d0e45c5a50e23"
|
||||
"sha256:65aeaa77ae87c7fc95de56285282546cfa9c886dc8e5dc78313db1c25e21bc07",
|
||||
"sha256:6ac6d467d9f053e95aaacd79f831dbecfe730f419c6c7022cb316b365cd9199d"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.0.1"
|
||||
"version": "==4.2.0"
|
||||
},
|
||||
"pytest-cov": {
|
||||
"hashes": [
|
||||
"sha256:513c425e931a0344944f84ea47f3956be0e416d95acbd897a44970c8d926d5d7",
|
||||
"sha256:e360f048b7dae3f2f2a9a4d067b2dd6b6a015d384d1577c994a43f3f7cbad762"
|
||||
"sha256:0ab664b25c6aa9716cbf203b17ddb301932383046082c081b9848a0edf5add33",
|
||||
"sha256:230ef817450ab0699c6cc3c9c8f7a829c34674456f2ed8df1fe1d39780f7c87f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.6.0"
|
||||
"version": "==2.6.1"
|
||||
},
|
||||
"python-dateutil": {
|
||||
"hashes": [
|
||||
@@ -637,6 +558,13 @@
|
||||
],
|
||||
"version": "==2.7.5"
|
||||
},
|
||||
"python-multipart": {
|
||||
"hashes": [
|
||||
"sha256:f7bb5f611fc600d15fa47b3974c8aa16e93724513b49b5f95c81e6624c83fa43"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.0.5"
|
||||
},
|
||||
"pytoml": {
|
||||
"hashes": [
|
||||
"sha256:ca2d0cb127c938b8b76a9a0d0f855cf930c1d50cc3a0af6d3595b566519a1013"
|
||||
@@ -698,19 +626,6 @@
|
||||
"index": "pypi",
|
||||
"version": "==2.21.0"
|
||||
},
|
||||
"requirements-detector": {
|
||||
"hashes": [
|
||||
"sha256:9fbc4b24e8b7c3663aff32e3eba34596848c6b91bd425079b386973bd8d08931"
|
||||
],
|
||||
"version": "==0.6"
|
||||
},
|
||||
"rope": {
|
||||
"hashes": [
|
||||
"sha256:a108c445e1cd897fe19272ab7877d172e7faf3d4148c80e7d20faba42ea8f7b2"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.11.0"
|
||||
},
|
||||
"send2trash": {
|
||||
"hashes": [
|
||||
"sha256:60001cc07d707fe247c94f74ca6ac0d3255aabcb930529690897ca2a39db28b2",
|
||||
@@ -718,12 +633,6 @@
|
||||
],
|
||||
"version": "==1.5.0"
|
||||
},
|
||||
"setoptconf": {
|
||||
"hashes": [
|
||||
"sha256:5b0b5d8e0077713f5d5152d4f63be6f048d9a1bb66be15d089a11c898c3cf49c"
|
||||
],
|
||||
"version": "==0.2.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
|
||||
@@ -731,13 +640,6 @@
|
||||
],
|
||||
"version": "==1.12.0"
|
||||
},
|
||||
"snowballstemmer": {
|
||||
"hashes": [
|
||||
"sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128",
|
||||
"sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89"
|
||||
],
|
||||
"version": "==1.2.1"
|
||||
},
|
||||
"terminado": {
|
||||
"hashes": [
|
||||
"sha256:55abf9ade563b8f9be1f34e4233c7b7bde726059947a593322e8a553cc4c067a",
|
||||
@@ -761,15 +663,9 @@
|
||||
},
|
||||
"tornado": {
|
||||
"hashes": [
|
||||
"sha256:0662d28b1ca9f67108c7e3b77afabfb9c7e87bde174fbda78186ecedc2499a9d",
|
||||
"sha256:4e5158d97583502a7e2739951553cbd88a72076f152b4b11b64b9a10c4c49409",
|
||||
"sha256:732e836008c708de2e89a31cb2fa6c0e5a70cb60492bee6f1ea1047500feaf7f",
|
||||
"sha256:8154ec22c450df4e06b35f131adc4f2f3a12ec85981a203301d310abf580500f",
|
||||
"sha256:8e9d728c4579682e837c92fdd98036bd5cdefa1da2aaf6acf26947e6dd0c01c5",
|
||||
"sha256:d4b3e5329f572f055b587efc57d29bd051589fb5a43ec8898c77a47ec2fa2bbb",
|
||||
"sha256:e5f2585afccbff22390cddac29849df463b252b711aa2ce7c5f3f342a5b3b444"
|
||||
"sha256:00ebd485a52bd7eaa3f35bdf8ab43c109aaa2edc722849b6905c1ffd8c958e82"
|
||||
],
|
||||
"version": "==5.1.1"
|
||||
"version": "==6.0a1"
|
||||
},
|
||||
"traitlets": {
|
||||
"hashes": [
|
||||
@@ -780,32 +676,36 @@
|
||||
},
|
||||
"typed-ast": {
|
||||
"hashes": [
|
||||
"sha256:0948004fa228ae071054f5208840a1e88747a357ec1101c17217bfe99b299d58",
|
||||
"sha256:10703d3cec8dcd9eef5a630a04056bbc898abc19bac5691612acba7d1325b66d",
|
||||
"sha256:1f6c4bd0bdc0f14246fd41262df7dfc018d65bb05f6e16390b7ea26ca454a291",
|
||||
"sha256:25d8feefe27eb0303b73545416b13d108c6067b846b543738a25ff304824ed9a",
|
||||
"sha256:29464a177d56e4e055b5f7b629935af7f49c196be47528cc94e0a7bf83fbc2b9",
|
||||
"sha256:2e214b72168ea0275efd6c884b114ab42e316de3ffa125b267e732ed2abda892",
|
||||
"sha256:3e0d5e48e3a23e9a4d1a9f698e32a542a4a288c871d33ed8df1b092a40f3a0f9",
|
||||
"sha256:519425deca5c2b2bdac49f77b2c5625781abbaf9a809d727d3a5596b30bb4ded",
|
||||
"sha256:57fe287f0cdd9ceaf69e7b71a2e94a24b5d268b35df251a88fef5cc241bf73aa",
|
||||
"sha256:668d0cec391d9aed1c6a388b0d5b97cd22e6073eaa5fbaa6d2946603b4871efe",
|
||||
"sha256:68ba70684990f59497680ff90d18e756a47bf4863c604098f10de9716b2c0bdd",
|
||||
"sha256:6de012d2b166fe7a4cdf505eee3aaa12192f7ba365beeefaca4ec10e31241a85",
|
||||
"sha256:79b91ebe5a28d349b6d0d323023350133e927b4de5b651a8aa2db69c761420c6",
|
||||
"sha256:8550177fa5d4c1f09b5e5f524411c44633c80ec69b24e0e98906dd761941ca46",
|
||||
"sha256:898f818399cafcdb93cbbe15fc83a33d05f18e29fb498ddc09b0214cdfc7cd51",
|
||||
"sha256:94b091dc0f19291adcb279a108f5d38de2430411068b219f41b343c03b28fb1f",
|
||||
"sha256:a26863198902cda15ab4503991e8cf1ca874219e0118cbf07c126bce7c4db129",
|
||||
"sha256:a8034021801bc0440f2e027c354b4eafd95891b573e12ff0418dec385c76785c",
|
||||
"sha256:bc978ac17468fe868ee589c795d06777f75496b1ed576d308002c8a5756fb9ea",
|
||||
"sha256:c05b41bc1deade9f90ddc5d988fe506208019ebba9f2578c622516fd201f5863",
|
||||
"sha256:c9b060bd1e5a26ab6e8267fd46fc9e02b54eb15fffb16d112d4c7b1c12987559",
|
||||
"sha256:edb04bdd45bfd76c8292c4d9654568efaedf76fe78eb246dde69bdb13b2dad87",
|
||||
"sha256:f19f2a4f547505fe9072e15f6f4ae714af51b5a681a97f187971f50c283193b6"
|
||||
"sha256:023625bfa9359e29bd6e24cac2a4503495b49761d48a5f1e38333fc4ac4d93fe",
|
||||
"sha256:07591f7a5fdff50e2e566c4c1e9df545c75d21e27d98d18cb405727ed0ef329c",
|
||||
"sha256:153e526b0f4ffbfada72d0bb5ffe8574ba02803d2f3a9c605c8cf99dfedd72a2",
|
||||
"sha256:3ad2bdcd46a4a1518d7376e9f5016d17718a9ed3c6a3f09203d832f6c165de4a",
|
||||
"sha256:3ea98c84df53ada97ee1c5159bb3bc784bd734231235a1ede14c8ae0775049f7",
|
||||
"sha256:51a7141ccd076fa561af107cfb7a8b6d06a008d92451a1ac7e73149d18e9a827",
|
||||
"sha256:52c93cd10e6c24e7ac97e8615da9f224fd75c61770515cb323316c30830ddb33",
|
||||
"sha256:6344c84baeda3d7b33e157f0b292e4dd53d05ddb57a63f738178c01cac4635c9",
|
||||
"sha256:64699ca1b3bd5070bdeb043e6d43bc1d0cebe08008548f4a6bee782b0ecce032",
|
||||
"sha256:74903f2e56bbffe29282ef8a5487d207d10be0f8513b41aff787d954a4cf91c9",
|
||||
"sha256:7891710dba83c29ee2bd51ecaa82f60f6bede40271af781110c08be134207bf2",
|
||||
"sha256:91976c56224e26c256a0de0f76d2004ab885a29423737684b4f7ebdd2f46dde2",
|
||||
"sha256:9bad678a576ecc71f25eba9f1e3fd8d01c28c12a2834850b458428b3e855f062",
|
||||
"sha256:b4726339a4c180a8b6ad9d8b50d2b6dc247e1b79b38fe2290549c98e82e4fd15",
|
||||
"sha256:ba36f6aa3f8933edf94ea35826daf92cbb3ec248b89eccdc053d4a815d285357",
|
||||
"sha256:bbc96bde544fd19e9ef168e4dfa5c3dfe704bfa78128fa76f361d64d6b0f731a",
|
||||
"sha256:c0c927f1e44469056f7f2dada266c79b577da378bbde3f6d2ada726d131e4824",
|
||||
"sha256:c0f9a3708008aa59f560fa1bd22385e05b79b8e38e0721a15a8402b089243442",
|
||||
"sha256:f0bf6f36ff9c5643004171f11d2fdc745aa3953c5aacf2536a0685db9ceb3fb1",
|
||||
"sha256:f5be39a0146be663cbf210a4d95c3c58b2d7df7b043c9047c5448e358f0550a2",
|
||||
"sha256:fcd198bf19d9213e5cbf2cde2b9ef20a9856e716f76f9476157f90ae6de06cc6"
|
||||
],
|
||||
"markers": "python_version < '3.7' and implementation_name == 'cpython'",
|
||||
"version": "==1.1.0"
|
||||
"version": "==1.2.0"
|
||||
},
|
||||
"ujson": {
|
||||
"hashes": [
|
||||
"sha256:f66073e5506e91d204ab0c614a148d5aa938bdbf104751be66f8ad7a222f5f86"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.35"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
@@ -834,12 +734,6 @@
|
||||
"sha256:fa618be8435447a017fd1bf2c7ae922d0428056cfc7449f7a8641edf76b48265"
|
||||
],
|
||||
"version": "==3.4.2"
|
||||
},
|
||||
"wrapt": {
|
||||
"hashes": [
|
||||
"sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6"
|
||||
],
|
||||
"version": "==1.10.11"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
135
README.md
@@ -5,30 +5,30 @@
|
||||
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/tiangolo/fastapi">
|
||||
<a href="https://travis-ci.org/tiangolo/fastapi" target="_blank">
|
||||
<img src="https://travis-ci.org/tiangolo/fastapi.svg?branch=master" alt="Build Status">
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/tiangolo/fastapi">
|
||||
<a href="https://codecov.io/gh/tiangolo/fastapi" target="_blank">
|
||||
<img src="https://codecov.io/gh/tiangolo/fastapi/branch/master/graph/badge.svg" alt="Coverage">
|
||||
</a>
|
||||
<a href="https://pypi.org/project/fastapi">
|
||||
<a href="https://pypi.org/project/fastapi" target="_blank">
|
||||
<img src="https://badge.fury.io/py/fastapi.svg" alt="Package version">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
**Documentation**: [https://fastapi.tiangolo.com](https://fastapi.tiangolo.com)
|
||||
**Documentation**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
|
||||
|
||||
**Source Code**: [https://github.com/tiangolo/fastapi](https://github.com/tiangolo/fastapi)
|
||||
**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+.
|
||||
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).
|
||||
* **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% *.
|
||||
* **Less bugs**: Reduce about 40% of human (developer) induced errors. *
|
||||
@@ -36,7 +36,7 @@ The key features are:
|
||||
* **Easy**: Designed to be easy to use and learn. Less time reading docs.
|
||||
* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Less 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" target="_blank">OpenAPI</a> and <a href="http://json-schema.org/" 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" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="http://json-schema.org/" target="_blank">JSON Schema</a>.
|
||||
|
||||
<small>* estimation based on tests on an internal development team, building production applications.</small>
|
||||
|
||||
@@ -65,6 +65,8 @@ $ pip install uvicorn
|
||||
|
||||
## Example
|
||||
|
||||
### Create it
|
||||
|
||||
* Create a file `main.py` with:
|
||||
|
||||
```Python
|
||||
@@ -72,50 +74,79 @@ from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get('/')
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {'hello': 'world'}
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
<details markdown="1">
|
||||
<summary>Or use <code>async def</code>...</summary>
|
||||
|
||||
Or if your code uses `async` / `await`, use `async def`:
|
||||
If your code uses `async` / `await`, use `async def`:
|
||||
|
||||
```Python hl_lines="6"
|
||||
```Python hl_lines="7 12"
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get('/')
|
||||
|
||||
@app.get("/")
|
||||
async def read_root():
|
||||
return {'hello': 'world'}
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
!!! note
|
||||
If you don't know, check the section about [`async` and `await` in the docs](async.md).
|
||||
**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 the server with:
|
||||
### Run it
|
||||
|
||||
Run the server with:
|
||||
|
||||
```bash
|
||||
uvicorn main:app --debug
|
||||
```
|
||||
|
||||
!!! note
|
||||
The command `uvicorn main:app` refers to:
|
||||
<details markdown="1">
|
||||
<summary>About the command <code>uvicorn main:app --debug</code>...</summary>
|
||||
|
||||
* `main`: the file `main.py` (the Python "module").
|
||||
* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
|
||||
* `--debug`: make the server restart after code changes. Only do this for development.
|
||||
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()`.
|
||||
* `--debug`: 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" target="_blank">http://127.0.0.1:8000</a>.
|
||||
Open your browser at <a href="http://127.0.0.1:8000/items/5?q=somequery" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
|
||||
|
||||
You will see the JSON response as:
|
||||
|
||||
```JSON
|
||||
{"hello": "world"}
|
||||
{"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" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
@@ -135,14 +166,12 @@ You will see the alternative automatic documentation (provided by <a href="https
|
||||
|
||||
## Example upgrade
|
||||
|
||||
Now modify the file `main.py` to include:
|
||||
Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||
|
||||
* a path parameter `item_id`.
|
||||
* a body, declared using standard Python types (thanks to Pydantic).
|
||||
* an optional query parameter `q`.
|
||||
Declare the body using standard Python types, thanks to Pydantic.
|
||||
|
||||
|
||||
```Python hl_lines="2 7 8 9 10 19"
|
||||
```Python hl_lines="2 7 8 9 10 24"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -155,14 +184,19 @@ class Item(BaseModel):
|
||||
is_offer: bool = None
|
||||
|
||||
|
||||
@app.get('/')
|
||||
async def read_root():
|
||||
return {'hello': 'world'}
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.post('/items/{item_id}')
|
||||
async def create_item(item_id: int, item: Item, q: str = None):
|
||||
return {"item_name": item.name, "item_id": item_id, "query": q}
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
def create_item(item_id: int, item: Item):
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
The server should reload automatically (because you added `--debug` to the `uvicorn` command above).
|
||||
@@ -171,7 +205,7 @@ The server should reload automatically (because you added `--debug` to the `uvic
|
||||
|
||||
Now go to <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
* The interactive API documentation will be automatically updated, including the new query, and body:
|
||||
* The interactive API documentation will be automatically updated, including the new body:
|
||||
|
||||

|
||||
|
||||
@@ -223,7 +257,7 @@ item: Item
|
||||
* 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:
|
||||
* <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.
|
||||
@@ -245,20 +279,20 @@ item: Item
|
||||
|
||||
Coming back to the previous code example, **FastAPI** will:
|
||||
|
||||
* Validate that there is an `item_id` in the path.
|
||||
* Validate that the `item_id` is of type `int`.
|
||||
* 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`).
|
||||
* 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).
|
||||
* Read the body as JSON:
|
||||
* 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 is 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 as an OpenAPI schema, that can be used by:
|
||||
* Interactive documentation sytems.
|
||||
* 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.
|
||||
|
||||
@@ -270,7 +304,7 @@ 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, "query": q}
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
...from:
|
||||
@@ -290,12 +324,12 @@ Try changing the line with:
|
||||

|
||||
|
||||
|
||||
For a more complete example including more features, [see the tutorial - user guide](tutorial/intro/).
|
||||
For a more complete example including more features, see the <a href="https://fastapi.tiangolo.com/tutorial/intro/">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 constrains** as `maximum_length` or `regex`.
|
||||
* 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).
|
||||
@@ -308,6 +342,11 @@ For a more complete example including more features, [see the tutorial - user gu
|
||||
* ...and more.
|
||||
|
||||
|
||||
## Performance
|
||||
|
||||
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=a979de55-980d-4721-a46f-77298b3f3923&hw=ph&test=fortune&l=zijzen-7" 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/" target="_blank">Benchmarks</a>.
|
||||
|
||||
## Optional Dependencies
|
||||
|
||||
@@ -332,7 +371,7 @@ 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.
|
||||
|
||||
You can install all of these with `pip3 install fastapi[full]`.
|
||||
You can install all of these with `pip3 install fastapi[all]`.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
15
dist/fastapi-0.1.0/pyproject.toml
vendored
@@ -1,15 +0,0 @@
|
||||
[build-system]
|
||||
requires = ["flit"]
|
||||
build-backend = "flit.buildapi"
|
||||
|
||||
[tool.flit.metadata]
|
||||
module = "fastapi"
|
||||
author = "Sebastián Ramírez"
|
||||
author-email = "tiangolo@gmail.com"
|
||||
home-page = "https://github.com/tiangolo/fastapi"
|
||||
classifiers = ["License :: OSI Approved :: MIT License"]
|
||||
requires = [
|
||||
"starlette >=0.9.7",
|
||||
"pydantic >=0.16"
|
||||
]
|
||||
requires-python = ">=3.6"
|
||||
374
docs/alternatives.md
Normal file
@@ -0,0 +1,374 @@
|
||||
What inspired **FastAPI**, how it compares to other alternatives and what it learned from them.
|
||||
|
||||
## Intro
|
||||
|
||||
**FastAPI** wouldn't exist if not for the previous work of others.
|
||||
|
||||
There have been many tools created before that have helped inspire its creation.
|
||||
|
||||
I have been avoiding the creation of a new framework for several years. First I tried to solve all the features covered by **FastAPI** using many different frameworks, plug-ins, and tools.
|
||||
|
||||
But at some point, there was no other option than creating something that provided all these features, taking the best ideas from previous tools, and combining them in the best way possible, using language features that weren't even available before (Python 3.6+ type hints).
|
||||
|
||||
## Previous tools
|
||||
|
||||
### <a href="https://www.djangoproject.com/" target="_blank">Django</a>
|
||||
|
||||
It's the most popular Python framework and is widely trusted. It is used to build systems like Instagram.
|
||||
|
||||
It's relatively tightly coupled with relational databases (like MySQL or PostgreSQL), so, having a NoSQL database (like Couchbase, MongoDB, Cassandra, etc) as the main store engine is not very easy.
|
||||
|
||||
It was created to generate the HTML in the backend, not to create APIs used by a modern frontend (like React, Vue.js and Angular) or by other systems (like <abbr title="Internet of Things">IoT</abbr> devices) communicating with it.
|
||||
|
||||
### <a href="https://www.django-rest-framework.org/" target="_blank">Django REST Framework</a>
|
||||
|
||||
Django REST framework was created to be a flexible toolkit for building Web APIs using Django underneath, to improve its API capabilities.
|
||||
|
||||
It is used by many companies including Mozilla, Red Hat and Eventbrite.
|
||||
|
||||
It was one of the first examples of **automatic API documentation**, and this was specifically one of the first ideas that inspired "the search for" **FastAPI**.
|
||||
|
||||
!!! note
|
||||
Django REST Framework was created by Tom Christie. The same creator of Starlette and Uvicorn, on which **FastAPI** is based.
|
||||
|
||||
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
Have an automatic API documentation web user interface.
|
||||
|
||||
### <a href="http://flask.pocoo.org/" 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.
|
||||
|
||||
This simplicity and flexibility allow doing things like using NoSQL databases as the main data storage system.
|
||||
|
||||
As it is very simple, it's relatively intuitive to learn, although the documentation gets somewhat technical at some points.
|
||||
|
||||
It is also commonly used for other applications that don't necessarily need a database, user management, or any of the many features that come pre-built in Django. Although many of these features can be added with plug-ins.
|
||||
|
||||
This decoupling of parts, and being a "microframework" that could be extended to cover exactly what is needed was a key feature that I wanted to keep.
|
||||
|
||||
Given the simplicity of Flask, it seemed like a good match for building APIs. The next thing to find was a "Django REST Framework" for Flask.
|
||||
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
Be a micro-framework. Making it easy to mix and match the tools and parts needed.
|
||||
|
||||
Have a simple and easy to use routing system.
|
||||
|
||||
|
||||
### <a href="http://docs.python-requests.org" target="_blank">Requests</a>
|
||||
|
||||
**FastAPI** is not actually an alternative to **Requests**. Their scope is very different.
|
||||
|
||||
It would actually be common to use Requests *inside* of a FastAPI application.
|
||||
|
||||
But still, FastAPI got quite some inspiration from Requests.
|
||||
|
||||
**Requests** is a library to *interact* with APIs (as a client), while **FastAPI** is a library to *build* APIs (as a server).
|
||||
|
||||
They are, more or less, at opposite ends, complementing each other.
|
||||
|
||||
Requests has a very simple and intuitive design, it's very easy to use, with sensible defaults. But at the same time, it's very powerful and customizable.
|
||||
|
||||
That's why, as said in the official website:
|
||||
|
||||
> Requests is one of the most downloaded Python packages of all time
|
||||
|
||||
The way you use it is very simple. For example, to do a `GET` request, you would write:
|
||||
|
||||
```Python
|
||||
response = requests.get("http://example.com/some/url")
|
||||
```
|
||||
|
||||
The FastAPI counterpart API path operation could look like:
|
||||
|
||||
```Python hl_lines="1"
|
||||
@app.get("/some/url")
|
||||
def read_url():
|
||||
return {"message": "Hello World"}
|
||||
```
|
||||
|
||||
See the similarities in `requests.get(...)` and `@app.get(...)`.
|
||||
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
* Have a simple and intuitive API.
|
||||
* Use HTTP method names (operations) directly, in a straightforward and intuitive way.
|
||||
* Have sensible defaults, but powerful customizations.
|
||||
|
||||
|
||||
### <a href="https://swagger.io/" target="_blank">Swagger</a> / <a href="https://github.com/OAI/OpenAPI-Specification/" target="_blank">OpenAPI</a>
|
||||
|
||||
The main feature I wanted from Django REST Framework was the automatic API documentation.
|
||||
|
||||
Then I found that there was a standard to document APIs, using JSON (or YAML, an extension of JSON) called Swagger.
|
||||
|
||||
And there was a web user interface for Swagger APIs already created. So, being able to generate Swagger documentation for an API would allow using this web user interface automatically.
|
||||
|
||||
At some point, Swagger was given to the Linux Foundation, to be renamed OpenAPI.
|
||||
|
||||
That's why when talking about version 2.0 it's common to say "Swagger", and for version 3+ "OpenAPI".
|
||||
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
Adopt and use an open standard for API specifications, instead of a custom schema.
|
||||
|
||||
And integrate standards-based user interface tools:
|
||||
|
||||
* <a href="https://github.com/swagger-api/swagger-ui" target="_blank">Swagger UI</a>
|
||||
* <a href="https://github.com/Rebilly/ReDoc" target="_blank">ReDoc</a>
|
||||
|
||||
These two were chosen for being fairly popular and stable, but doing a quick search, you could find dozens of additional alternative user interfaces for OpenAPI (that you can use with **FastAPI**).
|
||||
|
||||
### Flask REST frameworks
|
||||
|
||||
There are several Flask REST frameworks, but after investing the time and work into investigating them, I found that many are discontinued or abandoned, with several standing issues that made them unfit.
|
||||
|
||||
### <a href="https://marshmallow.readthedocs.io/en/3.0/" target="_blank">Marshmallow</a>
|
||||
|
||||
One of the main features needed by API systems is data "<abbr title="also called marshalling, convertion">serialization</abbr>" which is taking data from the code (Python) and converting it into something that can be sent through the network. For example, converting an object containing data from a database into a JSON object. Converting `datetime` objects into strings, etc.
|
||||
|
||||
Another big feature needed by APIs is data validation, making sure that the data is valid, given certain parameters. For example, that some field is an `int`, and not some random string. This is especially useful for incoming data.
|
||||
|
||||
Without a data validation system, you would have to do all the checks by hand, in code.
|
||||
|
||||
These features are what Marshmallow was built to provide. It is a great library, and I have used it a lot before.
|
||||
|
||||
But it was created before there existed Python type hints. So, to define every <abbr title="the definition of how data should be formed">schema</abbr> you need to use specific utils and classes provided by Marshmallow.
|
||||
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
Use code to define "schemas" that provide data types and validation, automatically.
|
||||
|
||||
### <a href="https://webargs.readthedocs.io/en/latest/" target="_blank">Webargs</a>
|
||||
|
||||
Another big feature required by APIs is <abbr title="reading and converting to Python data">parsing</abbr> data from incoming requests.
|
||||
|
||||
Webargs is a tool that was made to provide that on top of several frameworks, including Flask.
|
||||
|
||||
It uses Marshmallow underneath to do the data validation. And it was created by the same guys.
|
||||
|
||||
It's a great tool and I have used it a lot too, before having **FastAPI**.
|
||||
|
||||
!!! info
|
||||
Webargs was created by the same Marshmallow guys.
|
||||
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
Have automatic validation of incoming request data.
|
||||
|
||||
### <a href="https://apispec.readthedocs.io/en/stable/" target="_blank">APISpec</a>
|
||||
|
||||
Marshmallow and Webargs provide validation, parsing and serialization as plug-ins.
|
||||
|
||||
But documentation is still missing. Then APISpec was created.
|
||||
|
||||
It is a plug-in for many frameworks (and there's a plug-in for Starlette too).
|
||||
|
||||
The way it works is that you write the definition of the schema using YAML format inside the docstring of each function handling a route.
|
||||
|
||||
And it generates OpenAPI schemas.
|
||||
|
||||
That's how it works in Flask, Starlette, Responder, etc.
|
||||
|
||||
But then, we have again the problem of having a micro-syntax, inside of a Python string (a big YAML).
|
||||
|
||||
The editor can't help much with that. And if we modify parameters or Marshmallow schemas and forget to also modify that YAML docstring, the generated schema would be obsolete.
|
||||
|
||||
!!! info
|
||||
APISpec was created by the same Marshmallow guys.
|
||||
|
||||
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
Support the open standard for APIs, OpenAPI.
|
||||
|
||||
### <a href="https://flask-apispec.readthedocs.io/en/latest/" target="_blank">Flask-apispec</a>
|
||||
|
||||
It's a Flask plug-in, that ties together Webargs, Marshmallow and APISpec.
|
||||
|
||||
It uses the information from Webargs and Marshmallow to automatically generate OpenAPI schemas, using APISpec.
|
||||
|
||||
It's a great tool, very under-rated. It should be way more popular than many Flask plug-ins out there. It might be due to its documentation being too concise and abstract.
|
||||
|
||||
This solved having to write YAML (another syntax) inside of Python docstrings.
|
||||
|
||||
This combination of Flask, Flask-apispec with Marshmallow and Webargs was my favorite backend stack until building **FastAPI**.
|
||||
|
||||
Using it led to the creation of several Flask full-stack generators. These are the main stack I (and several external teams) have been using up to now:
|
||||
|
||||
* <a href="https://github.com/tiangolo/full-stack" target="_blank">https://github.com/tiangolo/full-stack</a>
|
||||
* <a href="https://github.com/tiangolo/full-stack-flask-couchbase" target="_blank">https://github.com/tiangolo/full-stack-flask-couchbase</a>
|
||||
* <a href="https://github.com/tiangolo/full-stack-flask-couchdb" target="_blank">https://github.com/tiangolo/full-stack-flask-couchdb</a>
|
||||
|
||||
And these same full-stack generators were the base of the <a href="/project-generation/" target="_blank">**FastAPI** project generator</a>.
|
||||
|
||||
!!! info
|
||||
Flask-apispec was created by the same Marshmallow guys.
|
||||
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
Generate the OpenAPI schema automatically, from the same code that defines serialization and validation.
|
||||
|
||||
### <a href="https://nestjs.com/" target="_blank">NestJS</a> (and <a href="https://angular.io/" target="_blank">Angular</a>)
|
||||
|
||||
This isn't even Python, NestJS is a JavaScript (TypeScript) NodeJS framework inspired by Angular.
|
||||
|
||||
It achieves something somewhat similar to what can be done with Flask-apispec.
|
||||
|
||||
It has an integrated dependency injection system, inspired by Angular two. It requires pre-registering the "injectables" (like all the other dependency injection systems I know), so, it adds to the verbosity and code repetition.
|
||||
|
||||
As the parameters are described with TypeScript types (similar to Python type hints), editor support is quite good.
|
||||
|
||||
But as TypeScript data is not preserved after compilation to JavaScript, it cannot rely on the types to define validation, serialization and documentation at the same time. Due to this and some design decisions, to get validation, serialization and automatic schema generation, it's needed to add decorators in many places. So, it becomes quite verbose.
|
||||
|
||||
It can't handle nested models very well. So, if the JSON body in the request is a JSON object that has inner fields that in turn are nested JSON objects, it cannot be properly documented and validated.
|
||||
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
Use Python types to have great editor support.
|
||||
|
||||
Have a powerful dependency injection system. Find a way to minimize code repetition.
|
||||
|
||||
### <a href="https://sanic.readthedocs.io/en/latest/" target="_blank">Sanic</a>
|
||||
|
||||
It was one of the first extremely fast Python frameworks based on `asyncio`. It was made to be very similar to Flask.
|
||||
|
||||
!!! note "Technical Details"
|
||||
It used <a href="https://github.com/MagicStack/uvloop" target="_blank">`uvloop`</a> instead of the default Python `asyncio` loop. That's what made it so fast.
|
||||
|
||||
It <a href="https://github.com/huge-success/sanic/issues/761" target="_blank">still doesn't implement the ASGI spec for Python asynchronous web development</a>, but it clearly inspired Uvicorn and Starlette, that are currently faster than Sanic in open benchmarks.
|
||||
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
Find a way to have a crazy performance.
|
||||
|
||||
That's why **FastAPI** is based on Starlette, as it is the fastest framework available (tested by third-party benchmarks).
|
||||
|
||||
### <a href="https://moltenframework.com/" target="_blank">Molten</a>
|
||||
|
||||
I discovered Molten in the first stages of building **FastAPI**. And it has quite similar ideas:
|
||||
|
||||
* Based on Python type hints.
|
||||
* Validation and documentation from these types.
|
||||
* Dependency Injection system.
|
||||
|
||||
It doesn't use a data validation, serialization and documentation third-party library like Pydantic, it has its own. So, these data type definitions would not be reusable as easily.
|
||||
|
||||
It requires a little bit more verbose configurations. And as it is based on WSGI (instead of ASGI), it is not designed to take advantage of the high-performance provided by tools like Uvicorn, Starlette and Sanic.
|
||||
|
||||
The dependency injection system requires pre-registration of the dependencies and the dependencies are solved based on the declared types. So, it's not possible to declare more than one "component" that provides a certain type.
|
||||
|
||||
Routes are declared in a single place, using functions declared in other places (instead of using decorators that can be placed right on top of the function that handles the endpoint). This is closer to how Django does it than to how Flask (and Starlette) does it. It separates in the code things that are relatively tightly coupled.
|
||||
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
Define extra validations for data types using the "default" value of model attributes. This improves editor support, and it was not available in Pydantic before.
|
||||
|
||||
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="https://github.com/encode/apistar" target="_blank">APIStar</a> (<= 0.5)
|
||||
|
||||
Right before deciding to build **FastAPI** I found **APIStar** server. It had almost everything I was looking for and had a great design.
|
||||
|
||||
It was actually the first implementation of a framework using Python type hints to declare parameters and requests that I ever saw (before NestJS and Molten).
|
||||
|
||||
It had automatic data validation, data serialization and OpenAPI schema generation based on the same type hints in several places.
|
||||
|
||||
Body schema definitions didn't use the same Python type hints like Pydantic, it was a bit more similar to Marshmallow, so, editor support wouldn't be as good, but still, APIStar was the best available option.
|
||||
|
||||
It had the best performance benchmarks at the time (only surpassed by Starlette).
|
||||
|
||||
At first, it didn't have an automatic API documentation web UI, but I knew I could add Swagger UI to it.
|
||||
|
||||
It had a dependency injection system. It required pre-registration of components, as other tools discussed above. But still, it was a great feature.
|
||||
|
||||
I was never able to use it in a full project, as it didn't have security integration, so, I couldn't replace all the features I was having with the full-stack generators based on Flask-apispec. I had in my backlog of projects to create a pull request adding that functionality.
|
||||
|
||||
But then, the project's focus shifted.
|
||||
|
||||
It was no longer an API web framework, as the creator needed to focus on Starlette.
|
||||
|
||||
Now APIStar is a set of tools to validate OpenAPI specifications, not a web framework.
|
||||
|
||||
!!! info
|
||||
APIStar was created by Tom Christie. The same guy that created:
|
||||
|
||||
* Django REST Framework
|
||||
* Starlette (in which **FastAPI** is based)
|
||||
* Uvicorn (used by Starlette and **FastAPI**)
|
||||
|
||||
!!! check "Inspired **FastAPI** to"
|
||||
Exist.
|
||||
|
||||
The idea of declaring multiple things (data validation, serialization and documentation) with the same Python types, that at the same time provided great editor support, was something I considered a brilliant idea.
|
||||
|
||||
And after searching for a long time for a similar framework and testing many different alternatives, APIStar was the best option available.
|
||||
|
||||
Then APIStar stopped to exist as a server and Starlette was created, and was a new better foundation for such a system. That was the final inspiration to build **FastAPI**.
|
||||
|
||||
I consider **FastAPI** a "spiritual successor" to APIStar, while improving and increasing the features, typing system, and other parts, based on the learnings from all these previous tools.
|
||||
|
||||
## Used by **FastAPI**
|
||||
|
||||
### <a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic</a>
|
||||
|
||||
Pydantic is a library to define data validation, serialization and documentation (using JSON Schema) based on Python type hints.
|
||||
|
||||
That makes it extremely intuitive.
|
||||
|
||||
It is comparable to Marshmallow. Although it's faster than Marshmallow in benchmarks. And as it is based on the same Python type hints, the editor support is great.
|
||||
|
||||
!!! check "**FastAPI** uses it to"
|
||||
Handle all the data validation, data serialization and automatic model documentation (based on JSON Schema).
|
||||
|
||||
**FastAPI** then takes that JSON Schema data and puts it in OpenAPI, apart from all the other things it does.
|
||||
|
||||
### <a href="https://www.starlette.io/" target="_blank">Starlette</a>
|
||||
|
||||
Starlette is a lightweight <abbr title="The new standard for building asynchronous Python web">ASGI</abbr> framework/toolkit, which is ideal for building high-performance asyncio services.
|
||||
|
||||
It is very simple and intuitive. It's designed to be easily extensible, and have modular components.
|
||||
|
||||
It has:
|
||||
|
||||
* Seriously impressive performance.
|
||||
* WebSocket support.
|
||||
* GraphQL support.
|
||||
* In-process background tasks.
|
||||
* Startup and shutdown events.
|
||||
* Test client built on requests.
|
||||
* CORS, GZip, Static Files, Streaming responses.
|
||||
* Session and Cookie support.
|
||||
* 100% test coverage.
|
||||
* 100% type annotated codebase.
|
||||
* Zero hard dependencies.
|
||||
|
||||
Starlette is currently the fastest Python framework tested. Only surpassed by Uvicorn, which is not a framework, but a server.
|
||||
|
||||
Starlette provides all the basic web microframework functionality.
|
||||
|
||||
But it doesn't provide automatic data validation, serialization or documentation.
|
||||
|
||||
That's one of the main things that **FastAPI** adds on top, all based on Python type hints (using Pydantic). That, plus the dependency injection system, security utilities, OpenAPI schema generation, etc.
|
||||
|
||||
!!! note "Technical Details"
|
||||
ASGI is a new "standard" being developed by Django core team members. It is still not a "Python standard" (a PEP), although they are in the process of doing that.
|
||||
|
||||
Nevertheless, it is already being used as a "standard" by several tools. This greatly improves interoperability, as you could switch Uvicorn for any other ASGI server (like Daphne or Hypercorn), or you could add ASGI compatible tools, like `python-socketio`.
|
||||
|
||||
!!! check "**FastAPI** uses it to"
|
||||
Handle all the core web parts. Adding features on top.
|
||||
|
||||
The class `FastAPI` itself inherits directly from the class `Starlette`.
|
||||
|
||||
So, anything that you can do with Starlette, you can do it directly with **FastAPI**, as it is basically Starlette on steroids.
|
||||
|
||||
### <a href="https://www.uvicorn.org/" target="_blank">Uvicorn</a>
|
||||
|
||||
Uvicorn is a lightning-fast ASGI server, built on uvloop and httptools.
|
||||
|
||||
It is not a web framework, but a server. For example, it doesn't provide tools for routing by paths. That's something that a framework like Starlette (or **FastAPI**) would provide on top.
|
||||
|
||||
It is the recommended server for Starlette and **FastAPI**.
|
||||
|
||||
!!! check "**FastAPI** recommends it as"
|
||||
The main web server to run **FastAPI** applications.
|
||||
|
||||
You can combine it with Gunicorn, to have an asynchronous multiprocess server.
|
||||
|
||||
Check more details in the <a href="/deployment/" target="_blank">Deployment</a> section.
|
||||
|
||||
## Benchmarks and speed
|
||||
|
||||
To understand, compare, and see the difference between Uvicorn, Starlette and FastAPI, check the section about [Benchmarks](/benchmarks/).
|
||||
32
docs/benchmarks.md
Normal file
@@ -0,0 +1,32 @@
|
||||
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=a979de55-980d-4721-a46f-77298b3f3923&hw=ph&test=fortune&l=zijzen-7" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
|
||||
|
||||
But when checking benchmarks and comparisons you should have the following in mind.
|
||||
|
||||
## Benchmarks and speed
|
||||
|
||||
When you check the benchmarks, it is common to see several tools of different types compared as equivalent.
|
||||
|
||||
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 hierarchy is like:
|
||||
|
||||
* **Uvicorn**: an ASGI server
|
||||
* **Starlette**: (uses Uvicorn) a web microframework
|
||||
* **FastAPI**: (uses Starlette) an API microframework with several additional features for building APIs, with data validation, etc.
|
||||
|
||||
* **Uvicorn**:
|
||||
* Will have the best performance, as it doesn't have much extra code apart from the server itself.
|
||||
* You wouldn't write an application in Uvicorn directly. That would mean that your code would have to include more or less, at least, all the code provided by Starlette (or **FastAPI**). And if you did that, your final application would have the same overhead as having used a framework and minimizing your app code and bugs.
|
||||
* If you are comparing Uvicorn, compare it against Daphne, Hypercorn, uWSGI, etc. Application servers.
|
||||
* **Starlette**:
|
||||
* Will have the next best performance, after Uvicorn. In fact, Starlette uses Uvicorn to run. So, it probably can only get "slower" than Uvicorn by having to execute more code.
|
||||
* But it provides you the tools to build simple web applications, with routing based on paths, etc.
|
||||
* If you are comparing Starlette, compare it against Sanic, Flask, Django, etc. Web frameworks (or microframeworks).
|
||||
* **FastAPI**:
|
||||
* The same way that Starlette uses Uvicorn and cannot be faster than it, **FastAPI** uses Starlette, so it cannot be faster than it.
|
||||
* FastAPI provides more features on top of Starlette. Features that you almost always need when building APIs, like data validation and serialization. And by using it, you get automatic documentation for free (the automatic documentation doesn't even add overhead to running applications, it is generated on startup).
|
||||
* If you didn't use FastAPI and used Starlette directly (or another tool, like Sanic, Flask, Responder, etc) you would have to implement all the data validation and serialization yourself. So, your final application would still have the same overhead as if it was built using FastAPI. And in many cases, this data validation and serialization is the biggest amount of code written in applications.
|
||||
* So, by using FastAPI you are saving development time, bugs, lines of code, and you would probably get the same performance (or better) you would if you didn't use it (as you would have to implement it all in your code).
|
||||
* If you are comparing FastAPI, compare it against a web application framework (or set of tools) that provides data validation, serialization and documentation, like Flask-apispec, NestJS, Molten, etc. Frameworks with integrated automatic data validation, serialization and documentation.
|
||||
@@ -1 +1,219 @@
|
||||
Coming soon...
|
||||
It is recommended to use <a href="https://www.docker.com/" target="_blank">**Docker**</a> for security, replicability, development simplicity, etc.
|
||||
|
||||
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 also easily use **FastAPI** in a standard server directly too (without Docker).
|
||||
|
||||
|
||||
## Docker
|
||||
|
||||
If you are using Docker, you can use the official Docker image:
|
||||
|
||||
### <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" 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" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
|
||||
|
||||
|
||||
### Build your Image
|
||||
|
||||
* Go to your project directory.
|
||||
* Create a `Dockerfile` with:
|
||||
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||
|
||||
COPY ./app /app
|
||||
```
|
||||
|
||||
* 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
|
||||
```
|
||||
|
||||
* Go to the project directory (in where your `Dockerfile` is, containing your `app` directory).
|
||||
* Build your FastAPI image:
|
||||
|
||||
```bash
|
||||
docker build -t myimage .
|
||||
```
|
||||
|
||||
* Run a container based on your image:
|
||||
|
||||
```bash
|
||||
docker run -d --name mycontainer -p 80:80 myimage
|
||||
```
|
||||
|
||||
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" target="_blank">http://192.168.99.100/items/5?q=somequery</a> or <a href="http://127.0.0.1/items/5?q=somequery" 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" target="_blank">http://192.168.99.100/docs</a> or <a href="http://127.0.0.1/docs" 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" target="_blank">Swagger UI</a>):
|
||||
|
||||

|
||||
|
||||
|
||||
### Alternative API docs
|
||||
|
||||
And you can also go to <a href="http://192.168.99.100/redoc" target="_blank">http://192.168.99.100/redoc</a> or <a href="http://127.0.0.1/redoc" 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" 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/" 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 "certificate" 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 is your server and how small each application you have there might be. But...
|
||||
* 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" 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 server multiple HTTPS domains/applications.
|
||||
* For this to work, a single component (program) running in the server, listening in the public IP address, must have all the HTTPS certificates in the server.
|
||||
* After having a secure connection, the communication protocol is the same HTTP.
|
||||
* It goes encrypted, but the encrypted contents are the same HTTP protocol.
|
||||
|
||||
|
||||
It is a common practice to have one program/HTTP server runing in 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 ofter called a <a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" target="_blank">TLS Termination Proxy</a>.
|
||||
|
||||
|
||||
### Let's Encrypt
|
||||
|
||||
Up to some years ago, 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/" 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 increased, by reducing their lifespan.
|
||||
|
||||
The domain's are securely verified and the certificates are generated automatically. This also allows automatizing the renewal of these certificates.
|
||||
|
||||
The idea is to automatize the acquisition and renewal of these certificates, so that you can have secure HTTPS, free, forever.
|
||||
|
||||
|
||||
### Traefik
|
||||
|
||||
<a href="https://traefik.io/" 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, all 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" 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 <a href="/project-generation/" target="_blank">FastAPI project generator</a>.
|
||||
|
||||
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 other 2 min.
|
||||
|
||||
|
||||
## Alternatively, deploy **FastAPI** without Docker
|
||||
|
||||
You can deploy **FastAPI** directly without Docker too.
|
||||
|
||||
You just need to install <a href="https://www.uvicorn.org/" target="_blank">Uvicorn</a> (or any other ASGI server).
|
||||
|
||||
And run your application the same way you have done in the tutorials, but without the `--debug` option, e.g.:
|
||||
|
||||
```bash
|
||||
uvicorn main:app --host 0.0.0.0 --port 80
|
||||
```
|
||||
|
||||
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/" target="_blank">Gunicorn</a> and <a href="https://www.uvicorn.org/#running-with-gunicorn" target="_blank">use it as a manager for Uvicorn</a>.
|
||||
|
||||
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.
|
||||
|
||||
@@ -27,7 +27,7 @@ Interactive API documentation and exploration web user interfaces. As the framew
|
||||
|
||||
It's all based on standard **Python 3.6 type** declarations (thanks to Pydantic). No new syntax to learn. Just standard modern Python.
|
||||
|
||||
If you need a 2 minute refresher of how to use Python types (even if you don't use FastAPI), check the tutorial section: [Python types](tutorial/python-types.md).
|
||||
If you need a 2 minute refresher of how to use Python types (even if you don't use FastAPI), check the tutorial section: [Python types](python-types.md).
|
||||
|
||||
You write standard Python with types:
|
||||
|
||||
@@ -61,15 +61,14 @@ second_user_data = {
|
||||
"joined": "2018-11-30",
|
||||
}
|
||||
|
||||
|
||||
# **second_user_data means:
|
||||
# pass the keys and values of the dict
|
||||
# directly as key-value arguments
|
||||
# equivalent to:
|
||||
# id=4, name="Mary", joined="2018-11-30"
|
||||
my_second_user: User = User(**second_user_data)
|
||||
```
|
||||
|
||||
!!! info
|
||||
`**second_user_data` means:
|
||||
|
||||
Pass the keys and values of the `second_user_data` dict directly as key-value arguments, equivalent to: `User(id=4, name="Mary", joined="2018-11-30")`
|
||||
|
||||
### Editor support
|
||||
|
||||
All the framework was designed to be easy and intuitive to use, all the decisons where tested on multiple editors even before starting development, to ensure the best development experience.
|
||||
@@ -154,7 +153,7 @@ Any integration is designed to be so simple to use (with dependencies) that you
|
||||
|
||||
### Tested
|
||||
|
||||
* 100% <abbr title="The amount of code that is automatically tested">test coverage</abbr> (* not yet, in a couple days).
|
||||
* 100% <abbr title="The amount of code that is automatically tested">test coverage</abbr>.
|
||||
* 100% <abbr title="Python type annotations, with this your editor and external tools can give you better support">type annotated</abbr> code base.
|
||||
* Used in production applications.
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 50 KiB |
BIN
docs/img/python-types/image01.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/img/python-types/image02.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
docs/img/python-types/image03.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
docs/img/python-types/image04.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/img/python-types/image05.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
docs/img/python-types/image06.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
docs/img/tutorial/bigger-applications/image01.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
docs/img/tutorial/body-schema/image01.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 65 KiB |
BIN
docs/img/tutorial/response-status-code/image01.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
docs/img/tutorial/response-status-code/image02.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
docs/img/tutorial/security/image01.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
docs/img/tutorial/security/image02.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
docs/img/tutorial/security/image03.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
docs/img/tutorial/security/image04.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
docs/img/tutorial/security/image05.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
docs/img/tutorial/security/image06.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
docs/img/tutorial/security/image07.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
docs/img/tutorial/security/image08.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
docs/img/tutorial/security/image09.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
docs/img/tutorial/security/image10.png
Normal file
|
After Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 61 KiB |
135
docs/index.md
@@ -5,30 +5,30 @@
|
||||
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/tiangolo/fastapi">
|
||||
<a href="https://travis-ci.org/tiangolo/fastapi" target="_blank">
|
||||
<img src="https://travis-ci.org/tiangolo/fastapi.svg?branch=master" alt="Build Status">
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/tiangolo/fastapi">
|
||||
<a href="https://codecov.io/gh/tiangolo/fastapi" target="_blank">
|
||||
<img src="https://codecov.io/gh/tiangolo/fastapi/branch/master/graph/badge.svg" alt="Coverage">
|
||||
</a>
|
||||
<a href="https://pypi.org/project/fastapi">
|
||||
<a href="https://pypi.org/project/fastapi" target="_blank">
|
||||
<img src="https://badge.fury.io/py/fastapi.svg" alt="Package version">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
**Documentation**: [https://fastapi.tiangolo.com](https://fastapi.tiangolo.com)
|
||||
**Documentation**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
|
||||
|
||||
**Source Code**: [https://github.com/tiangolo/fastapi](https://github.com/tiangolo/fastapi)
|
||||
**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+.
|
||||
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).
|
||||
* **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% *.
|
||||
* **Less bugs**: Reduce about 40% of human (developer) induced errors. *
|
||||
@@ -36,7 +36,7 @@ The key features are:
|
||||
* **Easy**: Designed to be easy to use and learn. Less time reading docs.
|
||||
* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Less 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" target="_blank">OpenAPI</a> and <a href="http://json-schema.org/" 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" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="http://json-schema.org/" target="_blank">JSON Schema</a>.
|
||||
|
||||
<small>* estimation based on tests on an internal development team, building production applications.</small>
|
||||
|
||||
@@ -65,6 +65,8 @@ $ pip install uvicorn
|
||||
|
||||
## Example
|
||||
|
||||
### Create it
|
||||
|
||||
* Create a file `main.py` with:
|
||||
|
||||
```Python
|
||||
@@ -72,50 +74,79 @@ from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get('/')
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {'hello': 'world'}
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
<details markdown="1">
|
||||
<summary>Or use <code>async def</code>...</summary>
|
||||
|
||||
Or if your code uses `async` / `await`, use `async def`:
|
||||
If your code uses `async` / `await`, use `async def`:
|
||||
|
||||
```Python hl_lines="6"
|
||||
```Python hl_lines="7 12"
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get('/')
|
||||
|
||||
@app.get("/")
|
||||
async def read_root():
|
||||
return {'hello': 'world'}
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
!!! note
|
||||
If you don't know, check the section about [`async` and `await` in the docs](async.md).
|
||||
**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 the server with:
|
||||
### Run it
|
||||
|
||||
Run the server with:
|
||||
|
||||
```bash
|
||||
uvicorn main:app --debug
|
||||
```
|
||||
|
||||
!!! note
|
||||
The command `uvicorn main:app` refers to:
|
||||
<details markdown="1">
|
||||
<summary>About the command <code>uvicorn main:app --debug</code>...</summary>
|
||||
|
||||
* `main`: the file `main.py` (the Python "module").
|
||||
* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
|
||||
* `--debug`: make the server restart after code changes. Only do this for development.
|
||||
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()`.
|
||||
* `--debug`: 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" target="_blank">http://127.0.0.1:8000</a>.
|
||||
Open your browser at <a href="http://127.0.0.1:8000/items/5?q=somequery" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
|
||||
|
||||
You will see the JSON response as:
|
||||
|
||||
```JSON
|
||||
{"hello": "world"}
|
||||
{"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" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
@@ -135,14 +166,12 @@ You will see the alternative automatic documentation (provided by <a href="https
|
||||
|
||||
## Example upgrade
|
||||
|
||||
Now modify the file `main.py` to include:
|
||||
Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||
|
||||
* a path parameter `item_id`.
|
||||
* a body, declared using standard Python types (thanks to Pydantic).
|
||||
* an optional query parameter `q`.
|
||||
Declare the body using standard Python types, thanks to Pydantic.
|
||||
|
||||
|
||||
```Python hl_lines="2 7 8 9 10 19"
|
||||
```Python hl_lines="2 7 8 9 10 24"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -155,14 +184,19 @@ class Item(BaseModel):
|
||||
is_offer: bool = None
|
||||
|
||||
|
||||
@app.get('/')
|
||||
async def read_root():
|
||||
return {'hello': 'world'}
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
|
||||
|
||||
@app.post('/items/{item_id}')
|
||||
async def create_item(item_id: int, item: Item, q: str = None):
|
||||
return {"item_name": item.name, "item_id": item_id, "query": q}
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
def create_item(item_id: int, item: Item):
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
The server should reload automatically (because you added `--debug` to the `uvicorn` command above).
|
||||
@@ -171,7 +205,7 @@ The server should reload automatically (because you added `--debug` to the `uvic
|
||||
|
||||
Now go to <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
* The interactive API documentation will be automatically updated, including the new query, and body:
|
||||
* The interactive API documentation will be automatically updated, including the new body:
|
||||
|
||||

|
||||
|
||||
@@ -223,7 +257,7 @@ item: Item
|
||||
* 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:
|
||||
* <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.
|
||||
@@ -245,20 +279,20 @@ item: Item
|
||||
|
||||
Coming back to the previous code example, **FastAPI** will:
|
||||
|
||||
* Validate that there is an `item_id` in the path.
|
||||
* Validate that the `item_id` is of type `int`.
|
||||
* 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`).
|
||||
* 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).
|
||||
* Read the body as JSON:
|
||||
* 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 is 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 as an OpenAPI schema, that can be used by:
|
||||
* Interactive documentation sytems.
|
||||
* 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.
|
||||
|
||||
@@ -270,7 +304,7 @@ 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, "query": q}
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
...from:
|
||||
@@ -290,12 +324,12 @@ Try changing the line with:
|
||||

|
||||
|
||||
|
||||
For a more complete example including more features, [see the tutorial - user guide](tutorial/intro/).
|
||||
For a more complete example including more features, see the <a href="https://fastapi.tiangolo.com/tutorial/intro/">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 constrains** as `maximum_length` or `regex`.
|
||||
* 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).
|
||||
@@ -308,6 +342,11 @@ For a more complete example including more features, [see the tutorial - user gu
|
||||
* ...and more.
|
||||
|
||||
|
||||
## Performance
|
||||
|
||||
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=a979de55-980d-4721-a46f-77298b3f3923&hw=ph&test=fortune&l=zijzen-7" 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/" target="_blank">Benchmarks</a>.
|
||||
|
||||
## Optional Dependencies
|
||||
|
||||
@@ -332,7 +371,7 @@ 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.
|
||||
|
||||
You can install all of these with `pip3 install fastapi[full]`.
|
||||
You can install all of these with `pip3 install fastapi[all]`.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
42
docs/project-generation.md
Normal file
@@ -0,0 +1,42 @@
|
||||
There is a project generator that you can use to get started, with a lot of the initial set up, security, database and first API endpoints already done for you.
|
||||
|
||||
## Full-Stack-FastAPI-Couchbase
|
||||
|
||||
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
|
||||
|
||||
### Features
|
||||
|
||||
* Full **Docker** integration (Docker based).
|
||||
* Docker Swarm Mode deployment.
|
||||
* **Docker Compose** integration and optimization for local development.
|
||||
* **Production ready** Python web server using Uvicorn and Gunicorn.
|
||||
* Python **FastAPI** backend with all its features.
|
||||
* **Celery** worker that can import and use code from the rest of the backend selectively (you don't have to install the complete app in each worker).
|
||||
* **NoSQL Couchbase** database that supports direct synchronization via Couchbase Sync Gateway for offline-first applications.
|
||||
* **Full Text Search** integrated, using Couchbase.
|
||||
* REST backend tests based on Pytest, integrated with Docker, so you can test the full API interaction, independent on the database. As it runs in Docker, it can build a new data store from scratch each time (so you can use ElasticSearch, MongoDB, or whatever you want, and just test that the API works).
|
||||
* Easy Python integration with **Jupyter** Kernels for remote or in-Docker development with extensions like Atom Hydrogen or Visual Studio Code Jupyter.
|
||||
* **Email notifications** for account creation and password recovery, compatible with:
|
||||
* Mailgun
|
||||
* SparkPost
|
||||
* SendGrid
|
||||
* ...any other provider that can generate standard SMTP credentials.
|
||||
* **Vue** frontend:
|
||||
* Generated with Vue CLI.
|
||||
* **JWT Authentication** handling.
|
||||
* Login view.
|
||||
* After login, main dashboard view.
|
||||
* Main dashboard with user creation and edition.
|
||||
* Self user edition.
|
||||
* **Vuex**.
|
||||
* **Vue-router**.
|
||||
* **Vuetify** for beautiful material design components.
|
||||
* **TypeScript**.
|
||||
* Docker server based on **Nginx** (configured to play nicely with Vue-router).
|
||||
* Docker multi-stage building, so you don't need to save or commit compiled code.
|
||||
* Frontend tests ran at build time (can be disabled too).
|
||||
* Made as modular as possible, so it works out of the box, but you can re-generate with Vue CLI or create it as you need, and re-use what you want.
|
||||
* Flower for Celery jobs monitoring.
|
||||
* Load balancing between frontend and backend with **Traefik**, so you can have both under the same domain, separated by path, but served by different containers.
|
||||
* Traefik integration, including Let's Encrypt **HTTPS** certificates automatic generation.
|
||||
* GitLab **CI** (continuous integration), including frontend and backend testing.
|
||||
288
docs/python-types.md
Normal file
@@ -0,0 +1,288 @@
|
||||
**Python 3.6+** has support for optional "type hints".
|
||||
|
||||
These **"type hints"** are a new syntax (since Python 3.6+) that allow declaring the <abbr title="for example: str, int, float, bool">type</abbr> of a variable.
|
||||
|
||||
By declaring types for your variables, editors and tools can give you better support.
|
||||
|
||||
This is just a **quick tutorial / refresher** about Python type hints. It covers only the minimum necessary to use them with **FastAPI**... which is actually very little.
|
||||
|
||||
**FastAPI** is all based on these type hints, they give it many advantages and benefits.
|
||||
|
||||
But even if you never use **FastAPI**, you would benefit from learning a bit about them.
|
||||
|
||||
!!! note
|
||||
If you are a Python expert, and you already know everything about type hints, skip to the next chapter.
|
||||
|
||||
## Motivation
|
||||
|
||||
Let's start with a simple example:
|
||||
|
||||
```Python
|
||||
{!./src/python_types/tutorial001.py!}
|
||||
```
|
||||
|
||||
Calling this program outputs:
|
||||
|
||||
```
|
||||
John Doe
|
||||
```
|
||||
|
||||
The function does the following:
|
||||
|
||||
* Takes a `fist_name` and `last_name`.
|
||||
* Converts the first letter of each one to upper case with `title()`.
|
||||
* <abbr title="Puts them together, as one. With the contents of one after the other.">Concatenates</abbr> them with a space in the middle.
|
||||
|
||||
```Python hl_lines="2"
|
||||
{!./src/python_types/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Edit it
|
||||
|
||||
It's a very simple program.
|
||||
|
||||
But now imagine that you were writing it from scratch.
|
||||
|
||||
At some point you would have started the definition of the function, you had the parameters ready...
|
||||
|
||||
But then you have to call "that method that converts the first letter to upper case".
|
||||
|
||||
Was it `upper`? Was it `uppercase`? `first_uppercase`? `capitalize`?
|
||||
|
||||
Then, you try with the old programer's friend, editor autocompletion.
|
||||
|
||||
You type the first parameter of the function, `first_name`, then a dot (`.`) and then hit `Ctrl+Space` to trigger the completion.
|
||||
|
||||
But, sadly, you get nothing useful:
|
||||
|
||||
<img src="/img/python-types/image01.png">
|
||||
|
||||
### Add types
|
||||
|
||||
Let's modify a single line from the previous version.
|
||||
|
||||
We will change exactly this fragment, the parameters of the function, from:
|
||||
|
||||
```Python
|
||||
first_name, last_name
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```Python
|
||||
first_name: str, last_name: str
|
||||
```
|
||||
|
||||
That's it.
|
||||
|
||||
Those are the "type hints":
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./src/python_types/tutorial002.py!}
|
||||
```
|
||||
|
||||
That is not the same as declaring default values like would be with:
|
||||
|
||||
```Python
|
||||
first_name="john", last_name="doe"
|
||||
```
|
||||
|
||||
It's a different thing.
|
||||
|
||||
We are using colons (`:`), not equals (`=`).
|
||||
|
||||
And adding type hints normally doesn't change what happens from what would happen without them.
|
||||
|
||||
But now, imagine you are again in the middle of creating that function, but with type hints.
|
||||
|
||||
At the same point, you try to trigger the autocomplete with `Ctrl+Space` and you see:
|
||||
|
||||
<img src="/img/python-types/image02.png">
|
||||
|
||||
With that, you can scroll, seeing the options, until you find the one that "rings a bell":
|
||||
|
||||
<img src="/img/python-types/image03.png">
|
||||
|
||||
## More motivation
|
||||
|
||||
Check this function, it already has type hints:
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./src/python_types/tutorial003.py!}
|
||||
```
|
||||
|
||||
Because the editor knows the types of the variables, you don't only get completion, you also get error checks:
|
||||
|
||||
<img src="/img/python-types/image04.png">
|
||||
|
||||
Now you know that you have to fix it, convert `age` to a string with `str(age)`:
|
||||
|
||||
```Python hl_lines="2"
|
||||
{!./src/python_types/tutorial004.py!}
|
||||
```
|
||||
|
||||
|
||||
## Declaring types
|
||||
|
||||
You just saw the main place to declare type hints. As function parameters.
|
||||
|
||||
This is also the main place you would use them with **FastAPI**.
|
||||
|
||||
### Simple types
|
||||
|
||||
You can declare all the standard Python types, not only `str`.
|
||||
|
||||
You can use, for example:
|
||||
|
||||
* `int`
|
||||
* `float`
|
||||
* `bool`
|
||||
* `bytes`
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./src/python_types/tutorial005.py!}
|
||||
```
|
||||
|
||||
### Types with subtypes
|
||||
|
||||
There are some data structures that can contain other values, like `dict`, `list`, `set` and `tuple`. And the internal values can have their own type too.
|
||||
|
||||
To declare those types and the subtypes, you can use the standard Python module `typing`.
|
||||
|
||||
It exists specifically to support these type hints.
|
||||
|
||||
#### Lists
|
||||
|
||||
For example, let's define a variable to be a `list` of `str`.
|
||||
|
||||
From `typing`, import `List` (with a capital `L`):
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!./src/python_types/tutorial006.py!}
|
||||
```
|
||||
|
||||
Declare the variable, with the same colon (`:`) syntax.
|
||||
|
||||
As the type, put the `List`.
|
||||
|
||||
As the list is a type that takes a "subtype", you put the subtype in square brackets:
|
||||
|
||||
```Python hl_lines="4"
|
||||
{!./src/python_types/tutorial006.py!}
|
||||
```
|
||||
|
||||
That means: "the variable `items` is a `list`, and each of the items in this list is a `str`".
|
||||
|
||||
By doing that, your editor can provide support even while processing items from the list.
|
||||
|
||||
Without types, that's almost impossible to achieve:
|
||||
|
||||
<img src="/img/python-types/image05.png">
|
||||
|
||||
Notice that the variable `item` is one of the elements in the list `items`.
|
||||
|
||||
And still, the editor knows it is a `str`, and provides support for that.
|
||||
|
||||
#### Tuples and Sets
|
||||
|
||||
You would do the same to declare `tuple`s and `set`s:
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!./src/python_types/tutorial007.py!}
|
||||
```
|
||||
|
||||
This means:
|
||||
|
||||
* The variable `items_t` is a `tuple`, and each of its items is an `int`.
|
||||
* The variable `items_s` is a `set`, and each of its items is of type `bytes`.
|
||||
|
||||
#### Dicts
|
||||
|
||||
To define a `dict`, you pass 2 subtypes, separated by commas.
|
||||
|
||||
The first subtype is for the keys of the `dict`.
|
||||
|
||||
The second subtype is for the values of the `dict`:
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!./src/python_types/tutorial008.py!}
|
||||
```
|
||||
|
||||
This means:
|
||||
|
||||
* The variable `prices` is a `dict`:
|
||||
* The keys of this `dict` are of type `str` (let's say, the name of each item).
|
||||
* The values of this `dict` are of type `float` (let's say, the price of each item).
|
||||
|
||||
|
||||
### Classes as types
|
||||
|
||||
You can also declare a class as the type of a variable.
|
||||
|
||||
Let's say you have a class `Person`, with a name:
|
||||
|
||||
```Python hl_lines="1 2 3"
|
||||
{!./src/python_types/tutorial009.py!}
|
||||
```
|
||||
|
||||
Then you can declare a variable to be of type `Person`:
|
||||
|
||||
```Python hl_lines="6"
|
||||
{!./src/python_types/tutorial009.py!}
|
||||
```
|
||||
|
||||
And then, again, you get all the editor support:
|
||||
|
||||
<img src="/img/python-types/image06.png">
|
||||
|
||||
|
||||
## Pydantic models
|
||||
|
||||
<a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic</a> is a Python library to perform data validation.
|
||||
|
||||
You declare the "shape" of the data as classes with attributes.
|
||||
|
||||
And each attribute has a type.
|
||||
|
||||
Then you create an instance of that class with some values and it will validate the values, convert them to the appropriate type (if that's the case) and give you an object with all the data.
|
||||
|
||||
And you get all the editor support with that resulting object.
|
||||
|
||||
Taken from the official Pydantic docs:
|
||||
|
||||
```Python
|
||||
{!./src/python_types/tutorial010.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
To learn more about <a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic, check its docs</a>.
|
||||
|
||||
**FastAPI** is all based on Pydantic.
|
||||
|
||||
You will see a lot more of all this in practice in the <a href="/tutorial/intro/" target="_blank">Tutorial - User Guide</a> (the next section).
|
||||
|
||||
|
||||
## Type hints in **FastAPI**
|
||||
|
||||
**FastAPI** takes advantage of these type hints to do several things.
|
||||
|
||||
With **FastAPI** you declare parameters with type hints and you get:
|
||||
|
||||
* **Editor support**.
|
||||
* **Type checks**.
|
||||
|
||||
...and **FastAPI** uses the same declarations to:
|
||||
|
||||
* **Define requirements**: from request path parameters, query parameters, headers, bodies, dependencies, etc.
|
||||
* **Convert data**: from the request to the required type.
|
||||
* **Validate data**: coming from each request:
|
||||
* Generating **automatic errors** returned to the client when the data is invalid.
|
||||
* **Document** the API using OpenAPI:
|
||||
* which is then used by the automatic interactive documentation user interfaces.
|
||||
|
||||
This might all sound abstract. Don't worry. You'll see all this in action in the <a href="/tutorial/intro/" target="_blank">Tutorial - User Guide</a> (the next section).
|
||||
|
||||
The important thing is that by using standard Python types, in a single place (instead of adding more classes, decorators, etc), **FastAPI** will do a lot of the work for you.
|
||||
|
||||
!!! info
|
||||
If you already went through all the tutorial and came back to see more about types, a good resource is <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" target="_blank">the "cheat sheet" from `mypy`</a>.
|
||||
9
docs/release-notes.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## 0.2.0
|
||||
|
||||
* Fix typos in Security section: <a href="https://github.com/tiangolo/fastapi/pull/24" target="_blank">#24</a> by <a href="https://github.com/kkinder" target="_blank">@kkinder</a>
|
||||
|
||||
* Add support for Pydantic custom JSON encoders: <a href="https://github.com/tiangolo/fastapi/pull/21" target="_blank">#21</a> by <a href="https://github.com/euri10" target="_blank">@euri10</a>
|
||||
|
||||
## 0.1.19
|
||||
|
||||
* Upgrade Starlette version to the current latest `0.10.1`: <a href="https://github.com/tiangolo/fastapi/pull/17" target="_blank">#17</a> by <a href="https://github.com/euri10" target="_blank">@euri10</a>
|
||||
0
docs/src/bigger_applications/app/__init__.py
Normal file
@@ -1,7 +1,7 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
from .tutorial01 import router as users_router
|
||||
from .tutorial02 import router as items_router
|
||||
from .routers.items import router as items_router
|
||||
from .routers.users import router as users_router
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -3,11 +3,11 @@ from fastapi import APIRouter
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/")
|
||||
@router.get("/", tags=["items"])
|
||||
async def read_items():
|
||||
return [{"name": "Item Foo"}, {"name": "item Bar"}]
|
||||
|
||||
|
||||
@router.get("/{item_id}")
|
||||
@router.get("/{item_id}", tags=["items"])
|
||||
async def read_item(item_id: str):
|
||||
return {"name": "Fake Specific Item", "item_id": item_id}
|
||||
@@ -3,16 +3,16 @@ from fastapi import APIRouter
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/users/")
|
||||
@router.get("/users/", tags=["users"])
|
||||
async def read_users():
|
||||
return [{"username": "Foo"}, {"username": "Bar"}]
|
||||
|
||||
|
||||
@router.get("/users/{username}")
|
||||
async def read_user(username: str):
|
||||
return {"username": username}
|
||||
|
||||
|
||||
@router.get("/users/me")
|
||||
@router.get("/users/me", tags=["users"])
|
||||
async def read_user_me():
|
||||
return {"username": "fakecurrentuser"}
|
||||
|
||||
|
||||
@router.get("/users/{username}", tags=["users"])
|
||||
async def read_user(username: str):
|
||||
return {"username": username}
|
||||
@@ -15,7 +15,7 @@ class Item(BaseModel):
|
||||
async def update_item(
|
||||
*,
|
||||
item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000),
|
||||
q: str,
|
||||
q: str = None,
|
||||
item: Item = None,
|
||||
):
|
||||
results = {"item_id": item_id}
|
||||
@@ -10,3 +10,8 @@ async def common_parameters(q: str = None, skip: int = 0, limit: int = 100):
|
||||
@app.get("/items/")
|
||||
async def read_items(commons: dict = Depends(common_parameters)):
|
||||
return commons
|
||||
|
||||
|
||||
@app.get("/users/")
|
||||
async def read_users(commons: dict = Depends(common_parameters)):
|
||||
return commons
|
||||
23
docs/src/dependencies/tutorial002.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
|
||||
|
||||
|
||||
class CommonQueryParams:
|
||||
def __init__(self, q: str = None, skip: int = 0, limit: int = 100):
|
||||
self.q = q
|
||||
self.skip = skip
|
||||
self.limit = limit
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
|
||||
response = {}
|
||||
if commons.q:
|
||||
response.update({"q": commons.q})
|
||||
items = fake_items_db[commons.skip : commons.skip + commons.limit]
|
||||
response.update({"items": items})
|
||||
return response
|
||||
23
docs/src/dependencies/tutorial003.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
|
||||
|
||||
|
||||
class CommonQueryParams:
|
||||
def __init__(self, q: str = None, skip: int = 0, limit: int = 100):
|
||||
self.q = q
|
||||
self.skip = skip
|
||||
self.limit = limit
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(commons=Depends(CommonQueryParams)):
|
||||
response = {}
|
||||
if commons.q:
|
||||
response.update({"q": commons.q})
|
||||
items = fake_items_db[commons.skip : commons.skip + commons.limit]
|
||||
response.update({"items": items})
|
||||
return response
|
||||
23
docs/src/dependencies/tutorial004.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
|
||||
|
||||
|
||||
class CommonQueryParams:
|
||||
def __init__(self, q: str = None, skip: int = 0, limit: int = 100):
|
||||
self.q = q
|
||||
self.skip = skip
|
||||
self.limit = limit
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(commons: CommonQueryParams = Depends()):
|
||||
response = {}
|
||||
if commons.q:
|
||||
response.update({"q": commons.q})
|
||||
items = fake_items_db[commons.skip : commons.skip + commons.limit]
|
||||
response.update({"items": items})
|
||||
return response
|
||||
20
docs/src/dependencies/tutorial005.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from fastapi import Cookie, Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
def query_extractor(q: str = None):
|
||||
return q
|
||||
|
||||
|
||||
def query_or_cookie_extractor(
|
||||
q: str = Depends(query_extractor), last_query: str = Cookie(None)
|
||||
):
|
||||
if not q:
|
||||
return last_query
|
||||
return q
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
|
||||
return {"q_or_cookie": query_or_default}
|
||||
21
docs/src/dependencies/tutorial006.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class FixedContentQueryChecker:
|
||||
def __init__(self, fixed_content: str):
|
||||
self.fixed_content = fixed_content
|
||||
|
||||
def __call__(self, q: str = ""):
|
||||
if q:
|
||||
return self.fixed_content in q
|
||||
return False
|
||||
|
||||
|
||||
checker = FixedContentQueryChecker("bar")
|
||||
|
||||
|
||||
@app.get("/query-checker/")
|
||||
async def read_query_check(fixed_content_included: bool = Depends(checker)):
|
||||
return {"fixed_content_in_query": fixed_content_included}
|
||||
27
docs/src/extra_data_types/tutorial001.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from datetime import datetime, time, timedelta
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import Body, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def read_items(
|
||||
item_id: UUID,
|
||||
start_datetime: datetime = Body(None),
|
||||
end_datetime: datetime = Body(None),
|
||||
repeat_at: time = Body(None),
|
||||
process_after: timedelta = Body(None),
|
||||
):
|
||||
start_process = start_datetime + process_after
|
||||
duration = end_datetime - start_process
|
||||
return {
|
||||
"item_id": item_id,
|
||||
"start_datetime": start_datetime,
|
||||
"end_datetime": end_datetime,
|
||||
"repeat_at": repeat_at,
|
||||
"process_after": process_after,
|
||||
"start_process": start_process,
|
||||
"duration": duration,
|
||||
}
|
||||
@@ -11,10 +11,14 @@ USERPROFILE_DOC_TYPE = "userprofile"
|
||||
|
||||
|
||||
def get_bucket():
|
||||
cluster = Cluster("couchbase://couchbasehost:8091")
|
||||
cluster = Cluster(
|
||||
"couchbase://couchbasehost:8091?fetch_mutation_tokens=1&operation_timeout=30&n1ql_timeout=300"
|
||||
)
|
||||
authenticator = PasswordAuthenticator("username", "password")
|
||||
cluster.authenticate(authenticator)
|
||||
bucket: Bucket = cluster.open_bucket("bucket_name", lockmode=LOCKMODE_WAIT)
|
||||
bucket.timeout = 30
|
||||
bucket.n1ql_timeout = 300
|
||||
return bucket
|
||||
|
||||
|
||||
@@ -29,9 +33,6 @@ class UserInDB(User):
|
||||
type: str = USERPROFILE_DOC_TYPE
|
||||
hashed_password: str
|
||||
|
||||
class Meta:
|
||||
key: Optional[str] = None
|
||||
|
||||
|
||||
def get_user(bucket: Bucket, username: str):
|
||||
doc_id = f"userprofile::{username}"
|
||||
@@ -39,7 +40,6 @@ def get_user(bucket: Bucket, username: str):
|
||||
if not result.value:
|
||||
return None
|
||||
user = UserInDB(**result.value)
|
||||
user.Meta.key = result.key
|
||||
return user
|
||||
|
||||
|
||||