Когда веб-фреймворки Python, такие как Flask и Django, впервые приобрели известность, Python был несколько другим языком, чем сегодня. Многие элементы современного Python, такие как асинхронное выполнение и стандарт ASGI (интерфейс асинхронного серверного шлюза), либо находились в зачаточном состоянии, либо еще не существовали.
FastAPI — это веб-фреймворк Python, созданный с нуля для интеграции современных функций Python. Он использует стандарт ASGI для асинхронного одновременного подключения к клиентам и при необходимости может работать с WSGI. Асинхронные функции встроены в маршруты и конечные точки. А FastAPI позволяет эффективно разрабатывать веб-приложения с помощью чистого современного кода Python с подсказками типов.
Как следует из названия, основной вариант использования FastAPI — быстрое создание конечных точек API. Этого можно добиться так же легко, как вернуть данные словаря Python в формате JSON или использовать стандарт OpenAPI, включая интерактивный пользовательский интерфейс Swagger. Но FastAPI ни в коем случае не ограничивается API. Вы можете использовать его практически для всего, что делает веб-фреймворк: от доставки простых старых веб-страниц с использованием механизма шаблонов Jinja2 до обслуживания приложений на базе WebSockets.
Установить ФастAPI
FastAPI может устанавливать довольно много компонентов самостоятельно, поэтому лучше всего начинать любой проект FastAPI в новой, чистой виртуальной среде. Основные компоненты FastAPI можно установить с помощью pip install fastapi
.
Вам также потребуется установить сервер ASGI для локального тестирования. FastAPI хорошо работает с Uvicorn, поэтому мы будем использовать его в наших примерах. Вы можете использовать pip install uvicorn[standard]
установить Uvicorn с оптимальным набором компонентов с библиотеками C или использовать pip install uvicorn
для установки минимальной версии на чистом Python.
Простой пример FastAPI
Вот простое приложение FastAPI:
from fastapi import FastAPI
app = FastAPI()
@app.get("https://www.infoworld.com/")
async def root():
return {"greeting":"Hello world"}
Сохраните это как main.py
затем запустите его из своего «venv» с помощью команды uvicorn main:app
. app
объект — это то, что вы бы использовали для своего сервера ASGI. (Обратите внимание, что вы также можете использовать WSGI с адаптером ASGI-WSGI, но лучше всего использовать ASGI.)
Как только все заработает, перейдите к localhost:8000
(по умолчанию для тестового сервера Uvicorn). Вот увидишь {"greeting":"Hello world"}
в браузере — действительный ответ JSON, сгенерированный из словаря.
Это должно дать вам представление о том, насколько легко FastAPI позволяет доставлять JSON из конечной точки. Все, что вам нужно сделать, это создать маршрут и вернуть словарь Python, который будет автоматически сериализован в JSON. Есть шаги, которые вы можете предпринять для сериализации сложных типов данных, о которых мы поговорим позже.
Общие принципы приложения FastAPI должны быть знакомы каждому, кто работал с такими системами, как Flask:
-
app
объект импортируется на сервер ASGI или WSGI и используется для запуска приложения. - Вы можете использовать декораторы для добавления маршрутов в приложение. Например,
@app.get("https://www.infoworld.com/")
создаетGET
Маршрут метода в корне сайта с результатами, возвращаемыми обернутой функцией.
Однако некоторые различия уже должны быть заметны. Во-первых, ваши функции маршрутизации могут быть асинхронными, так что любые асинхронные компоненты, которые вы развертываете — например, асинхронное промежуточное соединение с базой данных — также могут выполняться в этих функциях.
Обратите внимание: ничто не мешает вам использовать обычные синхронные функции, если они вам нужны. Фактически, если у вас есть операция, требующая больших вычислительных затрат, а не операция, ожидающая ввода-вывода (что является лучшим вариантом использования async ), было бы лучше использовать функцию синхронизации и позволить FastAPI разобраться с этим. В остальное время используйте async.
Типы маршрутов в FastAPI
@app
Декоратор позволяет вам установить метод, используемый для маршрута, например, @app.get
или @app.post
. GET
, POST
, PUT
, DELETE
и менее используемые OPTIONS
, HEAD
, PATCH
и TRACE
все поддерживаются таким образом.
Вы также можете поддерживать несколько методов на данном маршруте, просто обернув несколько функций маршрута, например: @app.get("https://www.infoworld.com/")
по одной функции и @app.post("https://www.infoworld.com/")
на другом.
Параметры пути, запроса и формы в FastAPI
Если вы хотите извлечь переменные из пути маршрута, вы можете сделать это, определив их в объявлении маршрута, а затем передав их функции маршрута.
@app.get("/users/{user_id}")
async def user(user_id: str):
return {"user_id":user_id}
Чтобы извлечь параметры запроса из URL-адреса, вы можете использовать типизированные объявления в функции маршрута, которые FastAPI автоматически обнаружит:
userlist = ["Spike","Jet","Ed","Faye","Ein"]
@app.get("/userlist")
async def userlist_(start: int = 0, limit: int = 3):
return userlist[start:start+limit]
Таким образом, параметры запроса start
и limit
будет автоматически извлечен из URL-адреса и передан в этих именованных переменных. Если бы эти параметры не существовали, им были бы присвоены значения по умолчанию.
Обработка данных формы немного сложнее. Сначала вам придется установить дополнительную библиотеку, python-multipart
для анализа данных формы (pip install python-multipart
). Затем вы используете синтаксис, аналогичный синтаксису параметров запроса, но с некоторыми изменениями:
from fastapi import Form
@app.post("/lookup")
async def userlookup(username: str = Form(...), user_id: str = Form("")):
return {"username": username, "user_id":user_id}
Form
объект извлекает именованный параметр (username
, user_id
) из отправленной формы и передает ее. Обратите внимание: если вы используете Form(...)
в объявлении это намек на то, что рассматриваемый параметр необходимыйкак и username
здесь. Для необязательный элемент формы, передайте значение по умолчанию для этого элемента в Form
как и user_id
здесь (Form("")
).
Типы ответов в FastAPI
Типом ответа по умолчанию для FastAPI является JSON, и до сих пор все примеры возвращали данные, которые автоматически сериализуются как JSON. Но вы можете возвращать и другие виды ответов. Например:
from fastapi.responses import HTMLResponse
@app.get("https://www.infoworld.com/")
def root():
return HTMLResponse("<b>Hello world</b>")
fastapi.responses
модуль поддерживает множество распространенных типов ответов:
HTMLResponse
илиPlainTextResponse
: возвращает текст в формате HTML или обычный текст.RedirectResponse
: перенаправляет на указанный URL-адрес.FileResponse
: возвращает файл по указанному пути в асинхронной потоковой передаче.StreamingResponse
: принимает генератор и передает результаты клиенту.
Вы также можете использовать общий Response
объект и укажите собственный настраиваемый код состояния, заголовки, контент и тип мультимедиа.
Если вы хотите программно сгенерировать HTML для HTMLResponse
вы можете сделать это с помощью Jinja2 или другого шаблонизатора по вашему выбору.
Объект Response в FastAPI
Обратите внимание: если вы хотите работать с ответом, например, установив файлы cookie или заголовки, вы можете сделать это, приняв Response
объект в качестве параметра в вашей функции маршрута:
from fastapi import Response
@app.get("https://www.infoworld.com/")
def modify_header(response:Response):
response.headers["X-New-Header"] = "Hi, I'm a new header!"
return {"msg":"Headers modified in response"}
Файлы cookie в FastAPI
Получение файлов cookie от клиента работает примерно так же, как обработка параметров запроса или формы:
from fastapi import Cookie
@app.get("https://www.infoworld.com/")
async def main(user_nonce: Optional[str]=Cookie(none)):
return {"user_nonce": user_nonce}
Установка файлов cookie осуществляется с помощью .set_cookie()
метод на Response
объект:
from fastapi import Response
@app.post("https://www.infoworld.com/")
async def main(response: Response):
response.set_cookie(key="user_nonce", value="")
return {"msg":"User nonce cookie cleared"}
Использование моделей Pydantic с FastAPI
Типы в Python, как правило, не являются обязательными, но FastAPI является более строгим в использовании типов, чем многие другие платформы Python. FastAPI использует библиотеку Pydantic для декларативной проверки отправленных данных, поэтому вам не нужно писать логику, чтобы сделать это самостоятельно.
Вот пример того, как Pydantic можно использовать для проверки входящего JSON:
from typing import List, Optional
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class Movie(BaseModel):
name: str
year: int
rating: Optional[int] = None
tags: List[str] = []
@app.post("/movies/", response_model=Movie)
async def create_movie(movie: Movie):
return movie
Этот фрагмент будет принимать данные JSON через POST (нет HTML-форма!) с полями name
, year
, rating
и tags
. Затем будут проверены типы каждого из этих полей. Например, следующие данные будут действительными:
{
"name":"Blade Runner 2049",
"year": 2018,
"rating": 5,
"tags": ["science fiction","dystopia"]
}
Если year
были строкой, которую можно было интерпретировать как целое число (например, "2018"
) он будет автоматически преобразован в правильный тип данных. Но если бы у нас был year
значение, которое нельзя интерпретировать как целое число, оно будет отклонено.
Использование WebSockets в FastAPI
Конечные точки WebSocket в FastAPI также просты:
from fastapi import FastAPI, WebSocket
@app.websocket("/ws")
async def ws_connection(websocket: WebSocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"You said: {data}")
Этот пример получает соединение в конечной точке /ws
обычно устанавливаемый в JavaScript с помощью WebSocket
объект, затем ожидает ввода и повторяет ответ в цикле.
WebSockets, как правило, не обеспечивают особой безопасности аутентификации. Обычной практикой является создание защищенного соединения WebSockets, а затем отправка в сокет в качестве первого сообщения какого-либо токена или учетных данных, которые аутентифицируют пользователя. FastAPI не предоставляет дополнительных механизмов для защиты соединений WebSocket, поэтому вам придется создавать эту функциональность самостоятельно.
Использование Swagger/OpenAPI в FastAPI
OpenAPI, ранее известный как Swagger, представляет собой стандарт в формате JSON для описания конечных точек API. Клиент может прочитать определение OpenAPI для конечной точки и автоматически определить схемы данных, отправляемых и получаемых API-интерфейсами веб-сайта.
FastAPI автоматически генерирует определения OpenAPI для всех конечных точек веб-сайта. Если вы посетите /openapi.json
в корне сайта FastAPI вы получите файл JSON, описывающий каждую конечную точку, данные, которые она может получать, и данные, которые она возвращает.
Еще одно удобство, которое предоставляет FastAPI, — это автоматически генерируемые интерфейсы документации для ваших API, с которыми вы можете взаимодействовать через веб-интерфейс. Если вы перейдете к /docs
, вы увидите страницу с вашими API, созданную ReDoc; идти к /docs
и вы увидите один, созданный пользовательским интерфейсом Swagger (более старый, менее продвинутый). Оба пользовательских интерфейса документации являются настраиваемыми.
FastAPI также предоставляет возможности для расширения или изменения автоматически сгенерированной схемы, ее условной генерации или даже ее отключения.
FastAPI автоматически генерирует спецификации OpenAPI для всех конечных точек, с которыми вы можете взаимодействовать через веб-интерфейс, также автоматически создаваемый FastAPI. При необходимости этот интерфейс можно отключить.
Заключение
По мере развития и адаптации Python развиваются и библиотеки, используемые с ним для решения общих задач. FastAPI, возможно, является одной из новейших веб-платформ, но она уже приобрела большую известность благодаря своему перспективному дизайну. Любой нетривиальный веб-проект Python заслуживает рассмотрения в качестве кандидата.
Дальше читайте это:
- Облачные вычисления больше не являются пустяком
- Что такое генеративный ИИ? Искусственный интеллект, который создает
- Программирование с помощью ИИ: советы и лучшие практики от разработчиков
- Python пытается удалить GIL и повысить параллелизм
- 7 причин, по которым Java по-прежнему хороша
- Война за лицензирование открытого исходного кода окончена