私の出版物の読者は、マイクロサービスの開発に API ファースト アプローチを採用するというアイデアをよくご存知でしょう。開発を開始する前に、予想される URI と基礎となるオブジェクト モデルを記述することの利点を私は何度も実感してきました。 しかし、30 年以上テクノロジーに携わってきた中で、私は の現実を予想するようになりました。言い換えれば、API ファーストが不可能な状況があることは十分予想しています。 代替フロー この記事では、マイクロサービスを作成するチームが、openapi.json ファイルを手動で定義しなくても、他のユーザーが使用できる OpenAPI 仕様を提供することに成功する方法の例を説明したいと思います。 また、自分の快適ゾーンから抜け出して、Java、.NET、さらには JavaScript を使用せずにこれを実行したいと考えていました。 FastAPI の発見 私のほとんどの記事の結論では、私の個人的なミッションステートメントについてよく言及しています。 「知的財産の価値を高める機能や特性を提供することに時間を集中してください。他のすべてにはフレームワーク、製品、サービスを活用してください。」 – J. ベスター このミッション ステートメントで私が言いたいのは、より高いレベルで設定された目標や目的を達成するために、自分の時間を最大限に活用する責任を自分に負わせることです。基本的に、私たちの焦点がウィジェットの販売数を増やすことにある場合、私の時間はそれを可能にする方法を見つけることに費やされるべきであり、既存のフレームワーク、製品、またはサービスによってすでに解決されている課題には手を出さないようにします。 私は新しいマイクロサービスのプログラミング言語として Python を選択しました。これまで、以前の記事で書いた Python コードの 99% は (SODD) または ChatGPT 主導の回答の結果でした。明らかに、Python は私の得意分野ではありません。 、Stack Overflow Driven Development 現状を把握したので、ソース言語の経験がほとんどない状態で、自分のミッション ステートメントに準拠した新しい Python ベースの RESTful マイクロサービスを作成したいと考えました。 その時、私は を見つけました。 FastAPI FastAPI は 2018 年から存在しており、Python タイプのヒントを使用して RESTful API を提供することに重点を置いたフレームワークです。FastAPI の最も優れた点は、開発者の視点から追加の労力をかけずに OpenAPI 3 仕様を自動的に生成できることです。 記事 API の使用例 この記事では、消費者が最近公開した記事のリストを取得できる RESTful API を提供する Article API というアイデアが思い浮かびました。 簡単にするために、特定の に次のプロパティが含まれていると仮定します。 Article – シンプルで一意の識別子プロパティ(数値) id – 記事のタイトル(文字列) title – 記事の完全なURL(文字列) url – 記事が出版された年(数字) year 記事 API には次の URI が含まれます。 GET – 記事のリストを取得します /articles GET – idプロパティで単一の記事を取得します /articles/{article_id} POST – 新しい記事を追加する /articles FastAPI の実践 ターミナルで、fast-api-demo という新しい Python プロジェクトを作成し、次のコマンドを実行しました。 $ 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 のユースケースに合わせて オブジェクトを定義しました。 Article 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) 次に、別のターミナル ウィンドウで、 curl リクエストを送信しました ( にパイプしました)。 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 } 展開の準備 単に Article 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 また、 を使用してマイクロサービスを起動する方法を Heroku に指示する というファイルも必要でした。その内容は次のようになります。 uvicorn Procfile web: uvicorn api:app --host=0.0.0.0 --port=${PORT} Herokuにデプロイしてみましょう Python を初めて使用する方 (私もそうです) のために、 ドキュメントを役立つガイドとして使用しました。 Heroku で Python を使い始めるための Heroku CLI はすでにインストールされていたので、ターミナルから Heroku エコシステムにログインするだけで済みました。 $ heroku login すべての更新を GitLab のリポジトリにチェックインするようにしました。 次に、次のコマンドを使用して 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 remote コマンドを発行すると、リモートが Heroku エコシステムに自動的に追加されたことがわかります。 $ git remote heroku origin アプリを Heroku にデプロイするには、次のコマンドを使用するだけです。 fast-api-demo $ git push heroku main すべての設定が完了したら、新しい Python ベースのサービスが Heroku ダッシュボードで稼働していることを検証できました。 サービスが実行されている場合、次の curl コマンドを発行することで、Article API から の を取得できます。 id = 1 Article $ curl --location 'https://powerful-bayou-23686-2d5be7cf118b.herokuapp.com/articles/1' curl コマンドは 応答と次の JSON ペイロードを返します。 200 OK { "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 機能を活用すると、消費者は自動的に生成された URI に移動して、完全に機能する v3 仕様を受け取ることができます。 /docs https://powerful-bayou-23686-2d5be7cf118b.herokuapp.com/docs この URL を呼び出すと、広く採用されている Swagger UI を使用する Article API マイクロサービスが返されます。 Article API を使用するクライアントを生成する ファイルを探している場合は、 URI を使用できます。 openapi.json /openapi.json https://powerful-bayou-23686-2d5be7cf118b.herokuapp.com/openapi.json 私の例では、JSON ベースの OpenAPI v3 仕様は次のようになります。 { "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 ファースト アプローチの使用に興味がない人々と戦う覚悟ができていました。この演習から私が学んだのは、FastAPI のような製品を使用すると、実用的な RESTful マイクロサービスを迅速に定義して作成できると同時に、完全に使用可能な OpenAPI v3 仕様も自動的に組み込むことができるということです。 結局のところ、FastAPI は、他のチームが信頼できる標準化された契約を生成するフレームワークを活用して、チームが目標と目的に集中できるようにします。その結果、私の個人的なミッション ステートメントに従うための別の道が生まれました。 途中で、私は初めて Heroku を使用して Python ベースのサービスをデプロイしました。これは、よく書かれたドキュメントを確認する以外に、私の側ではほとんど労力を必要としないことがわかりました。そのため、Heroku プラットフォームについても、ミッション ステートメントのもう 1 つのボーナスについて言及する必要があります。 この記事のソースコードに興味がある方は、 で見つけることができます。 GitLab 本当に素晴らしい一日をお過ごしください!