Compare commits

...

34 Commits

Author SHA1 Message Date
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
190 changed files with 3496 additions and 598 deletions

View File

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

90
Pipfile.lock generated
View File

@@ -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
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:
@@ -287,10 +321,11 @@ Try changing the line with:
...and see how your editor will auto-complete the attributes and know their types:
![editor support](img/vscode-completion.png)
![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: 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>
---
@@ -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:
@@ -287,10 +321,11 @@ Try changing the line with:
...and see how your editor will auto-complete the attributes and know their types:
![editor support](img/vscode-completion.png)
![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:

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

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

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

View 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

View 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

View 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

View File

@@ -0,0 +1,6 @@
from typing import List
def process_items(items: List[str]):
for item in items:
print(item)

View 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

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

View 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

View 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

View 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

View 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

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