0 added
0 removed
Original
2026-01-01
Modified
2026-02-21
1
<p><a>#статьи</a></p>
1
<p><a>#статьи</a></p>
2
<ul><li>13 окт 2025</li>
2
<ul><li>13 окт 2025</li>
3
<li>0</li>
3
<li>0</li>
4
</ul><p>Расскажем про быстрый самодокументирующийся фреймворк для создания веб-API.</p>
4
</ul><p>Расскажем про быстрый самодокументирующийся фреймворк для создания веб-API.</p>
5
<p>Иллюстрация: Оля Ежак для Skillbox Media</p>
5
<p>Иллюстрация: Оля Ежак для Skillbox Media</p>
6
<p>Пишет о сетях, инструментах для разработчиков и языках программирования. Любит готовить, играть в инди‑игры и программировать на Python.</p>
6
<p>Пишет о сетях, инструментах для разработчиков и языках программирования. Любит готовить, играть в инди‑игры и программировать на Python.</p>
7
<p>Python - не самый быстрый язык, и для задач с высокими нагрузками разработчики часто выбирают Go или Node.js. Но с появлением FastAPI ситуация изменилась: теперь на Python можно создавать быстрые, асинхронные и легко масштабируемые веб-приложения. В этой статье рассказываем, что делает FastAPI особенным, и показываем, как с нуля собрать рабочий API с автоматической документацией.</p>
7
<p>Python - не самый быстрый язык, и для задач с высокими нагрузками разработчики часто выбирают Go или Node.js. Но с появлением FastAPI ситуация изменилась: теперь на Python можно создавать быстрые, асинхронные и легко масштабируемые веб-приложения. В этой статье рассказываем, что делает FastAPI особенным, и показываем, как с нуля собрать рабочий API с автоматической документацией.</p>
8
<p><strong>Содержание</strong></p>
8
<p><strong>Содержание</strong></p>
9
<ul><li><a>Что такое FastAP</a></li>
9
<ul><li><a>Что такое FastAP</a></li>
10
<li><a>Чем хорош FastAPI</a></li>
10
<li><a>Чем хорош FastAPI</a></li>
11
<li><a>Недостатки FastAPI</a></li>
11
<li><a>Недостатки FastAPI</a></li>
12
<li><a>Создаём свой API с помощью FastAPI</a></li>
12
<li><a>Создаём свой API с помощью FastAPI</a></li>
13
<li><a>Обзор проекта</a></li>
13
<li><a>Обзор проекта</a></li>
14
<li><a>Что дальше?</a></li>
14
<li><a>Что дальше?</a></li>
15
</ul><p>FastAPI - это современный фреймворк для создания веб-приложений и API на Python, который стал популярным благодаря простоте и скорости работы. С его помощью можно буквально за несколько строк кода создать сервер, который принимает запросы, обрабатывает их и возвращает результаты - например, данные из базы, ответ нейросети или результат вычислений.</p>
15
</ul><p>FastAPI - это современный фреймворк для создания веб-приложений и API на Python, который стал популярным благодаря простоте и скорости работы. С его помощью можно буквально за несколько строк кода создать сервер, который принимает запросы, обрабатывает их и возвращает результаты - например, данные из базы, ответ нейросети или результат вычислений.</p>
16
<p>FastAPI создали в 2018 году, чтобы исправить слабые места старых Python-фреймворков вроде Flask и Django. Эти инструменты отлично подходили для создания классических сайтов, но начинали тормозить с ростом числа запросов и переходом на асинхронный Python.</p>
16
<p>FastAPI создали в 2018 году, чтобы исправить слабые места старых Python-фреймворков вроде Flask и Django. Эти инструменты отлично подходили для создания классических сайтов, но начинали тормозить с ростом числа запросов и переходом на асинхронный Python.</p>
17
<p>Новый фреймворк собрал под капотом несколько важных технологий, которые делают его быстрым и удобным:</p>
17
<p>Новый фреймворк собрал под капотом несколько важных технологий, которые делают его быстрым и удобным:</p>
18
<ul><li><strong>Starlette</strong>отвечает за ядро приложения - то, как сервер принимает и обрабатывает запросы. Благодаря ей FastAPI работает асинхронно и выдерживает большую нагрузку.</li>
18
<ul><li><strong>Starlette</strong>отвечает за ядро приложения - то, как сервер принимает и обрабатывает запросы. Благодаря ей FastAPI работает асинхронно и выдерживает большую нагрузку.</li>
19
<li><strong>Pydantic</strong>помогает проверять данные - например, если пользователь отправил текст вместо числа, фреймворк сразу покажет ошибку, не давая "упасть" всему приложению.</li>
19
<li><strong>Pydantic</strong>помогает проверять данные - например, если пользователь отправил текст вместо числа, фреймворк сразу покажет ошибку, не давая "упасть" всему приложению.</li>
20
<li><strong>Аннотации типов Python</strong>позволяют писать код понятнее и безопаснее - вы просто указываете, каких данных ждёте, а FastAPI сам проверяет их и подставляет всё нужное в документацию.</li>
20
<li><strong>Аннотации типов Python</strong>позволяют писать код понятнее и безопаснее - вы просто указываете, каких данных ждёте, а FastAPI сам проверяет их и подставляет всё нужное в документацию.</li>
21
</ul><p>FastAPI применяют там, где нужно оперативно обрабатывать запросы, - от небольших сервисов до крупных платформ. Python-разработчики создают на нём бэкенд веб-приложений, DevOps-инженеры и инженеры по интеграции используют его для микросервисов и соединения разных систем между собой, а ML-специалисты разворачивают с его помощью модели и делают их доступными через API.</p>
21
</ul><p>FastAPI применяют там, где нужно оперативно обрабатывать запросы, - от небольших сервисов до крупных платформ. Python-разработчики создают на нём бэкенд веб-приложений, DevOps-инженеры и инженеры по интеграции используют его для микросервисов и соединения разных систем между собой, а ML-специалисты разворачивают с его помощью модели и делают их доступными через API.</p>
22
<p>Фреймворк используют для создания чат-ботов и даже IoT-устройств, где нужно мгновенно реагировать на поток данных.</p>
22
<p>Фреймворк используют для создания чат-ботов и даже IoT-устройств, где нужно мгновенно реагировать на поток данных.</p>
23
<p>Главные достоинства FastAPI - высокая производительность, надёжность и автоматическая документация.</p>
23
<p>Главные достоинства FastAPI - высокая производительность, надёжность и автоматическая документация.</p>
24
<p><strong>Производительность.</strong>Сравнима с <a>Node.js</a>и <a>Go</a>благодаря асинхронному подходу: фреймворк не ждёт, пока одна операция полностью завершится, прежде чем начать следующую. Он может обрабатывать множество запросов одновременно - или, точнее, переключаться между ними так быстро, что это почти не ощущается.</p>
24
<p><strong>Производительность.</strong>Сравнима с <a>Node.js</a>и <a>Go</a>благодаря асинхронному подходу: фреймворк не ждёт, пока одна операция полностью завершится, прежде чем начать следующую. Он может обрабатывать множество запросов одновременно - или, точнее, переключаться между ними так быстро, что это почти не ощущается.</p>
25
<p>Производительность фреймворка подтвердили независимые тесты, в частности тест<a>Sharkbench</a>: приложения FastAPI показали одну из самых высоких скоростей среди Python-фреймворков. Это значительно экономит ресурсы сервера, что подходит для приложений с большим трафиком.</p>
25
<p>Производительность фреймворка подтвердили независимые тесты, в частности тест<a>Sharkbench</a>: приложения FastAPI показали одну из самых высоких скоростей среди Python-фреймворков. Это значительно экономит ресурсы сервера, что подходит для приложений с большим трафиком.</p>
26
<p><strong>Типизация и валидация.</strong>При использовании FastAPI вы будете писать меньше кода благодаря аннотации типов: вы указываете типы данных, и фреймворк сам проверяет их.</p>
26
<p><strong>Типизация и валидация.</strong>При использовании FastAPI вы будете писать меньше кода благодаря аннотации типов: вы указываете типы данных, и фреймворк сам проверяет их.</p>
27
<p>Например, вот простая функция, которая складывает два числа без аннотаций:</p>
27
<p>Например, вот простая функция, которая складывает два числа без аннотаций:</p>
28
def add(a, b): return a + b result = add(5, 3) # работает result2 = add("5", "3") # тоже работает, но результат будет "53", что может быть ошибкой<p>В этом примере Python не знает, какие типы должны быть у a и b. Поэтому функция складывает числа или объединяет строки в зависимости от того, какие данные передали. Если типы неверны, ошибки не будет, но результат получится неправильным.</p>
28
def add(a, b): return a + b result = add(5, 3) # работает result2 = add("5", "3") # тоже работает, но результат будет "53", что может быть ошибкой<p>В этом примере Python не знает, какие типы должны быть у a и b. Поэтому функция складывает числа или объединяет строки в зависимости от того, какие данные передали. Если типы неверны, ошибки не будет, но результат получится неправильным.</p>
29
<p>А вот пример FastAPI с типизацией прямо в параметрах функции:</p>
29
<p>А вот пример FastAPI с типизацией прямо в параметрах функции:</p>
30
from fastapi import FastAPI app = FastAPI() # Параметры a и b сразу типизируем как int @app.get("/add") def add_numbers(a: int, b: int): return {"result": a + b}<p>Здесь a: int и b: int - FastAPI сразу проверяет, что в запросе пришли числа. Сам запрос выглядит так:</p>
30
from fastapi import FastAPI app = FastAPI() # Параметры a и b сразу типизируем как int @app.get("/add") def add_numbers(a: int, b: int): return {"result": a + b}<p>Здесь a: int и b: int - FastAPI сразу проверяет, что в запросе пришли числа. Сам запрос выглядит так:</p>
31
GET /add?a=5&b=3<p>Ответ:</p>
31
GET /add?a=5&b=3<p>Ответ:</p>
32
{ "result": 8 }<p>Если передать не число, например a=five, FastAPI автоматически вернёт ошибку и скажет, что данные некорректны.</p>
32
{ "result": 8 }<p>Если передать не число, например a=five, FastAPI автоматически вернёт ошибку и скажет, что данные некорректны.</p>
33
<p><strong>Интерактивная документация.</strong>FastAPI генерирует документацию автоматически. Он сам создаёт страницу, где видно все доступные эндпойнты (адреса запросов), параметры и возможные ответы.</p>
33
<p><strong>Интерактивная документация.</strong>FastAPI генерирует документацию автоматически. Он сам создаёт страницу, где видно все доступные эндпойнты (адреса запросов), параметры и возможные ответы.</p>
34
<p>Когда вы запускаете приложение, FastAPI добавляет два специальных маршрута - обычно это /docs и /redoc. Если открыть их в браузере, вы увидите интерактивную страницу: можно выбрать любой метод API, посмотреть, какие данные он принимает, и протестировать прямо из браузера.</p>
34
<p>Когда вы запускаете приложение, FastAPI добавляет два специальных маршрута - обычно это /docs и /redoc. Если открыть их в браузере, вы увидите интерактивную страницу: можно выбрать любой метод API, посмотреть, какие данные он принимает, и протестировать прямо из браузера.</p>
35
<p>Разработчики, тестировщики и аналитики могут видеть, как меняется структура API после обновлений кода, отслеживать новые поля, искать ошибки, проверять ответы сервера.</p>
35
<p>Разработчики, тестировщики и аналитики могут видеть, как меняется структура API после обновлений кода, отслеживать новые поля, искать ошибки, проверять ответы сервера.</p>
36
<p>FastAPI - классный и быстрый фреймворк, но у него есть свои минусы.</p>
36
<p>FastAPI - классный и быстрый фреймворк, но у него есть свои минусы.</p>
37
<p><strong>Асинхронность.</strong>Асинхронный режим работы делает FastAPI быстрым, но требует аккуратности. Если внутри асинхронной функции случайно использовать синхронный код, сервер будет ждать, и вся выгода от асинхронности исчезнет. Поэтому писать и отлаживать код на FastAPI сложнее, особенно новичкам.</p>
37
<p><strong>Асинхронность.</strong>Асинхронный режим работы делает FastAPI быстрым, но требует аккуратности. Если внутри асинхронной функции случайно использовать синхронный код, сервер будет ждать, и вся выгода от асинхронности исчезнет. Поэтому писать и отлаживать код на FastAPI сложнее, особенно новичкам.</p>
38
<p><strong>Производительность не всегда выше.</strong>FastAPI действительно быстрее Flask, когда нужно обрабатывать много запросов одновременно - например, при асинхронной работе. Но, если приложение выполняет простые задачи по очереди, разница почти незаметна. В некоторых случаях Flask или Django работают даже быстрее, потому что у них меньше встроенных проверок и они тратят меньше времени на обслуживание каждого запроса.</p>
38
<p><strong>Производительность не всегда выше.</strong>FastAPI действительно быстрее Flask, когда нужно обрабатывать много запросов одновременно - например, при асинхронной работе. Но, если приложение выполняет простые задачи по очереди, разница почти незаметна. В некоторых случаях Flask или Django работают даже быстрее, потому что у них меньше встроенных проверок и они тратят меньше времени на обслуживание каждого запроса.</p>
39
<p><strong>Недостаточно развитая экосистема.</strong>Если Django - это полновесный фреймворк для веб-разработки, то FastAPI напоминает, скорее, набор деталей, из которых нужно собрать всё самому. Здесь нет готовой админ-панели, систем для фоновых задач или модулей управления пользователями - алгоритмы регистрации, авторизации и подтверждения почты приходится писать вручную.</p>
39
<p><strong>Недостаточно развитая экосистема.</strong>Если Django - это полновесный фреймворк для веб-разработки, то FastAPI напоминает, скорее, набор деталей, из которых нужно собрать всё самому. Здесь нет готовой админ-панели, систем для фоновых задач или модулей управления пользователями - алгоритмы регистрации, авторизации и подтверждения почты приходится писать вручную.</p>
40
<p>Такой подход даёт свободу и гибкость, но требует больше опыта и времени. FastAPI лучше подходит тем, кто хочет сам решать, какие инструменты использовать, а не опираться на готовую архитектуру.</p>
40
<p>Такой подход даёт свободу и гибкость, но требует больше опыта и времени. FastAPI лучше подходит тем, кто хочет сам решать, какие инструменты использовать, а не опираться на готовую архитектуру.</p>
41
<p>Создадим полноценный API - с поддержкой баз данных и сервисом авторизации и аутентификации. Не беспокойтесь, если вы раньше не работали с базами данных: мы будем их имитировать. Но знать базовый Python версии 3.8 или новее и основы работы с терминалом нужно, иначе разобраться будет сложно.</p>
41
<p>Создадим полноценный API - с поддержкой баз данных и сервисом авторизации и аутентификации. Не беспокойтесь, если вы раньше не работали с базами данных: мы будем их имитировать. Но знать базовый Python версии 3.8 или новее и основы работы с терминалом нужно, иначе разобраться будет сложно.</p>
42
<p>Сначала создадим виртуальное окружение. Виртуальное окружение - это отдельная среда для Python, огороженная от общей среды в вашей ОС. Её создают, чтобы пакеты не конфликтовали с системой. Выполните в терминале:</p>
42
<p>Сначала создадим виртуальное окружение. Виртуальное окружение - это отдельная среда для Python, огороженная от общей среды в вашей ОС. Её создают, чтобы пакеты не конфликтовали с системой. Выполните в терминале:</p>
43
python -m venv fastapi_project<p>Или:</p>
43
python -m venv fastapi_project<p>Или:</p>
44
python3 -m venv fastapi_project<p>Вы создали папку fastapi_project и окружение. Если всё сделано правильно, то внутри папки fastapi_project будут папки bin, include, lib, lib64 и файл pyvenv.cfg.</p>
44
python3 -m venv fastapi_project<p>Вы создали папку fastapi_project и окружение. Если всё сделано правильно, то внутри папки fastapi_project будут папки bin, include, lib, lib64 и файл pyvenv.cfg.</p>
45
<p>Теперь окружение нужно активировать. На Linux или Mac:</p>
45
<p>Теперь окружение нужно активировать. На Linux или Mac:</p>
46
source fastapi_project/bin/activate<p>На Windows:</p>
46
source fastapi_project/bin/activate<p>На Windows:</p>
47
fastapi_project\Scripts\activate<p>Если вы следовали инструкции, то вы увидите (fastapi_project) перед строкой приглашения в терминале. Это значит, что окружение активно.</p>
47
fastapi_project\Scripts\activate<p>Если вы следовали инструкции, то вы увидите (fastapi_project) перед строкой приглашения в терминале. Это значит, что окружение активно.</p>
48
<em>Скриншот:<a>xfce4-terminal</a>/ Skillbox Media</em><p>Установите FastAPI:</p>
48
<em>Скриншот:<a>xfce4-terminal</a>/ Skillbox Media</em><p>Установите FastAPI:</p>
49
pip install fastapi[standard]<p>Теперь проект настроен, можно начинать работу.</p>
49
pip install fastapi[standard]<p>Теперь проект настроен, можно начинать работу.</p>
50
<p>Создадим первый API. Создайте внутри папки fastapi_project файл main.py и добавьте следующий код:</p>
50
<p>Создадим первый API. Создайте внутри папки fastapi_project файл main.py и добавьте следующий код:</p>
51
from fastapi import FastAPI app = FastAPI() @app.get("/") async def root(): return {"message": "Hello World"}<p>Запустите сервер, находясь в папке fastapi_project:</p>
51
from fastapi import FastAPI app = FastAPI() @app.get("/") async def root(): return {"message": "Hello World"}<p>Запустите сервер, находясь в папке fastapi_project:</p>
52
fastapi dev main.py<p>Откройте браузер и перейдите по ссылке <a>http://127.0.0.1:8000</a>. Вы увидите {"message": "Hello World"}.</p>
52
fastapi dev main.py<p>Откройте браузер и перейдите по ссылке <a>http://127.0.0.1:8000</a>. Вы увидите {"message": "Hello World"}.</p>
53
<em>Скриншот: Google Chrome / Skillbox Media</em><p>Документация доступна по ссылке<a>http://127.0.0.1:8000/docs</a>. Нажмите на GET /, Try it out, затем Execute - и увидите ответ.</p>
53
<em>Скриншот: Google Chrome / Skillbox Media</em><p>Документация доступна по ссылке<a>http://127.0.0.1:8000/docs</a>. Нажмите на GET /, Try it out, затем Execute - и увидите ответ.</p>
54
<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>В терминале ответ тоже отобразится.</p>
54
<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>В терминале ответ тоже отобразится.</p>
55
<em>Скриншот:<a>xfce4-terminal</a>/ Skillbox Media</em><p>Чтобы остановить сервер, нажмите<strong>Ctrl + C</strong>. Перезапускать сервер после изменений в коде не нужно: FastAPI умеет автоматически подгружать изменения. Если в вашем редакторе кода нет автосохранения, не забывайте сохранять файл после каждого изменения, иначе код на сервере не поменяется.</p>
55
<em>Скриншот:<a>xfce4-terminal</a>/ Skillbox Media</em><p>Чтобы остановить сервер, нажмите<strong>Ctrl + C</strong>. Перезапускать сервер после изменений в коде не нужно: FastAPI умеет автоматически подгружать изменения. Если в вашем редакторе кода нет автосохранения, не забывайте сохранять файл после каждого изменения, иначе код на сервере не поменяется.</p>
56
<p>Эндпойнты - это адреса в вашем API, по которым клиенты отправляют запросы. Мы уже обращались к автоматически прописанному эндпойнту /docs, когда открывали документацию. Теперь пропишем свои. Создайте файл endpoints.py внутри fastapi_project:</p>
56
<p>Эндпойнты - это адреса в вашем API, по которым клиенты отправляют запросы. Мы уже обращались к автоматически прописанному эндпойнту /docs, когда открывали документацию. Теперь пропишем свои. Создайте файл endpoints.py внутри fastapi_project:</p>
57
from fastapi import FastAPI # Функция для регистрации эндпойнтов def register_endpoints(app: FastAPI): # Эндпойнт для главной страницы @app.get("/") async def root(): return {"message": "Hello World"} # Эндпойнт с path-параметром item_id (часть URL) # Например, /items/5 вернёт {"item_id": 5} @app.get("/items/{item_id}") async def read_item(item_id: int): # item_id: int -- параметр должен быть числом return {"item_id": item_id}<p>Отредактируем main.py - импортируем функцию register_endpoints и вызовем её:</p>
57
from fastapi import FastAPI # Функция для регистрации эндпойнтов def register_endpoints(app: FastAPI): # Эндпойнт для главной страницы @app.get("/") async def root(): return {"message": "Hello World"} # Эндпойнт с path-параметром item_id (часть URL) # Например, /items/5 вернёт {"item_id": 5} @app.get("/items/{item_id}") async def read_item(item_id: int): # item_id: int -- параметр должен быть числом return {"item_id": item_id}<p>Отредактируем main.py - импортируем функцию register_endpoints и вызовем её:</p>
58
from fastapi import FastAPI from endpoints import register_endpoints # Создаём приложение FastAPI app = FastAPI() # Регистрируем эндпойнты register_endpoints(app)<p>Убедимся, что всё работает верно. Перейдите по <a>http://127.0.0.1:8000/items/5</a> - получите {"item_id": 5}.</p>
58
from fastapi import FastAPI from endpoints import register_endpoints # Создаём приложение FastAPI app = FastAPI() # Регистрируем эндпойнты register_endpoints(app)<p>Убедимся, что всё работает верно. Перейдите по <a>http://127.0.0.1:8000/items/5</a> - получите {"item_id": 5}.</p>
59
<em>Скриншот: Google Chrome / Skillbox Media</em><p>Если ввести<a>http://127.0.0.1:8000/items/abc</a>, FastAPI выдаст ошибку, так как ожидает число.</p>
59
<em>Скриншот: Google Chrome / Skillbox Media</em><p>Если ввести<a>http://127.0.0.1:8000/items/abc</a>, FastAPI выдаст ошибку, так как ожидает число.</p>
60
<em>Скриншот: Google Chrome / Skillbox Media</em><p>Конструкцию вида {"item_id": 5} называют path-параметром - это часть URL, которая может меняться. В нашем случае после items/ можно указать любое целое число.</p>
60
<em>Скриншот: Google Chrome / Skillbox Media</em><p>Конструкцию вида {"item_id": 5} называют path-параметром - это часть URL, которая может меняться. В нашем случае после items/ можно указать любое целое число.</p>
61
<p>Добавим query-параметр - это данные, которые передаются в URL после ?. Например,<a>http://127.0.0.1:8000/items/5?q=hello</a>передаёт параметр q со значением hello. С помощью query-параметров удобно передавать дополнительные данные, например поисковые запросы. Отредактируем эндпойнт items/:</p>
61
<p>Добавим query-параметр - это данные, которые передаются в URL после ?. Например,<a>http://127.0.0.1:8000/items/5?q=hello</a>передаёт параметр q со значением hello. С помощью query-параметров удобно передавать дополнительные данные, например поисковые запросы. Отредактируем эндпойнт items/:</p>
62
# Эндпойнт с path- и query-параметрами # Например, /items/5?q=hello вернёт {"item_id": 5, "q": "hello"} @app.get("/items/{item_id}") async def read_item(item_id: int, q: str = None): # q: str = None -- query-параметр, строка или ничего return {"item_id": item_id, "q": q}<p>Теперь по адресу<a>http://127.0.0.1:8000/items/5?q=hello</a>мы увидим ответ {"item_id": 5, "q": "hello"}.</p>
62
# Эндпойнт с path- и query-параметрами # Например, /items/5?q=hello вернёт {"item_id": 5, "q": "hello"} @app.get("/items/{item_id}") async def read_item(item_id: int, q: str = None): # q: str = None -- query-параметр, строка или ничего return {"item_id": item_id, "q": q}<p>Теперь по адресу<a>http://127.0.0.1:8000/items/5?q=hello</a>мы увидим ответ {"item_id": 5, "q": "hello"}.</p>
63
<em>Скриншот: Google Chrome / Skillbox Media</em><p>А по адресу<a>http://127.0.0.1:8000/items/5</a> - {"item_id": 5, "q": null}.</p>
63
<em>Скриншот: Google Chrome / Skillbox Media</em><p>А по адресу<a>http://127.0.0.1:8000/items/5</a> - {"item_id": 5, "q": null}.</p>
64
<em>Скриншот: Google Chrome / Skillbox Media</em><p>Иногда нужно ограничить значения, которые пользователь может передать в URL. Например, мы хотим прописать эндпойнт models/ с параметром {model}, который будет принимать только два значения: a и b. Для этого используем встроенный модуль Enum - он отлично подходит для перечисления констант. Добавьте импорт Enum и класс для хранения значений в endpoints.py:</p>
64
<em>Скриншот: Google Chrome / Skillbox Media</em><p>Иногда нужно ограничить значения, которые пользователь может передать в URL. Например, мы хотим прописать эндпойнт models/ с параметром {model}, который будет принимать только два значения: a и b. Для этого используем встроенный модуль Enum - он отлично подходит для перечисления констант. Добавьте импорт Enum и класс для хранения значений в endpoints.py:</p>
65
from enum import Enum # Определяем Enum - список разрешённых значений class Model(str, Enum): a = "a" # Разрешённое значение "a" b = "b" # Разрешённое значение "b"<p>Добавим в конец функции register_endpoints новый эндпойнт (следите за отступами):</p>
65
from enum import Enum # Определяем Enum - список разрешённых значений class Model(str, Enum): a = "a" # Разрешённое значение "a" b = "b" # Разрешённое значение "b"<p>Добавим в конец функции register_endpoints новый эндпойнт (следите за отступами):</p>
66
# Эндпойнт /models/{model} принимает только a или b @app.get("/models/{model}") async def get_model(model: Model): # model: Model -- проверяет, что значение из Enum return {"model": model}<p>Перейдите на <a>http://127.0.0.1:8000/models/a</a> - увидите {"model": "a"}. Аналогично для<a>http://127.0.0.1:8000/models/b</a>. Если перейти по <a>http://127.0.0.1:8000/models/c</a>, FastAPI выдаст ошибку, так как c не входит в список разрешённых значений, определённых в Model.</p>
66
# Эндпойнт /models/{model} принимает только a или b @app.get("/models/{model}") async def get_model(model: Model): # model: Model -- проверяет, что значение из Enum return {"model": model}<p>Перейдите на <a>http://127.0.0.1:8000/models/a</a> - увидите {"model": "a"}. Аналогично для<a>http://127.0.0.1:8000/models/b</a>. Если перейти по <a>http://127.0.0.1:8000/models/c</a>, FastAPI выдаст ошибку, так как c не входит в список разрешённых значений, определённых в Model.</p>
67
<em>Скриншот: Google Chrome / Skillbox Media</em><p>Добавим два эндпойнта для пользователей - один фиксированный и один динамический:</p>
67
<em>Скриншот: Google Chrome / Skillbox Media</em><p>Добавим два эндпойнта для пользователей - один фиксированный и один динамический:</p>
68
# Фиксированный путь для текущего пользователя @app.get("/users/me") async def read_user_me(): return {"user_id": "me"} # Динамический путь для любого пользователя @app.get("/users/{user_id}") async def read_user(user_id: str): # user_id: str -- принимает строку return {"user_id": user_id}<p>Порядок важен, чтобы FastAPI не путал их. Теперь по адресу<a>http://127.0.0.1:8000/users/me</a>будет ответ {"user_id": "me"}.</p>
68
# Фиксированный путь для текущего пользователя @app.get("/users/me") async def read_user_me(): return {"user_id": "me"} # Динамический путь для любого пользователя @app.get("/users/{user_id}") async def read_user(user_id: str): # user_id: str -- принимает строку return {"user_id": user_id}<p>Порядок важен, чтобы FastAPI не путал их. Теперь по адресу<a>http://127.0.0.1:8000/users/me</a>будет ответ {"user_id": "me"}.</p>
69
<p>По адресу, например,<a>http://127.0.0.1:8000/users/igor</a>будет ответ {"user_id": "igor"}.</p>
69
<p>По адресу, например,<a>http://127.0.0.1:8000/users/igor</a>будет ответ {"user_id": "igor"}.</p>
70
<p>Добавим возможность принимать данные от пользователя через тело запроса. Тело запроса выступает в качестве формы, которую пользователь заполняет и отправляет на сервер.</p>
70
<p>Добавим возможность принимать данные от пользователя через тело запроса. Тело запроса выступает в качестве формы, которую пользователь заполняет и отправляет на сервер.</p>
71
<p>Мы будем использовать Pydantic - инструмент, который проверяет, имеют ли данные правильный формат (например, число - это число, а не буквы). Если данные неверные, FastAPI автоматически вернёт ошибку. Также мы добавим проверку, чтобы отклонять слишком дорогие товары.</p>
71
<p>Мы будем использовать Pydantic - инструмент, который проверяет, имеют ли данные правильный формат (например, число - это число, а не буквы). Если данные неверные, FastAPI автоматически вернёт ошибку. Также мы добавим проверку, чтобы отклонять слишком дорогие товары.</p>
72
<p>Обновите импорты endpoints.py:</p>
72
<p>Обновите импорты endpoints.py:</p>
73
from fastapi import FastAPI, HTTPException from pydantic import BaseModel from enum import Enum<p>Добавьте класс для описания структуры данных:</p>
73
from fastapi import FastAPI, HTTPException from pydantic import BaseModel from enum import Enum<p>Добавьте класс для описания структуры данных:</p>
74
class Item(BaseModel): name: str # Название - строка price: float # Цена - число description: str | None = None # Описание - строка или ничего<p>Добавьте новый эндпойнт в конец register_endpoints:</p>
74
class Item(BaseModel): name: str # Название - строка price: float # Цена - число description: str | None = None # Описание - строка или ничего<p>Добавьте новый эндпойнт в конец register_endpoints:</p>
75
# Эндпойнт для создания товара через POST @app.post("/items/") async def create_item(item: Item): # Проверяем цену if item.price > 100: raise HTTPException(status_code=400, detail="Too expensive") return item<p>Откройте<a>http://127.0.0.1:8000/docs</a>, найдите эндпойнт POST /items/, нажмите Try it out и отправьте запрос в формате JSON. Это формат данных, похожий на словарь Python:</p>
75
# Эндпойнт для создания товара через POST @app.post("/items/") async def create_item(item: Item): # Проверяем цену if item.price > 100: raise HTTPException(status_code=400, detail="Too expensive") return item<p>Откройте<a>http://127.0.0.1:8000/docs</a>, найдите эндпойнт POST /items/, нажмите Try it out и отправьте запрос в формате JSON. Это формат данных, похожий на словарь Python:</p>
76
{ "name": "apple", "price": 1.5, "description": "A juicy apple" }<p>Вы получите ответ {"name": "apple", "price": 1.5, "description": "A juicy apple"}. Если отправить {"name": "apple", "price": "abc"}, FastAPI вернёт ошибку 422, так как price должен быть числом. Если отправить {"name": "apple", "price": 150}, вы получите ошибку 400 с сообщением "Too expensive", потому что цена выше 100.</p>
76
{ "name": "apple", "price": 1.5, "description": "A juicy apple" }<p>Вы получите ответ {"name": "apple", "price": 1.5, "description": "A juicy apple"}. Если отправить {"name": "apple", "price": "abc"}, FastAPI вернёт ошибку 422, так как price должен быть числом. Если отправить {"name": "apple", "price": 150}, вы получите ошибку 400 с сообщением "Too expensive", потому что цена выше 100.</p>
77
<p>Аутентификация проверяет, кто вы, а авторизация - что вы можете делать. Мы добавим два способа защиты: API-ключ (секретный код в заголовке запроса) и HTTP Basic (имя пользователя и пароль). Начнём с ключа. Создайте файл auth.py в fastapi_project:</p>
77
<p>Аутентификация проверяет, кто вы, а авторизация - что вы можете делать. Мы добавим два способа защиты: API-ключ (секретный код в заголовке запроса) и HTTP Basic (имя пользователя и пароль). Начнём с ключа. Создайте файл auth.py в fastapi_project:</p>
78
from fastapi import Depends, HTTPException from fastapi.security import APIKeyHeader # Настраиваем API-ключ в заголовке X-Key api_key = APIKeyHeader(name="X-Key") fake_keys = ["secret"] # Функция проверки API-ключа def get_key(key: str = Depends(api_key)): if key not in fake_keys: raise HTTPException(status_code=401, detail="Invalid API Key") return key<p>В endpoints.py обновите импорты:</p>
78
from fastapi import Depends, HTTPException from fastapi.security import APIKeyHeader # Настраиваем API-ключ в заголовке X-Key api_key = APIKeyHeader(name="X-Key") fake_keys = ["secret"] # Функция проверки API-ключа def get_key(key: str = Depends(api_key)): if key not in fake_keys: raise HTTPException(status_code=401, detail="Invalid API Key") return key<p>В endpoints.py обновите импорты:</p>
79
from fastapi import FastAPI, HTTPException, Depends from pydantic import BaseModel from enum import Enum from auth import get_key<p>Замените эндпойнт get.items/ на эндпойнт с API-ключем в endpoints.py:</p>
79
from fastapi import FastAPI, HTTPException, Depends from pydantic import BaseModel from enum import Enum from auth import get_key<p>Замените эндпойнт get.items/ на эндпойнт с API-ключем в endpoints.py:</p>
80
# Эндпойнт с API-ключом @app.get("/items/{item_id}") async def read_item(item_id: int, q: str = None, key=Depends(get_key)): return {"item_id": item_id, "q": q}<p>В /docs для GET /items/{item_id} введите secret в Authorize. Форма для входа доступна по появляющейся справа зелёной кнопке с иконкой замка.</p>
80
# Эндпойнт с API-ключом @app.get("/items/{item_id}") async def read_item(item_id: int, q: str = None, key=Depends(get_key)): return {"item_id": item_id, "q": q}<p>В /docs для GET /items/{item_id} введите secret в Authorize. Форма для входа доступна по появляющейся справа зелёной кнопке с иконкой замка.</p>
81
<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Проверьте с item_id=5 - получите ответ {"item_id": 5, "q": null}. С неверным ключом вылезет ошибка 401.</p>
81
<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Проверьте с item_id=5 - получите ответ {"item_id": 5, "q": null}. С неверным ключом вылезет ошибка 401.</p>
82
Ответ сервера при попытке запроса с неправильным API-ключом<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Добавим авторизацию. Обновите импорты в auth.py:</p>
82
Ответ сервера при попытке запроса с неправильным API-ключом<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Добавим авторизацию. Обновите импорты в auth.py:</p>
83
from fastapi import Depends, HTTPException from fastapi.security import APIKeyHeader, HTTPBasic, HTTPBasicCredentials from secrets import compare_digest<p>Добавьте в конец файла проверку имени и пароля для обычного пользователя и для админа:</p>
83
from fastapi import Depends, HTTPException from fastapi.security import APIKeyHeader, HTTPBasic, HTTPBasicCredentials from secrets import compare_digest<p>Добавьте в конец файла проверку имени и пароля для обычного пользователя и для админа:</p>
84
# HTTP Basic basic = HTTPBasic() # Функция проверки имени и пароля def get_user(credentials: HTTPBasicCredentials = Depends(basic)): if not compare_digest(credentials.password, "pass"): raise HTTPException(status_code=401, detail="Invalid credentials") return credentials.username # Проверка админа def admin_only(user: str = Depends(get_user)): if user != "admin": raise HTTPException(status_code=403, detail="Admins only") return user<p>В endpoints.py обновляем импорт из auth.py:</p>
84
# HTTP Basic basic = HTTPBasic() # Функция проверки имени и пароля def get_user(credentials: HTTPBasicCredentials = Depends(basic)): if not compare_digest(credentials.password, "pass"): raise HTTPException(status_code=401, detail="Invalid credentials") return credentials.username # Проверка админа def admin_only(user: str = Depends(get_user)): if user != "admin": raise HTTPException(status_code=403, detail="Admins only") return user<p>В endpoints.py обновляем импорт из auth.py:</p>
85
from auth import get_key, get_user, admin_only<p>Обновляем эндпойнт с фиксированным пользователем:</p>
85
from auth import get_key, get_user, admin_only<p>Обновляем эндпойнт с фиксированным пользователем:</p>
86
# Эндпойнт с HTTP Basic @app.get("/users/me") async def read_user_me(user: str = Depends(get_user)): return {"user_id": user}<p>Добавляем админский эндпойнт:</p>
86
# Эндпойнт с HTTP Basic @app.get("/users/me") async def read_user_me(user: str = Depends(get_user)): return {"user_id": user}<p>Добавляем админский эндпойнт:</p>
87
# Эндпойнт только для админа @app.get("/admin/") async def admin_only_endpoint(user: str = Depends(admin_only)): return {"message": "Welcome, admin"}<p>Убедимся, что всё работает. Зайдите в /docs. Для GET /users/me введите логин user и пароль pass в Authorize → HTTP Basic. В ответе должно быть {"user_id": <ваш логин>}.</p>
87
# Эндпойнт только для админа @app.get("/admin/") async def admin_only_endpoint(user: str = Depends(admin_only)): return {"message": "Welcome, admin"}<p>Убедимся, что всё работает. Зайдите в /docs. Для GET /users/me введите логин user и пароль pass в Authorize → HTTP Basic. В ответе должно быть {"user_id": <ваш логин>}.</p>
88
<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Для GET /admin/ попробуйте Try it out → Execute без авторизации - появится ошибка 403 с сообщением "Admin’s only".</p>
88
<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Для GET /admin/ попробуйте Try it out → Execute без авторизации - появится ошибка 403 с сообщением "Admin’s only".</p>
89
<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Если ввести логин admin и пароль pass, появится ответ {"message": "Welcome, admin"}.</p>
89
<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Если ввести логин admin и пароль pass, появится ответ {"message": "Welcome, admin"}.</p>
90
<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Создадим<a>database.py</a>в fastapi_project:</p>
90
<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Создадим<a>database.py</a>в fastapi_project:</p>
91
import json # Функция загрузки данных из db.json def load_db(): try: with open("db.json", "r") as f: return json.load(f) # Читаем JSON как список except FileNotFoundError: # Если файла нет, возвращаем пустой список return [] # Функция сохранения данных в db.json def save_db(data): with open("db.json", "w") as f: json.dump(data, f) # Записываем список в JSON # Загружаем базу данных при старте db = load_db()<p>Добавим импорт в endpoints.py:</p>
91
import json # Функция загрузки данных из db.json def load_db(): try: with open("db.json", "r") as f: return json.load(f) # Читаем JSON как список except FileNotFoundError: # Если файла нет, возвращаем пустой список return [] # Функция сохранения данных в db.json def save_db(data): with open("db.json", "w") as f: json.dump(data, f) # Записываем список в JSON # Загружаем базу данных при старте db = load_db()<p>Добавим импорт в endpoints.py:</p>
92
from database import db, save_db<p>В register_endpoints замените старый эндпойнт post/items/ на следующий:</p>
92
from database import db, save_db<p>В register_endpoints замените старый эндпойнт post/items/ на следующий:</p>
93
# Эндпойнт для создания товара. Сохраняет товар в db.json @app.post("/items/") async def create_item(item: Item): # Проверяем цену if item.price > 100: raise HTTPException(status_code=400, detail="Too expensive") db.append(item.dict()) # Добавляем товар в список save_db(db) # Сохраняем в db.json return item<p>В /docs отправьте POST-запрос на /items/:</p>
93
# Эндпойнт для создания товара. Сохраняет товар в db.json @app.post("/items/") async def create_item(item: Item): # Проверяем цену if item.price > 100: raise HTTPException(status_code=400, detail="Too expensive") db.append(item.dict()) # Добавляем товар в список save_db(db) # Сохраняем в db.json return item<p>В /docs отправьте POST-запрос на /items/:</p>
94
{ "name": "apple", "price": 1.5, "description": "A juicy apple" }<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Товар сохранится в автоматически созданном файле db.json.</p>
94
{ "name": "apple", "price": 1.5, "description": "A juicy apple" }<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Товар сохранится в автоматически созданном файле db.json.</p>
95
<p>Чтобы посмотреть все добавленные товары, пропишем ещё один эндпойнт в endpoints.py:</p>
95
<p>Чтобы посмотреть все добавленные товары, пропишем ещё один эндпойнт в endpoints.py:</p>
96
# Эндпойнт для получения всех товаров @app.get("/items/") async def get_items(): return db<p>В /docs выполните GET-запрос на /items/ - увидите список товаров, например [{"name": "apple", "price": 1.5, "description": "A juicy apple"}].</p>
96
# Эндпойнт для получения всех товаров @app.get("/items/") async def get_items(): return db<p>В /docs выполните GET-запрос на /items/ - увидите список товаров, например [{"name": "apple", "price": 1.5, "description": "A juicy apple"}].</p>
97
<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Наш проект готов! В итоге у вас в папке fastapi_project должно быть пять файлов: main.py, endpoints.py, auth.py, database.py и db.json. Если что-то работает не так, как задумано, сверьте код.</p>
97
<em>Скриншот:<a>FastAPI</a>/ Skillbox Media</em><p>Наш проект готов! В итоге у вас в папке fastapi_project должно быть пять файлов: main.py, endpoints.py, auth.py, database.py и db.json. Если что-то работает не так, как задумано, сверьте код.</p>
98
<p>main.py:</p>
98
<p>main.py:</p>
99
from fastapi import FastAPI from endpoints import register_endpoints # Создаём приложение FastAPI app = FastAPI() # Регистрируем эндпойнты register_endpoints(app)<p>endpoints.py:</p>
99
from fastapi import FastAPI from endpoints import register_endpoints # Создаём приложение FastAPI app = FastAPI() # Регистрируем эндпойнты register_endpoints(app)<p>endpoints.py:</p>
100
from fastapi import FastAPI, HTTPException, Depends from pydantic import BaseModel from enum import Enum from auth import get_key, get_user, admin_only from database import db, save_db class Item(BaseModel): name: str # Название - строка price: float # Цена - число description: str | None = None # Описание - строка или ничего # Определяем Enum - список разрешённых значений class Model(str, Enum): a = "a" # Разрешённое значение "a" b = "b" # Разрешённое значение "b" # Функция для регистрации эндпойнтов def register_endpoints(app: FastAPI): # Эндпойнт для главной страницы @app.get("/") async def root(): return {"message": "Hello World"} # Эндпойнт с API-ключом @app.get("/items/{item_id}") async def read_item(item_id: int, q: str = None, key=Depends(get_key)): return {"item_id": item_id, "q": q} # Эндпойнт /models/{model} принимает только a или b @app.get("/models/{model}") async def get_model(model: Model): # model: Model - проверяет, что значение из Enum return {"model": model} # Фиксированный путь для текущего пользователя @app.get("/users/me") async def read_user_me(user: str = Depends(get_user)): return {"user_id": user} # Динамический путь для любого пользователя @app.get("/users/{user_id}") async def read_user(user_id: str): # user_id: str - принимает строку return {"user_id": user_id} # Эндпойнт только для админа @app.get("/admin/") async def admin_only_endpoint(user: str = Depends(admin_only)): return {"message": "Welcome, admin"} # Эндпойнт для создания товара. Сохраняет товар в db.json @app.post("/items/") async def create_item(item: Item): # Проверяем цену if item.price > 100: raise HTTPException(status_code=400, detail="Too expensive") db.append(item.dict()) # Добавляем товар в список save_db(db) # Сохраняем в db.json return item # Эндпойнт для получения всех товаров @app.get("/items/") async def get_items(): return db<p>auth.py:</p>
100
from fastapi import FastAPI, HTTPException, Depends from pydantic import BaseModel from enum import Enum from auth import get_key, get_user, admin_only from database import db, save_db class Item(BaseModel): name: str # Название - строка price: float # Цена - число description: str | None = None # Описание - строка или ничего # Определяем Enum - список разрешённых значений class Model(str, Enum): a = "a" # Разрешённое значение "a" b = "b" # Разрешённое значение "b" # Функция для регистрации эндпойнтов def register_endpoints(app: FastAPI): # Эндпойнт для главной страницы @app.get("/") async def root(): return {"message": "Hello World"} # Эндпойнт с API-ключом @app.get("/items/{item_id}") async def read_item(item_id: int, q: str = None, key=Depends(get_key)): return {"item_id": item_id, "q": q} # Эндпойнт /models/{model} принимает только a или b @app.get("/models/{model}") async def get_model(model: Model): # model: Model - проверяет, что значение из Enum return {"model": model} # Фиксированный путь для текущего пользователя @app.get("/users/me") async def read_user_me(user: str = Depends(get_user)): return {"user_id": user} # Динамический путь для любого пользователя @app.get("/users/{user_id}") async def read_user(user_id: str): # user_id: str - принимает строку return {"user_id": user_id} # Эндпойнт только для админа @app.get("/admin/") async def admin_only_endpoint(user: str = Depends(admin_only)): return {"message": "Welcome, admin"} # Эндпойнт для создания товара. Сохраняет товар в db.json @app.post("/items/") async def create_item(item: Item): # Проверяем цену if item.price > 100: raise HTTPException(status_code=400, detail="Too expensive") db.append(item.dict()) # Добавляем товар в список save_db(db) # Сохраняем в db.json return item # Эндпойнт для получения всех товаров @app.get("/items/") async def get_items(): return db<p>auth.py:</p>
101
from fastapi import Depends, HTTPException from fastapi.security import APIKeyHeader, HTTPBasic, HTTPBasicCredentials from secrets import compare_digest # Настраиваем API-ключ api_key = APIKeyHeader(name="X-Key") fake_keys = ["secret"] def get_key(key: str = Depends(api_key)): if key not in fake_keys: raise HTTPException(status_code=401, detail="Invalid API Key") return key # Настраиваем HTTP Basic basic = HTTPBasic() # Функция проверки имени и пароля def get_user(credentials: HTTPBasicCredentials = Depends(basic)): # Проверяем только пароль "pass", имя может быть любым if not compare_digest(credentials.password, "pass"): raise HTTPException(status_code=401, detail="Invalid credentials") return credentials.username # Проверка админа def admin_only(user: str = Depends(get_user)): if user != "admin": raise HTTPException(status_code=403, detail="Admins only") return user<p>database.py:</p>
101
from fastapi import Depends, HTTPException from fastapi.security import APIKeyHeader, HTTPBasic, HTTPBasicCredentials from secrets import compare_digest # Настраиваем API-ключ api_key = APIKeyHeader(name="X-Key") fake_keys = ["secret"] def get_key(key: str = Depends(api_key)): if key not in fake_keys: raise HTTPException(status_code=401, detail="Invalid API Key") return key # Настраиваем HTTP Basic basic = HTTPBasic() # Функция проверки имени и пароля def get_user(credentials: HTTPBasicCredentials = Depends(basic)): # Проверяем только пароль "pass", имя может быть любым if not compare_digest(credentials.password, "pass"): raise HTTPException(status_code=401, detail="Invalid credentials") return credentials.username # Проверка админа def admin_only(user: str = Depends(get_user)): if user != "admin": raise HTTPException(status_code=403, detail="Admins only") return user<p>database.py:</p>
102
import json # Функция загрузки данных из db.json def load_db(): try: with open("db.json", "r") as f: return json.load(f) # Читаем JSON как список except FileNotFoundError: # Если файла нет, возвращаем пустой список return [] # Функция сохранения данных в db.json def save_db(data): with open("db.json", "w") as f: json.dump(data, f) # Записываем список в JSON # Загружаем базу данных при старте db = load_db()<p>db.json будет хранить всё, что вы сохранили с помощью POST-запросов. В нашем случае там будет один товар:</p>
102
import json # Функция загрузки данных из db.json def load_db(): try: with open("db.json", "r") as f: return json.load(f) # Читаем JSON как список except FileNotFoundError: # Если файла нет, возвращаем пустой список return [] # Функция сохранения данных в db.json def save_db(data): with open("db.json", "w") as f: json.dump(data, f) # Записываем список в JSON # Загружаем базу данных при старте db = load_db()<p>db.json будет хранить всё, что вы сохранили с помощью POST-запросов. В нашем случае там будет один товар:</p>
103
{ "name": "apple", "price": 1.5, "description": "A juicy apple" }<p>Убедитесь, что финальные версии файлов сохранены, а команды в терминале написаны без ошибок.</p>
103
{ "name": "apple", "price": 1.5, "description": "A juicy apple" }<p>Убедитесь, что финальные версии файлов сохранены, а команды в терминале написаны без ошибок.</p>
104
<p>Чтобы глубже понять FastAPI, изучите<a>официальную документацию</a>. Она охватывает все фичи: от асинхронности до интеграций. Там есть туториалы, примеры кода и советы по best practices. Документация на английском, но с автоматическим переводом на русский. Начните с раздела "Tutorial - User Guide". Она обновляется регулярно, так что информация всегда свежая. Это лучший источник для освоения продвинутых тем.</p>
104
<p>Чтобы глубже понять FastAPI, изучите<a>официальную документацию</a>. Она охватывает все фичи: от асинхронности до интеграций. Там есть туториалы, примеры кода и советы по best practices. Документация на английском, но с автоматическим переводом на русский. Начните с раздела "Tutorial - User Guide". Она обновляется регулярно, так что информация всегда свежая. Это лучший источник для освоения продвинутых тем.</p>
105
<p>Для проекта мы имитировали базы данных. Но для реальных проектов это не годится. Чтобы понять, как правильно, изучите<a>реляционные и нереляционные базы данных</a>.</p>
105
<p>Для проекта мы имитировали базы данных. Но для реальных проектов это не годится. Чтобы понять, как правильно, изучите<a>реляционные и нереляционные базы данных</a>.</p>
106
<p>Реальные проекты нужно тестировать. На Python есть несколько библиотек для тестирования. Самая популярная -<a>Pytest</a>.</p>
106
<p>Реальные проекты нужно тестировать. На Python есть несколько библиотек для тестирования. Самая популярная -<a>Pytest</a>.</p>
107
<p>Чтобы проект был доступен другим пользователям, его нужно грамотно развернуть. Сегодня стандарт индустрии - Docker. Тому, как развернуть с его помощью приложение на FastAPI, посвящён<a>отдельный подраздел в документации</a>.</p>
107
<p>Чтобы проект был доступен другим пользователям, его нужно грамотно развернуть. Сегодня стандарт индустрии - Docker. Тому, как развернуть с его помощью приложение на FastAPI, посвящён<a>отдельный подраздел в документации</a>.</p>
108
<p>Python для всех</p>
108
<p>Python для всех</p>
109
<p>Вы освоите Python на практике и создадите проекты для портфолио - телеграм-бот, веб-парсер и сайт с нуля. А ещё получите готовый план выхода на удалёнку и фриланс. Спикер - руководитель отдела разработки в "Сбере".</p>
109
<p>Вы освоите Python на практике и создадите проекты для портфолио - телеграм-бот, веб-парсер и сайт с нуля. А ещё получите готовый план выхода на удалёнку и фриланс. Спикер - руководитель отдела разработки в "Сбере".</p>
110
<p><a>Пройти бесплатно</a></p>
110
<p><a>Пройти бесплатно</a></p>
111
<a><b>Бесплатный курс по разработке на Python ➞</b>Пройдите бесплатный курс по Python и создайте с нуля телеграм-бот, веб-парсер и сайт. Спикер - руководитель отдела разработки в "Сбере". Пройти курс</a>
111
<a><b>Бесплатный курс по разработке на Python ➞</b>Пройдите бесплатный курс по Python и создайте с нуля телеграм-бот, веб-парсер и сайт. Спикер - руководитель отдела разработки в "Сбере". Пройти курс</a>