Compare commits

...

66 Commits

Author SHA1 Message Date
Sebastián Ramírez
098e629344 🔖 Bump version, after changes in OAuth2 utils 2018-12-24 20:21:28 +04:00
Sebastián Ramírez
bbe5f28b77 📝 Add docs for OAuth2 security 2018-12-24 20:20:48 +04:00
Sebastián Ramírez
4a0922ebab ♻️ Update OAuth2 class utilities to be dependencies 2018-12-24 20:20:21 +04:00
Sebastián Ramírez
8f16868c6a Add passlib and pyjwt to development dependencies 2018-12-24 20:19:05 +04:00
Sebastián Ramírez
bc3e7f2bbc 🔖 Version bump, fixing several issues, lots of docs and tests 2018-12-24 09:35:20 +04:00
Sebastián Ramírez
58848be2de Add pending tests to temporal dir 2018-12-24 09:35:02 +04:00
Sebastián Ramírez
cfb65d0e15 🐛 Fix utility OAuth2PasswordRequestForm to use forms
and be used as a dependency
2018-12-24 09:34:28 +04:00
Sebastián Ramírez
855daa2e53 📝 Add tutorial for complete OAuth2 password flow 2018-12-24 09:33:48 +04:00
Sebastián Ramírez
de54e85152 📝 Add Security tutorial: Get current user 2018-12-24 08:03:59 +04:00
Sebastián Ramírez
b8d3070daf 📝 Add first Security tutorials 2018-12-23 23:25:57 +04:00
Sebastián Ramírez
471c9cfc2d 📝 Add example screenshot for dependencies 2018-12-23 21:29:59 +04:00
Sebastián Ramírez
b79c13baed 📝 Update and add docs for dependencies 2018-12-23 21:21:37 +04:00
Sebastián Ramírez
332ee4aee1 📝 Update and clarify first-steps tutorial 2018-12-23 18:42:29 +04:00
Sebastián Ramírez
ad40f4a457 📝 Fix double editor screenshot 2018-12-22 20:23:24 +04:00
Sebastián Ramírez
6b9931f882 Add tests for metadata 2018-12-22 18:47:05 +04:00
Sebastián Ramírez
4c51bb6714 Test extra routes, with parameters directly 2018-12-22 18:30:34 +04:00
Sebastián Ramírez
57ff677027 Add tests for validation errors in response 2018-12-22 18:20:01 +04:00
Sebastián Ramírez
613c3f3e95 Test all HTTP methods 2018-12-22 18:18:19 +04:00
Sebastián Ramírez
bf6d923ca8 Add ujson for local development 2018-12-22 17:23:51 +04:00
Sebastián Ramírez
252188c686 Update tests for HTML content and remove unneeded tests 2018-12-22 17:23:04 +04:00
Sebastián Ramírez
510fec9bee ♻️ Refactor jsonable_encoder and test it
with nested arbitrary classes
2018-12-22 17:15:04 +04:00
Sebastián Ramírez
a73709507c Add docs, tests and fixes for extra data types
including refactor of jsonable_encoder to allow other object and model types
2018-12-22 14:35:48 +04:00
Sebastián Ramírez
75407b9295 🚨 Fix mypy type errors 2018-12-22 09:05:13 +04:00
Sebastián Ramírez
3180f35bdd Fix OpenAPI test for body schema 2018-12-22 09:00:58 +04:00
Sebastián Ramírez
d498b7feb3 Add tests for response_model 2018-12-22 08:54:52 +04:00
Sebastián Ramírez
3269e6a95c Test custom responses 2018-12-22 08:47:44 +04:00
Sebastián Ramírez
f1808de18e Add tests for form and files 2018-12-22 08:39:26 +04:00
Sebastián Ramírez
748dc375db 🐛 Fix Form and File params must always be embeded
and add tests for forms and files
2018-12-22 08:24:48 +04:00
Sebastián Ramírez
b38fb937b0 🔇 Remove debugging prints 2018-12-22 08:21:02 +04:00
Sebastián Ramírez
23ef570bf6 Add test-cov-html script for local coverage
analysis and debugging
2018-12-22 07:42:24 +04:00
Sebastián Ramírez
c25a71e352 🐛 Re-implement check for body as a workaround
while encode/starlette#287 is merged
2018-12-22 07:40:56 +04:00
Sebastián Ramírez
0c5e684ff9 📝 Add Project Generation section 2018-12-21 20:27:03 +04:00
Sebastián Ramírez
b097a538ab 🔖 Bump version, after fix for email_validator and docs 2018-12-21 16:33:45 +04:00
Sebastián Ramírez
a0628f3f6f 📝 Update docs to improve look in GitHub 2018-12-21 16:32:09 +04:00
Sebastián Ramírez
16f6dc66e2 📝 Update README from docs source 2018-12-21 16:24:15 +04:00
Sebastián Ramírez
07b68365f1 📝 Update docs and index to make clear what FastAPI does 2018-12-21 16:23:28 +04:00
Sebastián Ramírez
0a65c41909 📝 Move tutorial src files to top level docs 2018-12-21 16:22:33 +04:00
Sebastián Ramírez
d5e782074f 🐛 Fix email_validator error, generated by autoflake 2018-12-21 14:51:17 +04:00
Sebastián Ramírez
b5a0c228e5 Recover extensive tests for path and params 2018-12-18 23:48:02 +04:00
Sebastián Ramírez
4b94da956c Update query param tests and docs 2018-12-18 23:38:38 +04:00
Sebastián Ramírez
b59e8ffcf6 🎨 Format tests for Cookies 2018-12-18 23:15:26 +04:00
Sebastián Ramírez
7f382127cc Add tests for body with Schema 2018-12-18 23:15:03 +04:00
Sebastián Ramírez
3513b039b9 Test cookies 2018-12-18 23:04:53 +04:00
Sebastián Ramírez
4cf15503cb 📝 Make badges be links to new tab (_blank) 2018-12-18 23:00:04 +04:00
Sebastián Ramírez
22dc7e9132 Test for missing required body 2018-12-18 22:57:09 +04:00
Sebastián Ramírez
7ee32ea197 📝 Fix broken link to docs 2018-12-18 22:56:36 +04:00
Sebastián Ramírez
e6ca71523b 📝 Update docs highlighting after re-sort imports
coming back to flit, after pipenv
2018-12-18 22:55:30 +04:00
Sebastián Ramírez
7da9625505 💚 Revert to flit install and re-format
As it has shown to be more reliable, and closer to final user environments
2018-12-18 22:36:04 +04:00
Sebastián Ramírez
ae50492735 Add tests for header parameters 2018-12-18 22:33:59 +04:00
Sebastián Ramírez
bcb967f98a 💚 Try fixing Travis, again... 2018-12-18 22:22:07 +04:00
Sebastián Ramírez
19c6a2b9bd 🐛 Install dev-packages with pipenv, not pip 2018-12-18 22:13:42 +04:00
Sebastián Ramírez
01dd913634 💚 Install dev-packages in Travis 2018-12-18 22:11:04 +04:00
Sebastián Ramírez
343ecb7669 💚 Use pipenv in Travis 2018-12-18 22:08:47 +04:00
Sebastián Ramírez
e9f2a3c291 Update tutorial renamer to exclude files 2018-12-18 21:59:51 +04:00
Sebastián Ramírez
00e2e544c7 ♻️ Re-format tutorials, files names and tests
for tutorial files
2018-12-18 21:59:06 +04:00
Sebastián Ramírez
dcb076b752 🐛 Fix optional bodies raising an error
when not provided in the request
2018-12-18 21:11:24 +04:00
Sebastián Ramírez
659b8ae8af 📝 Update docs, typos, aclarations, fix examples
for NoSQL models
2018-12-17 22:50:22 +04:00
Sebastián Ramírez
2a48b10be3 📝 Add Python type hints tutorial 2018-12-17 22:27:26 +04:00
Sebastián Ramírez
5bd167e0e7 📝 Add second tutorial src for python-types 2018-12-17 20:41:19 +04:00
Sebastián Ramírez
58b69493a9 📝 Add tutorial src for python-types 2018-12-17 20:36:53 +04:00
Sebastián Ramírez
786c392bd5 💚 Fix Netlify build with pipenv 2018-12-17 18:56:48 +04:00
Sebastián Ramírez
acc15230ea Update query tests, application type checks
and temporarily disable coverage fail, to allow publishing docs from Travis
2018-12-17 15:48:38 +04:00
Sebastián Ramírez
a84960b13d 💚 Update Netlify docs build, try 78 2018-12-15 22:16:54 +04:00
Sebastián Ramírez
61779949f4 🔥 Remove un-used requirements.txt 2018-12-15 22:11:28 +04:00
Sebastián Ramírez
10134803a9 💚 Call docs build with Python module 2018-12-15 22:10:12 +04:00
Sebastián Ramírez
5085652479 🔥 Remove dist hidden old file 2018-12-15 22:07:37 +04:00
239 changed files with 6240 additions and 927 deletions

View File

@@ -20,6 +20,8 @@ mkdocs = "*"
mkdocs-material = "*"
markdown-include = "*"
autoflake = "*"
email-validator = "*"
ujson = "*"
[packages]
starlette = "*"

101
Pipfile.lock generated
View File

@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "deb42eb176158abbd62d0af06fc60f571ae7da3012f7baafb1bcca08c363273b"
"sha256": "a0f966a95cb84845ca4aad02c44fc0e7c5e2047fc44dcf19a95a4abaa02d0197"
},
"pipfile-spec": 6,
"requires": {
@@ -34,10 +34,10 @@
},
"starlette": {
"hashes": [
"sha256:a7b24496638b9e755bc31a72b0596939f3dd0e6eb1878ff55da5647be026a9e3"
"sha256:01f04283b49a8cb0c8921baa90dbafe47e953f0a265f6ebb38176038e4bd9bf8"
],
"index": "pypi",
"version": "==0.9.8"
"version": "==0.9.9"
}
},
"develop": {
@@ -174,6 +174,13 @@
],
"version": "==0.5.0"
},
"dnspython": {
"hashes": [
"sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01",
"sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d"
],
"version": "==1.16.0"
},
"docutils": {
"hashes": [
"sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
@@ -188,6 +195,13 @@
],
"version": "==0.1.9"
},
"email-validator": {
"hashes": [
"sha256:ddc4b5b59fa699bb10127adcf7ad4de78fde4ec539a072b104b8bb16da666ae5"
],
"index": "pypi",
"version": "==1.0.3"
},
"entrypoints": {
"hashes": [
"sha256:10ad569bb245e7e2ba425285b9fa3e8178a0dc92fc53b1e1c553805e15a8825b",
@@ -250,11 +264,11 @@
},
"jedi": {
"hashes": [
"sha256:0191c447165f798e6a730285f2eee783fff81b0d3df261945ecb80983b5c3ca7",
"sha256:b7493f73a2febe0dc33d51c99b474547f7f6c0b2c8fb2b21f453eef204c12148"
"sha256:571702b5bd167911fe9036e5039ba67f820d6502832285cde8c881ab2b2149fd",
"sha256:c8481b5e59d34a5c7c42e98f6625e633f6ef59353abea6437472c7ec2093f191"
],
"index": "pypi",
"version": "==0.13.1"
"version": "==0.13.2"
},
"jinja2": {
"hashes": [
@@ -457,10 +471,10 @@
},
"notebook": {
"hashes": [
"sha256:661341909008d1e7bfa1541904006f9789fa3de1cbec8379d2879819454cc04b",
"sha256:91705b109fc785198faed892489cddb233265564d5e2dad5e4f7974af05ee8dd"
"sha256:3ab2db8bc10e6edbd264c3c4b800bee276c99818386ee0c146d98d7e6bcf0a67",
"sha256:d908673a4010787625c8952e91a22adf737db031f2aa0793ad92f6558918a74a"
],
"version": "==5.7.2"
"version": "==5.7.4"
},
"pandocfilters": {
"hashes": [
@@ -564,10 +578,10 @@
},
"pygments": {
"hashes": [
"sha256:6301ecb0997a52d2d31385e62d0a4a4cf18d2f2da7054a5ddad5c366cd39cee7",
"sha256:82666aac15622bd7bb685a4ee7f6625dd716da3ef7473620c192c0168aae64fc"
"sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a",
"sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d"
],
"version": "==2.3.0"
"version": "==2.3.1"
},
"pylint": {
"hashes": [
@@ -610,17 +624,17 @@
},
"pyrsistent": {
"hashes": [
"sha256:05910b7ff43cec0a853c15da0bfaf2867faa95f29b08e71f5846a195f1f38c75"
"sha256:59880cc33ac293515892b2969aa8f4ed2cec592cbd0be4c4e20f2410468bbc62"
],
"version": "==0.14.7"
"version": "==0.14.8"
},
"pytest": {
"hashes": [
"sha256:1d131cc532be0023ef8ae265e2a779938d0619bb6c2510f52987ffcba7fa1ee4",
"sha256:ca4761407f1acc85ffd1609f464ca20bb71a767803505bd4127d0e45c5a50e23"
"sha256:f689bf2fc18c4585403348dd56f47d87780bf217c53ed9ae7a3e2d7faa45f8e9",
"sha256:f812ea39a0153566be53d88f8de94839db1e8a05352ed8a49525d7d7f37861e9"
],
"index": "pypi",
"version": "==4.0.1"
"version": "==4.0.2"
},
"pytest-cov": {
"hashes": [
@@ -780,32 +794,37 @@
},
"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:0555eca1671ebe09eb5f2176723826f6f44cca5060502fea259de9b0e893ab53",
"sha256:0ca96128ea66163aea13911c9b4b661cb345eb729a20be15c034271360fc7474",
"sha256:16ccd06d614cf81b96de42a37679af12526ea25a208bce3da2d9226f44563868",
"sha256:1e21ae7b49a3f744958ffad1737dfbdb43e1137503ccc59f4e32c4ac33b0bd1c",
"sha256:37670c6fd857b5eb68aa5d193e14098354783b5138de482afa401cc2644f5a7f",
"sha256:46d84c8e3806619ece595aaf4f37743083f9454c9ea68a517f1daa05126daf1d",
"sha256:5b972bbb3819ece283a67358103cc6671da3646397b06e7acea558444daf54b2",
"sha256:6306ffa64922a7b58ee2e8d6f207813460ca5a90213b4a400c2e730375049246",
"sha256:6cb25dc95078931ecbd6cbcc4178d1b8ae8f2b513ae9c3bd0b7f81c2191db4c6",
"sha256:7e19d439fee23620dea6468d85bfe529b873dace39b7e5b0c82c7099681f8a22",
"sha256:7f5cd83af6b3ca9757e1127d852f497d11c7b09b4716c355acfbebf783d028da",
"sha256:81e885a713e06faeef37223a5b1167615db87f947ecc73f815b9d1bbd6b585be",
"sha256:94af325c9fe354019a29f9016277c547ad5d8a2d98a02806f27a7436b2da6735",
"sha256:b1e5445c6075f509d5764b84ce641a1535748801253b97f3b7ea9d948a22853a",
"sha256:cb061a959fec9a514d243831c514b51ccb940b58a5ce572a4e209810f2507dcf",
"sha256:cc8d0b703d573cbabe0d51c9d68ab68df42a81409e4ed6af45a04a95484b96a5",
"sha256:da0afa955865920edb146926455ec49da20965389982f91e926389666f5cf86a",
"sha256:dc76738331d61818ce0b90647aedde17bbba3d3f9e969d83c1d9087b4f978862",
"sha256:e7ec9a1445d27dbd0446568035f7106fa899a36f55e52ade28020f7b3845180d",
"sha256:f741ba03feb480061ab91a465d1a3ed2d40b52822ada5b4017770dfcb88f839f",
"sha256:fe800a58547dd424cd286b7270b967b5b3316b993d86453ede184a17b5a6b17d"
],
"markers": "python_version < '3.7' and implementation_name == 'cpython'",
"version": "==1.1.0"
"version": "==1.1.1"
},
"ujson": {
"hashes": [
"sha256:f66073e5506e91d204ab0c614a148d5aa938bdbf104751be66f8ad7a222f5f86"
],
"index": "pypi",
"version": "==1.35"
},
"urllib3": {
"hashes": [

114
README.md
View File

@@ -5,22 +5,22 @@
<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>
---
@@ -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 recive 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:
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
@@ -245,13 +279,13 @@ 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.
@@ -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,7 +324,7 @@ Try changing the line with:
![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
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:

View File

@@ -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"

View File

@@ -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.

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 73 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 77 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

@@ -5,22 +5,22 @@
<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>
---
@@ -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 recive 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:
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
@@ -245,13 +279,13 @@ 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.
@@ -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,7 +324,7 @@ Try changing the line with:
![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
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:

View 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
View 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>.

View File

View File

View File

@@ -8,11 +8,11 @@ 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")
async def read_user_me():
return {"username": "fakecurrentuser"}
@router.get("/users/{username}")
async def read_user(username: str):
return {"username": username}

View 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.tutorial001 import router as users_router
from .routers.tutorial002 import router as items_router
app = FastAPI()

View File

@@ -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}

View File

@@ -1,5 +1,4 @@
from fastapi import Depends, FastAPI
from pydantic import BaseModel
app = FastAPI()
@@ -7,18 +6,15 @@ app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams(BaseModel):
q: str = None
skip: int = None
limit: int = None
async def common_parameters(q: str = None, skip: int = 0, limit: int = 100):
return CommonQueryParams(q=q, skip=skip, limit=limit)
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(common_parameters)):
async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
response = {}
if commons.q:
response.update({"q": commons.q})

View 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.limit]
response.update({"items": items})
return response

View 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.limit]
response.update({"items": items})
return response

View 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}

View 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}

View 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,
}

View File

@@ -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

View File

@@ -0,0 +1,6 @@
def get_full_name(first_name, last_name):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))

View File

@@ -0,0 +1,6 @@
def get_full_name(first_name: str, last_name: str):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))

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