paint-brush
FastAPI дал мне спецификацию OpenAPI действительно... быстрок@johnjvester
2,049 чтения
2,049 чтения

FastAPI дал мне спецификацию OpenAPI действительно... быстро

к John Vester16m2024/04/22
Read on Terminal Reader

Слишком долго; Читать

Когда API First невозможен, FastAPI может сэкономить время команд, позволяя полностью документировать и автоматически использовать существующие микросервисы RESTful с использованием OpenAPI v3.
featured image - FastAPI дал мне спецификацию OpenAPI действительно... быстро
John Vester HackerNoon profile picture

Читатели моих публикаций, вероятно, знакомы с идеей использования подхода API First к разработке микросервисов. Бесчисленное количество раз я осознавал преимущества описания ожидаемых URI и базовых объектных моделей до начала какой-либо разработки.


Однако за 30 с лишним лет работы в сфере навигации я стал ожидать реальности альтернативных потоков . Другими словами, я полностью ожидаю, что возникнут ситуации, когда API First просто невозможен.


В этой статье я хотел рассмотреть пример того, как команды, производящие микросервисы, могут по-прежнему успешно предоставлять спецификацию OpenAPI для использования другими без определения файла openapi.json вручную.


Я также хотел выйти за пределы своей зоны комфорта и сделать это без использования Java, .NET или даже JavaScript.

Знакомство с FastAPI

В заключение большинства своих статей я часто упоминаю свою личную миссию:


«Сосредоточьте свое время на предоставлении функций/функций, которые увеличивают ценность вашей интеллектуальной собственности. Используйте платформы, продукты и услуги для всего остального». – Дж. Вестер


Моя цель в этой формулировке миссии — взять на себя ответственность за максимально эффективное использование своего времени при попытке достичь целей и задач, поставленных на более высоком уровне. По сути, если наша цель — продать больше виджетов, мое время следует потратить на поиск способов сделать это возможным — избегать проблем, которые уже решены с помощью существующих инфраструктур, продуктов или услуг.


В качестве языка программирования для своего нового микросервиса я выбрал Python. На сегодняшний день 99% кода Python, который я написал для своих предыдущих статей, было результатом либо разработки, управляемой переполнением стека (SODD), либо ответов, основанных на ChatGPT. Очевидно, что Python выходит за пределы моей зоны комфорта.


Теперь, когда я определил положение вещей, я захотел создать новый микросервис RESTful на основе Python, который соответствует моей личной формулировке миссии и имеет минимальный опыт работы с исходным языком.


Именно тогда я нашел FastAPI .


FastAPI существует с 2018 года и представляет собой платформу, ориентированную на предоставление RESTful API с использованием подсказок типа Python. Самое приятное в FastAPI — это возможность автоматически генерировать спецификации OpenAPI 3 без каких-либо дополнительных усилий со стороны разработчика.

Вариант использования API статьи

В этой статье на ум пришла идея API статей, предоставляющего RESTful API, который позволяет потребителям получать список моих недавно опубликованных статей.


Для простоты предположим, что данная Article содержит следующие свойства:

  • id – простой, уникальный идентификатор свойства (число)
  • title – название статьи (строка)
  • url – полный URL статьи (строка)
  • year – год публикации статьи (число)


API статей будет включать следующие URI:

  • GET /articles – получит список статей.
  • GET /articles/{article_id} – получит одну статью по свойству id.
  • POST /articles – добавляет новую статью.

FastAPI в действии

В своем терминале я создал новый проект Python под названием fast-api-demo, а затем выполнил следующие команды:


 $ pip install --upgrade pip $ pip install fastapi $ pip install uvicorn


Я создал новый файл Python под названием api.py и добавил некоторые импортированные данные, а также установил переменную app :


 from fastapi import FastAPI, HTTPException from pydantic import BaseModel app = FastAPI() if __name__ == "__main__": import uvicorn uvicorn.run(app, host="localhost", port=8000)


Затем я определил объект Article , соответствующий варианту использования API статей:


 class Article(BaseModel): id: int title: str url: str year: int


Когда модель была создана, мне нужно было добавить URI… что оказалось довольно просто:


 # Route to add a new article @app.post("/articles") def create_article(article: Article): articles.append(article) return article # Route to get all articles @app.get("/articles") def get_articles(): return articles # Route to get a specific article by ID @app.get("/articles/{article_id}") def get_article(article_id: int): for article in articles: if article.id == article_id: return article raise HTTPException(status_code=404, detail="Article not found")


Чтобы избавить себя от использования внешнего хранилища данных, я решил добавить некоторые из своих недавно опубликованных статей программно:


 articles = [ Article(id=1, title="Distributed Cloud Architecture for Resilient Systems: Rethink Your Approach To Resilient Cloud Services", url="https://dzone.com/articles/distributed-cloud-architecture-for-resilient-syste", year=2023), Article(id=2, title="Using Unblocked to Fix a Service That Nobody Owns", url="https://dzone.com/articles/using-unblocked-to-fix-a-service-that-nobody-owns", year=2023), Article(id=3, title="Exploring the Horizon of Microservices With KubeMQ's New Control Center", url="https://dzone.com/articles/exploring-the-horizon-of-microservices-with-kubemq", year=2024), Article(id=4, title="Build a Digital Collectibles Portal Using Flow and Cadence (Part 1)", url="https://dzone.com/articles/build-a-digital-collectibles-portal-using-flow-and-1", year=2024), Article(id=5, title="Build a Flow Collectibles Portal Using Cadence (Part 2)", url="https://dzone.com/articles/build-a-flow-collectibles-portal-using-cadence-par-1", year=2024), Article(id=6, title="Eliminate Human-Based Actions With Automated Deployments: Improving Commit-to-Deploy Ratios Along the Way", url="https://dzone.com/articles/eliminate-human-based-actions-with-automated-deplo", year=2024), Article(id=7, title="Vector Tutorial: Conducting Similarity Search in Enterprise Data", url="https://dzone.com/articles/using-pgvector-to-locate-similarities-in-enterpris", year=2024), Article(id=8, title="DevSecOps: It's Time To Pay for Your Demand, Not Ingestion", url="https://dzone.com/articles/devsecops-its-time-to-pay-for-your-demand", year=2024), ]


Хотите верьте, хотите нет, но на этом разработка микросервиса Article API завершена.


Для быстрой проверки работоспособности я развернул свой сервис API локально:


 $ python api.py INFO: Started server process [320774] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://localhost:8000 (Press CTRL+C to quit)


Затем в другом окне терминала я отправил запрос на завивку (и передал его в json_pp ):


 $ curl localhost:8000/articles/1 | json_pp { "id": 1, "title": "Distributed Cloud Architecture for Resilient Systems: Rethink Your Approach To Resilient Cloud Services", "url": "https://dzone.com/articles/distributed-cloud-architecture-for-resilient-syste", "year": 2023 }


Подготовка к развертыванию

Вместо того, чтобы просто запускать API статей локально, я подумал, что смогу посмотреть, насколько легко можно развернуть микросервис. Поскольку я никогда раньше не развертывал микросервис Python в Heroku , я почувствовал, что сейчас самое время попробовать.


Прежде чем погрузиться в Heroku, мне нужно было создать файл requirements.txt для описания зависимостей сервиса. Для этого я установил и запустил pipreqs :


 $ pip install pipreqs $ pipreqs


Это создало для меня файл requirements.txt со следующей информацией:


 fastapi==0.110.1 pydantic==2.6.4 uvicorn==0.29.0


Мне также понадобился файл Procfile , который сообщает Heroku, как развернуть мой микросервис с помощью uvicorn . Его содержимое выглядело так:


 web: uvicorn api:app --host=0.0.0.0 --port=${PORT}


Давайте развернем в Heroku

Для тех из вас, кто плохо знаком с Python (как и я), я использовал документацию «Начало работы с Heroku с Python» в качестве полезного руководства.


Поскольку у меня уже был установлен интерфейс командной строки Heroku, мне просто нужно было войти в экосистему Heroku со своего терминала:


 $ heroku login


Я обязательно проверял все свои обновления в своем репозитории на GitLab.


Затем создание нового приложения в Heroku можно выполнить с помощью CLI с помощью следующей команды:


 $ heroku create


CLI ответил уникальным именем приложения, а также URL-адресом приложения и репозиторием на основе git, связанным с приложением:


 Creating app... done, powerful-bayou-23686 https://powerful-bayou-23686-2d5be7cf118b.herokuapp.com/ | https://git.heroku.com/powerful-bayou-23686.git


Обратите внимание: к тому времени, как вы прочитаете эту статью, моего приложения уже не будет в сети.


Проверь это. Когда я запускаю удаленную команду git, я вижу, что удаленный компьютер был автоматически добавлен в экосистему Heroku:


 $ git remote heroku origin


Чтобы развернуть приложение fast-api-demo в Heroku, мне нужно всего лишь использовать следующую команду:


 $ git push heroku main


Когда все настроено, я смог убедиться, что мой новый сервис на основе Python запущен и работает на панели инструментов Heroku:


При запущенной службе можно получить Article с id = 1 из API статей, выполнив следующую команду Curl:


 $ curl --location 'https://powerful-bayou-23686-2d5be7cf118b.herokuapp.com/articles/1'


Команда Curl возвращает ответ 200 OK и следующую полезную нагрузку JSON:


 { "id": 1, "title": "Distributed Cloud Architecture for Resilient Systems: Rethink Your Approach To Resilient Cloud Services", "url": "https://dzone.com/articles/distributed-cloud-architecture-for-resilient-syste", "year": 2023 }


Автоматическая доставка спецификаций OpenAPI 3

Использование встроенной в FastAPI функциональности OpenAPI позволяет потребителям получить полнофункциональную спецификацию v3, перейдя к автоматически сгенерированному URI /docs :


 https://powerful-bayou-23686-2d5be7cf118b.herokuapp.com/docs


Вызов этого URL-адреса возвращает микросервис Article API с использованием широко распространенного пользовательского интерфейса Swagger:


Тем, кто ищет файл openapi.json для создания клиентов для использования API статей, можно использовать URI /openapi.json :


 https://powerful-bayou-23686-2d5be7cf118b.herokuapp.com/openapi.json


В моем примере спецификация OpenAPI v3 на основе JSON выглядит так, как показано ниже:


 { "openapi": "3.1.0", "info": { "title": "FastAPI", "version": "0.1.0" }, "paths": { "/articles": { "get": { "summary": "Get Articles", "operationId": "get_articles_articles_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { } } } } } }, "post": { "summary": "Create Article", "operationId": "create_article_articles_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Article" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/articles/{article_id}": { "get": { "summary": "Get Article", "operationId": "get_article_articles__article_id__get", "parameters": [ { "name": "article_id", "in": "path", "required": true, "schema": { "type": "integer", "title": "Article Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } } }, "components": { "schemas": { "Article": { "properties": { "id": { "type": "integer", "title": "Id" }, "title": { "type": "string", "title": "Title" }, "url": { "type": "string", "title": "Url" }, "year": { "type": "integer", "title": "Year" } }, "type": "object", "required": [ "id", "title", "url", "year" ], "title": "Article" }, "HTTPValidationError": { "properties": { "detail": { "items": { "$ref": "#/components/schemas/ValidationError" }, "type": "array", "title": "Detail" } }, "type": "object", "title": "HTTPValidationError" }, "ValidationError": { "properties": { "loc": { "items": { "anyOf": [ { "type": "string" }, { "type": "integer" } ] }, "type": "array", "title": "Location" }, "msg": { "type": "string", "title": "Message" }, "type": { "type": "string", "title": "Error Type" } }, "type": "object", "required": [ "loc", "msg", "type" ], "title": "ValidationError" } } } }


В результате следующую спецификацию можно использовать для создания клиентов на нескольких разных языках с помощью OpenAPI Generator .

Заключение

В начале этой статьи я был готов вступить в бой и встретиться с любым, кто не заинтересован в использовании подхода API First. Из этого упражнения я узнал, что такой продукт, как FastAPI, может помочь быстро определить и создать работающий микросервис RESTful, в то же время автоматически включая полностью потребляемую спецификацию OpenAPI v3.


Оказывается, FastAPI позволяет командам сосредоточиться на своих целях и задачах, используя структуру, которая создает стандартизированный контракт, на который могут положиться другие. В результате появился другой путь следования моей личной миссии.


Попутно я впервые использовал Heroku для развертывания сервиса на основе Python. Оказалось, что это не потребовало от меня особых усилий, кроме просмотра хорошо написанной документации. Поэтому необходимо упомянуть еще один бонус в заявлении миссии для платформы Heroku.


Если вас интересует исходный код этой статьи, вы можете найти его на GitLab .


Хорошего дня!