Complete documentation with a flow page with curl examples

This commit is contained in:
François Voron
2020-04-25 14:32:08 +02:00
parent a9ee467518
commit bf0c924501
4 changed files with 478 additions and 1 deletions

View File

@@ -27,6 +27,7 @@ bumpversion = "*"
httpx-oauth = "*"
httpx = "*"
asgi_lifespan = "*"
uvicorn = "*"
[packages]
fastapi = ">=0.54.0,<0.55.0"

70
Pipfile.lock generated
View File

@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "a48a987916237d8921c987fc4212dfc0f32a71235f5cbce8fe078e9e3b311be6"
"sha256": "0867361a489e0c0b3a9267aa3e8a7cb89e378db6e0e0d6c831d454982f8272d8"
},
"pipfile-spec": 6,
"requires": {
@@ -500,6 +500,24 @@
],
"version": "==2020.4.24"
},
"httptools": {
"hashes": [
"sha256:0a4b1b2012b28e68306575ad14ad5e9120b34fccd02a81eb08838d7e3bbb48be",
"sha256:3592e854424ec94bd17dc3e0c96a64e459ec4147e6d53c0a42d0ebcef9cb9c5d",
"sha256:41b573cf33f64a8f8f3400d0a7faf48e1888582b6f6e02b82b9bd4f0bf7497ce",
"sha256:56b6393c6ac7abe632f2294da53f30d279130a92e8ae39d8d14ee2e1b05ad1f2",
"sha256:86c6acd66765a934e8730bf0e9dfaac6fdcf2a4334212bd4a0a1c78f16475ca6",
"sha256:96da81e1992be8ac2fd5597bf0283d832287e20cb3cfde8996d2b00356d4e17f",
"sha256:96eb359252aeed57ea5c7b3d79839aaa0382c9d3149f7d24dd7172b1bcecb009",
"sha256:a2719e1d7a84bb131c4f1e0cb79705034b48de6ae486eb5297a139d6a3296dce",
"sha256:ac0aa11e99454b6a66989aa2d44bca41d4e0f968e395a0a8f164b401fefe359a",
"sha256:bc3114b9edbca5a1eb7ae7db698c669eb53eb8afbbebdde116c174925260849c",
"sha256:fa3cd71e31436911a44620473e873a256851e1f53dee56669dae403ba41756a4",
"sha256:fea04e126014169384dee76a153d4573d90d0cbd1d12185da089f73c78390437"
],
"markers": "sys_platform != 'win32' and sys_platform != 'cygwin' and platform_python_implementation != 'PyPy'",
"version": "==0.1.1"
},
"httpx": {
"hashes": [
"sha256:405b4749f597b1f45cae5bffc17b23dc251cce30a0c4c8126f1007b9e728a615",
@@ -971,6 +989,29 @@
],
"version": "==1.25.9"
},
"uvicorn": {
"hashes": [
"sha256:0f58170165c4495f563d8224b2f415a0829af0412baa034d6f777904613087fd",
"sha256:6fdaf8e53bf1b2ddf0fe9ed06079b5348d7d1d87b3365fe2549e6de0d49e631c"
],
"index": "pypi",
"version": "==0.11.3"
},
"uvloop": {
"hashes": [
"sha256:08b109f0213af392150e2fe6f81d33261bb5ce968a288eb698aad4f46eb711bd",
"sha256:123ac9c0c7dd71464f58f1b4ee0bbd81285d96cdda8bc3519281b8973e3a461e",
"sha256:4315d2ec3ca393dd5bc0b0089d23101276778c304d42faff5dc4579cb6caef09",
"sha256:4544dcf77d74f3a84f03dd6278174575c44c67d7165d4c42c71db3fdc3860726",
"sha256:afd5513c0ae414ec71d24f6f123614a80f3d27ca655a4fcf6cabe50994cc1891",
"sha256:b4f591aa4b3fa7f32fb51e2ee9fea1b495eb75b0b3c8d0ca52514ad675ae63f7",
"sha256:bcac356d62edd330080aed082e78d4b580ff260a677508718f88016333e2c9c5",
"sha256:e7514d7a48c063226b7d06617cbb12a14278d4323a065a8d46a7962686ce2e95",
"sha256:f07909cd9fc08c52d294b1570bba92186181ca01fe3dc9ffba68955273dd7362"
],
"markers": "sys_platform != 'win32' and sys_platform != 'cygwin' and platform_python_implementation != 'PyPy'",
"version": "==0.14.0"
},
"wcwidth": {
"hashes": [
"sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1",
@@ -978,6 +1019,33 @@
],
"version": "==0.1.9"
},
"websockets": {
"hashes": [
"sha256:0e4fb4de42701340bd2353bb2eee45314651caa6ccee80dbd5f5d5978888fed5",
"sha256:1d3f1bf059d04a4e0eb4985a887d49195e15ebabc42364f4eb564b1d065793f5",
"sha256:20891f0dddade307ffddf593c733a3fdb6b83e6f9eef85908113e628fa5a8308",
"sha256:295359a2cc78736737dd88c343cd0747546b2174b5e1adc223824bcaf3e164cb",
"sha256:2db62a9142e88535038a6bcfea70ef9447696ea77891aebb730a333a51ed559a",
"sha256:3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c",
"sha256:3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170",
"sha256:3ef56fcc7b1ff90de46ccd5a687bbd13a3180132268c4254fc0fa44ecf4fc422",
"sha256:4f9f7d28ce1d8f1295717c2c25b732c2bc0645db3215cf757551c392177d7cb8",
"sha256:5c01fd846263a75bc8a2b9542606927cfad57e7282965d96b93c387622487485",
"sha256:5c65d2da8c6bce0fca2528f69f44b2f977e06954c8512a952222cea50dad430f",
"sha256:751a556205d8245ff94aeef23546a1113b1dd4f6e4d102ded66c39b99c2ce6c8",
"sha256:7ff46d441db78241f4c6c27b3868c9ae71473fe03341340d2dfdbe8d79310acc",
"sha256:965889d9f0e2a75edd81a07592d0ced54daa5b0785f57dc429c378edbcffe779",
"sha256:9b248ba3dd8a03b1a10b19efe7d4f7fa41d158fdaa95e2cf65af5a7b95a4f989",
"sha256:9bef37ee224e104a413f0780e29adb3e514a5b698aabe0d969a6ba426b8435d1",
"sha256:c1ec8db4fac31850286b7cd3b9c0e1b944204668b8eb721674916d4e28744092",
"sha256:c8a116feafdb1f84607cb3b14aa1418424ae71fee131642fc568d21423b51824",
"sha256:ce85b06a10fc65e6143518b96d3dca27b081a740bae261c2fb20375801a9d56d",
"sha256:d705f8aeecdf3262379644e4b55107a3b55860eb812b673b28d0fbc347a60c55",
"sha256:e898a0863421650f0bebac8ba40840fc02258ef4714cb7e1fd76b6a6354bda36",
"sha256:f8a7bff6e8664afc4e6c28b983845c5bc14965030e3fb98789734d416af77c4b"
],
"version": "==8.1"
},
"zipp": {
"hashes": [
"sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b",

406
docs/usage/flow.md Normal file
View File

@@ -0,0 +1,406 @@
# Flow
This page will present you a complete registration and authentication flow once you've setup **FastAPI Users**. Each example will be presented with a `cURL` and an `axios` example.
## 1. Registration
First step, of course, is to register as a user.
### Request
=== "cURL"
``` bash
curl \
-H "Content-Type: application/json" \
-X POST \
-d "{\"email\": \"king.arthur@camelot.bt\",\"password\": \"guinevere\"}" \
http://localhost:9000/users/register
```
=== "axios"
```ts
axios.post('http://localhost:9000/users/register', {
email: 'king.arthur@camelot.bt',
password: 'guinevere',
})
.then((response) => console.log(response))
.catch((error) => console.log(error));
```
### Response
You'll get a JSON response looking like this:
```json
{
"id": "4fd3477b-eccf-4ee3-8f7d-68ad72261476",
"email": "king.arthur@camelot.bt",
"is_active": true,
"is_superuser": false
}
```
!!! info
Several things to bear in mind:
* If you have defined other required fields in your `User` model (like a first name or a birthdate), you'll have to provide them in the payload.
* The user is active by default.
* The user cannot set `is_active` or `is_superuser` itself at registration. Only a superuser can do it by PATCHing the user.
## 2. Login
Now, you can login as this new user.
Each [authentication backend](../configuration/authentication/index.md) will produce a single route. For example, the [JWT backend](../configuration/authentication/jwt.md) will produce the `/users/login/jwt` route. Each backend will have a different response.
### JWT backend
#### Request
=== "cURL"
``` bash
curl \
-H "Content-Type: multipart/form-data" \
-X POST \
-F "username=king.arthur@camelot.bt" \
-F "password=guinevere" \
http://localhost:9000/users/login/jwt
```
=== "axios"
```ts
const formData = new FormData();
formData.set('username', 'king.arthur@camelot.bt');
formData.set('password', 'guinevere');
axios.post(
'http://localhost:9000/users/login/jwt',
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
},
},
)
.then((response) => console.log(response))
.catch((error) => console.log(error));
```
!!! warning
Notice that we don't send it as a JSON payload here but with **form data** instead. Also, the email is provided by a field named **`username`**.
#### Response
You'll get a JSON response looking like this:
```json
{
"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNGZkMzQ3N2ItZWNjZi00ZWUzLThmN2QtNjhhZDcyMjYxNDc2IiwiYXVkIjoiZmFzdGFwaS11c2VyczphdXRoIiwiZXhwIjoxNTg3ODE4NDI5fQ.anO3JR8-WYCozZ4_2-PQ2Ov9O38RaLP2RAzQIiZhteM"
}
```
You can use this token to make authenticated requests as the user `king.arthur@camelot.bt`. We'll see how in the next section.
### Cookie backend
#### Request
=== "cURL"
``` bash
curl \
-v \
-H "Content-Type: multipart/form-data" \
-X POST \
-F "username=king.arthur@camelot.bt" \
-F "password=guinevere" \
http://localhost:9000/users/login/cookie
```
=== "axios"
```ts
const formData = new FormData();
formData.set('username', 'king.arthur@camelot.bt');
formData.set('password', 'guinevere');
axios.post(
'http://localhost:9000/users/login/cookie',
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
},
},
)
.then((response) => console.log(response))
.catch((error) => console.log(error));
```
!!! warning
Notice that we don't send it as a JSON payload here but with **form data** instead. Also, the email is provided by a field named **`username`**.
#### Response
You'll get a empty response. However, the response will come with a `Set-Cookie` header (that's why we added the `-v` option in `cURL` to see them).
```
set-cookie: fastapiusersauth=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYzYwNjBmMTEtNTM0OS00YTI0LThiNGEtYTJhODc1ZGM1Mzk1IiwiYXVkIjoiZmFzdGFwaS11c2VyczphdXRoIiwiZXhwIjoxNTg3ODE4OTQ3fQ.qNA4oPVYhoqrJIk-zvAyEfEVoEnP156G30H_SWEU0sU; HttpOnly; Max-Age=3600; Path=/; Secure
```
You can make authenticated requests as the user `king.arthur@camelot.bt` by setting a `Cookie` header with this cookie.
!!! tip
The cookie backend is more suited for browsers, as they handle them automatically. This means that if you make a login request in the browser, it will automatically store the cookie and automatically send it in subsequent requests.
## 3. Get my profile
Now that we can authenticate, we can get our own profile data. Depending on your [authentication backend](../configuration/authentication/index.md), the method to authenticate the request will vary. We'll stick with JWT from now on.
### Request
=== "cURL"
``` bash
export TOKEN="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNGZkMzQ3N2ItZWNjZi00ZWUzLThmN2QtNjhhZDcyMjYxNDc2IiwiYXVkIjoiZmFzdGFwaS11c2VyczphdXRoIiwiZXhwIjoxNTg3ODE4NDI5fQ.anO3JR8-WYCozZ4_2-PQ2Ov9O38RaLP2RAzQIiZhteM";
curl \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-X GET \
http://localhost:9000/users/me
```
=== "axios"
```ts
const TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNGZkMzQ3N2ItZWNjZi00ZWUzLThmN2QtNjhhZDcyMjYxNDc2IiwiYXVkIjoiZmFzdGFwaS11c2VyczphdXRoIiwiZXhwIjoxNTg3ODE4NDI5fQ.anO3JR8-WYCozZ4_2-PQ2Ov9O38RaLP2RAzQIiZhteM';
axios.get(
'http://localhost:9000/users/me', {
headers: {
'Authorization': `Bearer ${TOKEN}`,
},
})
.then((response) => console.log(response))
.catch((error) => console.log(error));
```
### Response
You'll get a JSON response looking like this:
```json
{
"id": "4fd3477b-eccf-4ee3-8f7d-68ad72261476",
"email": "king.arthur@camelot.bt",
"is_active": true,
"is_superuser": false
}
```
!!! tip
If you use one of the [dependency callable](./dependency-callables.md) to protect one of your own endpoint, you'll have to authenticate exactly in the same way.
## 4. Update my profile
We can also update our own profile. For example, we can change our password like this.
### Request
=== "cURL"
``` bash
curl \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-X PATCH \
-d "{\"password\": \"lancelot\"}" \
http://localhost:9000/users/me
```
=== "axios"
```ts
axios.patch(
'http://localhost:9000/users/me',
{
password: 'lancelot',
},
{
headers: {
'Authorization': `Bearer ${TOKEN}`,
},
},
)
.then((response) => console.log(response))
.catch((error) => console.log(error));
```
### Response
You'll get a JSON response looking like this:
```json
{
"id": "4fd3477b-eccf-4ee3-8f7d-68ad72261476",
"email": "king.arthur@camelot.bt",
"is_active": true,
"is_superuser": false
}
```
!!! info
Once again, the user cannot set `is_active` or `is_superuser` itself. Only a superuser can do it by PATCHing the user.
## 5. Become a superuser 🦸🏻‍♂️
If you want to manage the users of your application, you'll have to become a **superuser**.
The very first superuser can only be set at **database level**: open it through a CLI or a GUI, find your user and set the `is_superuser` column/property to `true`.
### 5.1. Get the profile of any user
Now that you are a superuser, you can leverage the power of [superuser routes](./routes.md#superuser). You can for example get the profile of any user in the database given its id.
#### Request
=== "cURL"
``` bash
curl \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-X GET \
http://localhost:9000/users/4fd3477b-eccf-4ee3-8f7d-68ad72261476
```
=== "axios"
```ts
axios.get(
'http://localhost:9000/users/4fd3477b-eccf-4ee3-8f7d-68ad72261476', {
headers: {
'Authorization': `Bearer ${TOKEN}`,
},
})
.then((response) => console.log(response))
.catch((error) => console.log(error));
```
#### Response
You'll get a JSON response looking like this:
```json
{
"id": "4fd3477b-eccf-4ee3-8f7d-68ad72261476",
"email": "king.arthur@camelot.bt",
"is_active": true,
"is_superuser": false
}
```
### 5.1. Update any user
We can now update the profile of any user. For example, we can promote it as superuser.
#### Request
=== "cURL"
``` bash
curl \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-X PATCH \
-d "{\"is_superuser\": true}" \
http://localhost:9000/users/4fd3477b-eccf-4ee3-8f7d-68ad72261476
```
=== "axios"
```ts
axios.patch(
'http://localhost:9000/users/4fd3477b-eccf-4ee3-8f7d-68ad72261476',
{
is_superuser: true,
},
{
headers: {
'Authorization': `Bearer ${TOKEN}`,
},
},
)
.then((response) => console.log(response))
.catch((error) => console.log(error));
```
#### Response
You'll get a JSON response looking like this:
```json
{
"id": "4fd3477b-eccf-4ee3-8f7d-68ad72261476",
"email": "king.arthur@camelot.bt",
"is_active": true,
"is_superuser": true
}
```
### 5.2. Delete any user
Finally, we can delete a user.
#### Request
=== "cURL"
``` bash
curl \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-X DELETE \
http://localhost:9000/users/4fd3477b-eccf-4ee3-8f7d-68ad72261476
```
=== "axios"
```ts
axios.delete(
'http://localhost:9000/users/4fd3477b-eccf-4ee3-8f7d-68ad72261476',
{
headers: {
'Authorization': `Bearer ${TOKEN}`,
},
},
)
.then((response) => console.log(response))
.catch((error) => console.log(error));
```
#### Response
You'll get an empty response.
## 6. Logout
We can also end the session. Note that it doesn't apply to every [authentication backends](../configuration/authentication/index.md). For JWT, it doesn't make sense to end the session, the token is valid until it expires. However, for Cookie backend, the server will clear the cookie.
### Request
=== "cURL"
``` bash
curl \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-X POST \
http://localhost:9000/users/logout/cookie
```
=== "axios"
```ts
axios.post('http://localhost:9000/users/logout/cookie',
null,
{
headers: {
'Authorization': `Bearer ${TOKEN}`,
},
}
)
.then((response) => console.log(response))
.catch((error) => console.log(error));
```
### Response
You'll get an empty response.
## Conclusion
That's it! You now have a good overview of how you can manage the users through the API. Be sure to check the [Routes](./routes.md) page to have all the details about each endpoints.

View File

@@ -23,6 +23,7 @@ markdown_extensions:
- codehilite
- pymdownx.superfences
- pymdownx.tasklist
- pymdownx.tabbed
nav:
- About: index.md
@@ -41,5 +42,6 @@ nav:
- configuration/full_example.md
- configuration/oauth.md
- Usage:
- usage/flow.md
- usage/routes.md
- usage/dependency-callables.md