paint-brush
FastAPI Bana Gerçekten Bir OpenAPI Özelliği Sağladı... Hızlıile@johnjvester
2,049 okumalar
2,049 okumalar

FastAPI Bana Gerçekten Bir OpenAPI Özelliği Sağladı... Hızlı

ile John Vester16m2024/04/22
Read on Terminal Reader

Çok uzun; Okumak

API First bir seçenek olmadığında FastAPI, mevcut RESTful mikro hizmetlerin tamamen belgelenmesine ve OpenAPI v3 kullanılarak otomatik olarak kullanılmasına izin vererek ekiplere zaman kazandırabilir.
featured image - FastAPI Bana Gerçekten Bir OpenAPI Özelliği Sağladı... Hızlı
John Vester HackerNoon profile picture

Yayınlarımı okuyanlar muhtemelen mikro hizmetlerin geliştirilmesinde API First yaklaşımını kullanma fikrine aşinadır. Sayısız kez, herhangi bir geliştirme başlamadan önce beklenen URI'leri ve temeldeki nesne modellerini tanımlamanın faydalarını fark ettim.


Bununla birlikte, 30 yılı aşkın navigasyon teknolojimde, alternatif akışların gerçeklerini beklemeye başladım. Başka bir deyişle, API First'ün mümkün olmadığı durumların olmasını kesinlikle bekliyorum.


Bu makale için, mikro hizmetler üreten ekiplerin, bir openapi.json dosyasını manuel olarak tanımlamadan başkalarının kullanması için bir OpenAPI spesifikasyonu sağlamada hala nasıl başarılı olabileceğine dair bir örnek üzerinden geçmek istedim.


Ayrıca konfor alanımın dışına çıkıp bunu Java, .NET ve hatta JavaScript kullanmadan yapmak istedim.

FastAPI'yi Keşfetmek

Çoğu makalemin sonunda kişisel misyon beyanımı sık sık dile getiriyorum:


“Zamanınızı fikri mülkiyetinizin değerini artıran özellikler/işlevsellik sunmaya odaklayın. Diğer her şey için çerçevelerden, ürünlerden ve hizmetlerden yararlanın." – J. Vester


Bu misyon beyanındaki amacım, daha yüksek düzeyde belirlenen amaç ve hedeflere ulaşmaya çalışırken zamanımı en iyi şekilde kullanma konusunda kendimi sorumlu kılmaktır. Temel olarak, eğer odak noktamız daha fazla widget satmaksa, zamanımı bunu mümkün kılacak yollar bulmaya, mevcut çerçeveler, ürünler veya hizmetler tarafından halihazırda çözülmüş olan zorluklardan uzak durmaya harcamalıyım.


Yeni mikro hizmetim için programlama dili olarak Python'u seçtim. Bugüne kadar önceki makalelerim için yazdığım Python kodunun %99'u Yığın Taşması Odaklı Geliştirme (SODD) veya ChatGPT odaklı yanıtların sonucudur. Açıkçası Python konfor alanımın dışında kalıyor.


Artık işlerin nerede durduğunu belirlediğime göre, kaynak dilde minimum deneyimle kişisel misyon beyanıma uyan yeni bir Python tabanlı RESTful mikro hizmet oluşturmak istedim.


İşte o zaman FastAPI'yi buldum.


FastAPI 2018'den beri varlığını sürdürüyor ve Python tipi ipuçlarını kullanarak RESTful API'ler sunmaya odaklanan bir çerçevedir. FastAPI'nin en iyi yanı, geliştiricinin bakış açısından herhangi bir ek çaba gerektirmeden OpenAPI 3 spesifikasyonlarını otomatik olarak oluşturma yeteneğidir.

Article API Kullanım Örneği

Bu makale için aklıma, tüketicilerin yakın zamanda yayınlanan makalelerimin bir listesini almasına olanak tanıyan bir RESTful API sağlayan bir Makale API'si fikri geldi.


İşleri basitleştirmek için belirli bir Article aşağıdaki özellikleri içerdiğini varsayalım:

  • id – basit, benzersiz tanımlayıcı özellik (sayı)
  • title – makalenin başlığı (dize)
  • url – makalenin tam URL'si (dize)
  • year – makalenin yayınlandığı yıl (sayı)


Makale API'si aşağıdaki URI'leri içerecektir:

  • GET /articles – makalelerin listesini getirir
  • GET /articles/{article_id} – id özelliğine göre tek bir makaleyi alır
  • POST /articles – yeni bir makale ekler

FastAPI İş Başında

Terminalimde fast-api-demo adında yeni bir Python projesi oluşturdum ve ardından aşağıdaki komutları yürüttüm:


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


api.py adında yeni bir Python dosyası oluşturdum ve bazı içe aktarmalar ekledim, ayrıca bir app değişkeni oluşturdum:


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


Daha sonra Article API kullanım durumuyla eşleşecek bir Article nesnesi tanımladım:


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


Model oluşturulduktan sonra URI'leri eklemem gerekiyordu… bunun oldukça kolay olduğu ortaya çıktı:


 # 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")


Kendimi harici bir veri deposuna dahil olmaktan kurtarmak için yakın zamanda yayınlanan makalelerimden bazılarını programlı olarak eklemeye karar verdim:


 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), ]


İster inanın ister inanmayın, bu, Article API mikro hizmetinin gelişimini tamamlıyor.


Hızlı bir akıl sağlığı kontrolü için API hizmetimi yerel olarak başlattım:


 $ 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)


Sonra başka bir terminal penceresinde bir curl isteği gönderdim (ve bunu json_pp aktardım):


 $ 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 }


Dağıtıma Hazırlanıyor

Article API'yi yerel olarak çalıştırmak yerine mikro hizmeti ne kadar kolay dağıtabileceğimi göreceğimi düşündüm. Daha önce Heroku'ya hiç Python mikro hizmeti dağıtmadığım için şimdi denemek için harika bir zaman olacağını hissettim.


Heroku'ya dalmadan önce hizmetin bağımlılıklarını açıklamak için bir requirements.txt dosyası oluşturmam gerekiyordu. Bunu yapmak için pipreqs kurdum ve çalıştırdım:


 $ pip install pipreqs $ pipreqs


Bu benim için aşağıdaki bilgileri içeren bir requirements.txt dosyası oluşturdu:


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


Ayrıca Heroku'ya mikro hizmetimi uvicorn ile nasıl çalıştıracağımı söyleyen Procfile adlı bir dosyaya ihtiyacım vardı. İçeriği şuna benziyordu:


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


Heroku'ya konuşlanalım

Python'a yeni başlayanlar için (benim gibi), Heroku'ya Python ile Başlarken belgelerini yararlı bir kılavuz olarak kullandım.


Heroku CLI'yi zaten kurduğum için terminalimden Heroku ekosistemine giriş yapmam gerekiyordu:


 $ heroku login


Tüm güncellemelerimi GitLab'daki havuzumda kontrol ettiğimden emin oldum.


Daha sonra, Heroku'da yeni bir uygulamanın oluşturulması aşağıdaki komut aracılığıyla CLI kullanılarak gerçekleştirilebilir:


 $ heroku create


CLI, uygulamanın URL'si ve uygulamayla ilişkili git tabanlı deponun yanı sıra benzersiz bir uygulama adıyla yanıt verdi:


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


Lütfen unutmayın; siz bu makaleyi okuduğunuzda uygulamam artık çevrimiçi olmayacaktır.


Şunu kontrol et. Git Remote komutunu verdiğimde, Heroku ekosistemine otomatik olarak bir uzaktan kumandanın eklendiğini görebiliyorum:


 $ git remote heroku origin


fast-api-demo uygulamasını Heroku'ya dağıtmak için tek yapmam gereken aşağıdaki komutu kullanmak:


 $ git push heroku main


Her şey ayarlandığında, yeni Python tabanlı hizmetimin Heroku kontrol panelinde çalışır durumda olduğunu doğrulayabildim:


Hizmet çalışırken, aşağıdaki curl komutunu vererek id = 1 olan Article Article API'sinden almak mümkündür:


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


curl komutu bir 200 OK yanıtı ve aşağıdaki JSON yükünü döndürür:


 { "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 Spesifikasyonlarını Otomatik Olarak Sunma

FastAPI'nin yerleşik OpenAPI işlevselliğinden yararlanmak, tüketicilerin otomatik olarak oluşturulan /docs URI'sine giderek tamamen işlevsel bir v3 spesifikasyonu almasına olanak tanır:


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


Bu URL'nin çağrılması, yaygın olarak benimsenen Swagger kullanıcı arayüzünü kullanan Article API mikro hizmetini döndürür:


Article API'yi kullanacak istemciler oluşturmak için bir openapi.json dosyası arayanlar için /openapi.json URI'si kullanılabilir:


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


Örneğim için JSON tabanlı OpenAPI v3 spesifikasyonu aşağıda gösterildiği gibi görünüyor:


 { "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" } } } }


Sonuç olarak, OpenAPI Generator aracılığıyla birçok farklı dilde istemci oluşturmak için aşağıdaki belirtim kullanılabilir.

Çözüm

Bu makalenin başında, API First yaklaşımını kullanmakla ilgilenmeyen herkesle savaşmaya ve yüzleşmeye hazırdım. Bu alıştırmadan öğrendiğim şey, FastAPI gibi bir ürünün, çalışan bir RESTful mikro hizmetinin hızlı bir şekilde tanımlanmasına ve üretilmesine yardımcı olabileceği ve aynı zamanda otomatik olarak tamamen tüketilebilir bir OpenAPI v3 spesifikasyonunu da içerebileceğidir.


FastAPI'nin, diğerlerinin güvenebileceği standartlaştırılmış bir sözleşme sağlayan bir çerçeveden yararlanarak ekiplerin amaç ve hedeflerine odaklanmalarına olanak tanıdığı ortaya çıktı. Sonuç olarak, kişisel misyon beyanıma uymanın başka bir yolu ortaya çıktı.


Bu arada Heroku'yu ilk kez Python tabanlı bir hizmeti dağıtmak için kullandım. Bunun, iyi yazılmış bazı belgeleri incelemek dışında benim açımdan çok az çaba gerektirdiği ortaya çıktı. Bu nedenle Heroku platformu için başka bir misyon bildirimi bonusundan da bahsetmek gerekiyor.


Bu makalenin kaynak koduyla ilgileniyorsanız GitLab'da bulabilirsiniz.


Gerçekten harika bir gün geçirin!