66 changed files with 2061 additions and 2657 deletions
@ -1,314 +0,0 @@ |
|||||
# ↔ 🗄 |
|
||||
|
|
||||
!!! warning |
|
||||
👉 👍 🏧 ⚒. 👆 🎲 💪 🚶 ⚫️. |
|
||||
|
|
||||
🚥 👆 📄 🔰 - 👩💻 🦮, 👆 💪 🎲 🚶 👉 📄. |
|
||||
|
|
||||
🚥 👆 ⏪ 💭 👈 👆 💪 🔀 🏗 🗄 🔗, 😣 👂. |
|
||||
|
|
||||
📤 💼 🌐❔ 👆 💪 💪 🔀 🏗 🗄 🔗. |
|
||||
|
|
||||
👉 📄 👆 🔜 👀 ❔. |
|
||||
|
|
||||
## 😐 🛠️ |
|
||||
|
|
||||
😐 (🔢) 🛠️, ⏩. |
|
||||
|
|
||||
`FastAPI` 🈸 (👐) ✔️ `.openapi()` 👩🔬 👈 📈 📨 🗄 🔗. |
|
||||
|
|
||||
🍕 🈸 🎚 🏗, *➡ 🛠️* `/openapi.json` (⚖️ ⚫️❔ 👆 ⚒ 👆 `openapi_url`) ®. |
|
||||
|
|
||||
⚫️ 📨 🎻 📨 ⏮️ 🏁 🈸 `.openapi()` 👩🔬. |
|
||||
|
|
||||
🔢, ⚫️❔ 👩🔬 `.openapi()` 🔨 ✅ 🏠 `.openapi_schema` 👀 🚥 ⚫️ ✔️ 🎚 & 📨 👫. |
|
||||
|
|
||||
🚥 ⚫️ 🚫, ⚫️ 🏗 👫 ⚙️ 🚙 🔢 `fastapi.openapi.utils.get_openapi`. |
|
||||
|
|
||||
& 👈 🔢 `get_openapi()` 📨 🔢: |
|
||||
|
|
||||
* `title`: 🗄 📛, 🎦 🩺. |
|
||||
* `version`: ⏬ 👆 🛠️, ✅ `2.5.0`. |
|
||||
* `openapi_version`: ⏬ 🗄 🔧 ⚙️. 🔢, ⏪: `3.0.2`. |
|
||||
* `description`: 📛 👆 🛠️. |
|
||||
* `routes`: 📇 🛣, 👫 🔠 ® *➡ 🛠️*. 👫 ✊ ⚪️➡️ `app.routes`. |
|
||||
|
|
||||
## 🔑 🔢 |
|
||||
|
|
||||
⚙️ ℹ 🔛, 👆 💪 ⚙️ 🎏 🚙 🔢 🏗 🗄 🔗 & 🔐 🔠 🍕 👈 👆 💪. |
|
||||
|
|
||||
🖼, ➡️ 🚮 <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">📄 🗄 ↔ 🔌 🛃 🔱</a>. |
|
||||
|
|
||||
### 😐 **FastAPI** |
|
||||
|
|
||||
🥇, ✍ 🌐 👆 **FastAPI** 🈸 🛎: |
|
||||
|
|
||||
```Python hl_lines="1 4 7-9" |
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!} |
|
||||
``` |
|
||||
|
|
||||
### 🏗 🗄 🔗 |
|
||||
|
|
||||
⤴️, ⚙️ 🎏 🚙 🔢 🏗 🗄 🔗, 🔘 `custom_openapi()` 🔢: |
|
||||
|
|
||||
```Python hl_lines="2 15-20" |
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!} |
|
||||
``` |
|
||||
|
|
||||
### 🔀 🗄 🔗 |
|
||||
|
|
||||
🔜 👆 💪 🚮 📄 ↔, ❎ 🛃 `x-logo` `info` "🎚" 🗄 🔗: |
|
||||
|
|
||||
```Python hl_lines="21-23" |
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!} |
|
||||
``` |
|
||||
|
|
||||
### 💾 🗄 🔗 |
|
||||
|
|
||||
👆 💪 ⚙️ 🏠 `.openapi_schema` "💾", 🏪 👆 🏗 🔗. |
|
||||
|
|
||||
👈 🌌, 👆 🈸 🏆 🚫 ✔️ 🏗 🔗 🔠 🕰 👩💻 📂 👆 🛠️ 🩺. |
|
||||
|
|
||||
⚫️ 🔜 🏗 🕴 🕐, & ⤴️ 🎏 💾 🔗 🔜 ⚙️ ⏭ 📨. |
|
||||
|
|
||||
```Python hl_lines="13-14 24-25" |
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!} |
|
||||
``` |
|
||||
|
|
||||
### 🔐 👩🔬 |
|
||||
|
|
||||
🔜 👆 💪 ❎ `.openapi()` 👩🔬 ⏮️ 👆 🆕 🔢. |
|
||||
|
|
||||
```Python hl_lines="28" |
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!} |
|
||||
``` |
|
||||
|
|
||||
### ✅ ⚫️ |
|
||||
|
|
||||
🕐 👆 🚶 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> 👆 🔜 👀 👈 👆 ⚙️ 👆 🛃 🔱 (👉 🖼, **FastAPI**'Ⓜ 🔱): |
|
||||
|
|
||||
<img src="/img/tutorial/extending-openapi/image01.png"> |
|
||||
|
|
||||
## 👤-🕸 🕸 & 🎚 🩺 |
|
||||
|
|
||||
🛠️ 🩺 ⚙️ **🦁 🎚** & **📄**, & 🔠 👈 💪 🕸 & 🎚 📁. |
|
||||
|
|
||||
🔢, 👈 📁 🍦 ⚪️➡️ <abbr title="Content Delivery Network: A service, normally composed of several servers, that provides static files, like JavaScript and CSS. It's commonly used to serve those files from the server closer to the client, improving performance.">💲</abbr>. |
|
||||
|
|
||||
✋️ ⚫️ 💪 🛃 ⚫️, 👆 💪 ⚒ 🎯 💲, ⚖️ 🍦 📁 👆. |
|
||||
|
|
||||
👈 ⚠, 🖼, 🚥 👆 💪 👆 📱 🚧 👷 ⏪ 📱, 🍵 📂 🕸 🔐, ⚖️ 🇧🇿 🕸. |
|
||||
|
|
||||
📥 👆 🔜 👀 ❔ 🍦 👈 📁 👆, 🎏 FastAPI 📱, & 🔗 🩺 ⚙️ 👫. |
|
||||
|
|
||||
### 🏗 📁 📊 |
|
||||
|
|
||||
➡️ 💬 👆 🏗 📁 📊 👀 💖 👉: |
|
||||
|
|
||||
``` |
|
||||
. |
|
||||
├── app |
|
||||
│ ├── __init__.py |
|
||||
│ ├── main.py |
|
||||
``` |
|
||||
|
|
||||
🔜 ✍ 📁 🏪 📚 🎻 📁. |
|
||||
|
|
||||
👆 🆕 📁 📊 💪 👀 💖 👉: |
|
||||
|
|
||||
``` |
|
||||
. |
|
||||
├── app |
|
||||
│ ├── __init__.py |
|
||||
│ ├── main.py |
|
||||
└── static/ |
|
||||
``` |
|
||||
|
|
||||
### ⏬ 📁 |
|
||||
|
|
||||
⏬ 🎻 📁 💪 🩺 & 🚮 👫 🔛 👈 `static/` 📁. |
|
||||
|
|
||||
👆 💪 🎲 ▶️️-🖊 🔠 🔗 & 🖊 🎛 🎏 `Save link as...`. |
|
||||
|
|
||||
**🦁 🎚** ⚙️ 📁: |
|
||||
|
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a> |
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a> |
|
||||
|
|
||||
& **📄** ⚙️ 📁: |
|
||||
|
|
||||
* <a href="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js" class="external-link" target="_blank">`redoc.standalone.js`</a> |
|
||||
|
|
||||
⏮️ 👈, 👆 📁 📊 💪 👀 💖: |
|
||||
|
|
||||
``` |
|
||||
. |
|
||||
├── app |
|
||||
│ ├── __init__.py |
|
||||
│ ├── main.py |
|
||||
└── static |
|
||||
├── redoc.standalone.js |
|
||||
├── swagger-ui-bundle.js |
|
||||
└── swagger-ui.css |
|
||||
``` |
|
||||
|
|
||||
### 🍦 🎻 📁 |
|
||||
|
|
||||
* 🗄 `StaticFiles`. |
|
||||
* "🗻" `StaticFiles()` 👐 🎯 ➡. |
|
||||
|
|
||||
```Python hl_lines="7 11" |
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!} |
|
||||
``` |
|
||||
|
|
||||
### 💯 🎻 📁 |
|
||||
|
|
||||
▶️ 👆 🈸 & 🚶 <a href="http://127.0.0.1:8000/static/redoc.standalone.js" class="external-link" target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a>. |
|
||||
|
|
||||
👆 🔜 👀 📶 📏 🕸 📁 **📄**. |
|
||||
|
|
||||
⚫️ 💪 ▶️ ⏮️ 🕳 💖: |
|
||||
|
|
||||
```JavaScript |
|
||||
/*! |
|
||||
* ReDoc - OpenAPI/Swagger-generated API Reference Documentation |
|
||||
* ------------------------------------------------------------- |
|
||||
* Version: "2.0.0-rc.18" |
|
||||
* Repo: https://github.com/Redocly/redoc |
|
||||
*/ |
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof m |
|
||||
|
|
||||
... |
|
||||
``` |
|
||||
|
|
||||
👈 ✔ 👈 👆 💆♂ 💪 🍦 🎻 📁 ⚪️➡️ 👆 📱, & 👈 👆 🥉 🎻 📁 🩺 ☑ 🥉. |
|
||||
|
|
||||
🔜 👥 💪 🔗 📱 ⚙️ 📚 🎻 📁 🩺. |
|
||||
|
|
||||
### ❎ 🏧 🩺 |
|
||||
|
|
||||
🥇 🔁 ❎ 🏧 🩺, 📚 ⚙️ 💲 🔢. |
|
||||
|
|
||||
❎ 👫, ⚒ 👫 📛 `None` 🕐❔ 🏗 👆 `FastAPI` 📱: |
|
||||
|
|
||||
```Python hl_lines="9" |
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!} |
|
||||
``` |
|
||||
|
|
||||
### 🔌 🛃 🩺 |
|
||||
|
|
||||
🔜 👆 💪 ✍ *➡ 🛠️* 🛃 🩺. |
|
||||
|
|
||||
👆 💪 🏤-⚙️ FastAPI 🔗 🔢 ✍ 🕸 📃 🩺, & 🚶♀️ 👫 💪 ❌: |
|
||||
|
|
||||
* `openapi_url`: 📛 🌐❔ 🕸 📃 🩺 💪 🤚 🗄 🔗 👆 🛠️. 👆 💪 ⚙️ 📥 🔢 `app.openapi_url`. |
|
||||
* `title`: 📛 👆 🛠️. |
|
||||
* `oauth2_redirect_url`: 👆 💪 ⚙️ `app.swagger_ui_oauth2_redirect_url` 📥 ⚙️ 🔢. |
|
||||
* `swagger_js_url`: 📛 🌐❔ 🕸 👆 🦁 🎚 🩺 💪 🤚 **🕸** 📁. 👉 1️⃣ 👈 👆 👍 📱 🔜 🍦. |
|
||||
* `swagger_css_url`: 📛 🌐❔ 🕸 👆 🦁 🎚 🩺 💪 🤚 **🎚** 📁. 👉 1️⃣ 👈 👆 👍 📱 🔜 🍦. |
|
||||
|
|
||||
& ➡ 📄... |
|
||||
|
|
||||
```Python hl_lines="2-6 14-22 25-27 30-36" |
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!} |
|
||||
``` |
|
||||
|
|
||||
!!! tip |
|
||||
*➡ 🛠️* `swagger_ui_redirect` 👩🎓 🕐❔ 👆 ⚙️ Oauth2️⃣. |
|
||||
|
|
||||
🚥 👆 🛠️ 👆 🛠️ ⏮️ Oauth2️⃣ 🐕🦺, 👆 🔜 💪 🔓 & 👟 🔙 🛠️ 🩺 ⏮️ 📎 🎓. & 🔗 ⏮️ ⚫️ ⚙️ 🎰 Oauth2️⃣ 🤝. |
|
||||
|
|
||||
🦁 🎚 🔜 🍵 ⚫️ ⛅ 🎑 👆, ✋️ ⚫️ 💪 👉 "❎" 👩🎓. |
|
||||
|
|
||||
### ✍ *➡ 🛠️* 💯 ⚫️ |
|
||||
|
|
||||
🔜, 💪 💯 👈 🌐 👷, ✍ *➡ 🛠️*: |
|
||||
|
|
||||
```Python hl_lines="39-41" |
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!} |
|
||||
``` |
|
||||
|
|
||||
### 💯 ⚫️ |
|
||||
|
|
||||
🔜, 👆 🔜 💪 🔌 👆 📻, 🚶 👆 🩺 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, & 🔃 📃. |
|
||||
|
|
||||
& 🍵 🕸, 👆 🔜 💪 👀 🩺 👆 🛠️ & 🔗 ⏮️ ⚫️. |
|
||||
|
|
||||
## 🛠️ 🦁 🎚 |
|
||||
|
|
||||
👆 💪 🔗 ➕ <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">🦁 🎚 🔢</a>. |
|
||||
|
|
||||
🔗 👫, 🚶♀️ `swagger_ui_parameters` ❌ 🕐❔ 🏗 `FastAPI()` 📱 🎚 ⚖️ `get_swagger_ui_html()` 🔢. |
|
||||
|
|
||||
`swagger_ui_parameters` 📨 📖 ⏮️ 📳 🚶♀️ 🦁 🎚 🔗. |
|
||||
|
|
||||
FastAPI 🗜 📳 **🎻** ⚒ 👫 🔗 ⏮️ 🕸, 👈 ⚫️❔ 🦁 🎚 💪. |
|
||||
|
|
||||
### ❎ ❕ 🎦 |
|
||||
|
|
||||
🖼, 👆 💪 ❎ ❕ 🎦 🦁 🎚. |
|
||||
|
|
||||
🍵 🔀 ⚒, ❕ 🎦 🛠️ 🔢: |
|
||||
|
|
||||
<img src="/img/tutorial/extending-openapi/image02.png"> |
|
||||
|
|
||||
✋️ 👆 💪 ❎ ⚫️ ⚒ `syntaxHighlight` `False`: |
|
||||
|
|
||||
```Python hl_lines="3" |
|
||||
{!../../../docs_src/extending_openapi/tutorial003.py!} |
|
||||
``` |
|
||||
|
|
||||
...& ⤴️ 🦁 🎚 🏆 🚫 🎦 ❕ 🎦 🚫🔜: |
|
||||
|
|
||||
<img src="/img/tutorial/extending-openapi/image03.png"> |
|
||||
|
|
||||
### 🔀 🎢 |
|
||||
|
|
||||
🎏 🌌 👆 💪 ⚒ ❕ 🎦 🎢 ⏮️ 🔑 `"syntaxHighlight.theme"` (👀 👈 ⚫️ ✔️ ❣ 🖕): |
|
||||
|
|
||||
```Python hl_lines="3" |
|
||||
{!../../../docs_src/extending_openapi/tutorial004.py!} |
|
||||
``` |
|
||||
|
|
||||
👈 📳 🔜 🔀 ❕ 🎦 🎨 🎢: |
|
||||
|
|
||||
<img src="/img/tutorial/extending-openapi/image04.png"> |
|
||||
|
|
||||
### 🔀 🔢 🦁 🎚 🔢 |
|
||||
|
|
||||
FastAPI 🔌 🔢 📳 🔢 ☑ 🌅 ⚙️ 💼. |
|
||||
|
|
||||
⚫️ 🔌 👫 🔢 📳: |
|
||||
|
|
||||
```Python |
|
||||
{!../../../fastapi/openapi/docs.py[ln:7-13]!} |
|
||||
``` |
|
||||
|
|
||||
👆 💪 🔐 🙆 👫 ⚒ 🎏 💲 ❌ `swagger_ui_parameters`. |
|
||||
|
|
||||
🖼, ❎ `deepLinking` 👆 💪 🚶♀️ 👉 ⚒ `swagger_ui_parameters`: |
|
||||
|
|
||||
```Python hl_lines="3" |
|
||||
{!../../../docs_src/extending_openapi/tutorial005.py!} |
|
||||
``` |
|
||||
|
|
||||
### 🎏 🦁 🎚 🔢 |
|
||||
|
|
||||
👀 🌐 🎏 💪 📳 👆 💪 ⚙️, ✍ 🛂 <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">🩺 🦁 🎚 🔢</a>. |
|
||||
|
|
||||
### 🕸-🕴 ⚒ |
|
||||
|
|
||||
🦁 🎚 ✔ 🎏 📳 **🕸-🕴** 🎚 (🖼, 🕸 🔢). |
|
||||
|
|
||||
FastAPI 🔌 👫 🕸-🕴 `presets` ⚒: |
|
||||
|
|
||||
```JavaScript |
|
||||
presets: [ |
|
||||
SwaggerUIBundle.presets.apis, |
|
||||
SwaggerUIBundle.SwaggerUIStandalonePreset |
|
||||
] |
|
||||
``` |
|
||||
|
|
||||
👫 **🕸** 🎚, 🚫 🎻, 👆 💪 🚫 🚶♀️ 👫 ⚪️➡️ 🐍 📟 🔗. |
|
||||
|
|
||||
🚥 👆 💪 ⚙️ 🕸-🕴 📳 💖 📚, 👆 💪 ⚙️ 1️⃣ 👩🔬 🔛. 🔐 🌐 🦁 🎚 *➡ 🛠️* & ❎ ✍ 🙆 🕸 👆 💪. |
|
@ -1,258 +0,0 @@ |
|||||
# 🛠️ FastAPI 🔛 🪔 |
|
||||
|
|
||||
👉 📄 👆 🔜 💡 ❔ 💪 🛠️ **FastAPI** 🈸 🔛 <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">🪔</a> ⚙️ 🆓 📄. 👶 |
|
||||
|
|
||||
⚫️ 🔜 ✊ 👆 🔃 **1️⃣0️⃣ ⏲**. |
|
||||
|
|
||||
!!! info |
|
||||
<a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">🪔</a> **FastAPI** 💰. 👶 |
|
||||
|
|
||||
## 🔰 **FastAPI** 📱 |
|
||||
|
|
||||
* ✍ 📁 👆 📱, 🖼, `./fastapideta/` & ⛔ 🔘 ⚫️. |
|
||||
|
|
||||
### FastAPI 📟 |
|
||||
|
|
||||
* ✍ `main.py` 📁 ⏮️: |
|
||||
|
|
||||
```Python |
|
||||
from fastapi import FastAPI |
|
||||
|
|
||||
app = FastAPI() |
|
||||
|
|
||||
|
|
||||
@app.get("/") |
|
||||
def read_root(): |
|
||||
return {"Hello": "World"} |
|
||||
|
|
||||
|
|
||||
@app.get("/items/{item_id}") |
|
||||
def read_item(item_id: int): |
|
||||
return {"item_id": item_id} |
|
||||
``` |
|
||||
|
|
||||
### 📄 |
|
||||
|
|
||||
🔜, 🎏 📁 ✍ 📁 `requirements.txt` ⏮️: |
|
||||
|
|
||||
```text |
|
||||
fastapi |
|
||||
``` |
|
||||
|
|
||||
!!! tip |
|
||||
👆 🚫 💪 ❎ Uvicorn 🛠️ 🔛 🪔, 👐 👆 🔜 🎲 💚 ❎ ⚫️ 🌐 💯 👆 📱. |
|
||||
|
|
||||
### 📁 📊 |
|
||||
|
|
||||
👆 🔜 🔜 ✔️ 1️⃣ 📁 `./fastapideta/` ⏮️ 2️⃣ 📁: |
|
||||
|
|
||||
``` |
|
||||
. |
|
||||
└── main.py |
|
||||
└── requirements.txt |
|
||||
``` |
|
||||
|
|
||||
## ✍ 🆓 🪔 🏧 |
|
||||
|
|
||||
🔜 ✍ <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">🆓 🏧 🔛 🪔</a>, 👆 💪 📧 & 🔐. |
|
||||
|
|
||||
👆 🚫 💪 💳. |
|
||||
|
|
||||
## ❎ ✳ |
|
||||
|
|
||||
🕐 👆 ✔️ 👆 🏧, ❎ 🪔 <abbr title="Command Line Interface application">✳</abbr>: |
|
||||
|
|
||||
=== "💾, 🇸🇻" |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ curl -fsSL https://get.deta.dev/cli.sh | sh |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
=== "🚪 📋" |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ iwr https://get.deta.dev/cli.ps1 -useb | iex |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
⏮️ ❎ ⚫️, 📂 🆕 📶 👈 ❎ ✳ 🔍. |
|
||||
|
|
||||
🆕 📶, ✔ 👈 ⚫️ ☑ ❎ ⏮️: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta --help |
|
||||
|
|
||||
Deta command line interface for managing deta micros. |
|
||||
Complete documentation available at https://docs.deta.sh |
|
||||
|
|
||||
Usage: |
|
||||
deta [flags] |
|
||||
deta [command] |
|
||||
|
|
||||
Available Commands: |
|
||||
auth Change auth settings for a deta micro |
|
||||
|
|
||||
... |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
!!! tip |
|
||||
🚥 👆 ✔️ ⚠ ❎ ✳, ✅ <a href="https://docs.deta.sh/docs/micros/getting_started?ref=fastapi" class="external-link" target="_blank">🛂 🪔 🩺</a>. |
|
||||
|
|
||||
## 💳 ⏮️ ✳ |
|
||||
|
|
||||
🔜 💳 🪔 ⚪️➡️ ✳ ⏮️: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta login |
|
||||
|
|
||||
Please, log in from the web page. Waiting.. |
|
||||
Logged in successfully. |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
👉 🔜 📂 🕸 🖥 & 🔓 🔁. |
|
||||
|
|
||||
## 🛠️ ⏮️ 🪔 |
|
||||
|
|
||||
⏭, 🛠️ 👆 🈸 ⏮️ 🪔 ✳: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta new |
|
||||
|
|
||||
Successfully created a new micro |
|
||||
|
|
||||
// Notice the "endpoint" 🔍 |
|
||||
|
|
||||
{ |
|
||||
"name": "fastapideta", |
|
||||
"runtime": "python3.7", |
|
||||
"endpoint": "https://qltnci.deta.dev", |
|
||||
"visor": "enabled", |
|
||||
"http_auth": "enabled" |
|
||||
} |
|
||||
|
|
||||
Adding dependencies... |
|
||||
|
|
||||
|
|
||||
---> 100% |
|
||||
|
|
||||
|
|
||||
Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6 |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
👆 🔜 👀 🎻 📧 🎏: |
|
||||
|
|
||||
```JSON hl_lines="4" |
|
||||
{ |
|
||||
"name": "fastapideta", |
|
||||
"runtime": "python3.7", |
|
||||
"endpoint": "https://qltnci.deta.dev", |
|
||||
"visor": "enabled", |
|
||||
"http_auth": "enabled" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
!!! tip |
|
||||
👆 🛠️ 🔜 ✔️ 🎏 `"endpoint"` 📛. |
|
||||
|
|
||||
## ✅ ⚫️ |
|
||||
|
|
||||
🔜 📂 👆 🖥 👆 `endpoint` 📛. 🖼 🔛 ⚫️ `https://qltnci.deta.dev`, ✋️ 👆 🔜 🎏. |
|
||||
|
|
||||
👆 🔜 👀 🎻 📨 ⚪️➡️ 👆 FastAPI 📱: |
|
||||
|
|
||||
```JSON |
|
||||
{ |
|
||||
"Hello": "World" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
& 🔜 🚶 `/docs` 👆 🛠️, 🖼 🔛 ⚫️ 🔜 `https://qltnci.deta.dev/docs`. |
|
||||
|
|
||||
⚫️ 🔜 🎦 👆 🩺 💖: |
|
||||
|
|
||||
<img src="/img/deployment/deta/image01.png"> |
|
||||
|
|
||||
## 🛠️ 📢 🔐 |
|
||||
|
|
||||
🔢, 🪔 🔜 🍵 🤝 ⚙️ 🍪 👆 🏧. |
|
||||
|
|
||||
✋️ 🕐 👆 🔜, 👆 💪 ⚒ ⚫️ 📢 ⏮️: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta auth disable |
|
||||
|
|
||||
Successfully disabled http auth |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
🔜 👆 💪 💰 👈 📛 ⏮️ 🙆 & 👫 🔜 💪 🔐 👆 🛠️. 👶 |
|
||||
|
|
||||
## 🇺🇸🔍 |
|
||||
|
|
||||
㊗ ❗ 👆 🛠️ 👆 FastAPI 📱 🪔 ❗ 👶 👶 |
|
||||
|
|
||||
, 👀 👈 🪔 ☑ 🍵 🇺🇸🔍 👆, 👆 🚫 ✔️ ✊ 💅 👈 & 💪 💭 👈 👆 👩💻 🔜 ✔️ 🔐 🗜 🔗. 👶 👶 |
|
||||
|
|
||||
## ✅ 🕶 |
|
||||
|
|
||||
⚪️➡️ 👆 🩺 🎚 (👫 🔜 📛 💖 `https://qltnci.deta.dev/docs`) 📨 📨 👆 *➡ 🛠️* `/items/{item_id}`. |
|
||||
|
|
||||
🖼 ⏮️ 🆔 `5`. |
|
||||
|
|
||||
🔜 🚶 <a href="https://web.deta.sh/" class="external-link" target="_blank">https://web.deta.sh</a>. |
|
||||
|
|
||||
👆 🔜 👀 📤 📄 ◀️ 🤙 <abbr title="it comes from Micro(server)">"◾"</abbr> ⏮️ 🔠 👆 📱. |
|
||||
|
|
||||
👆 🔜 👀 📑 ⏮️ "ℹ", & 📑 "🕶", 🚶 📑 "🕶". |
|
||||
|
|
||||
📤 👆 💪 ✔ ⏮️ 📨 📨 👆 📱. |
|
||||
|
|
||||
👆 💪 ✍ 👫 & 🏤-🤾 👫. |
|
||||
|
|
||||
<img src="/img/deployment/deta/image02.png"> |
|
||||
|
|
||||
## 💡 🌅 |
|
||||
|
|
||||
☝, 👆 🔜 🎲 💚 🏪 💽 👆 📱 🌌 👈 😣 🔘 🕰. 👈 👆 💪 ⚙️ <a href="https://docs.deta.sh/docs/base/py_tutorial?ref=fastapi" class="external-link" target="_blank">🪔 🧢</a>, ⚫️ ✔️ 👍 **🆓 🎚**. |
|
||||
|
|
||||
👆 💪 ✍ 🌅 <a href="https://docs.deta.sh?ref=fastapi" class="external-link" target="_blank">🪔 🩺</a>. |
|
||||
|
|
||||
## 🛠️ 🔧 |
|
||||
|
|
||||
👟 🔙 🔧 👥 🔬 [🛠️ 🔧](./concepts.md){.internal-link target=_blank}, 📥 ❔ 🔠 👫 🔜 🍵 ⏮️ 🪔: |
|
||||
|
|
||||
* **🇺🇸🔍**: 🍵 🪔, 👫 🔜 🤝 👆 📁 & 🍵 🇺🇸🔍 🔁. |
|
||||
* **🏃♂ 🔛 🕴**: 🍵 🪔, 🍕 👫 🐕🦺. |
|
||||
* **⏏**: 🍵 🪔, 🍕 👫 🐕🦺. |
|
||||
* **🧬**: 🍵 🪔, 🍕 👫 🐕🦺. |
|
||||
* **💾**: 📉 🔁 🪔, 👆 💪 📧 👫 📈 ⚫️. |
|
||||
* **⏮️ 🔁 ⏭ ▶️**: 🚫 🔗 🐕🦺, 👆 💪 ⚒ ⚫️ 👷 ⏮️ 👫 💾 ⚙️ ⚖️ 🌖 ✍. |
|
||||
|
|
||||
!!! note |
|
||||
🪔 🔧 ⚒ ⚫️ ⏩ (& 🆓) 🛠️ 🙅 🈸 🔜. |
|
||||
|
|
||||
⚫️ 💪 📉 📚 ⚙️ 💼, ✋️ 🎏 🕰, ⚫️ 🚫 🐕🦺 🎏, 💖 ⚙️ 🔢 💽 (↖️ ⚪️➡️ 🪔 👍 ☁ 💽 ⚙️), 🛃 🕹 🎰, ♒️. |
|
||||
|
|
||||
👆 💪 ✍ 🌅 ℹ <a href="https://docs.deta.sh/docs/micros/about/" class="external-link" target="_blank">🪔 🩺</a> 👀 🚥 ⚫️ ▶️️ ⚒ 👆. |
|
@ -0,0 +1,90 @@ |
|||||
|
# ↔ 🗄 |
||||
|
|
||||
|
!!! warning |
||||
|
👉 👍 🏧 ⚒. 👆 🎲 💪 🚶 ⚫️. |
||||
|
|
||||
|
🚥 👆 📄 🔰 - 👩💻 🦮, 👆 💪 🎲 🚶 👉 📄. |
||||
|
|
||||
|
🚥 👆 ⏪ 💭 👈 👆 💪 🔀 🏗 🗄 🔗, 😣 👂. |
||||
|
|
||||
|
📤 💼 🌐❔ 👆 💪 💪 🔀 🏗 🗄 🔗. |
||||
|
|
||||
|
👉 📄 👆 🔜 👀 ❔. |
||||
|
|
||||
|
## 😐 🛠️ |
||||
|
|
||||
|
😐 (🔢) 🛠️, ⏩. |
||||
|
|
||||
|
`FastAPI` 🈸 (👐) ✔️ `.openapi()` 👩🔬 👈 📈 📨 🗄 🔗. |
||||
|
|
||||
|
🍕 🈸 🎚 🏗, *➡ 🛠️* `/openapi.json` (⚖️ ⚫️❔ 👆 ⚒ 👆 `openapi_url`) ®. |
||||
|
|
||||
|
⚫️ 📨 🎻 📨 ⏮️ 🏁 🈸 `.openapi()` 👩🔬. |
||||
|
|
||||
|
🔢, ⚫️❔ 👩🔬 `.openapi()` 🔨 ✅ 🏠 `.openapi_schema` 👀 🚥 ⚫️ ✔️ 🎚 & 📨 👫. |
||||
|
|
||||
|
🚥 ⚫️ 🚫, ⚫️ 🏗 👫 ⚙️ 🚙 🔢 `fastapi.openapi.utils.get_openapi`. |
||||
|
|
||||
|
& 👈 🔢 `get_openapi()` 📨 🔢: |
||||
|
|
||||
|
* `title`: 🗄 📛, 🎦 🩺. |
||||
|
* `version`: ⏬ 👆 🛠️, ✅ `2.5.0`. |
||||
|
* `openapi_version`: ⏬ 🗄 🔧 ⚙️. 🔢, ⏪: `3.0.2`. |
||||
|
* `description`: 📛 👆 🛠️. |
||||
|
* `routes`: 📇 🛣, 👫 🔠 ® *➡ 🛠️*. 👫 ✊ ⚪️➡️ `app.routes`. |
||||
|
|
||||
|
## 🔑 🔢 |
||||
|
|
||||
|
⚙️ ℹ 🔛, 👆 💪 ⚙️ 🎏 🚙 🔢 🏗 🗄 🔗 & 🔐 🔠 🍕 👈 👆 💪. |
||||
|
|
||||
|
🖼, ➡️ 🚮 <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">📄 🗄 ↔ 🔌 🛃 🔱</a>. |
||||
|
|
||||
|
### 😐 **FastAPI** |
||||
|
|
||||
|
🥇, ✍ 🌐 👆 **FastAPI** 🈸 🛎: |
||||
|
|
||||
|
```Python hl_lines="1 4 7-9" |
||||
|
{!../../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### 🏗 🗄 🔗 |
||||
|
|
||||
|
⤴️, ⚙️ 🎏 🚙 🔢 🏗 🗄 🔗, 🔘 `custom_openapi()` 🔢: |
||||
|
|
||||
|
```Python hl_lines="2 15-20" |
||||
|
{!../../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### 🔀 🗄 🔗 |
||||
|
|
||||
|
🔜 👆 💪 🚮 📄 ↔, ❎ 🛃 `x-logo` `info` "🎚" 🗄 🔗: |
||||
|
|
||||
|
```Python hl_lines="21-23" |
||||
|
{!../../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### 💾 🗄 🔗 |
||||
|
|
||||
|
👆 💪 ⚙️ 🏠 `.openapi_schema` "💾", 🏪 👆 🏗 🔗. |
||||
|
|
||||
|
👈 🌌, 👆 🈸 🏆 🚫 ✔️ 🏗 🔗 🔠 🕰 👩💻 📂 👆 🛠️ 🩺. |
||||
|
|
||||
|
⚫️ 🔜 🏗 🕴 🕐, & ⤴️ 🎏 💾 🔗 🔜 ⚙️ ⏭ 📨. |
||||
|
|
||||
|
```Python hl_lines="13-14 24-25" |
||||
|
{!../../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### 🔐 👩🔬 |
||||
|
|
||||
|
🔜 👆 💪 ❎ `.openapi()` 👩🔬 ⏮️ 👆 🆕 🔢. |
||||
|
|
||||
|
```Python hl_lines="28" |
||||
|
{!../../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### ✅ ⚫️ |
||||
|
|
||||
|
🕐 👆 🚶 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> 👆 🔜 👀 👈 👆 ⚙️ 👆 🛃 🔱 (👉 🖼, **FastAPI**'Ⓜ 🔱): |
||||
|
|
||||
|
<img src="/img/tutorial/extending-openapi/image01.png"> |
@ -1,318 +0,0 @@ |
|||||
# Extending OpenAPI |
|
||||
|
|
||||
!!! warning |
|
||||
This is a rather advanced feature. You probably can skip it. |
|
||||
|
|
||||
If you are just following the tutorial - user guide, you can probably skip this section. |
|
||||
|
|
||||
If you already know that you need to modify the generated OpenAPI schema, continue reading. |
|
||||
|
|
||||
There are some cases where you might need to modify the generated OpenAPI schema. |
|
||||
|
|
||||
In this section you will see how. |
|
||||
|
|
||||
## The normal process |
|
||||
|
|
||||
The normal (default) process, is as follows. |
|
||||
|
|
||||
A `FastAPI` application (instance) has an `.openapi()` method that is expected to return the OpenAPI schema. |
|
||||
|
|
||||
As part of the application object creation, a *path operation* for `/openapi.json` (or for whatever you set your `openapi_url`) is registered. |
|
||||
|
|
||||
It just returns a JSON response with the result of the application's `.openapi()` method. |
|
||||
|
|
||||
By default, what the method `.openapi()` does is check the property `.openapi_schema` to see if it has contents and return them. |
|
||||
|
|
||||
If it doesn't, it generates them using the utility function at `fastapi.openapi.utils.get_openapi`. |
|
||||
|
|
||||
And that function `get_openapi()` receives as parameters: |
|
||||
|
|
||||
* `title`: The OpenAPI title, shown in the docs. |
|
||||
* `version`: The version of your API, e.g. `2.5.0`. |
|
||||
* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.1.0`. |
|
||||
* `summary`: A short summary of the API. |
|
||||
* `description`: The description of your API, this can include markdown and will be shown in the docs. |
|
||||
* `routes`: A list of routes, these are each of the registered *path operations*. They are taken from `app.routes`. |
|
||||
|
|
||||
!!! info |
|
||||
The parameter `summary` is available in OpenAPI 3.1.0 and above, supported by FastAPI 0.99.0 and above. |
|
||||
|
|
||||
## Overriding the defaults |
|
||||
|
|
||||
Using the information above, you can use the same utility function to generate the OpenAPI schema and override each part that you need. |
|
||||
|
|
||||
For example, let's add <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">ReDoc's OpenAPI extension to include a custom logo</a>. |
|
||||
|
|
||||
### Normal **FastAPI** |
|
||||
|
|
||||
First, write all your **FastAPI** application as normally: |
|
||||
|
|
||||
```Python hl_lines="1 4 7-9" |
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!} |
|
||||
``` |
|
||||
|
|
||||
### Generate the OpenAPI schema |
|
||||
|
|
||||
Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function: |
|
||||
|
|
||||
```Python hl_lines="2 15-21" |
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!} |
|
||||
``` |
|
||||
|
|
||||
### Modify the OpenAPI schema |
|
||||
|
|
||||
Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema: |
|
||||
|
|
||||
```Python hl_lines="22-24" |
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!} |
|
||||
``` |
|
||||
|
|
||||
### Cache the OpenAPI schema |
|
||||
|
|
||||
You can use the property `.openapi_schema` as a "cache", to store your generated schema. |
|
||||
|
|
||||
That way, your application won't have to generate the schema every time a user opens your API docs. |
|
||||
|
|
||||
It will be generated only once, and then the same cached schema will be used for the next requests. |
|
||||
|
|
||||
```Python hl_lines="13-14 25-26" |
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!} |
|
||||
``` |
|
||||
|
|
||||
### Override the method |
|
||||
|
|
||||
Now you can replace the `.openapi()` method with your new function. |
|
||||
|
|
||||
```Python hl_lines="29" |
|
||||
{!../../../docs_src/extending_openapi/tutorial001.py!} |
|
||||
``` |
|
||||
|
|
||||
### Check it |
|
||||
|
|
||||
Once you go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> you will see that you are using your custom logo (in this example, **FastAPI**'s logo): |
|
||||
|
|
||||
<img src="/img/tutorial/extending-openapi/image01.png"> |
|
||||
|
|
||||
## Self-hosting JavaScript and CSS for docs |
|
||||
|
|
||||
The API docs use **Swagger UI** and **ReDoc**, and each of those need some JavaScript and CSS files. |
|
||||
|
|
||||
By default, those files are served from a <abbr title="Content Delivery Network: A service, normally composed of several servers, that provides static files, like JavaScript and CSS. It's commonly used to serve those files from the server closer to the client, improving performance.">CDN</abbr>. |
|
||||
|
|
||||
But it's possible to customize it, you can set a specific CDN, or serve the files yourself. |
|
||||
|
|
||||
That's useful, for example, if you need your app to keep working even while offline, without open Internet access, or in a local network. |
|
||||
|
|
||||
Here you'll see how to serve those files yourself, in the same FastAPI app, and configure the docs to use them. |
|
||||
|
|
||||
### Project file structure |
|
||||
|
|
||||
Let's say your project file structure looks like this: |
|
||||
|
|
||||
``` |
|
||||
. |
|
||||
├── app |
|
||||
│ ├── __init__.py |
|
||||
│ ├── main.py |
|
||||
``` |
|
||||
|
|
||||
Now create a directory to store those static files. |
|
||||
|
|
||||
Your new file structure could look like this: |
|
||||
|
|
||||
``` |
|
||||
. |
|
||||
├── app |
|
||||
│ ├── __init__.py |
|
||||
│ ├── main.py |
|
||||
└── static/ |
|
||||
``` |
|
||||
|
|
||||
### Download the files |
|
||||
|
|
||||
Download the static files needed for the docs and put them on that `static/` directory. |
|
||||
|
|
||||
You can probably right-click each link and select an option similar to `Save link as...`. |
|
||||
|
|
||||
**Swagger UI** uses the files: |
|
||||
|
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a> |
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a> |
|
||||
|
|
||||
And **ReDoc** uses the file: |
|
||||
|
|
||||
* <a href="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js" class="external-link" target="_blank">`redoc.standalone.js`</a> |
|
||||
|
|
||||
After that, your file structure could look like: |
|
||||
|
|
||||
``` |
|
||||
. |
|
||||
├── app |
|
||||
│ ├── __init__.py |
|
||||
│ ├── main.py |
|
||||
└── static |
|
||||
├── redoc.standalone.js |
|
||||
├── swagger-ui-bundle.js |
|
||||
└── swagger-ui.css |
|
||||
``` |
|
||||
|
|
||||
### Serve the static files |
|
||||
|
|
||||
* Import `StaticFiles`. |
|
||||
* "Mount" a `StaticFiles()` instance in a specific path. |
|
||||
|
|
||||
```Python hl_lines="7 11" |
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!} |
|
||||
``` |
|
||||
|
|
||||
### Test the static files |
|
||||
|
|
||||
Start your application and go to <a href="http://127.0.0.1:8000/static/redoc.standalone.js" class="external-link" target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a>. |
|
||||
|
|
||||
You should see a very long JavaScript file for **ReDoc**. |
|
||||
|
|
||||
It could start with something like: |
|
||||
|
|
||||
```JavaScript |
|
||||
/*! |
|
||||
* ReDoc - OpenAPI/Swagger-generated API Reference Documentation |
|
||||
* ------------------------------------------------------------- |
|
||||
* Version: "2.0.0-rc.18" |
|
||||
* Repo: https://github.com/Redocly/redoc |
|
||||
*/ |
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof m |
|
||||
|
|
||||
... |
|
||||
``` |
|
||||
|
|
||||
That confirms that you are being able to serve static files from your app, and that you placed the static files for the docs in the correct place. |
|
||||
|
|
||||
Now we can configure the app to use those static files for the docs. |
|
||||
|
|
||||
### Disable the automatic docs |
|
||||
|
|
||||
The first step is to disable the automatic docs, as those use the CDN by default. |
|
||||
|
|
||||
To disable them, set their URLs to `None` when creating your `FastAPI` app: |
|
||||
|
|
||||
```Python hl_lines="9" |
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!} |
|
||||
``` |
|
||||
|
|
||||
### Include the custom docs |
|
||||
|
|
||||
Now you can create the *path operations* for the custom docs. |
|
||||
|
|
||||
You can re-use FastAPI's internal functions to create the HTML pages for the docs, and pass them the needed arguments: |
|
||||
|
|
||||
* `openapi_url`: the URL where the HTML page for the docs can get the OpenAPI schema for your API. You can use here the attribute `app.openapi_url`. |
|
||||
* `title`: the title of your API. |
|
||||
* `oauth2_redirect_url`: you can use `app.swagger_ui_oauth2_redirect_url` here to use the default. |
|
||||
* `swagger_js_url`: the URL where the HTML for your Swagger UI docs can get the **JavaScript** file. This is the one that your own app is now serving. |
|
||||
* `swagger_css_url`: the URL where the HTML for your Swagger UI docs can get the **CSS** file. This is the one that your own app is now serving. |
|
||||
|
|
||||
And similarly for ReDoc... |
|
||||
|
|
||||
```Python hl_lines="2-6 14-22 25-27 30-36" |
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!} |
|
||||
``` |
|
||||
|
|
||||
!!! tip |
|
||||
The *path operation* for `swagger_ui_redirect` is a helper for when you use OAuth2. |
|
||||
|
|
||||
If you integrate your API with an OAuth2 provider, you will be able to authenticate and come back to the API docs with the acquired credentials. And interact with it using the real OAuth2 authentication. |
|
||||
|
|
||||
Swagger UI will handle it behind the scenes for you, but it needs this "redirect" helper. |
|
||||
|
|
||||
### Create a *path operation* to test it |
|
||||
|
|
||||
Now, to be able to test that everything works, create a *path operation*: |
|
||||
|
|
||||
```Python hl_lines="39-41" |
|
||||
{!../../../docs_src/extending_openapi/tutorial002.py!} |
|
||||
``` |
|
||||
|
|
||||
### Test it |
|
||||
|
|
||||
Now, you should be able to disconnect your WiFi, go to your docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, and reload the page. |
|
||||
|
|
||||
And even without Internet, you would be able to see the docs for your API and interact with it. |
|
||||
|
|
||||
## Configuring Swagger UI |
|
||||
|
|
||||
You can configure some extra <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">Swagger UI parameters</a>. |
|
||||
|
|
||||
To configure them, pass the `swagger_ui_parameters` argument when creating the `FastAPI()` app object or to the `get_swagger_ui_html()` function. |
|
||||
|
|
||||
`swagger_ui_parameters` receives a dictionary with the configurations passed to Swagger UI directly. |
|
||||
|
|
||||
FastAPI converts the configurations to **JSON** to make them compatible with JavaScript, as that's what Swagger UI needs. |
|
||||
|
|
||||
### Disable Syntax Highlighting |
|
||||
|
|
||||
For example, you could disable syntax highlighting in Swagger UI. |
|
||||
|
|
||||
Without changing the settings, syntax highlighting is enabled by default: |
|
||||
|
|
||||
<img src="/img/tutorial/extending-openapi/image02.png"> |
|
||||
|
|
||||
But you can disable it by setting `syntaxHighlight` to `False`: |
|
||||
|
|
||||
```Python hl_lines="3" |
|
||||
{!../../../docs_src/extending_openapi/tutorial003.py!} |
|
||||
``` |
|
||||
|
|
||||
...and then Swagger UI won't show the syntax highlighting anymore: |
|
||||
|
|
||||
<img src="/img/tutorial/extending-openapi/image03.png"> |
|
||||
|
|
||||
### Change the Theme |
|
||||
|
|
||||
The same way you could set the syntax highlighting theme with the key `"syntaxHighlight.theme"` (notice that it has a dot in the middle): |
|
||||
|
|
||||
```Python hl_lines="3" |
|
||||
{!../../../docs_src/extending_openapi/tutorial004.py!} |
|
||||
``` |
|
||||
|
|
||||
That configuration would change the syntax highlighting color theme: |
|
||||
|
|
||||
<img src="/img/tutorial/extending-openapi/image04.png"> |
|
||||
|
|
||||
### Change Default Swagger UI Parameters |
|
||||
|
|
||||
FastAPI includes some default configuration parameters appropriate for most of the use cases. |
|
||||
|
|
||||
It includes these default configurations: |
|
||||
|
|
||||
```Python |
|
||||
{!../../../fastapi/openapi/docs.py[ln:7-13]!} |
|
||||
``` |
|
||||
|
|
||||
You can override any of them by setting a different value in the argument `swagger_ui_parameters`. |
|
||||
|
|
||||
For example, to disable `deepLinking` you could pass these settings to `swagger_ui_parameters`: |
|
||||
|
|
||||
```Python hl_lines="3" |
|
||||
{!../../../docs_src/extending_openapi/tutorial005.py!} |
|
||||
``` |
|
||||
|
|
||||
### Other Swagger UI Parameters |
|
||||
|
|
||||
To see all the other possible configurations you can use, read the official <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">docs for Swagger UI parameters</a>. |
|
||||
|
|
||||
### JavaScript-only settings |
|
||||
|
|
||||
Swagger UI also allows other configurations to be **JavaScript-only** objects (for example, JavaScript functions). |
|
||||
|
|
||||
FastAPI also includes these JavaScript-only `presets` settings: |
|
||||
|
|
||||
```JavaScript |
|
||||
presets: [ |
|
||||
SwaggerUIBundle.presets.apis, |
|
||||
SwaggerUIBundle.SwaggerUIStandalonePreset |
|
||||
] |
|
||||
``` |
|
||||
|
|
||||
These are **JavaScript** objects, not strings, so you can't pass them from Python code directly. |
|
||||
|
|
||||
If you need to use JavaScript-only configurations like those, you can use one of the methods above. Override all the Swagger UI *path operation* and manually write any JavaScript you need. |
|
@ -0,0 +1,17 @@ |
|||||
|
# Deploy FastAPI on Cloud Providers |
||||
|
|
||||
|
You can use virtually **any cloud provider** to deploy your FastAPI application. |
||||
|
|
||||
|
In most of the cases, the main cloud providers have guides to deploy FastAPI with them. |
||||
|
|
||||
|
## Cloud Providers - Sponsors |
||||
|
|
||||
|
Some cloud providers ✨ [**sponsor FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, this ensures the continued and healthy **development** of FastAPI and its **ecosystem**. |
||||
|
|
||||
|
And it shows their true commitment to FastAPI and its **community** (you), as they not only want to provide you a **good service** but also want to make sure you have a **good and healthy framework**, FastAPI. 🙇 |
||||
|
|
||||
|
You might want to try their services and follow their guides: |
||||
|
|
||||
|
* <a href="https://docs.platform.sh/languages/python.html?utm_source=fastapi-signup&utm_medium=banner&utm_campaign=FastAPI-signup-June-2023" class="external-link" target="_blank">Platform.sh</a> |
||||
|
* <a href="https://docs.porter.run/language-specific-guides/fastapi" class="external-link" target="_blank">Porter</a> |
||||
|
* <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> |
@ -1,391 +0,0 @@ |
|||||
# Deploy FastAPI on Deta Space |
|
||||
|
|
||||
In this section you will learn how to easily deploy a **FastAPI** application on <a href="https://deta.space?ref=fastapi" class="external-link" target="_blank">Deta Space</a>, for free. 🎁 |
|
||||
|
|
||||
It will take you about **10 minutes** to deploy an API that you can use. After that, you can optionally release it to anyone. |
|
||||
|
|
||||
Let's dive in. |
|
||||
|
|
||||
!!! info |
|
||||
<a href="https://deta.space?ref=fastapi" class="external-link" target="_blank">Deta</a> is a **FastAPI** sponsor. 🎉 |
|
||||
|
|
||||
## A simple **FastAPI** app |
|
||||
|
|
||||
* To start, create an empty directory with the name of your app, for example `./fastapi-deta/`, and then navigate into it. |
|
||||
|
|
||||
```console |
|
||||
$ mkdir fastapi-deta |
|
||||
$ cd fastapi-deta |
|
||||
``` |
|
||||
|
|
||||
### FastAPI code |
|
||||
|
|
||||
* Create a `main.py` file with: |
|
||||
|
|
||||
```Python |
|
||||
from fastapi import FastAPI |
|
||||
|
|
||||
app = FastAPI() |
|
||||
|
|
||||
|
|
||||
@app.get("/") |
|
||||
def read_root(): |
|
||||
return {"Hello": "World"} |
|
||||
|
|
||||
|
|
||||
@app.get("/items/{item_id}") |
|
||||
def read_item(item_id: int): |
|
||||
return {"item_id": item_id} |
|
||||
``` |
|
||||
|
|
||||
### Requirements |
|
||||
|
|
||||
Now, in the same directory create a file `requirements.txt` with: |
|
||||
|
|
||||
```text |
|
||||
fastapi |
|
||||
uvicorn[standard] |
|
||||
``` |
|
||||
|
|
||||
### Directory structure |
|
||||
|
|
||||
You will now have a directory `./fastapi-deta/` with two files: |
|
||||
|
|
||||
``` |
|
||||
. |
|
||||
└── main.py |
|
||||
└── requirements.txt |
|
||||
``` |
|
||||
|
|
||||
## Create a free **Deta Space** account |
|
||||
|
|
||||
Next, create a free account on <a href="https://deta.space/signup?dev_mode=true&ref=fastapi" class="external-link" target="_blank">Deta Space</a>, you just need an email and password. |
|
||||
|
|
||||
You don't even need a credit card, but make sure **Developer Mode** is enabled when you sign up. |
|
||||
|
|
||||
|
|
||||
## Install the CLI |
|
||||
|
|
||||
Once you have your account, install the Deta Space <abbr title="Command Line Interface application">CLI</abbr>: |
|
||||
|
|
||||
=== "Linux, macOS" |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ curl -fsSL https://get.deta.dev/space-cli.sh | sh |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
=== "Windows PowerShell" |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ iwr https://get.deta.dev/space-cli.ps1 -useb | iex |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
After installing it, open a new terminal so that the installed CLI is detected. |
|
||||
|
|
||||
In a new terminal, confirm that it was correctly installed with: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ space --help |
|
||||
|
|
||||
Deta command line interface for managing deta micros. |
|
||||
Complete documentation available at https://deta.space/docs |
|
||||
|
|
||||
Usage: |
|
||||
space [flags] |
|
||||
space [command] |
|
||||
|
|
||||
Available Commands: |
|
||||
help Help about any command |
|
||||
link link code to project |
|
||||
login login to space |
|
||||
new create new project |
|
||||
push push code for project |
|
||||
release create release for a project |
|
||||
validate validate spacefile in dir |
|
||||
version Space CLI version |
|
||||
... |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
!!! tip |
|
||||
If you have problems installing the CLI, check the official <a href="https://deta.space/docs/en/basics/cli?ref=fastapi" class="external-link" target="_blank">Deta Space Documentation</a>. |
|
||||
|
|
||||
## Login with the CLI |
|
||||
|
|
||||
In order to authenticate your CLI with Deta Space, you will need an access token. |
|
||||
|
|
||||
To obtain this token, open your <a href="https://deta.space/login?ref=fastapi" class="external-link" target="_blank">Deta Space Canvas</a>, open the **Teletype** (command bar at the bottom of the Canvas), and then click on **Settings**. From there, select **Generate Token** and copy the resulting token. |
|
||||
|
|
||||
<img src="/img/deployment/deta/image03.png"> |
|
||||
|
|
||||
Now run `space login` from the Space CLI. Upon pasting the token into the CLI prompt and pressing enter, you should see a confirmation message. |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ space login |
|
||||
|
|
||||
To authenticate the Space CLI with your Space account, generate a new access token in your Space settings and paste it below: |
|
||||
|
|
||||
# Enter access token (41 chars) >$ ***************************************** |
|
||||
|
|
||||
👍 Login Successful! |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
## Create a new project in Space |
|
||||
|
|
||||
Now that you've authenticated with the Space CLI, use it to create a new <a href="https://deta.space/docs/en/basics/projects" class="external-link" target="_blank">Space Project</a>: |
|
||||
|
|
||||
```console |
|
||||
$ space new |
|
||||
|
|
||||
# What is your project's name? >$ fastapi-deta |
|
||||
``` |
|
||||
|
|
||||
The Space CLI will ask you to name the project, we will call ours `fastapi-deta`. |
|
||||
|
|
||||
Then, it will try to automatically detect which framework or language you are using, showing you what it finds. In our case it will identify the Python app with the following message, prompting you to confirm: |
|
||||
|
|
||||
```console |
|
||||
⚙️ No Spacefile found, trying to auto-detect configuration ... |
|
||||
👇 Deta detected the following configuration: |
|
||||
|
|
||||
Micros: |
|
||||
name: fastapi-deta |
|
||||
L src: . |
|
||||
L engine: python3.9 |
|
||||
|
|
||||
# Do you want to bootstrap "fastapi-deta" with this configuration? (y/n)$ y |
|
||||
``` |
|
||||
|
|
||||
After you confirm, your project will be created in Deta Space inside a special app called <a href="https://deta.space/docs/en/basics/projects#projects-in-builder?ref=fastapi" class="external-link" target="_blank">Builder</a>. Builder is a toolbox that helps you to create and manage your apps in Deta Space. |
|
||||
|
|
||||
The CLI will also create a `Spacefile` locally in the `fastapi-deta` directory. The <a href="https://deta.space/docs/en/reference/spacefile?ref=fastapi" class="external-link" target="_blank">Spacefile</a> is a configuration file which tells Deta Space how to run your app. The `Spacefile` for your app will be as follows: |
|
||||
|
|
||||
```yaml |
|
||||
v: 0 |
|
||||
micros: |
|
||||
- name: fastapi-deta |
|
||||
src: . |
|
||||
engine: python3.9 |
|
||||
``` |
|
||||
|
|
||||
It is a `yaml` file, and you can use it to add features like scheduled tasks or modify how your app functions, which we'll do later. To learn more, read <a href="https://deta.space/docs/en/reference/spacefile" class="external-link" target="_blank">the `Spacefile` documentation</a>. |
|
||||
|
|
||||
!!! tip |
|
||||
The Space CLI will also create a hidden `.space` folder in your local directory to link your local environment with Deta Space. This folder should not be included in your version control and will automatically be added to your `.gitignore` file, if you have initialized a Git repository. |
|
||||
|
|
||||
## Define the run command in the Spacefile |
|
||||
|
|
||||
The `run` command in the Spacefile tells Space what command should be executed to start your app. In this case it would be `uvicorn main:app`. |
|
||||
|
|
||||
```diff |
|
||||
v: 0 |
|
||||
micros: |
|
||||
- name: fastapi-deta |
|
||||
src: . |
|
||||
engine: python3.9 |
|
||||
+ run: uvicorn main:app |
|
||||
``` |
|
||||
|
|
||||
## Deploy to Deta Space |
|
||||
|
|
||||
To get your FastAPI live in the cloud, use one more CLI command: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ space push |
|
||||
|
|
||||
---> 100% |
|
||||
|
|
||||
build complete... created revision: satyr-jvjk |
|
||||
|
|
||||
✔ Successfully pushed your code and created a new Revision! |
|
||||
ℹ Updating your development instance with the latest Revision, it will be available on your Canvas shortly. |
|
||||
``` |
|
||||
</div> |
|
||||
|
|
||||
This command will package your code, upload all the necessary files to Deta Space, and run a remote build of your app, resulting in a **revision**. Whenever you run `space push` successfully, a live instance of your API is automatically updated with the latest revision. |
|
||||
|
|
||||
!!! tip |
|
||||
You can manage your <a href="https://deta.space/docs/en/basics/revisions#whats-a-revision" class="external-link" target="_blank">revisions</a> by opening your project in the Builder app. The live copy of your API will be visible under the **Develop** tab in Builder. |
|
||||
|
|
||||
## Check it |
|
||||
|
|
||||
The live instance of your API will also be added automatically to your Canvas (the dashboard) on Deta Space. |
|
||||
|
|
||||
<img src="/img/deployment/deta/image04.png"> |
|
||||
|
|
||||
Click on the new app called `fastapi-deta`, and it will open your API in a new browser tab on a URL like `https://fastapi-deta-gj7ka8.deta.app/`. |
|
||||
|
|
||||
You will get a JSON response from your FastAPI app: |
|
||||
|
|
||||
```JSON |
|
||||
{ |
|
||||
"Hello": "World" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
And now you can head over to the `/docs` of your API. For this example, it would be `https://fastapi-deta-gj7ka8.deta.app/docs`. |
|
||||
|
|
||||
<img src="/img/deployment/deta/image05.png"> |
|
||||
|
|
||||
## Enable public access |
|
||||
|
|
||||
Deta will handle authentication for your account using cookies. By default, every app or API that you `push` or install to your Space is personal - it's only accessible to you. |
|
||||
|
|
||||
But you can also make your API public using the `Spacefile` from earlier. |
|
||||
|
|
||||
With a `public_routes` parameter, you can specify which paths of your API should be available to the public. |
|
||||
|
|
||||
Set your `public_routes` to `"*"` to open every route of your API to the public: |
|
||||
|
|
||||
```yaml |
|
||||
v: 0 |
|
||||
micros: |
|
||||
- name: fastapi-deta |
|
||||
src: . |
|
||||
engine: python3.9 |
|
||||
public_routes: |
|
||||
- "/*" |
|
||||
``` |
|
||||
|
|
||||
Then run `space push` again to update your live API on Deta Space. |
|
||||
|
|
||||
Once it deploys, you can share your URL with anyone and they will be able to access your API. 🚀 |
|
||||
|
|
||||
## HTTPS |
|
||||
|
|
||||
Congrats! You deployed your FastAPI app to Deta Space! 🎉 🍰 |
|
||||
|
|
||||
Also, notice that Deta Space correctly handles HTTPS for you, so you don't have to take care of that and can be sure that your users will have a secure encrypted connection. ✅ 🔒 |
|
||||
|
|
||||
## Create a release |
|
||||
|
|
||||
Space also allows you to publish your API. When you publish it, anyone else can install their own copy of your API, in their own Deta Space cloud. |
|
||||
|
|
||||
To do so, run `space release` in the Space CLI to create an **unlisted release**: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ space release |
|
||||
|
|
||||
# Do you want to use the latest revision (buzzard-hczt)? (y/n)$ y |
|
||||
|
|
||||
~ Creating a Release with the latest Revision |
|
||||
|
|
||||
---> 100% |
|
||||
|
|
||||
creating release... |
|
||||
publishing release in edge locations.. |
|
||||
completed... |
|
||||
released: fastapi-deta-exp-msbu |
|
||||
https://deta.space/discovery/r/5kjhgyxewkdmtotx |
|
||||
|
|
||||
Lift off -- successfully created a new Release! |
|
||||
Your Release is available globally on 5 Deta Edges |
|
||||
Anyone can install their own copy of your app. |
|
||||
``` |
|
||||
</div> |
|
||||
|
|
||||
This command publishes your revision as a release and gives you a link. Anyone you give this link to can install your API. |
|
||||
|
|
||||
|
|
||||
You can also make your app publicly discoverable by creating a **listed release** with `space release --listed` in the Space CLI: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ space release --listed |
|
||||
|
|
||||
# Do you want to use the latest revision (buzzard-hczt)? (y/n)$ y |
|
||||
|
|
||||
~ Creating a listed Release with the latest Revision ... |
|
||||
|
|
||||
creating release... |
|
||||
publishing release in edge locations.. |
|
||||
completed... |
|
||||
released: fastapi-deta-exp-msbu |
|
||||
https://deta.space/discovery/@user/fastapi-deta |
|
||||
|
|
||||
Lift off -- successfully created a new Release! |
|
||||
Your Release is available globally on 5 Deta Edges |
|
||||
Anyone can install their own copy of your app. |
|
||||
Listed on Discovery for others to find! |
|
||||
``` |
|
||||
</div> |
|
||||
|
|
||||
This will allow anyone to find and install your app via <a href="https://deta.space/discovery?ref=fastapi" class="external-link" target="_blank">Deta Discovery</a>. Read more about <a href="https://deta.space/docs/en/basics/releases?ref=fastapi" class="external-link" target="_blank">releasing your app in the docs</a>. |
|
||||
|
|
||||
## Check runtime logs |
|
||||
|
|
||||
Deta Space also lets you inspect the logs of every app you build or install. |
|
||||
|
|
||||
Add some logging functionality to your app by adding a `print` statement to your `main.py` file. |
|
||||
|
|
||||
```py |
|
||||
from fastapi import FastAPI |
|
||||
|
|
||||
app = FastAPI() |
|
||||
|
|
||||
|
|
||||
@app.get("/") |
|
||||
def read_root(): |
|
||||
return {"Hello": "World"} |
|
||||
|
|
||||
|
|
||||
@app.get("/items/{item_id}") |
|
||||
def read_item(item_id: int): |
|
||||
print(item_id) |
|
||||
return {"item_id": item_id} |
|
||||
``` |
|
||||
|
|
||||
The code within the `read_item` function includes a print statement that will output the `item_id` that is included in the URL. Send a request to your _path operation_ `/items/{item_id}` from the docs UI (which will have a URL like `https://fastapi-deta-gj7ka8.deta.app/docs`), using an ID like `5` as an example. |
|
||||
|
|
||||
Now go to your <a href="https://deta.space?ref=fastapi" class="external-link" target="_blank">Space's Canvas</a>. Click on the context menu (`...`) of your live app instance, and then click on **View Logs**. Here you can view your app's logs, sorted by time. |
|
||||
|
|
||||
<img src="/img/deployment/deta/image06.png"> |
|
||||
|
|
||||
## Learn more |
|
||||
|
|
||||
At some point, you will probably want to store some data for your app in a way that persists through time. For that you can use <a href="https://deta.space/docs/en/basics/data#deta-base?ref=fastapi" class="external-link" target="_blank">Deta Base</a> and <a href="https://deta.space/docs/en/basics/data#deta-drive?ref=fastapi" class="external-link" target="_blank">Deta Drive</a>, both of which have a generous **free tier**. |
|
||||
|
|
||||
You can also read more in the <a href="https://deta.space/docs/?ref=fastapi" class="external-link" target="_blank">Deta Space Documentation</a>. |
|
||||
|
|
||||
!!! tip |
|
||||
If you have any Deta related questions, comments, or feedback, head to the <a href="https://go.deta.dev/discord" class="external-link" target="_blank">Deta Discord server</a>. |
|
||||
|
|
||||
|
|
||||
## Deployment Concepts |
|
||||
|
|
||||
Coming back to the concepts we discussed in [Deployments Concepts](./concepts.md){.internal-link target=_blank}, here's how each of them would be handled with Deta Space: |
|
||||
|
|
||||
- **HTTPS**: Handled by Deta Space, they will give you a subdomain and handle HTTPS automatically. |
|
||||
- **Running on startup**: Handled by Deta Space, as part of their service. |
|
||||
- **Restarts**: Handled by Deta Space, as part of their service. |
|
||||
- **Replication**: Handled by Deta Space, as part of their service. |
|
||||
- **Authentication**: Handled by Deta Space, as part of their service. |
|
||||
- **Memory**: Limit predefined by Deta Space, you could contact them to increase it. |
|
||||
- **Previous steps before starting**: Can be configured using the <a href="https://deta.space/docs/en/reference/spacefile?ref=fastapi" class="external-link" target="_blank">`Spacefile`</a>. |
|
||||
|
|
||||
!!! note |
|
||||
Deta Space is designed to make it easy and free to build cloud applications for yourself. Then you can optionally share them with anyone. |
|
||||
|
|
||||
It can simplify several use cases, but at the same time, it doesn't support others, like using external databases (apart from Deta's own NoSQL database system), custom virtual machines, etc. |
|
||||
|
|
||||
You can read more details in the <a href="https://deta.space/docs/en/basics/micros?ref=fastapi" class="external-link" target="_blank">Deta Space Documentation</a> to see if it's the right choice for you. |
|
@ -1,4 +1,4 @@ |
|||||
# Async SQL (Relational) Databases |
# Async SQL (Relational) Databases with Encode/Databases |
||||
|
|
||||
!!! info |
!!! info |
||||
These docs are about to be updated. 🎉 |
These docs are about to be updated. 🎉 |
@ -0,0 +1,78 @@ |
|||||
|
# Configure Swagger UI |
||||
|
|
||||
|
You can configure some extra <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">Swagger UI parameters</a>. |
||||
|
|
||||
|
To configure them, pass the `swagger_ui_parameters` argument when creating the `FastAPI()` app object or to the `get_swagger_ui_html()` function. |
||||
|
|
||||
|
`swagger_ui_parameters` receives a dictionary with the configurations passed to Swagger UI directly. |
||||
|
|
||||
|
FastAPI converts the configurations to **JSON** to make them compatible with JavaScript, as that's what Swagger UI needs. |
||||
|
|
||||
|
## Disable Syntax Highlighting |
||||
|
|
||||
|
For example, you could disable syntax highlighting in Swagger UI. |
||||
|
|
||||
|
Without changing the settings, syntax highlighting is enabled by default: |
||||
|
|
||||
|
<img src="/img/tutorial/extending-openapi/image02.png"> |
||||
|
|
||||
|
But you can disable it by setting `syntaxHighlight` to `False`: |
||||
|
|
||||
|
```Python hl_lines="3" |
||||
|
{!../../../docs_src/configure_swagger_ui/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
...and then Swagger UI won't show the syntax highlighting anymore: |
||||
|
|
||||
|
<img src="/img/tutorial/extending-openapi/image03.png"> |
||||
|
|
||||
|
## Change the Theme |
||||
|
|
||||
|
The same way you could set the syntax highlighting theme with the key `"syntaxHighlight.theme"` (notice that it has a dot in the middle): |
||||
|
|
||||
|
```Python hl_lines="3" |
||||
|
{!../../../docs_src/configure_swagger_ui/tutorial002.py!} |
||||
|
``` |
||||
|
|
||||
|
That configuration would change the syntax highlighting color theme: |
||||
|
|
||||
|
<img src="/img/tutorial/extending-openapi/image04.png"> |
||||
|
|
||||
|
## Change Default Swagger UI Parameters |
||||
|
|
||||
|
FastAPI includes some default configuration parameters appropriate for most of the use cases. |
||||
|
|
||||
|
It includes these default configurations: |
||||
|
|
||||
|
```Python |
||||
|
{!../../../fastapi/openapi/docs.py[ln:7-13]!} |
||||
|
``` |
||||
|
|
||||
|
You can override any of them by setting a different value in the argument `swagger_ui_parameters`. |
||||
|
|
||||
|
For example, to disable `deepLinking` you could pass these settings to `swagger_ui_parameters`: |
||||
|
|
||||
|
```Python hl_lines="3" |
||||
|
{!../../../docs_src/configure_swagger_ui/tutorial003.py!} |
||||
|
``` |
||||
|
|
||||
|
## Other Swagger UI Parameters |
||||
|
|
||||
|
To see all the other possible configurations you can use, read the official <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration" class="external-link" target="_blank">docs for Swagger UI parameters</a>. |
||||
|
|
||||
|
## JavaScript-only settings |
||||
|
|
||||
|
Swagger UI also allows other configurations to be **JavaScript-only** objects (for example, JavaScript functions). |
||||
|
|
||||
|
FastAPI also includes these JavaScript-only `presets` settings: |
||||
|
|
||||
|
```JavaScript |
||||
|
presets: [ |
||||
|
SwaggerUIBundle.presets.apis, |
||||
|
SwaggerUIBundle.SwaggerUIStandalonePreset |
||||
|
] |
||||
|
``` |
||||
|
|
||||
|
These are **JavaScript** objects, not strings, so you can't pass them from Python code directly. |
||||
|
|
||||
|
If you need to use JavaScript-only configurations like those, you can use one of the methods above. Override all the Swagger UI *path operation* and manually write any JavaScript you need. |
@ -0,0 +1,199 @@ |
|||||
|
# Custom Docs UI Static Assets (Self-Hosting) |
||||
|
|
||||
|
The API docs use **Swagger UI** and **ReDoc**, and each of those need some JavaScript and CSS files. |
||||
|
|
||||
|
By default, those files are served from a <abbr title="Content Delivery Network: A service, normally composed of several servers, that provides static files, like JavaScript and CSS. It's commonly used to serve those files from the server closer to the client, improving performance.">CDN</abbr>. |
||||
|
|
||||
|
But it's possible to customize it, you can set a specific CDN, or serve the files yourself. |
||||
|
|
||||
|
## Custom CDN for JavaScript and CSS |
||||
|
|
||||
|
Let's say that you want to use a different <abbr title="Content Delivery Network">CDN</abbr>, for example you want to use `https://unpkg.com/`. |
||||
|
|
||||
|
This could be useful if for example you live in a country that restricts some URLs. |
||||
|
|
||||
|
### Disable the automatic docs |
||||
|
|
||||
|
The first step is to disable the automatic docs, as by default, those use the default CDN. |
||||
|
|
||||
|
To disable them, set their URLs to `None` when creating your `FastAPI` app: |
||||
|
|
||||
|
```Python hl_lines="8" |
||||
|
{!../../../docs_src/custom_docs_ui/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Include the custom docs |
||||
|
|
||||
|
Now you can create the *path operations* for the custom docs. |
||||
|
|
||||
|
You can re-use FastAPI's internal functions to create the HTML pages for the docs, and pass them the needed arguments: |
||||
|
|
||||
|
* `openapi_url`: the URL where the HTML page for the docs can get the OpenAPI schema for your API. You can use here the attribute `app.openapi_url`. |
||||
|
* `title`: the title of your API. |
||||
|
* `oauth2_redirect_url`: you can use `app.swagger_ui_oauth2_redirect_url` here to use the default. |
||||
|
* `swagger_js_url`: the URL where the HTML for your Swagger UI docs can get the **JavaScript** file. This is the custom CDN URL. |
||||
|
* `swagger_css_url`: the URL where the HTML for your Swagger UI docs can get the **CSS** file. This is the custom CDN URL. |
||||
|
|
||||
|
And similarly for ReDoc... |
||||
|
|
||||
|
```Python hl_lines="2-6 11-19 22-24 27-33" |
||||
|
{!../../../docs_src/custom_docs_ui/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
!!! tip |
||||
|
The *path operation* for `swagger_ui_redirect` is a helper for when you use OAuth2. |
||||
|
|
||||
|
If you integrate your API with an OAuth2 provider, you will be able to authenticate and come back to the API docs with the acquired credentials. And interact with it using the real OAuth2 authentication. |
||||
|
|
||||
|
Swagger UI will handle it behind the scenes for you, but it needs this "redirect" helper. |
||||
|
|
||||
|
### Create a *path operation* to test it |
||||
|
|
||||
|
Now, to be able to test that everything works, create a *path operation*: |
||||
|
|
||||
|
```Python hl_lines="36-38" |
||||
|
{!../../../docs_src/custom_docs_ui/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Test it |
||||
|
|
||||
|
Now, you should be able to go to your docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, and reload the page, it will load those assets from the new CDN. |
||||
|
|
||||
|
## Self-hosting JavaScript and CSS for docs |
||||
|
|
||||
|
Self-hosting the JavaScript and CSS could be useful if, for example, you need your app to keep working even while offline, without open Internet access, or in a local network. |
||||
|
|
||||
|
Here you'll see how to serve those files yourself, in the same FastAPI app, and configure the docs to use them. |
||||
|
|
||||
|
### Project file structure |
||||
|
|
||||
|
Let's say your project file structure looks like this: |
||||
|
|
||||
|
``` |
||||
|
. |
||||
|
├── app |
||||
|
│ ├── __init__.py |
||||
|
│ ├── main.py |
||||
|
``` |
||||
|
|
||||
|
Now create a directory to store those static files. |
||||
|
|
||||
|
Your new file structure could look like this: |
||||
|
|
||||
|
``` |
||||
|
. |
||||
|
├── app |
||||
|
│ ├── __init__.py |
||||
|
│ ├── main.py |
||||
|
└── static/ |
||||
|
``` |
||||
|
|
||||
|
### Download the files |
||||
|
|
||||
|
Download the static files needed for the docs and put them on that `static/` directory. |
||||
|
|
||||
|
You can probably right-click each link and select an option similar to `Save link as...`. |
||||
|
|
||||
|
**Swagger UI** uses the files: |
||||
|
|
||||
|
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a> |
||||
|
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a> |
||||
|
|
||||
|
And **ReDoc** uses the file: |
||||
|
|
||||
|
* <a href="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js" class="external-link" target="_blank">`redoc.standalone.js`</a> |
||||
|
|
||||
|
After that, your file structure could look like: |
||||
|
|
||||
|
``` |
||||
|
. |
||||
|
├── app |
||||
|
│ ├── __init__.py |
||||
|
│ ├── main.py |
||||
|
└── static |
||||
|
├── redoc.standalone.js |
||||
|
├── swagger-ui-bundle.js |
||||
|
└── swagger-ui.css |
||||
|
``` |
||||
|
|
||||
|
### Serve the static files |
||||
|
|
||||
|
* Import `StaticFiles`. |
||||
|
* "Mount" a `StaticFiles()` instance in a specific path. |
||||
|
|
||||
|
```Python hl_lines="7 11" |
||||
|
{!../../../docs_src/custom_docs_ui/tutorial002.py!} |
||||
|
``` |
||||
|
|
||||
|
### Test the static files |
||||
|
|
||||
|
Start your application and go to <a href="http://127.0.0.1:8000/static/redoc.standalone.js" class="external-link" target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a>. |
||||
|
|
||||
|
You should see a very long JavaScript file for **ReDoc**. |
||||
|
|
||||
|
It could start with something like: |
||||
|
|
||||
|
```JavaScript |
||||
|
/*! |
||||
|
* ReDoc - OpenAPI/Swagger-generated API Reference Documentation |
||||
|
* ------------------------------------------------------------- |
||||
|
* Version: "2.0.0-rc.18" |
||||
|
* Repo: https://github.com/Redocly/redoc |
||||
|
*/ |
||||
|
!function(e,t){"object"==typeof exports&&"object"==typeof m |
||||
|
|
||||
|
... |
||||
|
``` |
||||
|
|
||||
|
That confirms that you are being able to serve static files from your app, and that you placed the static files for the docs in the correct place. |
||||
|
|
||||
|
Now we can configure the app to use those static files for the docs. |
||||
|
|
||||
|
### Disable the automatic docs for static files |
||||
|
|
||||
|
The same as when using a custom CDN, the first step is to disable the automatic docs, as those use the CDN by default. |
||||
|
|
||||
|
To disable them, set their URLs to `None` when creating your `FastAPI` app: |
||||
|
|
||||
|
```Python hl_lines="9" |
||||
|
{!../../../docs_src/custom_docs_ui/tutorial002.py!} |
||||
|
``` |
||||
|
|
||||
|
### Include the custom docs for static files |
||||
|
|
||||
|
And the same way as with a custom CDN, now you can create the *path operations* for the custom docs. |
||||
|
|
||||
|
Again, you can re-use FastAPI's internal functions to create the HTML pages for the docs, and pass them the needed arguments: |
||||
|
|
||||
|
* `openapi_url`: the URL where the HTML page for the docs can get the OpenAPI schema for your API. You can use here the attribute `app.openapi_url`. |
||||
|
* `title`: the title of your API. |
||||
|
* `oauth2_redirect_url`: you can use `app.swagger_ui_oauth2_redirect_url` here to use the default. |
||||
|
* `swagger_js_url`: the URL where the HTML for your Swagger UI docs can get the **JavaScript** file. **This is the one that your own app is now serving**. |
||||
|
* `swagger_css_url`: the URL where the HTML for your Swagger UI docs can get the **CSS** file. **This is the one that your own app is now serving**. |
||||
|
|
||||
|
And similarly for ReDoc... |
||||
|
|
||||
|
```Python hl_lines="2-6 14-22 25-27 30-36" |
||||
|
{!../../../docs_src/custom_docs_ui/tutorial002.py!} |
||||
|
``` |
||||
|
|
||||
|
!!! tip |
||||
|
The *path operation* for `swagger_ui_redirect` is a helper for when you use OAuth2. |
||||
|
|
||||
|
If you integrate your API with an OAuth2 provider, you will be able to authenticate and come back to the API docs with the acquired credentials. And interact with it using the real OAuth2 authentication. |
||||
|
|
||||
|
Swagger UI will handle it behind the scenes for you, but it needs this "redirect" helper. |
||||
|
|
||||
|
### Create a *path operation* to test static files |
||||
|
|
||||
|
Now, to be able to test that everything works, create a *path operation*: |
||||
|
|
||||
|
```Python hl_lines="39-41" |
||||
|
{!../../../docs_src/custom_docs_ui/tutorial002.py!} |
||||
|
``` |
||||
|
|
||||
|
### Test Static Files UI |
||||
|
|
||||
|
Now, you should be able to disconnect your WiFi, go to your docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, and reload the page. |
||||
|
|
||||
|
And even without Internet, you would be able to see the docs for your API and interact with it. |
@ -0,0 +1,87 @@ |
|||||
|
# Extending OpenAPI |
||||
|
|
||||
|
There are some cases where you might need to modify the generated OpenAPI schema. |
||||
|
|
||||
|
In this section you will see how. |
||||
|
|
||||
|
## The normal process |
||||
|
|
||||
|
The normal (default) process, is as follows. |
||||
|
|
||||
|
A `FastAPI` application (instance) has an `.openapi()` method that is expected to return the OpenAPI schema. |
||||
|
|
||||
|
As part of the application object creation, a *path operation* for `/openapi.json` (or for whatever you set your `openapi_url`) is registered. |
||||
|
|
||||
|
It just returns a JSON response with the result of the application's `.openapi()` method. |
||||
|
|
||||
|
By default, what the method `.openapi()` does is check the property `.openapi_schema` to see if it has contents and return them. |
||||
|
|
||||
|
If it doesn't, it generates them using the utility function at `fastapi.openapi.utils.get_openapi`. |
||||
|
|
||||
|
And that function `get_openapi()` receives as parameters: |
||||
|
|
||||
|
* `title`: The OpenAPI title, shown in the docs. |
||||
|
* `version`: The version of your API, e.g. `2.5.0`. |
||||
|
* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.1.0`. |
||||
|
* `summary`: A short summary of the API. |
||||
|
* `description`: The description of your API, this can include markdown and will be shown in the docs. |
||||
|
* `routes`: A list of routes, these are each of the registered *path operations*. They are taken from `app.routes`. |
||||
|
|
||||
|
!!! info |
||||
|
The parameter `summary` is available in OpenAPI 3.1.0 and above, supported by FastAPI 0.99.0 and above. |
||||
|
|
||||
|
## Overriding the defaults |
||||
|
|
||||
|
Using the information above, you can use the same utility function to generate the OpenAPI schema and override each part that you need. |
||||
|
|
||||
|
For example, let's add <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">ReDoc's OpenAPI extension to include a custom logo</a>. |
||||
|
|
||||
|
### Normal **FastAPI** |
||||
|
|
||||
|
First, write all your **FastAPI** application as normally: |
||||
|
|
||||
|
```Python hl_lines="1 4 7-9" |
||||
|
{!../../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Generate the OpenAPI schema |
||||
|
|
||||
|
Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function: |
||||
|
|
||||
|
```Python hl_lines="2 15-21" |
||||
|
{!../../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Modify the OpenAPI schema |
||||
|
|
||||
|
Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema: |
||||
|
|
||||
|
```Python hl_lines="22-24" |
||||
|
{!../../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Cache the OpenAPI schema |
||||
|
|
||||
|
You can use the property `.openapi_schema` as a "cache", to store your generated schema. |
||||
|
|
||||
|
That way, your application won't have to generate the schema every time a user opens your API docs. |
||||
|
|
||||
|
It will be generated only once, and then the same cached schema will be used for the next requests. |
||||
|
|
||||
|
```Python hl_lines="13-14 25-26" |
||||
|
{!../../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Override the method |
||||
|
|
||||
|
Now you can replace the `.openapi()` method with your new function. |
||||
|
|
||||
|
```Python hl_lines="29" |
||||
|
{!../../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Check it |
||||
|
|
||||
|
Once you go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> you will see that you are using your custom logo (in this example, **FastAPI**'s logo): |
||||
|
|
||||
|
<img src="/img/tutorial/extending-openapi/image01.png"> |
@ -0,0 +1,39 @@ |
|||||
|
# General - How To - Recipes |
||||
|
|
||||
|
Here are several pointers to other places in the docs, for general or frequent questions. |
||||
|
|
||||
|
## Filter Data - Security |
||||
|
|
||||
|
To ensure that you don't return more data than you should, read the docs for [Tutorial - Response Model - Return Type](../tutorial/response-model.md){.internal-link target=_blank}. |
||||
|
|
||||
|
## Documentation Tags - OpenAPI |
||||
|
|
||||
|
To add tags to your *path operations*, and group them in the docs UI, read the docs for [Tutorial - Path Operation Configurations - Tags](../tutorial/path-operation-configuration.md#tags){.internal-link target=_blank}. |
||||
|
|
||||
|
## Documentation Summary and Description - OpenAPI |
||||
|
|
||||
|
To add a summary and description to your *path operations*, and show them in the docs UI, read the docs for [Tutorial - Path Operation Configurations - Summary and Description](../tutorial/path-operation-configuration.md#summary-and-description){.internal-link target=_blank}. |
||||
|
|
||||
|
## Documentation Response description - OpenAPI |
||||
|
|
||||
|
To define the description of the response, shown in the docs UI, read the docs for [Tutorial - Path Operation Configurations - Response description](../tutorial/path-operation-configuration.md#response-description){.internal-link target=_blank}. |
||||
|
|
||||
|
## Documentation Deprecate a *Path Operation* - OpenAPI |
||||
|
|
||||
|
To deprecate a *path operation*, and show it in the docs UI, read the docs for [Tutorial - Path Operation Configurations - Deprecation](../tutorial/path-operation-configuration.md#deprecate-a-path-operation){.internal-link target=_blank}. |
||||
|
|
||||
|
## Convert any Data to JSON-compatible |
||||
|
|
||||
|
To convert any data to JSON-compatible, read the docs for [Tutorial - JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}. |
||||
|
|
||||
|
## OpenAPI Metadata - Docs |
||||
|
|
||||
|
To add metadata to your OpenAPI schema, including a license, version, contact, etc, read the docs for [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md){.internal-link target=_blank}. |
||||
|
|
||||
|
## OpenAPI Custom URL |
||||
|
|
||||
|
To customize the OpenAPI URL (or remove it), read the docs for [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md#openapi-url){.internal-link target=_blank}. |
||||
|
|
||||
|
## OpenAPI Docs URLs |
||||
|
|
||||
|
To update the URLs used for the automatically generated docs user interfaces, read the docs for [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md#docs-urls){.internal-link target=_blank}. |
@ -0,0 +1,11 @@ |
|||||
|
# How To - Recipes |
||||
|
|
||||
|
Here you will see different recipes or "how to" guides for **several topics**. |
||||
|
|
||||
|
Most of these ideas would be more or less **independent**, and in most cases you should only need to study them if they apply directly to **your project**. |
||||
|
|
||||
|
If something seems interesting and useful to your project, go ahead and check it, but otherwise, you might probably just skip them. |
||||
|
|
||||
|
!!! tip |
||||
|
|
||||
|
If you want to **learn FastAPI** in a structured way (recommended), go and read the [Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} chapter by chapter instead. |
@ -1,4 +1,4 @@ |
|||||
# NoSQL (Distributed / Big Data) Databases |
# NoSQL (Distributed / Big Data) Databases with Couchbase |
||||
|
|
||||
!!! info |
!!! info |
||||
These docs are about to be updated. 🎉 |
These docs are about to be updated. 🎉 |
After Width: | Height: | Size: 4.7 KiB |
@ -1,245 +0,0 @@ |
|||||
# Déployer FastAPI sur Deta |
|
||||
|
|
||||
Dans cette section, vous apprendrez à déployer facilement une application **FastAPI** sur <a href="https://www.deta. |
|
||||
sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> en utilisant le plan tarifaire gratuit. 🎁 |
|
||||
|
|
||||
Cela vous prendra environ **10 minutes**. |
|
||||
|
|
||||
!!! info |
|
||||
<a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> sponsorise **FastAPI**. 🎉 |
|
||||
|
|
||||
## Une application **FastAPI** de base |
|
||||
|
|
||||
* Créez un répertoire pour votre application, par exemple `./fastapideta/` et déplacez-vous dedans. |
|
||||
|
|
||||
### Le code FastAPI |
|
||||
|
|
||||
* Créer un fichier `main.py` avec : |
|
||||
|
|
||||
```Python |
|
||||
from fastapi import FastAPI |
|
||||
|
|
||||
app = FastAPI() |
|
||||
|
|
||||
|
|
||||
@app.get("/") |
|
||||
def read_root(): |
|
||||
return {"Hello": "World"} |
|
||||
|
|
||||
|
|
||||
@app.get("/items/{item_id}") |
|
||||
def read_item(item_id: int): |
|
||||
return {"item_id": item_id} |
|
||||
``` |
|
||||
|
|
||||
### Dépendances |
|
||||
|
|
||||
Maintenant, dans le même répertoire, créez un fichier `requirements.txt` avec : |
|
||||
|
|
||||
```text |
|
||||
fastapi |
|
||||
``` |
|
||||
|
|
||||
!!! tip "Astuce" |
|
||||
Il n'est pas nécessaire d'installer Uvicorn pour déployer sur Deta, bien qu'il soit probablement souhaitable de l'installer localement pour tester votre application. |
|
||||
|
|
||||
### Structure du répertoire |
|
||||
|
|
||||
Vous aurez maintenant un répertoire `./fastapideta/` avec deux fichiers : |
|
||||
|
|
||||
``` |
|
||||
. |
|
||||
└── main.py |
|
||||
└── requirements.txt |
|
||||
``` |
|
||||
|
|
||||
## Créer un compte gratuit sur Deta |
|
||||
|
|
||||
Créez maintenant un <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">compte gratuit |
|
||||
sur Deta</a>, vous avez juste besoin d'une adresse email et d'un mot de passe. |
|
||||
|
|
||||
Vous n'avez même pas besoin d'une carte de crédit. |
|
||||
|
|
||||
## Installer le CLI (Interface en Ligne de Commande) |
|
||||
|
|
||||
Une fois que vous avez votre compte, installez le <abbr title="Command Line Interface application">CLI</abbr> de Deta : |
|
||||
|
|
||||
=== "Linux, macOS" |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ curl -fsSL https://get.deta.dev/cli.sh | sh |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
=== "Windows PowerShell" |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ iwr https://get.deta.dev/cli.ps1 -useb | iex |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
Après l'avoir installé, ouvrez un nouveau terminal afin que la nouvelle installation soit détectée. |
|
||||
|
|
||||
Dans un nouveau terminal, confirmez qu'il a été correctement installé avec : |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta --help |
|
||||
|
|
||||
Deta command line interface for managing deta micros. |
|
||||
Complete documentation available at https://docs.deta.sh |
|
||||
|
|
||||
Usage: |
|
||||
deta [flags] |
|
||||
deta [command] |
|
||||
|
|
||||
Available Commands: |
|
||||
auth Change auth settings for a deta micro |
|
||||
|
|
||||
... |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
!!! tip "Astuce" |
|
||||
Si vous rencontrez des problèmes pour installer le CLI, consultez la <a href="https://docs.deta. sh/docs/micros/getting_started?ref=fastapi" class="external-link" target="_blank">documentation officielle de Deta (en anglais)</a>. |
|
||||
|
|
||||
## Connexion avec le CLI |
|
||||
|
|
||||
Maintenant, connectez-vous à Deta depuis le CLI avec : |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta login |
|
||||
|
|
||||
Please, log in from the web page. Waiting.. |
|
||||
Logged in successfully. |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
Cela ouvrira un navigateur web et permettra une authentification automatique. |
|
||||
|
|
||||
## Déployer avec Deta |
|
||||
|
|
||||
Ensuite, déployez votre application avec le CLI de Deta : |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta new |
|
||||
|
|
||||
Successfully created a new micro |
|
||||
|
|
||||
// Notice the "endpoint" 🔍 |
|
||||
|
|
||||
{ |
|
||||
"name": "fastapideta", |
|
||||
"runtime": "python3.7", |
|
||||
"endpoint": "https://qltnci.deta.dev", |
|
||||
"visor": "enabled", |
|
||||
"http_auth": "enabled" |
|
||||
} |
|
||||
|
|
||||
Adding dependencies... |
|
||||
|
|
||||
|
|
||||
---> 100% |
|
||||
|
|
||||
|
|
||||
Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6 |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
Vous verrez un message JSON similaire à : |
|
||||
|
|
||||
```JSON hl_lines="4" |
|
||||
{ |
|
||||
"name": "fastapideta", |
|
||||
"runtime": "python3.7", |
|
||||
"endpoint": "https://qltnci.deta.dev", |
|
||||
"visor": "enabled", |
|
||||
"http_auth": "enabled" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
!!! tip "Astuce" |
|
||||
Votre déploiement aura une URL `"endpoint"` différente. |
|
||||
|
|
||||
## Vérifiez |
|
||||
|
|
||||
Maintenant, dans votre navigateur ouvrez votre URL `endpoint`. Dans l'exemple ci-dessus, c'était |
|
||||
`https://qltnci.deta.dev`, mais la vôtre sera différente. |
|
||||
|
|
||||
Vous verrez la réponse JSON de votre application FastAPI : |
|
||||
|
|
||||
```JSON |
|
||||
{ |
|
||||
"Hello": "World" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
Et maintenant naviguez vers `/docs` dans votre API, dans l'exemple ci-dessus ce serait `https://qltnci.deta.dev/docs`. |
|
||||
|
|
||||
Vous verrez votre documentation comme suit : |
|
||||
|
|
||||
<img src="/img/deployment/deta/image01.png"> |
|
||||
|
|
||||
## Activer l'accès public |
|
||||
|
|
||||
Par défaut, Deta va gérer l'authentification en utilisant des cookies pour votre compte. |
|
||||
|
|
||||
Mais une fois que vous êtes prêt, vous pouvez le rendre public avec : |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta auth disable |
|
||||
|
|
||||
Successfully disabled http auth |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
Maintenant, vous pouvez partager cette URL avec n'importe qui et ils seront en mesure d'accéder à votre API. 🚀 |
|
||||
|
|
||||
## HTTPS |
|
||||
|
|
||||
Félicitations ! Vous avez déployé votre application FastAPI sur Deta ! 🎉 🍰 |
|
||||
|
|
||||
Remarquez également que Deta gère correctement HTTPS pour vous, vous n'avez donc pas à vous en occuper et pouvez être sûr que vos clients auront une connexion cryptée sécurisée. ✅ 🔒 |
|
||||
|
|
||||
## Vérifiez le Visor |
|
||||
|
|
||||
À partir de l'interface graphique de votre documentation (dans une URL telle que `https://qltnci.deta.dev/docs`) |
|
||||
envoyez une requête à votre *opération de chemin* `/items/{item_id}`. |
|
||||
|
|
||||
Par exemple avec l'ID `5`. |
|
||||
|
|
||||
Allez maintenant sur <a href="https://web.deta.sh/" class="external-link" target="_blank">https://web.deta.sh</a>. |
|
||||
|
|
||||
Vous verrez qu'il y a une section à gauche appelée <abbr title="ça vient de Micro(server)">"Micros"</abbr> avec chacune de vos applications. |
|
||||
|
|
||||
Vous verrez un onglet avec "Details", et aussi un onglet "Visor", allez à l'onglet "Visor". |
|
||||
|
|
||||
Vous pouvez y consulter les requêtes récentes envoyées à votre application. |
|
||||
|
|
||||
Vous pouvez également les modifier et les relancer. |
|
||||
|
|
||||
<img src="/img/deployment/deta/image02.png"> |
|
||||
|
|
||||
## En savoir plus |
|
||||
|
|
||||
À un moment donné, vous voudrez probablement stocker certaines données pour votre application d'une manière qui |
|
||||
persiste dans le temps. Pour cela, vous pouvez utiliser <a href="https://docs.deta.sh/docs/base/py_tutorial?ref=fastapi" class="external-link" target="_blank">Deta Base</a>, il dispose également d'un généreux **plan gratuit**. |
|
||||
|
|
||||
Vous pouvez également en lire plus dans la <a href="https://docs.deta.sh?ref=fastapi" class="external-link" target="_blank">documentation Deta</a>. |
|
@ -0,0 +1,323 @@ |
|||||
|
# デプロイメントのコンセプト |
||||
|
|
||||
|
**FastAPI**を用いたアプリケーションをデプロイするとき、もしくはどのようなタイプのWeb APIであっても、おそらく気になるコンセプトがいくつかあります。 |
||||
|
|
||||
|
それらを活用することでアプリケーションを**デプロイするための最適な方法**を見つけることができます。 |
||||
|
|
||||
|
重要なコンセプトのいくつかを紹介します: |
||||
|
|
||||
|
* セキュリティ - HTTPS |
||||
|
* 起動時の実行 |
||||
|
* 再起動 |
||||
|
* レプリケーション(実行中のプロセス数) |
||||
|
* メモリー |
||||
|
* 開始前の事前のステップ |
||||
|
|
||||
|
これらが**デプロイメント**にどのような影響を与えるかを見ていきましょう。 |
||||
|
|
||||
|
最終的な目的は、**安全な方法で**APIクライアントに**サービスを提供**し、**中断を回避**するだけでなく、**計算リソース**(例えばリモートサーバー/仮想マシン)を可能な限り効率的に使用することです。🚀 |
||||
|
|
||||
|
この章では前述した**コンセプト**についてそれぞれ説明します。 |
||||
|
|
||||
|
この説明を通して、普段とは非常に異なる環境や存在しないであろう**将来の**環境に対し、デプロイの方法を決める上で必要な**直感**を与えてくれることを願っています。 |
||||
|
|
||||
|
これらのコンセプトを意識することにより、**あなた自身のAPI**をデプロイするための最適な方法を**評価**し、**設計**することができるようになるでしょう。 |
||||
|
|
||||
|
次の章では、FastAPIアプリケーションをデプロイするための**具体的なレシピ**を紹介します。 |
||||
|
|
||||
|
しかし、今はこれらの重要な**コンセプトに基づくアイデア**を確認しましょう。これらのコンセプトは、他のどのタイプのWeb APIにも当てはまります。💡 |
||||
|
|
||||
|
## セキュリティ - HTTPS |
||||
|
|
||||
|
<!-- NOTE: https.md written in Japanese does not exist, so it redirects to English one --> |
||||
|
[前チャプターのHTTPSについて](./https.md){.internal-link target=_blank}では、HTTPSがどのようにAPIを暗号化するのかについて学びました。 |
||||
|
|
||||
|
通常、アプリケーションサーバにとって**外部の**コンポーネントである**TLS Termination Proxy**によって提供されることが一般的です。このプロキシは通信の暗号化を担当します。 |
||||
|
|
||||
|
さらにセキュアな通信において、HTTPS証明書の定期的な更新を行いますが、これはTLS Termination Proxyと同じコンポーネントが担当することもあれば、別のコンポーネントが担当することもあります。 |
||||
|
|
||||
|
### HTTPS 用ツールの例 |
||||
|
TLS Termination Proxyとして使用できるツールには以下のようなものがあります: |
||||
|
|
||||
|
* Traefik |
||||
|
* 証明書の更新を自動的に処理 ✨ |
||||
|
* Caddy |
||||
|
* 証明書の更新を自動的に処理 ✨ |
||||
|
* Nginx |
||||
|
* 証明書更新のためにCertbotのような外部コンポーネントを使用 |
||||
|
* HAProxy |
||||
|
* 証明書更新のためにCertbotのような外部コンポーネントを使用 |
||||
|
* Nginx のような Ingress Controller を持つ Kubernetes |
||||
|
* 証明書の更新に cert-manager のような外部コンポーネントを使用 |
||||
|
* クラウド・プロバイダーがサービスの一部として内部的に処理(下記を参照👇) |
||||
|
|
||||
|
もう1つの選択肢は、HTTPSのセットアップを含んだより多くの作業を行う**クラウド・サービス**を利用することです。 このサービスには制限があったり、料金が高くなったりする可能性があります。しかしその場合、TLS Termination Proxyを自分でセットアップする必要はないです。 |
||||
|
|
||||
|
次の章で具体例をいくつか紹介します。 |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
次に考慮すべきコンセプトは、実際のAPIを実行するプログラム(例:Uvicorn)に関連するものすべてです。 |
||||
|
|
||||
|
## プログラム と プロセス |
||||
|
|
||||
|
私たちは「**プロセス**」という言葉についてたくさん話すので、その意味や「**プログラム**」という言葉との違いを明確にしておくと便利です。 |
||||
|
|
||||
|
### プログラムとは何か |
||||
|
|
||||
|
**プログラム**という言葉は、一般的にいろいろなものを表現するのに使われます: |
||||
|
|
||||
|
* プログラマが書く**コード**、**Pythonファイル** |
||||
|
* OSによって実行することができるファイル(例: `python`, `python.exe` or `uvicorn`) |
||||
|
* OS上で**実行**している間、CPUを使用し、メモリ上に何かを保存する特定のプログラム(**プロセス**とも呼ばれる) |
||||
|
|
||||
|
### プロセスとは何か |
||||
|
|
||||
|
**プロセス**という言葉は通常、より具体的な意味で使われ、OSで実行されているものだけを指します(先ほどの最後の説明のように): |
||||
|
|
||||
|
* OS上で**実行**している特定のプログラム |
||||
|
* これはファイルやコードを指すのではなく、OSによって**実行**され、管理されているものを指します。 |
||||
|
* どんなプログラムやコードも、それが**実行されているときにだけ機能**します。つまり、**プロセスとして実行されているときだけ**です。 |
||||
|
* プロセスは、ユーザーにあるいはOSによって、 **終了**(あるいは "kill")させることができます。その時点で、プロセスは実行/実行されることを停止し、それ以降は**何もできなくなります**。 |
||||
|
* コンピュータで実行されている各アプリケーションは、実行中のプログラムや各ウィンドウなど、その背後にいくつかのプロセスを持っています。そして通常、コンピュータが起動している間、**多くのプロセスが**同時に実行されています。 |
||||
|
* **同じプログラム**の**複数のプロセス**が同時に実行されていることがあります。 |
||||
|
|
||||
|
OSの「タスク・マネージャー」や「システム・モニター」(または同様のツール)を確認すれば、これらのプロセスの多くが実行されているの見ることができるでしょう。 |
||||
|
|
||||
|
例えば、同じブラウザプログラム(Firefox、Chrome、Edgeなど)を実行しているプロセスが複数あることがわかります。通常、1つのタブにつき1つのプロセスが実行され、さらに他のプロセスも実行されます。 |
||||
|
|
||||
|
<img class="shadow" src="/img/deployment/concepts/image01.png"> |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
さて、**プロセス**と**プログラム**という用語の違いを確認したところで、デプロイメントについて話を続けます。 |
||||
|
|
||||
|
## 起動時の実行 |
||||
|
|
||||
|
ほとんどの場合、Web APIを作成するときは、クライアントがいつでもアクセスできるように、**常に**中断されることなく**実行される**ことを望みます。もちろん、特定の状況でのみ実行させたい特別な理由がある場合は別ですが、その時間のほとんどは、常に実行され、**利用可能**であることを望みます。 |
||||
|
|
||||
|
### リモートサーバー上での実行 |
||||
|
|
||||
|
リモートサーバー(クラウドサーバー、仮想マシンなど)をセットアップするときにできる最も簡単なことは、ローカルで開発するときと同じように、Uvicorn(または同様のもの)を手動で実行することです。 この方法は**開発中**には役に立つと思われます。 |
||||
|
|
||||
|
しかし、サーバーへの接続が切れた場合、**実行中のプロセス**はおそらくダウンしてしまうでしょう。 |
||||
|
|
||||
|
そしてサーバーが再起動された場合(アップデートやクラウドプロバイダーからのマイグレーションの後など)、おそらくあなたはそれに**気づかないでしょう**。そのため、プロセスを手動で再起動しなければならないことすら気づかないでしょう。つまり、APIはダウンしたままなのです。😱 |
||||
|
|
||||
|
### 起動時に自動的に実行 |
||||
|
|
||||
|
一般的に、サーバープログラム(Uvicornなど)はサーバー起動時に自動的に開始され、**人の介入**を必要とせずに、APIと一緒にプロセスが常に実行されるようにしたいと思われます(UvicornがFastAPIアプリを実行するなど)。 |
||||
|
|
||||
|
### 別のプログラムの用意 |
||||
|
|
||||
|
これを実現するために、通常は**別のプログラム**を用意し、起動時にアプリケーションが実行されるようにします。そして多くの場合、他のコンポーネントやアプリケーション、例えばデータベースも実行されるようにします。 |
||||
|
|
||||
|
### 起動時に実行するツールの例 |
||||
|
|
||||
|
実行するツールの例をいくつか挙げます: |
||||
|
|
||||
|
* Docker |
||||
|
* Kubernetes |
||||
|
* Docker Compose |
||||
|
* Swarm モードによる Docker |
||||
|
* Systemd |
||||
|
* Supervisor |
||||
|
* クラウドプロバイダーがサービスの一部として内部的に処理 |
||||
|
* そのほか... |
||||
|
|
||||
|
次の章で、より具体的な例を挙げていきます。 |
||||
|
|
||||
|
## 再起動 |
||||
|
|
||||
|
起動時にアプリケーションが実行されることを確認するのと同様に、失敗後にアプリケーションが**再起動**されることも確認したいと思われます。 |
||||
|
|
||||
|
### 我々は間違いを犯す |
||||
|
|
||||
|
私たち人間は常に**間違い**を犯します。ソフトウェアには、ほとんど常に**バグ**があらゆる箇所に隠されています。🐛 |
||||
|
|
||||
|
### 小さなエラーは自動的に処理される |
||||
|
|
||||
|
FastAPIでWeb APIを構築する際に、コードにエラーがある場合、FastAPIは通常、エラーを引き起こした単一のリクエストにエラーを含めます。🛡 |
||||
|
|
||||
|
クライアントはそのリクエストに対して**500 Internal Server Error**を受け取りますが、アプリケーションは完全にクラッシュするのではなく、次のリクエストのために動作を続けます。 |
||||
|
|
||||
|
### 重大なエラー - クラッシュ |
||||
|
|
||||
|
しかしながら、**アプリケーション全体をクラッシュさせるようなコードを書いて**UvicornとPythonをクラッシュさせるようなケースもあるかもしれません。💥 |
||||
|
|
||||
|
それでも、ある箇所でエラーが発生したからといって、アプリケーションを停止させたままにしたくないでしょう。 少なくとも壊れていない*パスオペレーション*については、**実行し続けたい**はずです。 |
||||
|
|
||||
|
### クラッシュ後の再起動 |
||||
|
|
||||
|
しかし、実行中の**プロセス**をクラッシュさせるような本当にひどいエラーの場合、少なくとも2〜3回ほどプロセスを**再起動**させる外部コンポーネントが必要でしょう。 |
||||
|
|
||||
|
!!! tip |
||||
|
...とはいえ、アプリケーション全体が**すぐにクラッシュする**のであれば、いつまでも再起動し続けるのは意味がないでしょう。しかし、その場合はおそらく開発中か少なくともデプロイ直後に気づくと思われます。 |
||||
|
|
||||
|
そこで、**将来**クラッシュする可能性があり、それでも再スタートさせることに意味があるような、主なケースに焦点を当ててみます。 |
||||
|
|
||||
|
あなたはおそらく**外部コンポーネント**がアプリケーションの再起動を担当することを望むと考えます。 なぜなら、その時点でUvicornとPythonを使った同じアプリケーションはすでにクラッシュしており、同じアプリケーションの同じコードに対して何もできないためです。 |
||||
|
|
||||
|
### 自動的に再起動するツールの例 |
||||
|
|
||||
|
ほとんどの場合、前述した**起動時にプログラムを実行する**ために使用されるツールは、自動で**再起動**することにも利用されます。 |
||||
|
|
||||
|
例えば、次のようなものがあります: |
||||
|
|
||||
|
* Docker |
||||
|
* Kubernetes |
||||
|
* Docker Compose |
||||
|
* Swarm モードによる Docker |
||||
|
* Systemd |
||||
|
* Supervisor |
||||
|
* クラウドプロバイダーがサービスの一部として内部的に処理 |
||||
|
* そのほか... |
||||
|
|
||||
|
## レプリケーション - プロセスとメモリー |
||||
|
|
||||
|
FastAPI アプリケーションでは、Uvicorn のようなサーバープログラムを使用し、**1つのプロセス**で1度に複数のクライアントに同時に対応できます。 |
||||
|
|
||||
|
しかし、多くの場合、複数のワーカー・プロセスを同時に実行したいと考えるでしょう。 |
||||
|
|
||||
|
### 複数のプロセス - Worker |
||||
|
|
||||
|
クライアントの数が単一のプロセスで処理できる数を超えており(たとえば仮想マシンがそれほど大きくない場合)、かつサーバーの CPU に**複数のコア**がある場合、同じアプリケーションで同時に**複数のプロセス**を実行させ、すべてのリクエストを分散させることができます。 |
||||
|
|
||||
|
同じAPIプログラムの**複数のプロセス**を実行する場合、それらは一般的に**Worker/ワーカー**と呼ばれます。 |
||||
|
|
||||
|
### ワーカー・プロセス と ポート |
||||
|
<!-- NOTE: https.md written in Japanese does not exist, so it redirects to English one --> |
||||
|
|
||||
|
[HTTPSについて](./https.md){.internal-link target=_blank}のドキュメントで、1つのサーバーで1つのポートとIPアドレスの組み合わせでリッスンできるのは1つのプロセスだけであることを覚えていますでしょうか? |
||||
|
|
||||
|
これはいまだに同じです。 |
||||
|
|
||||
|
そのため、**複数のプロセス**を同時に持つには**ポートでリッスンしている単一のプロセス**が必要であり、それが何らかの方法で各ワーカー・プロセスに通信を送信することが求められます。 |
||||
|
|
||||
|
### プロセスあたりのメモリー |
||||
|
|
||||
|
さて、プログラムがメモリにロードする際には、例えば機械学習モデルや大きなファイルの内容を変数に入れたりする場合では、**サーバーのメモリ(RAM)**を少し消費します。 |
||||
|
|
||||
|
そして複数のプロセスは通常、**メモリを共有しません**。これは、実行中の各プロセスがそれぞれ独自の変数やメモリ等を持っていることを意味します。つまり、コード内で大量のメモリを消費している場合、**各プロセス**は同等の量のメモリを消費することになります。 |
||||
|
|
||||
|
### サーバーメモリー |
||||
|
|
||||
|
例えば、あなたのコードが **1GBのサイズの機械学習モデル**をロードする場合、APIで1つのプロセスを実行すると、少なくとも1GBのRAMを消費します。 |
||||
|
|
||||
|
また、**4つのプロセス**(4つのワーカー)を起動すると、それぞれが1GBのRAMを消費します。つまり、合計でAPIは**4GBのRAM**を消費することになります。 |
||||
|
|
||||
|
リモートサーバーや仮想マシンのRAMが3GBしかない場合、4GB以上のRAMをロードしようとすると問題が発生します。🚨 |
||||
|
|
||||
|
### 複数プロセス - 例 |
||||
|
|
||||
|
この例では、2つの**ワーカー・プロセス**を起動し制御する**マネージャー・ プロセス**があります。 |
||||
|
|
||||
|
このマネージャー・ プロセスは、おそらくIPの**ポート**でリッスンしているものです。そして、すべての通信をワーカー・プロセスに転送します。 |
||||
|
|
||||
|
これらのワーカー・プロセスは、アプリケーションを実行するものであり、**リクエスト**を受けて**レスポンス**を返すための主要な計算を行い、あなたが変数に入れたものは何でもRAMにロードします。 |
||||
|
|
||||
|
<img src="/img/deployment/concepts/process-ram.svg"> |
||||
|
|
||||
|
そしてもちろん、同じマシンでは、あなたのアプリケーションとは別に、**他のプロセス**も実行されているでしょう。 |
||||
|
|
||||
|
興味深いことに、各プロセスが使用する**CPU**の割合は時間とともに大きく**変動**する可能性がありますが、**メモリ(RAM)**は通常、多かれ少なかれ**安定**します。 |
||||
|
|
||||
|
毎回同程度の計算を行うAPIがあり、多くのクライアントがいるのであれば、**CPU使用率**もおそらく**安定**するでしょう(常に急激に上下するのではなく)。 |
||||
|
|
||||
|
### レプリケーション・ツールと戦略の例 |
||||
|
|
||||
|
これを実現するにはいくつかのアプローチがありますが、具体的な戦略については次の章(Dockerやコンテナの章など)で詳しく説明します。 |
||||
|
|
||||
|
考慮すべき主な制約は、**パブリックIP**の**ポート**を処理する**単一の**コンポーネントが存在しなければならないということです。 |
||||
|
|
||||
|
そして、レプリケートされた**プロセス/ワーカー**に通信を**送信**する方法を持つ必要があります。 |
||||
|
|
||||
|
考えられる組み合わせと戦略をいくつか紹介します: |
||||
|
|
||||
|
* **Gunicorn**が**Uvicornワーカー**を管理 |
||||
|
* Gunicornは**IP**と**ポート**をリッスンする**プロセスマネージャ**で、レプリケーションは**複数のUvicornワーカー・プロセス**を持つことによって行われる。 |
||||
|
* **Uvicorn**が**Uvicornワーカー**を管理 |
||||
|
* 1つのUvicornの**プロセスマネージャー**が**IP**と**ポート**をリッスンし、**複数のUvicornワーカー・プロセス**を起動する。 |
||||
|
* **Kubernetes**やその他の分散**コンテナ・システム** |
||||
|
* **Kubernetes**レイヤーの何かが**IP**と**ポート**をリッスンする。レプリケーションは、**複数のコンテナ**にそれぞれ**1つのUvicornプロセス**を実行させることで行われる。 |
||||
|
* **クラウド・サービス**によるレプリケーション |
||||
|
* クラウド・サービスはおそらく**あなたのためにレプリケーションを処理**します。**実行するプロセス**や使用する**コンテナイメージ**を定義できるかもしれませんが、いずれにせよ、それはおそらく**単一のUvicornプロセス**であり、クラウドサービスはそのレプリケーションを担当するでしょう。 |
||||
|
|
||||
|
!!! tip |
||||
|
これらの**コンテナ**やDockerそしてKubernetesに関する項目が、まだあまり意味をなしていなくても心配しないでください。 |
||||
|
<!-- NOTE: the current version of docker.md is outdated compared to English one. --> |
||||
|
|
||||
|
コンテナ・イメージ、Docker、Kubernetesなどについては、次の章で詳しく説明します: [コンテナ内のFastAPI - Docker](./docker.md){.internal-link target=_blank}. |
||||
|
|
||||
|
## 開始前の事前のステップ |
||||
|
|
||||
|
アプリケーションを**開始する前**に、いくつかのステップを実行したい場合が多くあります。 |
||||
|
|
||||
|
例えば、**データベース・マイグレーション** を実行したいかもしれません。 |
||||
|
|
||||
|
しかしほとんどの場合、これらの手順を**1度**に実行したいと考えるでしょう。 |
||||
|
|
||||
|
そのため、アプリケーションを開始する前の**事前のステップ**を実行する**単一のプロセス**を用意したいと思われます。 |
||||
|
|
||||
|
そして、それらの事前のステップを実行しているのが単一のプロセスであることを確認する必要があります。このことはその後アプリケーション自体のために**複数のプロセス**(複数のワーカー)を起動した場合も同様です。 |
||||
|
|
||||
|
これらのステップが**複数のプロセス**によって実行された場合、**並列**に実行されることによって作業が**重複**することになります。そして、もしそのステップがデータベースのマイグレーションのような繊細なものであった場合、互いに競合を引き起こす可能性があります。 |
||||
|
|
||||
|
もちろん、事前のステップを何度も実行しても問題がない場合もあり、その際は対処がかなり楽になります。 |
||||
|
|
||||
|
!!! tip |
||||
|
また、セットアップによっては、アプリケーションを開始する前の**事前のステップ**が必要ない場合もあることを覚えておいてください。 |
||||
|
|
||||
|
その場合は、このようなことを心配する必要はないです。🤷 |
||||
|
|
||||
|
### 事前ステップの戦略例 |
||||
|
|
||||
|
これは**システムを**デプロイする方法に**大きく依存**するだろうし、おそらくプログラムの起動方法や再起動の処理などにも関係してくるでしょう。 |
||||
|
|
||||
|
考えられるアイデアをいくつか挙げてみます: |
||||
|
|
||||
|
* アプリコンテナの前に実行されるKubernetesのInitコンテナ |
||||
|
* 事前のステップを実行し、アプリケーションを起動するbashスクリプト |
||||
|
* 利用するbashスクリプトを起動/再起動したり、エラーを検出したりする方法は以前として必要になるでしょう。 |
||||
|
|
||||
|
!!! tip |
||||
|
<!-- NOTE: the current version of docker.md is outdated compared to English one. --> |
||||
|
コンテナを使った具体的な例については、次の章で紹介します: [コンテナ内のFastAPI - Docker](./docker.md){.internal-link target=_blank}. |
||||
|
|
||||
|
## リソースの利用 |
||||
|
|
||||
|
あなたのサーバーは**リソース**であり、プログラムを実行しCPUの計算時間や利用可能なRAMメモリを消費または**利用**することができます。 |
||||
|
|
||||
|
システムリソースをどれくらい消費/利用したいですか? 「少ない方が良い」と考えるのは簡単かもしれないですが、実際には、**クラッシュせずに可能な限り**最大限に活用したいでしょう。 |
||||
|
|
||||
|
3台のサーバーにお金を払っているにも関わらず、そのRAMとCPUを少ししか使っていないとしたら、おそらく**お金を無駄にしている** 💸、おそらく**サーバーの電力を無駄にしている** 🌎ことになるでしょう。 |
||||
|
|
||||
|
その場合は、サーバーを2台だけにして、そのリソース(CPU、メモリ、ディスク、ネットワーク帯域幅など)をより高い割合で使用する方がよいでしょう。 |
||||
|
|
||||
|
一方、2台のサーバーがあり、そのCPUとRAMの**100%を使用している**場合、ある時点で1つのプロセスがより多くのメモリを要求し、サーバーはディスクを「メモリ」として使用しないといけません。(何千倍も遅くなる可能性があります。) |
||||
|
もしくは**クラッシュ**することもあれば、あるいはあるプロセスが何らかの計算をする必要があり、そしてCPUが再び空くまで待たなければならないかもしれません。 |
||||
|
|
||||
|
この場合、**1つ余分なサーバー**を用意し、その上でいくつかのプロセスを実行し、すべてのサーバーが**十分なRAMとCPU時間を持つようにする**のがよいでしょう。 |
||||
|
|
||||
|
また、何らかの理由でAPIの利用が急増する可能性もあります。もしかしたらそれが流行ったのかもしれないし、他のサービスやボットが使い始めたのかもしれないです。そのような場合に備えて、余分なリソースを用意しておくと安心でしょう。 |
||||
|
|
||||
|
例えば、リソース使用率の**50%から90%の範囲**で**任意の数字**をターゲットとすることができます。 |
||||
|
|
||||
|
重要なのは、デプロイメントを微調整するためにターゲットを設定し測定することが、おそらく使用したい主要な要素であることです。 |
||||
|
|
||||
|
`htop`のような単純なツールを使って、サーバーで使用されているCPUやRAM、あるいは各プロセスで使用されている量を見ることができます。あるいは、より複雑な監視ツールを使って、サーバに分散して使用することもできます。 |
||||
|
|
||||
|
## まとめ |
||||
|
|
||||
|
アプリケーションのデプロイ方法を決定する際に、考慮すべきであろう主要なコンセプトのいくつかを紹介していきました: |
||||
|
|
||||
|
* セキュリティ - HTTPS |
||||
|
* 起動時の実行 |
||||
|
* 再起動 |
||||
|
* レプリケーション(実行中のプロセス数) |
||||
|
* メモリー |
||||
|
* 開始前の事前ステップ |
||||
|
|
||||
|
これらの考え方とその適用方法を理解することで、デプロイメントを設定したり調整したりする際に必要な直感的な判断ができるようになるはずです。🤓 |
||||
|
|
||||
|
次のセクションでは、あなたが取り得る戦略について、より具体的な例を挙げます。🚀 |
@ -1,240 +0,0 @@ |
|||||
# Deta にデプロイ |
|
||||
|
|
||||
このセクションでは、**FastAPI** アプリケーションを <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> の無料プランを利用して、簡単にデプロイする方法を学習します。🎁 |
|
||||
|
|
||||
所要時間は約**10分**です。 |
|
||||
|
|
||||
!!! info "備考" |
|
||||
<a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> は **FastAPI** のスポンサーです。🎉 |
|
||||
|
|
||||
## ベーシックな **FastAPI** アプリ |
|
||||
|
|
||||
* アプリのためのディレクトリ (例えば `./fastapideta/`) を作成し、その中に入ってください。 |
|
||||
|
|
||||
### FastAPI のコード |
|
||||
|
|
||||
* 以下の `main.py` ファイルを作成してください: |
|
||||
|
|
||||
```Python |
|
||||
from fastapi import FastAPI |
|
||||
|
|
||||
app = FastAPI() |
|
||||
|
|
||||
|
|
||||
@app.get("/") |
|
||||
def read_root(): |
|
||||
return {"Hello": "World"} |
|
||||
|
|
||||
|
|
||||
@app.get("/items/{item_id}") |
|
||||
def read_item(item_id: int): |
|
||||
return {"item_id": item_id} |
|
||||
``` |
|
||||
|
|
||||
### Requirements |
|
||||
|
|
||||
では、同じディレクトリに以下の `requirements.txt` ファイルを作成してください: |
|
||||
|
|
||||
```text |
|
||||
fastapi |
|
||||
``` |
|
||||
|
|
||||
!!! tip "豆知識" |
|
||||
アプリのローカルテストのために Uvicorn をインストールしたくなるかもしれませんが、Deta へのデプロイには不要です。 |
|
||||
|
|
||||
### ディレクトリ構造 |
|
||||
|
|
||||
以下の2つのファイルと1つの `./fastapideta/` ディレクトリがあるはずです: |
|
||||
|
|
||||
``` |
|
||||
. |
|
||||
└── main.py |
|
||||
└── requirements.txt |
|
||||
``` |
|
||||
|
|
||||
## Detaの無料アカウントの作成 |
|
||||
|
|
||||
それでは、<a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Detaの無料アカウント</a>を作成しましょう。必要なものはメールアドレスとパスワードだけです。 |
|
||||
|
|
||||
クレジットカードさえ必要ありません。 |
|
||||
|
|
||||
## CLIのインストール |
|
||||
|
|
||||
アカウントを取得したら、Deta <abbr title="Command Line Interface application">CLI</abbr> をインストールしてください: |
|
||||
|
|
||||
=== "Linux, macOS" |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ curl -fsSL https://get.deta.dev/cli.sh | sh |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
=== "Windows PowerShell" |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ iwr https://get.deta.dev/cli.ps1 -useb | iex |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
インストールしたら、インストールした CLI を有効にするために新たなターミナルを開いてください。 |
|
||||
|
|
||||
新たなターミナル上で、正しくインストールされたか確認します: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta --help |
|
||||
|
|
||||
Deta command line interface for managing deta micros. |
|
||||
Complete documentation available at https://docs.deta.sh |
|
||||
|
|
||||
Usage: |
|
||||
deta [flags] |
|
||||
deta [command] |
|
||||
|
|
||||
Available Commands: |
|
||||
auth Change auth settings for a deta micro |
|
||||
|
|
||||
... |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
!!! tip "豆知識" |
|
||||
CLI のインストールに問題が発生した場合は、<a href="https://docs.deta.sh/docs/micros/getting_started?ref=fastapi" class="external-link" target="_blank">Deta 公式ドキュメント</a>を参照してください。 |
|
||||
|
|
||||
## CLIでログイン |
|
||||
|
|
||||
CLI から Deta にログインしてみましょう: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta login |
|
||||
|
|
||||
Please, log in from the web page. Waiting.. |
|
||||
Logged in successfully. |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
自動的にウェブブラウザが開いて、認証処理が行われます。 |
|
||||
|
|
||||
## Deta でデプロイ |
|
||||
|
|
||||
次に、アプリケーションを Deta CLIでデプロイしましょう: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta new |
|
||||
|
|
||||
Successfully created a new micro |
|
||||
|
|
||||
// Notice the "endpoint" 🔍 |
|
||||
|
|
||||
{ |
|
||||
"name": "fastapideta", |
|
||||
"runtime": "python3.7", |
|
||||
"endpoint": "https://qltnci.deta.dev", |
|
||||
"visor": "enabled", |
|
||||
"http_auth": "enabled" |
|
||||
} |
|
||||
|
|
||||
Adding dependencies... |
|
||||
|
|
||||
|
|
||||
---> 100% |
|
||||
|
|
||||
|
|
||||
Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6 |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
次のようなJSONメッセージが表示されます: |
|
||||
|
|
||||
```JSON hl_lines="4" |
|
||||
{ |
|
||||
"name": "fastapideta", |
|
||||
"runtime": "python3.7", |
|
||||
"endpoint": "https://qltnci.deta.dev", |
|
||||
"visor": "enabled", |
|
||||
"http_auth": "enabled" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
!!! tip "豆知識" |
|
||||
あなたのデプロイでは異なる `"endpoint"` URLが表示されるでしょう。 |
|
||||
|
|
||||
## 確認 |
|
||||
|
|
||||
それでは、`endpoint` URLをブラウザで開いてみましょう。上記の例では `https://qltnci.deta.dev` ですが、あなたのURLは異なるはずです。 |
|
||||
|
|
||||
FastAPIアプリから返ってきたJSONレスポンスが表示されます: |
|
||||
|
|
||||
```JSON |
|
||||
{ |
|
||||
"Hello": "World" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
そして `/docs` へ移動してください。上記の例では、`https://qltnci.deta.dev/docs` です。 |
|
||||
|
|
||||
次のようなドキュメントが表示されます: |
|
||||
|
|
||||
<img src="/img/deployment/deta/image01.png"> |
|
||||
|
|
||||
## パブリックアクセスの有効化 |
|
||||
|
|
||||
デフォルトでは、Deta はクッキーを用いてアカウントの認証を行います。 |
|
||||
|
|
||||
しかし、準備が整えば、以下の様に公開できます: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta auth disable |
|
||||
|
|
||||
Successfully disabled http auth |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
ここで、URLを共有するとAPIにアクセスできるようになります。🚀 |
|
||||
|
|
||||
## HTTPS |
|
||||
|
|
||||
おめでとうございます!あなたの FastAPI アプリが Deta へデプロイされました!🎉 🍰 |
|
||||
|
|
||||
また、DetaがHTTPSを正しく処理するため、その処理を行う必要がなく、クライアントは暗号化された安全な通信が利用できます。✅ 🔒 |
|
||||
|
|
||||
## Visor を確認 |
|
||||
|
|
||||
ドキュメントUI (`https://qltnci.deta.dev/docs` のようなURLにある) は *path operation* `/items/{item_id}` へリクエストを送ることができます。 |
|
||||
|
|
||||
ID `5` の例を示します。 |
|
||||
|
|
||||
まず、<a href="https://web.deta.sh/" class="external-link" target="_blank">https://web.deta.sh</a> へアクセスします。 |
|
||||
|
|
||||
左側に各アプリの <abbr title="it comes from Micro(server)">「Micros」</abbr> というセクションが表示されます。 |
|
||||
|
|
||||
また、「Details」や「Visor」タブが表示されています。「Visor」タブへ移動してください。 |
|
||||
|
|
||||
そこでアプリに送られた直近のリクエストが調べられます。 |
|
||||
|
|
||||
また、それらを編集してリプレイできます。 |
|
||||
|
|
||||
<img src="/img/deployment/deta/image02.png"> |
|
||||
|
|
||||
## さらに詳しく知る |
|
||||
|
|
||||
様々な箇所で永続的にデータを保存したくなるでしょう。そのためには <a href="https://docs.deta.sh/docs/base/py_tutorial?ref=fastapi" class="external-link" target="_blank">Deta Base</a> を使用できます。惜しみない **無料利用枠** もあります。 |
|
||||
|
|
||||
詳しくは <a href="https://docs.deta.sh?ref=fastapi" class="external-link" target="_blank">Deta ドキュメント</a>を参照してください。 |
|
@ -0,0 +1,182 @@ |
|||||
|
# Server Workers - Gunicorn と Uvicorn |
||||
|
|
||||
|
前回のデプロイメントのコンセプトを振り返ってみましょう: |
||||
|
|
||||
|
* セキュリティ - HTTPS |
||||
|
* 起動時の実行 |
||||
|
* 再起動 |
||||
|
* **レプリケーション(実行中のプロセス数)** |
||||
|
* メモリ |
||||
|
* 開始前の事前ステップ |
||||
|
|
||||
|
ここまでのドキュメントのチュートリアルでは、おそらくUvicornのような**サーバープログラム**を**単一のプロセス**で実行しています。 |
||||
|
|
||||
|
アプリケーションをデプロイする際には、**複数のコア**を利用し、そしてより多くのリクエストを処理できるようにするために、プロセスの**レプリケーション**を持つことを望むでしょう。 |
||||
|
|
||||
|
前のチャプターである[デプロイメントのコンセプト](./concepts.md){.internal-link target=_blank}にて見てきたように、有効な戦略がいくつかあります。 |
||||
|
|
||||
|
ここでは<a href="https://gunicorn.org/" class="external-link" target="_blank">**Gunicorn**</a>が**Uvicornのワーカー・プロセス**を管理する場合の使い方について紹介していきます。 |
||||
|
|
||||
|
!!! info |
||||
|
<!-- NOTE: the current version of docker.md is outdated compared to English one. --> |
||||
|
DockerやKubernetesなどのコンテナを使用している場合は、次の章で詳しく説明します: [コンテナ内のFastAPI - Docker](./docker.md){.internal-link target=_blank} |
||||
|
|
||||
|
特に**Kubernetes**上で実行する場合は、おそらく**Gunicornを使用せず**、**コンテナごとに単一のUvicornプロセス**を実行することになりますが、それについてはこの章の後半で説明します。 |
||||
|
|
||||
|
## GunicornによるUvicornのワーカー・プロセスの管理 |
||||
|
|
||||
|
**Gunicorn**は**WSGI標準**のアプリケーションサーバーです。このことは、GunicornはFlaskやDjangoのようなアプリケーションにサービスを提供できることを意味します。Gunicornそれ自体は**FastAPI**と互換性がないですが、というのもFastAPIは最新の**<a href="https://asgi.readthedocs.io/en/latest/" class="external-link" target="_blank">ASGI 標準</a>**を使用しているためです。 |
||||
|
|
||||
|
しかし、Gunicornは**プロセスマネージャー**として動作し、ユーザーが特定の**ワーカー・プロセスクラス**を使用するように指示することができます。するとGunicornはそのクラスを使い1つ以上の**ワーカー・プロセス**を開始します。 |
||||
|
|
||||
|
そして**Uvicorn**には**Gunicorn互換のワーカークラス**があります。 |
||||
|
|
||||
|
この組み合わせで、Gunicornは**プロセスマネージャー**として動作し、**ポート**と**IP**をリッスンします。そして、**Uvicornクラス**を実行しているワーカー・プロセスに通信を**転送**します。 |
||||
|
|
||||
|
そして、Gunicorn互換の**Uvicornワーカー**クラスが、FastAPIが使えるように、Gunicornから送られてきたデータをASGI標準に変換する役割を担います。 |
||||
|
|
||||
|
## GunicornとUvicornをインストールする |
||||
|
|
||||
|
<div class="termy"> |
||||
|
|
||||
|
```console |
||||
|
$ pip install "uvicorn[standard]" gunicorn |
||||
|
|
||||
|
---> 100% |
||||
|
``` |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
これによりUvicornと(高性能を得るための)標準(`standard`)の追加パッケージとGunicornの両方がインストールされます。 |
||||
|
|
||||
|
## UvicornのワーカーとともにGunicornを実行する |
||||
|
|
||||
|
Gunicornを以下のように起動させることができます: |
||||
|
|
||||
|
<div class="termy"> |
||||
|
|
||||
|
```console |
||||
|
$ gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:80 |
||||
|
|
||||
|
[19499] [INFO] Starting gunicorn 20.1.0 |
||||
|
[19499] [INFO] Listening at: http://0.0.0.0:80 (19499) |
||||
|
[19499] [INFO] Using worker: uvicorn.workers.UvicornWorker |
||||
|
[19511] [INFO] Booting worker with pid: 19511 |
||||
|
[19513] [INFO] Booting worker with pid: 19513 |
||||
|
[19514] [INFO] Booting worker with pid: 19514 |
||||
|
[19515] [INFO] Booting worker with pid: 19515 |
||||
|
[19511] [INFO] Started server process [19511] |
||||
|
[19511] [INFO] Waiting for application startup. |
||||
|
[19511] [INFO] Application startup complete. |
||||
|
[19513] [INFO] Started server process [19513] |
||||
|
[19513] [INFO] Waiting for application startup. |
||||
|
[19513] [INFO] Application startup complete. |
||||
|
[19514] [INFO] Started server process [19514] |
||||
|
[19514] [INFO] Waiting for application startup. |
||||
|
[19514] [INFO] Application startup complete. |
||||
|
[19515] [INFO] Started server process [19515] |
||||
|
[19515] [INFO] Waiting for application startup. |
||||
|
[19515] [INFO] Application startup complete. |
||||
|
``` |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
それぞれのオプションの意味を見てみましょう: |
||||
|
|
||||
|
* `main:app`: `main`は"`main`"という名前のPythonモジュール、つまりファイル`main.py`を意味します。そして `app` は **FastAPI** アプリケーションの変数名です。 |
||||
|
* main:app`はPythonの`import`文と同じようなものだと想像できます: |
||||
|
|
||||
|
```Python |
||||
|
from main import app |
||||
|
``` |
||||
|
|
||||
|
* つまり、`main:app`のコロンは、`from main import app`のPythonの`import`の部分と同じになります。 |
||||
|
|
||||
|
* `--workers`: 使用するワーカー・プロセスの数で、それぞれがUvicornのワーカーを実行します。 |
||||
|
|
||||
|
* `--worker-class`: ワーカー・プロセスで使用するGunicorn互換のワーカークラスです。 |
||||
|
* ここではGunicornがインポートして使用できるクラスを渡します: |
||||
|
|
||||
|
```Python |
||||
|
import uvicorn.workers.UvicornWorker |
||||
|
``` |
||||
|
|
||||
|
* `--bind`: GunicornにリッスンするIPとポートを伝えます。コロン(`:`)でIPとポートを区切ります。 |
||||
|
* Uvicornを直接実行している場合は、`--bind 0.0.0.0:80` (Gunicornのオプション)の代わりに、`--host 0.0.0.0`と `--port 80`を使います。 |
||||
|
|
||||
|
出力では、各プロセスの**PID**(プロセスID)が表示されているのがわかります(単なる数字です)。 |
||||
|
|
||||
|
以下の通りです: |
||||
|
|
||||
|
* Gunicornの**プロセス・マネージャー**はPID `19499`(あなたの場合は違う番号でしょう)で始まります。 |
||||
|
* 次に、`Listening at: http://0.0.0.0:80`を開始します。 |
||||
|
* それから `uvicorn.workers.UvicornWorker` でワーカークラスを使用することを検出します。 |
||||
|
* そして、**4つのワーカー**を起動します。それぞれのワーカーのPIDは、`19511`、`19513`、`19514`、`19515`です。 |
||||
|
|
||||
|
Gunicornはまた、ワーカーの数を維持するために必要であれば、**ダウンしたプロセス**を管理し、**新しいプロセスを**再起動**させます。そのため、上記のリストにある**再起動**の概念に一部役立ちます。 |
||||
|
|
||||
|
しかしながら、必要であればGunicornを**再起動**させ、**起動時に実行**させるなど、外部のコンポーネントを持たせることも必要かもしれません。 |
||||
|
|
||||
|
## Uvicornとワーカー |
||||
|
|
||||
|
Uvicornには複数の**ワーカー・プロセス**を起動し実行するオプションもあります。 |
||||
|
|
||||
|
とはいうものの、今のところUvicornのワーカー・プロセスを扱う機能はGunicornよりも制限されています。そのため、このレベル(Pythonレベル)でプロセスマネージャーを持ちたいのであれば、Gunicornをプロセスマネージャーとして使ってみた方が賢明かもしれないです。 |
||||
|
|
||||
|
どんな場合であれ、以下のように実行します: |
||||
|
|
||||
|
<div class="termy"> |
||||
|
|
||||
|
```console |
||||
|
$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4 |
||||
|
<font color="#A6E22E">INFO</font>: Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit) |
||||
|
<font color="#A6E22E">INFO</font>: Started parent process [<font color="#A1EFE4"><b>27365</b></font>] |
||||
|
<font color="#A6E22E">INFO</font>: Started server process [<font color="#A1EFE4">27368</font>] |
||||
|
<font color="#A6E22E">INFO</font>: Waiting for application startup. |
||||
|
<font color="#A6E22E">INFO</font>: Application startup complete. |
||||
|
<font color="#A6E22E">INFO</font>: Started server process [<font color="#A1EFE4">27369</font>] |
||||
|
<font color="#A6E22E">INFO</font>: Waiting for application startup. |
||||
|
<font color="#A6E22E">INFO</font>: Application startup complete. |
||||
|
<font color="#A6E22E">INFO</font>: Started server process [<font color="#A1EFE4">27370</font>] |
||||
|
<font color="#A6E22E">INFO</font>: Waiting for application startup. |
||||
|
<font color="#A6E22E">INFO</font>: Application startup complete. |
||||
|
<font color="#A6E22E">INFO</font>: Started server process [<font color="#A1EFE4">27367</font>] |
||||
|
<font color="#A6E22E">INFO</font>: Waiting for application startup. |
||||
|
<font color="#A6E22E">INFO</font>: Application startup complete. |
||||
|
``` |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
ここで唯一の新しいオプションは `--workers` で、Uvicornに4つのワーカー・プロセスを起動するように指示しています。 |
||||
|
|
||||
|
各プロセスの **PID** が表示され、親プロセスの `27365` (これは **プロセスマネージャ**) と、各ワーカー・プロセスの **PID** が表示されます: `27368`、`27369`、`27370`、`27367`になります。 |
||||
|
|
||||
|
## デプロイメントのコンセプト |
||||
|
|
||||
|
ここでは、アプリケーションの実行を**並列化**し、CPUの**マルチコア**を活用し、**より多くのリクエスト**に対応できるようにするために、**Gunicorn**(またはUvicorn)を使用して**Uvicornワーカー・プロセス**を管理する方法を見ていきました。 |
||||
|
|
||||
|
上記のデプロイのコンセプトのリストから、ワーカーを使うことは主に**レプリケーション**の部分と、**再起動**を少し助けてくれます: |
||||
|
|
||||
|
* セキュリティ - HTTPS |
||||
|
* 起動時の実行 |
||||
|
* 再起動 |
||||
|
* レプリケーション(実行中のプロセス数) |
||||
|
* メモリー |
||||
|
* 開始前の事前のステップ |
||||
|
|
||||
|
|
||||
|
## コンテナとDocker |
||||
|
<!-- NOTE: the current version of docker.md is outdated compared to English one. --> |
||||
|
次章の[コンテナ内のFastAPI - Docker](./docker.md){.internal-link target=_blank}では、その他の**デプロイのコンセプト**を扱うために実施するであろう戦略をいくつか紹介します。 |
||||
|
|
||||
|
また、**GunicornとUvicornワーカー**を含む**公式Dockerイメージ**と、簡単なケースに役立ついくつかのデフォルト設定も紹介します。 |
||||
|
|
||||
|
また、(Gunicornを使わずに)Uvicornプロセスを1つだけ実行するために、**ゼロから独自のイメージを**構築する方法も紹介します。これは簡単なプロセスで、おそらく**Kubernetes**のような分散コンテナ管理システムを使うときにやりたいことでしょう。 |
||||
|
|
||||
|
## まとめ |
||||
|
|
||||
|
Uvicornワーカーを使ったプロセスマネージャとして**Gunicorn**(またはUvicorn)を使えば、**マルチコアCPU**を活用して**複数のプロセスを並列実行**できます。 |
||||
|
|
||||
|
これらのツールやアイデアは、**あなた自身のデプロイシステム**をセットアップしながら、他のデプロイコンセプトを自分で行う場合にも使えます。 |
||||
|
|
||||
|
次の章では、コンテナ(DockerやKubernetesなど)を使った**FastAPI**について学んでいきましょう。これらのツールには、他の**デプロイのコンセプト**も解決する簡単な方法があることがわかるでしょう。✨ |
@ -1,258 +0,0 @@ |
|||||
# Implantação FastAPI na Deta |
|
||||
|
|
||||
Nessa seção você aprenderá sobre como realizar a implantação de uma aplicação **FastAPI** na <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> utilizando o plano gratuito. 🎁 |
|
||||
|
|
||||
Isso tudo levará aproximadamente **10 minutos**. |
|
||||
|
|
||||
!!! info "Informação" |
|
||||
<a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">Deta</a> é uma patrocinadora do **FastAPI**. 🎉 |
|
||||
|
|
||||
## Uma aplicação **FastAPI** simples |
|
||||
|
|
||||
* Crie e entre em um diretório para a sua aplicação, por exemplo, `./fastapideta/`. |
|
||||
|
|
||||
### Código FastAPI |
|
||||
|
|
||||
* Crie o arquivo `main.py` com: |
|
||||
|
|
||||
```Python |
|
||||
from fastapi import FastAPI |
|
||||
|
|
||||
app = FastAPI() |
|
||||
|
|
||||
|
|
||||
@app.get("/") |
|
||||
def read_root(): |
|
||||
return {"Hello": "World"} |
|
||||
|
|
||||
|
|
||||
@app.get("/items/{item_id}") |
|
||||
def read_item(item_id: int): |
|
||||
return {"item_id": item_id} |
|
||||
``` |
|
||||
|
|
||||
### Requisitos |
|
||||
|
|
||||
Agora, no mesmo diretório crie o arquivo `requirements.txt` com: |
|
||||
|
|
||||
```text |
|
||||
fastapi |
|
||||
``` |
|
||||
|
|
||||
!!! tip "Dica" |
|
||||
Você não precisa instalar Uvicorn para realizar a implantação na Deta, embora provavelmente queira instalá-lo para testar seu aplicativo localmente. |
|
||||
|
|
||||
### Estrutura de diretório |
|
||||
|
|
||||
Agora você terá o diretório `./fastapideta/` com dois arquivos: |
|
||||
|
|
||||
``` |
|
||||
. |
|
||||
└── main.py |
|
||||
└── requirements.txt |
|
||||
``` |
|
||||
|
|
||||
## Crie uma conta gratuita na Deta |
|
||||
|
|
||||
Agora crie <a href="https://www.deta.sh/?ref=fastapi" class="external-link" target="_blank">uma conta gratuita na Deta</a>, você precisará apenas de um email e senha. |
|
||||
|
|
||||
Você nem precisa de um cartão de crédito. |
|
||||
|
|
||||
## Instale a CLI |
|
||||
|
|
||||
Depois de ter sua conta criada, instale Deta <abbr title="Interface de Linha de Comando">CLI</abbr>: |
|
||||
|
|
||||
=== "Linux, macOS" |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ curl -fsSL https://get.deta.dev/cli.sh | sh |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
=== "Windows PowerShell" |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ iwr https://get.deta.dev/cli.ps1 -useb | iex |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
Após a instalação, abra um novo terminal para que a CLI seja detectada. |
|
||||
|
|
||||
Em um novo terminal, confirme se foi instalado corretamente com: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta --help |
|
||||
|
|
||||
Deta command line interface for managing deta micros. |
|
||||
Complete documentation available at https://docs.deta.sh |
|
||||
|
|
||||
Usage: |
|
||||
deta [flags] |
|
||||
deta [command] |
|
||||
|
|
||||
Available Commands: |
|
||||
auth Change auth settings for a deta micro |
|
||||
|
|
||||
... |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
!!! tip "Dica" |
|
||||
Se você tiver problemas ao instalar a CLI, verifique a <a href="https://docs.deta.sh/docs/micros/getting_started?ref=fastapi" class="external-link" target="_blank">documentação oficial da Deta</a>. |
|
||||
|
|
||||
## Login pela CLI |
|
||||
|
|
||||
Agora faça login na Deta pela CLI com: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta login |
|
||||
|
|
||||
Please, log in from the web page. Waiting.. |
|
||||
Logged in successfully. |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
Isso abrirá um navegador da Web e autenticará automaticamente. |
|
||||
|
|
||||
## Implantação com Deta |
|
||||
|
|
||||
Em seguida, implante seu aplicativo com a Deta CLI: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta new |
|
||||
|
|
||||
Successfully created a new micro |
|
||||
|
|
||||
// Notice the "endpoint" 🔍 |
|
||||
|
|
||||
{ |
|
||||
"name": "fastapideta", |
|
||||
"runtime": "python3.7", |
|
||||
"endpoint": "https://qltnci.deta.dev", |
|
||||
"visor": "enabled", |
|
||||
"http_auth": "enabled" |
|
||||
} |
|
||||
|
|
||||
Adding dependencies... |
|
||||
|
|
||||
|
|
||||
---> 100% |
|
||||
|
|
||||
|
|
||||
Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6 |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
Você verá uma mensagem JSON semelhante a: |
|
||||
|
|
||||
```JSON hl_lines="4" |
|
||||
{ |
|
||||
"name": "fastapideta", |
|
||||
"runtime": "python3.7", |
|
||||
"endpoint": "https://qltnci.deta.dev", |
|
||||
"visor": "enabled", |
|
||||
"http_auth": "enabled" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
!!! tip "Dica" |
|
||||
Sua implantação terá um URL `"endpoint"` diferente. |
|
||||
|
|
||||
## Confira |
|
||||
|
|
||||
Agora, abra seu navegador na URL do `endpoint`. No exemplo acima foi `https://qltnci.deta.dev`, mas o seu será diferente. |
|
||||
|
|
||||
Você verá a resposta JSON do seu aplicativo FastAPI: |
|
||||
|
|
||||
```JSON |
|
||||
{ |
|
||||
"Hello": "World" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
Agora vá para o `/docs` da sua API, no exemplo acima seria `https://qltnci.deta.dev/docs`. |
|
||||
|
|
||||
Ele mostrará sua documentação como: |
|
||||
|
|
||||
<img src="/img/deployment/deta/image01.png"> |
|
||||
|
|
||||
## Permitir acesso público |
|
||||
|
|
||||
Por padrão, a Deta lidará com a autenticação usando cookies para sua conta. |
|
||||
|
|
||||
Mas quando estiver pronto, você pode torná-lo público com: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ deta auth disable |
|
||||
|
|
||||
Successfully disabled http auth |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
Agora você pode compartilhar essa URL com qualquer pessoa e elas conseguirão acessar sua API. 🚀 |
|
||||
|
|
||||
## HTTPS |
|
||||
|
|
||||
Parabéns! Você realizou a implantação do seu app FastAPI na Deta! 🎉 🍰 |
|
||||
|
|
||||
Além disso, observe que a Deta lida corretamente com HTTPS para você, para que você não precise cuidar disso e tenha a certeza de que seus clientes terão uma conexão criptografada segura. ✅ 🔒 |
|
||||
|
|
||||
## Verifique o Visor |
|
||||
|
|
||||
Na UI da sua documentação (você estará em um URL como `https://qltnci.deta.dev/docs`) envie um request para *operação de rota* `/items/{item_id}`. |
|
||||
|
|
||||
Por exemplo com ID `5`. |
|
||||
|
|
||||
Agora vá para <a href="https://web.deta.sh/" class="external-link" target="_blank">https://web.deta.sh</a>. |
|
||||
|
|
||||
Você verá que há uma seção à esquerda chamada <abbr title="it comes from Micro(server)">"Micros"</abbr> com cada um dos seus apps. |
|
||||
|
|
||||
Você verá uma aba com "Detalhes", e também a aba "Visor", vá para "Visor". |
|
||||
|
|
||||
Lá você pode inspecionar as solicitações recentes enviadas ao seu aplicativo. |
|
||||
|
|
||||
Você também pode editá-los e reproduzi-los novamente. |
|
||||
|
|
||||
<img src="/img/deployment/deta/image02.png"> |
|
||||
|
|
||||
## Saiba mais |
|
||||
|
|
||||
Em algum momento, você provavelmente desejará armazenar alguns dados para seu aplicativo de uma forma que persista ao longo do tempo. Para isso você pode usar <a href="https://docs.deta.sh/docs/base/py_tutorial?ref=fastapi" class="external-link" target="_blank">Deta Base</a>, que também tem um generoso **nível gratuito**. |
|
||||
|
|
||||
Você também pode ler mais na <a href="https://docs.deta.sh?ref=fastapi" class="external-link" target="_blank">documentação da Deta</a>. |
|
||||
|
|
||||
## Conceitos de implantação |
|
||||
|
|
||||
Voltando aos conceitos que discutimos em [Deployments Concepts](./concepts.md){.internal-link target=_blank}, veja como cada um deles seria tratado com a Deta: |
|
||||
|
|
||||
* **HTTPS**: Realizado pela Deta, eles fornecerão um subdomínio e lidarão com HTTPS automaticamente. |
|
||||
* **Executando na inicialização**: Realizado pela Deta, como parte de seu serviço. |
|
||||
* **Reinicialização**: Realizado pela Deta, como parte de seu serviço. |
|
||||
* **Replicação**: Realizado pela Deta, como parte de seu serviço. |
|
||||
* **Memória**: Limite predefinido pela Deta, você pode contatá-los para aumentá-lo. |
|
||||
* **Etapas anteriores a inicialização**: Não suportado diretamente, você pode fazê-lo funcionar com o sistema Cron ou scripts adicionais. |
|
||||
|
|
||||
!!! note "Nota" |
|
||||
O Deta foi projetado para facilitar (e gratuitamente) a implantação rápida de aplicativos simples. |
|
||||
|
|
||||
Ele pode simplificar vários casos de uso, mas, ao mesmo tempo, não suporta outros, como o uso de bancos de dados externos (além do próprio sistema de banco de dados NoSQL da Deta), máquinas virtuais personalizadas, etc. |
|
||||
|
|
||||
Você pode ler mais detalhes na <a href="https://docs.deta.sh/docs/micros/about/" class="external-link" target="_blank">documentação da Deta</a> para ver se é a escolha certa para você. |
|
@ -0,0 +1,178 @@ |
|||||
|
# Люди FastAPI |
||||
|
|
||||
|
FastAPI має дивовижну спільноту, яка вітає людей різного походження. |
||||
|
|
||||
|
## Творець – Супроводжувач |
||||
|
|
||||
|
Привіт! 👋 |
||||
|
|
||||
|
Це я: |
||||
|
|
||||
|
{% if people %} |
||||
|
<div class="user-list user-list-center"> |
||||
|
{% for user in people.maintainers %} |
||||
|
|
||||
|
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Answers: {{ user.answers }}</div><div class="count">Pull Requests: {{ user.prs }}</div></div> |
||||
|
{% endfor %} |
||||
|
|
||||
|
</div> |
||||
|
{% endif %} |
||||
|
|
||||
|
Я - творець і супроводжувач **FastAPI**. Детальніше про це можна прочитати в [Довідка FastAPI - Отримати довідку - Зв'язатися з автором](help-fastapi.md#connect-with-the-author){.internal-link target=_blank}. |
||||
|
|
||||
|
...Але тут я хочу показати вам спільноту. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
**FastAPI** отримує велику підтримку від спільноти. І я хочу відзначити їхній внесок. |
||||
|
|
||||
|
Це люди, які: |
||||
|
|
||||
|
* [Допомагають іншим із проблемами (запитаннями) у GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank}. |
||||
|
* [Створюють пул реквести](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}. |
||||
|
* Переглядають пул реквести, [особливо важливо для перекладів](contributing.md#translations){.internal-link target=_blank}. |
||||
|
|
||||
|
Оплески їм. 👏 🙇 |
||||
|
|
||||
|
## Найбільш активні користувачі минулого місяця |
||||
|
|
||||
|
Це користувачі, які [найбільше допомагали іншим із проблемами (запитаннями) у GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} протягом минулого місяця. ☕ |
||||
|
|
||||
|
{% if people %} |
||||
|
<div class="user-list user-list-center"> |
||||
|
{% for user in people.last_month_active %} |
||||
|
|
||||
|
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Issues replied: {{ user.count }}</div></div> |
||||
|
{% endfor %} |
||||
|
|
||||
|
</div> |
||||
|
{% endif %} |
||||
|
|
||||
|
## Експерти |
||||
|
|
||||
|
Ось **експерти FastAPI**. 🤓 |
||||
|
|
||||
|
Це користувачі, які [найбільше допомагали іншим із проблемами (запитаннями) у GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} протягом *всього часу*. |
||||
|
|
||||
|
Вони зарекомендували себе як експерти, допомагаючи багатьом іншим. ✨ |
||||
|
|
||||
|
{% if people %} |
||||
|
<div class="user-list user-list-center"> |
||||
|
{% for user in people.experts %} |
||||
|
|
||||
|
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Issues replied: {{ user.count }}</div></div> |
||||
|
{% endfor %} |
||||
|
|
||||
|
</div> |
||||
|
{% endif %} |
||||
|
|
||||
|
## Найкращі контрибютори |
||||
|
|
||||
|
Ось **Найкращі контрибютори**. 👷 |
||||
|
|
||||
|
Ці користувачі [створили найбільшу кількість пул реквестів](help-fastapi.md#create-a-pull-request){.internal-link target=_blank} які були *змержені*. |
||||
|
|
||||
|
Вони надали програмний код, документацію, переклади тощо. 📦 |
||||
|
|
||||
|
{% if people %} |
||||
|
<div class="user-list user-list-center"> |
||||
|
{% for user in people.top_contributors %} |
||||
|
|
||||
|
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Pull Requests: {{ user.count }}</div></div> |
||||
|
{% endfor %} |
||||
|
|
||||
|
</div> |
||||
|
{% endif %} |
||||
|
|
||||
|
Є багато інших контрибюторів (більше сотні), їх усіх можна побачити на сторінці <a href="https://github.com/tiangolo/fastapi/graphs/contributors" class="external-link" target="_blank">FastAPI GitHub Contributors</a>. 👷 |
||||
|
|
||||
|
## Найкращі рецензенти |
||||
|
|
||||
|
Ці користувачі є **Найкращими рецензентами**. 🕵️ |
||||
|
|
||||
|
### Рецензенти на переклади |
||||
|
|
||||
|
Я розмовляю лише кількома мовами (і не дуже добре 😅). Отже, рецензенти – це ті, хто має [**повноваження схвалювати переклади**](contributing.md#translations){.internal-link target=_blank} документації. Без них не було б документації кількома іншими мовами. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
**Найкращі рецензенти** 🕵️ переглянули більшість пул реквестів від інших, забезпечуючи якість коду, документації і особливо **перекладів**. |
||||
|
|
||||
|
{% if people %} |
||||
|
<div class="user-list user-list-center"> |
||||
|
{% for user in people.top_reviewers %} |
||||
|
|
||||
|
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Reviews: {{ user.count }}</div></div> |
||||
|
{% endfor %} |
||||
|
|
||||
|
</div> |
||||
|
{% endif %} |
||||
|
|
||||
|
## Спонсори |
||||
|
|
||||
|
Це **Спонсори**. 😎 |
||||
|
|
||||
|
Вони підтримують мою роботу з **FastAPI** (та іншими), переважно через <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub Sponsors</a>. |
||||
|
|
||||
|
{% if sponsors %} |
||||
|
|
||||
|
{% if sponsors.gold %} |
||||
|
|
||||
|
### Золоті спонсори |
||||
|
|
||||
|
{% for sponsor in sponsors.gold -%} |
||||
|
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a> |
||||
|
{% endfor %} |
||||
|
{% endif %} |
||||
|
|
||||
|
{% if sponsors.silver %} |
||||
|
|
||||
|
### Срібні спонсори |
||||
|
|
||||
|
{% for sponsor in sponsors.silver -%} |
||||
|
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a> |
||||
|
{% endfor %} |
||||
|
{% endif %} |
||||
|
|
||||
|
{% if sponsors.bronze %} |
||||
|
|
||||
|
### Бронзові спонсори |
||||
|
|
||||
|
{% for sponsor in sponsors.bronze -%} |
||||
|
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a> |
||||
|
{% endfor %} |
||||
|
{% endif %} |
||||
|
|
||||
|
{% endif %} |
||||
|
|
||||
|
### Індивідуальні спонсори |
||||
|
|
||||
|
{% if github_sponsors %} |
||||
|
{% for group in github_sponsors.sponsors %} |
||||
|
|
||||
|
<div class="user-list user-list-center"> |
||||
|
|
||||
|
{% for user in group %} |
||||
|
{% if user.login not in sponsors_badge.logins %} |
||||
|
|
||||
|
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a></div> |
||||
|
|
||||
|
{% endif %} |
||||
|
{% endfor %} |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
{% endfor %} |
||||
|
{% endif %} |
||||
|
|
||||
|
## Про дані - технічні деталі |
||||
|
|
||||
|
Основна мета цієї сторінки – висвітлити зусилля спільноти, щоб допомогти іншим. |
||||
|
|
||||
|
Особливо враховуючи зусилля, які зазвичай менш помітні, а в багатьох випадках більш важкі, як-от допомога іншим із проблемами та перегляд пул реквестів перекладів. |
||||
|
|
||||
|
Дані розраховуються щомісяця, ви можете ознайомитися з <a href="https://github.com/tiangolo/fastapi/blob/master/.github/actions/people/app/main.py" class="external-link" target="_blank">вихідним кодом тут</a>. |
||||
|
|
||||
|
Тут я також підкреслюю внески спонсорів. |
||||
|
|
||||
|
Я також залишаю за собою право оновлювати алгоритми підрахунку, види рейтингів, порогові значення тощо (про всяк випадок 🤷). |
@ -0,0 +1,38 @@ |
|||||
|
from fastapi import FastAPI |
||||
|
from fastapi.openapi.docs import ( |
||||
|
get_redoc_html, |
||||
|
get_swagger_ui_html, |
||||
|
get_swagger_ui_oauth2_redirect_html, |
||||
|
) |
||||
|
|
||||
|
app = FastAPI(docs_url=None, redoc_url=None) |
||||
|
|
||||
|
|
||||
|
@app.get("/docs", include_in_schema=False) |
||||
|
async def custom_swagger_ui_html(): |
||||
|
return get_swagger_ui_html( |
||||
|
openapi_url=app.openapi_url, |
||||
|
title=app.title + " - Swagger UI", |
||||
|
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, |
||||
|
swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js", |
||||
|
swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css", |
||||
|
) |
||||
|
|
||||
|
|
||||
|
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False) |
||||
|
async def swagger_ui_redirect(): |
||||
|
return get_swagger_ui_oauth2_redirect_html() |
||||
|
|
||||
|
|
||||
|
@app.get("/redoc", include_in_schema=False) |
||||
|
async def redoc_html(): |
||||
|
return get_redoc_html( |
||||
|
openapi_url=app.openapi_url, |
||||
|
title=app.title + " - ReDoc", |
||||
|
redoc_js_url="https://unpkg.com/redoc@next/bundles/redoc.standalone.js", |
||||
|
) |
||||
|
|
||||
|
|
||||
|
@app.get("/users/{username}") |
||||
|
async def read_user(username: str): |
||||
|
return {"message": f"Hello {username}"} |
@ -1,6 +1,6 @@ |
|||||
from fastapi.testclient import TestClient |
from fastapi.testclient import TestClient |
||||
|
|
||||
from docs_src.extending_openapi.tutorial003 import app |
from docs_src.configure_swagger_ui.tutorial001 import app |
||||
|
|
||||
client = TestClient(app) |
client = TestClient(app) |
||||
|
|
@ -1,6 +1,6 @@ |
|||||
from fastapi.testclient import TestClient |
from fastapi.testclient import TestClient |
||||
|
|
||||
from docs_src.extending_openapi.tutorial004 import app |
from docs_src.configure_swagger_ui.tutorial002 import app |
||||
|
|
||||
client = TestClient(app) |
client = TestClient(app) |
||||
|
|
@ -1,6 +1,6 @@ |
|||||
from fastapi.testclient import TestClient |
from fastapi.testclient import TestClient |
||||
|
|
||||
from docs_src.extending_openapi.tutorial005 import app |
from docs_src.configure_swagger_ui.tutorial003 import app |
||||
|
|
||||
client = TestClient(app) |
client = TestClient(app) |
||||
|
|
@ -0,0 +1,42 @@ |
|||||
|
import os |
||||
|
from pathlib import Path |
||||
|
|
||||
|
import pytest |
||||
|
from fastapi.testclient import TestClient |
||||
|
|
||||
|
|
||||
|
@pytest.fixture(scope="module") |
||||
|
def client(): |
||||
|
static_dir: Path = Path(os.getcwd()) / "static" |
||||
|
print(static_dir) |
||||
|
static_dir.mkdir(exist_ok=True) |
||||
|
from docs_src.custom_docs_ui.tutorial001 import app |
||||
|
|
||||
|
with TestClient(app) as client: |
||||
|
yield client |
||||
|
static_dir.rmdir() |
||||
|
|
||||
|
|
||||
|
def test_swagger_ui_html(client: TestClient): |
||||
|
response = client.get("/docs") |
||||
|
assert response.status_code == 200, response.text |
||||
|
assert "https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js" in response.text |
||||
|
assert "https://unpkg.com/swagger-ui-dist@5/swagger-ui.css" in response.text |
||||
|
|
||||
|
|
||||
|
def test_swagger_ui_oauth2_redirect_html(client: TestClient): |
||||
|
response = client.get("/docs/oauth2-redirect") |
||||
|
assert response.status_code == 200, response.text |
||||
|
assert "window.opener.swaggerUIRedirectOauth2" in response.text |
||||
|
|
||||
|
|
||||
|
def test_redoc_html(client: TestClient): |
||||
|
response = client.get("/redoc") |
||||
|
assert response.status_code == 200, response.text |
||||
|
assert "https://unpkg.com/redoc@next/bundles/redoc.standalone.js" in response.text |
||||
|
|
||||
|
|
||||
|
def test_api(client: TestClient): |
||||
|
response = client.get("/users/john") |
||||
|
assert response.status_code == 200, response.text |
||||
|
assert response.json()["message"] == "Hello john" |
@ -1,454 +0,0 @@ |
|||||
import time |
|
||||
from pathlib import Path |
|
||||
from unittest.mock import MagicMock |
|
||||
|
|
||||
import pytest |
|
||||
from fastapi.testclient import TestClient |
|
||||
|
|
||||
from ...utils import needs_pydanticv1 |
|
||||
|
|
||||
|
|
||||
@pytest.fixture(scope="module") |
|
||||
def client(): |
|
||||
# Import while creating the client to create the DB after starting the test session |
|
||||
from docs_src.sql_databases_peewee.sql_app.main import app |
|
||||
|
|
||||
test_db = Path("./test.db") |
|
||||
with TestClient(app) as c: |
|
||||
yield c |
|
||||
test_db.unlink() |
|
||||
|
|
||||
|
|
||||
@needs_pydanticv1 |
|
||||
def test_create_user(client): |
|
||||
test_user = {"email": "[email protected]", "password": "secret"} |
|
||||
response = client.post("/users/", json=test_user) |
|
||||
assert response.status_code == 200, response.text |
|
||||
data = response.json() |
|
||||
assert test_user["email"] == data["email"] |
|
||||
assert "id" in data |
|
||||
response = client.post("/users/", json=test_user) |
|
||||
assert response.status_code == 400, response.text |
|
||||
|
|
||||
|
|
||||
@needs_pydanticv1 |
|
||||
def test_get_user(client): |
|
||||
response = client.get("/users/1") |
|
||||
assert response.status_code == 200, response.text |
|
||||
data = response.json() |
|
||||
assert "email" in data |
|
||||
assert "id" in data |
|
||||
|
|
||||
|
|
||||
@needs_pydanticv1 |
|
||||
def test_inexistent_user(client): |
|
||||
response = client.get("/users/999") |
|
||||
assert response.status_code == 404, response.text |
|
||||
|
|
||||
|
|
||||
@needs_pydanticv1 |
|
||||
def test_get_users(client): |
|
||||
response = client.get("/users/") |
|
||||
assert response.status_code == 200, response.text |
|
||||
data = response.json() |
|
||||
assert "email" in data[0] |
|
||||
assert "id" in data[0] |
|
||||
|
|
||||
|
|
||||
time.sleep = MagicMock() |
|
||||
|
|
||||
|
|
||||
@needs_pydanticv1 |
|
||||
def test_get_slowusers(client): |
|
||||
response = client.get("/slowusers/") |
|
||||
assert response.status_code == 200, response.text |
|
||||
data = response.json() |
|
||||
assert "email" in data[0] |
|
||||
assert "id" in data[0] |
|
||||
|
|
||||
|
|
||||
@needs_pydanticv1 |
|
||||
def test_create_item(client): |
|
||||
item = {"title": "Foo", "description": "Something that fights"} |
|
||||
response = client.post("/users/1/items/", json=item) |
|
||||
assert response.status_code == 200, response.text |
|
||||
item_data = response.json() |
|
||||
assert item["title"] == item_data["title"] |
|
||||
assert item["description"] == item_data["description"] |
|
||||
assert "id" in item_data |
|
||||
assert "owner_id" in item_data |
|
||||
response = client.get("/users/1") |
|
||||
assert response.status_code == 200, response.text |
|
||||
user_data = response.json() |
|
||||
item_to_check = [it for it in user_data["items"] if it["id"] == item_data["id"]][0] |
|
||||
assert item_to_check["title"] == item["title"] |
|
||||
assert item_to_check["description"] == item["description"] |
|
||||
response = client.get("/users/1") |
|
||||
assert response.status_code == 200, response.text |
|
||||
user_data = response.json() |
|
||||
item_to_check = [it for it in user_data["items"] if it["id"] == item_data["id"]][0] |
|
||||
assert item_to_check["title"] == item["title"] |
|
||||
assert item_to_check["description"] == item["description"] |
|
||||
|
|
||||
|
|
||||
@needs_pydanticv1 |
|
||||
def test_read_items(client): |
|
||||
response = client.get("/items/") |
|
||||
assert response.status_code == 200, response.text |
|
||||
data = response.json() |
|
||||
assert data |
|
||||
first_item = data[0] |
|
||||
assert "title" in first_item |
|
||||
assert "description" in first_item |
|
||||
|
|
||||
|
|
||||
@needs_pydanticv1 |
|
||||
def test_openapi_schema(client): |
|
||||
response = client.get("/openapi.json") |
|
||||
assert response.status_code == 200, response.text |
|
||||
assert response.json() == { |
|
||||
"openapi": "3.1.0", |
|
||||
"info": {"title": "FastAPI", "version": "0.1.0"}, |
|
||||
"paths": { |
|
||||
"/users/": { |
|
||||
"get": { |
|
||||
"summary": "Read Users", |
|
||||
"operationId": "read_users_users__get", |
|
||||
"parameters": [ |
|
||||
{ |
|
||||
"required": False, |
|
||||
"schema": { |
|
||||
"title": "Skip", |
|
||||
"type": "integer", |
|
||||
"default": 0, |
|
||||
}, |
|
||||
"name": "skip", |
|
||||
"in": "query", |
|
||||
}, |
|
||||
{ |
|
||||
"required": False, |
|
||||
"schema": { |
|
||||
"title": "Limit", |
|
||||
"type": "integer", |
|
||||
"default": 100, |
|
||||
}, |
|
||||
"name": "limit", |
|
||||
"in": "query", |
|
||||
}, |
|
||||
], |
|
||||
"responses": { |
|
||||
"200": { |
|
||||
"description": "Successful Response", |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": { |
|
||||
"title": "Response Read Users Users Get", |
|
||||
"type": "array", |
|
||||
"items": {"$ref": "#/components/schemas/User"}, |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
"422": { |
|
||||
"description": "Validation Error", |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": { |
|
||||
"$ref": "#/components/schemas/HTTPValidationError" |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
"post": { |
|
||||
"summary": "Create User", |
|
||||
"operationId": "create_user_users__post", |
|
||||
"requestBody": { |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": {"$ref": "#/components/schemas/UserCreate"} |
|
||||
} |
|
||||
}, |
|
||||
"required": True, |
|
||||
}, |
|
||||
"responses": { |
|
||||
"200": { |
|
||||
"description": "Successful Response", |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": {"$ref": "#/components/schemas/User"} |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
"422": { |
|
||||
"description": "Validation Error", |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": { |
|
||||
"$ref": "#/components/schemas/HTTPValidationError" |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
"/users/{user_id}": { |
|
||||
"get": { |
|
||||
"summary": "Read User", |
|
||||
"operationId": "read_user_users__user_id__get", |
|
||||
"parameters": [ |
|
||||
{ |
|
||||
"required": True, |
|
||||
"schema": {"title": "User Id", "type": "integer"}, |
|
||||
"name": "user_id", |
|
||||
"in": "path", |
|
||||
} |
|
||||
], |
|
||||
"responses": { |
|
||||
"200": { |
|
||||
"description": "Successful Response", |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": {"$ref": "#/components/schemas/User"} |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
"422": { |
|
||||
"description": "Validation Error", |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": { |
|
||||
"$ref": "#/components/schemas/HTTPValidationError" |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
} |
|
||||
}, |
|
||||
"/users/{user_id}/items/": { |
|
||||
"post": { |
|
||||
"summary": "Create Item For User", |
|
||||
"operationId": "create_item_for_user_users__user_id__items__post", |
|
||||
"parameters": [ |
|
||||
{ |
|
||||
"required": True, |
|
||||
"schema": {"title": "User Id", "type": "integer"}, |
|
||||
"name": "user_id", |
|
||||
"in": "path", |
|
||||
} |
|
||||
], |
|
||||
"requestBody": { |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": {"$ref": "#/components/schemas/ItemCreate"} |
|
||||
} |
|
||||
}, |
|
||||
"required": True, |
|
||||
}, |
|
||||
"responses": { |
|
||||
"200": { |
|
||||
"description": "Successful Response", |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": {"$ref": "#/components/schemas/Item"} |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
"422": { |
|
||||
"description": "Validation Error", |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": { |
|
||||
"$ref": "#/components/schemas/HTTPValidationError" |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
} |
|
||||
}, |
|
||||
"/items/": { |
|
||||
"get": { |
|
||||
"summary": "Read Items", |
|
||||
"operationId": "read_items_items__get", |
|
||||
"parameters": [ |
|
||||
{ |
|
||||
"required": False, |
|
||||
"schema": { |
|
||||
"title": "Skip", |
|
||||
"type": "integer", |
|
||||
"default": 0, |
|
||||
}, |
|
||||
"name": "skip", |
|
||||
"in": "query", |
|
||||
}, |
|
||||
{ |
|
||||
"required": False, |
|
||||
"schema": { |
|
||||
"title": "Limit", |
|
||||
"type": "integer", |
|
||||
"default": 100, |
|
||||
}, |
|
||||
"name": "limit", |
|
||||
"in": "query", |
|
||||
}, |
|
||||
], |
|
||||
"responses": { |
|
||||
"200": { |
|
||||
"description": "Successful Response", |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": { |
|
||||
"title": "Response Read Items Items Get", |
|
||||
"type": "array", |
|
||||
"items": {"$ref": "#/components/schemas/Item"}, |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
"422": { |
|
||||
"description": "Validation Error", |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": { |
|
||||
"$ref": "#/components/schemas/HTTPValidationError" |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
} |
|
||||
}, |
|
||||
"/slowusers/": { |
|
||||
"get": { |
|
||||
"summary": "Read Slow Users", |
|
||||
"operationId": "read_slow_users_slowusers__get", |
|
||||
"parameters": [ |
|
||||
{ |
|
||||
"required": False, |
|
||||
"schema": { |
|
||||
"title": "Skip", |
|
||||
"type": "integer", |
|
||||
"default": 0, |
|
||||
}, |
|
||||
"name": "skip", |
|
||||
"in": "query", |
|
||||
}, |
|
||||
{ |
|
||||
"required": False, |
|
||||
"schema": { |
|
||||
"title": "Limit", |
|
||||
"type": "integer", |
|
||||
"default": 100, |
|
||||
}, |
|
||||
"name": "limit", |
|
||||
"in": "query", |
|
||||
}, |
|
||||
], |
|
||||
"responses": { |
|
||||
"200": { |
|
||||
"description": "Successful Response", |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": { |
|
||||
"title": "Response Read Slow Users Slowusers Get", |
|
||||
"type": "array", |
|
||||
"items": {"$ref": "#/components/schemas/User"}, |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
"422": { |
|
||||
"description": "Validation Error", |
|
||||
"content": { |
|
||||
"application/json": { |
|
||||
"schema": { |
|
||||
"$ref": "#/components/schemas/HTTPValidationError" |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
"components": { |
|
||||
"schemas": { |
|
||||
"HTTPValidationError": { |
|
||||
"title": "HTTPValidationError", |
|
||||
"type": "object", |
|
||||
"properties": { |
|
||||
"detail": { |
|
||||
"title": "Detail", |
|
||||
"type": "array", |
|
||||
"items": {"$ref": "#/components/schemas/ValidationError"}, |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
"Item": { |
|
||||
"title": "Item", |
|
||||
"required": ["title", "id", "owner_id"], |
|
||||
"type": "object", |
|
||||
"properties": { |
|
||||
"title": {"title": "Title", "type": "string"}, |
|
||||
"description": {"title": "Description", "type": "string"}, |
|
||||
"id": {"title": "Id", "type": "integer"}, |
|
||||
"owner_id": {"title": "Owner Id", "type": "integer"}, |
|
||||
}, |
|
||||
}, |
|
||||
"ItemCreate": { |
|
||||
"title": "ItemCreate", |
|
||||
"required": ["title"], |
|
||||
"type": "object", |
|
||||
"properties": { |
|
||||
"title": {"title": "Title", "type": "string"}, |
|
||||
"description": {"title": "Description", "type": "string"}, |
|
||||
}, |
|
||||
}, |
|
||||
"User": { |
|
||||
"title": "User", |
|
||||
"required": ["email", "id", "is_active"], |
|
||||
"type": "object", |
|
||||
"properties": { |
|
||||
"email": {"title": "Email", "type": "string"}, |
|
||||
"id": {"title": "Id", "type": "integer"}, |
|
||||
"is_active": {"title": "Is Active", "type": "boolean"}, |
|
||||
"items": { |
|
||||
"title": "Items", |
|
||||
"type": "array", |
|
||||
"items": {"$ref": "#/components/schemas/Item"}, |
|
||||
"default": [], |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
"UserCreate": { |
|
||||
"title": "UserCreate", |
|
||||
"required": ["email", "password"], |
|
||||
"type": "object", |
|
||||
"properties": { |
|
||||
"email": {"title": "Email", "type": "string"}, |
|
||||
"password": {"title": "Password", "type": "string"}, |
|
||||
}, |
|
||||
}, |
|
||||
"ValidationError": { |
|
||||
"title": "ValidationError", |
|
||||
"required": ["loc", "msg", "type"], |
|
||||
"type": "object", |
|
||||
"properties": { |
|
||||
"loc": { |
|
||||
"title": "Location", |
|
||||
"type": "array", |
|
||||
"items": { |
|
||||
"anyOf": [{"type": "string"}, {"type": "integer"}] |
|
||||
}, |
|
||||
}, |
|
||||
"msg": {"title": "Message", "type": "string"}, |
|
||||
"type": {"title": "Error Type", "type": "string"}, |
|
||||
}, |
|
||||
}, |
|
||||
} |
|
||||
}, |
|
||||
} |
|
Loading…
Reference in new issue