Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
1
Pipfile
@@ -20,6 +20,7 @@ mkdocs = "*"
|
||||
mkdocs-material = "*"
|
||||
markdown-include = "*"
|
||||
autoflake = "*"
|
||||
email-validator = "*"
|
||||
|
||||
[packages]
|
||||
starlette = "*"
|
||||
|
||||
90
Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "deb42eb176158abbd62d0af06fc60f571ae7da3012f7baafb1bcca08c363273b"
|
||||
"sha256": "64539bfa9f03f10715a5f83b1d62776513ae44518c0cff011b7540c17eada955"
|
||||
},
|
||||
"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": [
|
||||
@@ -616,11 +630,11 @@
|
||||
},
|
||||
"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,30 @@
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
|
||||
115
README.md
@@ -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:
|
||||
|
||||

|
||||
|
||||
@@ -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:
|
||||
@@ -287,10 +321,11 @@ Try changing the line with:
|
||||
|
||||
...and see how your editor will auto-complete the attributes and know their types:
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
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:
|
||||
|
||||
|
||||
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"
|
||||
@@ -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.
|
||||
|
||||
|
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 |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 61 KiB |
115
docs/index.md
@@ -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:
|
||||
|
||||

|
||||
|
||||
@@ -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:
|
||||
@@ -287,10 +321,11 @@ Try changing the line with:
|
||||
|
||||
...and see how your editor will auto-complete the attributes and know their types:
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
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:
|
||||
|
||||
|
||||
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>.
|
||||
0
docs/src/bigger_applications/__init__.py
Normal file
0
docs/src/bigger_applications/app/__init__.py
Normal 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}
|
||||
@@ -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()
|
||||
|
||||
@@ -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}
|
||||
@@ -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
|
||||
|
||||
|
||||
6
docs/src/python_types/tutorial001.py
Normal 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"))
|
||||
6
docs/src/python_types/tutorial002.py
Normal 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"))
|
||||
3
docs/src/python_types/tutorial003.py
Normal file
@@ -0,0 +1,3 @@
|
||||
def get_name_with_age(name: str, age: int):
|
||||
name_with_age = name + " is this old: " + age
|
||||
return name_with_age
|
||||
3
docs/src/python_types/tutorial004.py
Normal file
@@ -0,0 +1,3 @@
|
||||
def get_name_with_age(name: str, age: int):
|
||||
name_with_age = name + " is this old: " + str(age)
|
||||
return name_with_age
|
||||
2
docs/src/python_types/tutorial005.py
Normal file
@@ -0,0 +1,2 @@
|
||||
def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes):
|
||||
return item_a, item_b, item_c, item_d, item_d, item_e
|
||||
6
docs/src/python_types/tutorial006.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from typing import List
|
||||
|
||||
|
||||
def process_items(items: List[str]):
|
||||
for item in items:
|
||||
print(item)
|
||||
5
docs/src/python_types/tutorial007.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from typing import Set, Tuple
|
||||
|
||||
|
||||
def process_items(items_t: Tuple[int], items_s: Set[bytes]):
|
||||
return items_t, items_s
|
||||
7
docs/src/python_types/tutorial008.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from typing import Dict
|
||||
|
||||
|
||||
def process_items(prices: Dict[str, float]):
|
||||
for item_name, item_price in prices.items():
|
||||
print(item_name)
|
||||
print(item_price)
|
||||
7
docs/src/python_types/tutorial009.py
Normal file
@@ -0,0 +1,7 @@
|
||||
class Person:
|
||||
def __init__(self, name: str):
|
||||
self.name = name
|
||||
|
||||
|
||||
def get_person_name(one_person: Person):
|
||||
return one_person.name
|
||||
23
docs/src/python_types/tutorial010.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
id: int
|
||||
name = "John Doe"
|
||||
signup_ts: datetime = None
|
||||
friends: List[int] = []
|
||||
|
||||
|
||||
external_data = {
|
||||
"id": "123",
|
||||
"signup_ts": "2017-06-01 12:22",
|
||||
"friends": [1, "2", b"3"],
|
||||
}
|
||||
user = User(**external_data)
|
||||
print(user)
|
||||
# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]
|
||||
print(user.id)
|
||||
# > 123
|
||||
9
docs/src/query_params/tutorial005.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_user_item(item_id: str, needy: str):
|
||||
item = {"item_id": item_id, "needy": needy}
|
||||
return item
|
||||
9
docs/src/query_params/tutorial006.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_user_item(item_id: str, needy: str, skip: int = 0, limit: int = None):
|
||||
item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit}
|
||||
return item
|
||||