]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
:memo: Update docs and index to make clear what FastAPI does
authorSebastián Ramírez <tiangolo@gmail.com>
Fri, 21 Dec 2018 12:23:28 +0000 (16:23 +0400)
committerSebastián Ramírez <tiangolo@gmail.com>
Fri, 21 Dec 2018 12:23:28 +0000 (16:23 +0400)
18 files changed:
docs/features.md
docs/img/index/index-01-swagger-ui-simple.png
docs/img/index/index-02-redoc-simple.png
docs/img/index/index-03-swagger-02.png
docs/img/index/index-04-swagger-03.png
docs/img/index/index-05-swagger-04.png
docs/img/index/index-06-redoc-02.png
docs/img/pycharm-completion.png
docs/img/python-types/image01.png [moved from docs/img/tutorial/python-types/image01.png with 100% similarity]
docs/img/python-types/image02.png [moved from docs/img/tutorial/python-types/image02.png with 100% similarity]
docs/img/python-types/image03.png [moved from docs/img/tutorial/python-types/image03.png with 100% similarity]
docs/img/python-types/image04.png [moved from docs/img/tutorial/python-types/image04.png with 100% similarity]
docs/img/python-types/image05.png [moved from docs/img/tutorial/python-types/image05.png with 100% similarity]
docs/img/python-types/image06.png [moved from docs/img/tutorial/python-types/image06.png with 100% similarity]
docs/img/vscode-completion.png
docs/index.md
docs/python-types.md [new file with mode: 0644]
mkdocs.yml

index 28968e8bc57fe572ad09b08bd6b246a77d57b04a..c4e1598d8edefae08e94c2269fc897c078a3acd9 100644 (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:
 
index 71578341e87e5445eb0be7b6ece296309cecd298..5b591a6a73a26368774bc5338453d53f8fd48a14 100644 (file)
Binary files a/docs/img/index/index-01-swagger-ui-simple.png and b/docs/img/index/index-01-swagger-ui-simple.png differ
index ec2c1e31aee6ef8957d42cb0bcc31ddb9b25244c..a3b0e53b08c0666892f41ecf16895b103c21f641 100644 (file)
Binary files a/docs/img/index/index-02-redoc-simple.png and b/docs/img/index/index-02-redoc-simple.png differ
index 2f4beca5f581ae0cc132f54308be59553520b9c8..1b4040fde609d19db9f1a4726cc775a418bf3b7b 100644 (file)
Binary files a/docs/img/index/index-03-swagger-02.png and b/docs/img/index/index-03-swagger-02.png differ
index 9d4e4d1ba21f239b8c2e76dac138a14a61567148..7f1ead67b6e112c306a6379c259f6a7988875aff 100644 (file)
Binary files a/docs/img/index/index-04-swagger-03.png and b/docs/img/index/index-04-swagger-03.png differ
index 2dfef6bf7e086608605f168d332062ba4f4d3a3b..218fbb0ace13b9b70304bdcb0935ade97adb4366 100644 (file)
Binary files a/docs/img/index/index-05-swagger-04.png and b/docs/img/index/index-05-swagger-04.png differ
index 45c55e6635d43d4a4bd2ec1b81f678ee7ea8c640..7dcb9cdf1e7a54ad71ce1507e35fe82db5d28e52 100644 (file)
Binary files a/docs/img/index/index-06-redoc-02.png and b/docs/img/index/index-06-redoc-02.png differ
index 4768a94058fef17adf915d3b4d54783e709d5dfe..6cd204cd42d8b2af6730f352f3a74b27820f486c 100644 (file)
Binary files a/docs/img/pycharm-completion.png and b/docs/img/pycharm-completion.png differ
index f0d1c5ddf582fa3a602df9c1780b63e60c09ea43..ba6e22b028ec4d7961a50d599a1ed5357b828484 100644 (file)
Binary files a/docs/img/vscode-completion.png and b/docs/img/vscode-completion.png differ
index 3fc8aa7d3be0fce7c89ec6ba95bcdf387b80077a..2d743b52a21771707c89d482f81c37ef508f8f5a 100644 (file)
@@ -72,26 +72,42 @@ 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 _"In a hurry?"_ section about <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` and `await` in the docs</a>.
+**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:
 
@@ -99,23 +115,34 @@ async def read_root():
 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>
+
+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.
+* `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` <abbr title="also known as HTTP methods"><em>operations</em></abbr>.
+* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`.
+* The _path_ `/items/{item_id}` has an optional _query parameter_ `q` that is a `str`.
+
 ### 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 +162,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 +180,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.get("/items/{item_id}")
+def read_item(item_id: int, q: str = None):
+    return {"item_id": item_id, "q": q}
 
 
-@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.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 +201,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 +275,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 +300,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,6 +317,7 @@ 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)
 
 
diff --git a/docs/python-types.md b/docs/python-types.md
new file mode 100644 (file)
index 0000000..9483d92
--- /dev/null
@@ -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>.
\ No newline at end of file
index 2b0bce0f6ab7103bc284495acc7828bc634069ec..26cd6f9bc8f7767d590d32fcfb9bf8a8fce9898e 100644 (file)
@@ -16,9 +16,9 @@ edit_uri: ""
 nav:
     - FastAPI: 'index.md'
     - Features: 'features.md'
+    - Python types intro: 'python-types.md'
     - Tutorial - User Guide:
         - Tutorial - User Guide - Intro: 'tutorial/intro.md'
-        - Python types intro: 'tutorial/python-types.md'
         - First Steps: 'tutorial/first-steps.md'
         - Path Parameters: 'tutorial/path-params.md'
         - Query Parameters: 'tutorial/query-params.md'
@@ -51,11 +51,9 @@ nav:
             - OAuth2 with Password (and hashing), Bearer with JWT tokens: 'tutorial/security/oauth2-jwt.md'
         - Bigger Applications - Multiple Files: 'tutorial/bigger-applications.md'
         - Application Configuration: 'tutorial/application-configuration.md'
-        - Extra Starlette options: 'tutorial/extra-starlette.md'
-        
+        - Extra Starlette options: 'tutorial/extra-starlette.md'    
     - Concurrency and async / await: 'async.md'
     - Deployment: 'deployment.md'
-    
 
 markdown_extensions:
   - markdown.extensions.codehilite:
@@ -64,3 +62,4 @@ markdown_extensions:
       base_path: docs
   - admonition
   - codehilite
+  - extra