paint-brush
FastAPI đã cung cấp cho tôi thông số OpenAPI thực sự... Nhanhtừ tác giả@johnjvester
2,049 lượt đọc
2,049 lượt đọc

FastAPI đã cung cấp cho tôi thông số OpenAPI thực sự... Nhanh

từ tác giả John Vester16m2024/04/22
Read on Terminal Reader

dài quá đọc không nổi

Khi API First không phải là một tùy chọn, FastAPI có thể tiết kiệm thời gian cho các nhóm bằng cách cho phép các dịch vụ vi mô RESTful hiện có được ghi lại và sử dụng đầy đủ bằng cách sử dụng OpenAPI v3 một cách tự động.
featured image - FastAPI đã cung cấp cho tôi thông số OpenAPI thực sự... Nhanh
John Vester HackerNoon profile picture

Những người đọc các ấn phẩm của tôi có thể đã quen với ý tưởng sử dụng phương pháp tiếp cận API First để phát triển các dịch vụ vi mô. Vô số lần, tôi đã nhận ra lợi ích của việc mô tả các URI dự đoán và các mô hình đối tượng cơ bản trước khi bắt đầu bất kỳ quá trình phát triển nào.


Tuy nhiên, trong hơn 30 năm làm việc với công nghệ điều hướng, tôi đã dần mong đợi thực tế của các dòng chảy thay thế . Nói cách khác, tôi hoàn toàn mong đợi sẽ có những tình huống mà API First không thể thực hiện được.


Trong bài viết này, tôi muốn xem qua một ví dụ về cách các nhóm sản xuất vi dịch vụ vẫn có thể thành công trong việc cung cấp đặc tả OpenAPI cho những người khác sử dụng mà không cần xác định tệp openapi.json theo cách thủ công.


Tôi cũng muốn bước ra ngoài vùng an toàn của mình và làm điều này mà không cần sử dụng Java, .NET hoặc thậm chí là JavaScript.

Khám phá FastAPI

Ở phần kết của hầu hết các bài viết của mình, tôi thường đề cập đến tuyên bố sứ mệnh cá nhân của mình:


“Hãy tập trung thời gian vào việc cung cấp các tính năng/chức năng giúp nâng cao giá trị tài sản trí tuệ của bạn. Tận dụng các khuôn khổ, sản phẩm và dịch vụ cho mọi thứ khác.” – J. Vester


Quan điểm của tôi trong tuyên bố sứ mệnh này là khiến bản thân phải chịu trách nhiệm về việc tận dụng tốt nhất thời gian của mình khi cố gắng đạt được các mục tiêu và mục tiêu đặt ra ở cấp độ cao hơn. Về cơ bản, nếu trọng tâm của chúng tôi là bán nhiều vật dụng hơn, thì tôi nên dành thời gian để tìm cách biến điều đó thành hiện thực - tránh xa những thách thức đã được giải quyết bằng các khuôn khổ, sản phẩm hoặc dịch vụ hiện có.


Tôi đã chọn Python làm ngôn ngữ lập trình cho microservice mới của mình. Cho đến nay, 99% mã Python mà tôi đã viết cho các bài viết trước của mình là kết quả của các câu trả lời dựa trên Stack Overflow Driven Development (SODD) hoặc ChatGPT. Rõ ràng, Python nằm ngoài vùng an toàn của tôi.


Bây giờ tôi đã thiết lập cấp độ cho mọi thứ, tôi muốn tạo một dịch vụ vi mô RESTful dựa trên Python mới tuân thủ tuyên bố sứ mệnh cá nhân của tôi với kinh nghiệm tối thiểu về ngôn ngữ nguồn.


Đó là lúc tôi tìm thấy FastAPI .


FastAPI đã xuất hiện từ năm 2018 và là một framework tập trung vào việc cung cấp API RESTful bằng cách sử dụng các gợi ý kiểu Python. Phần hay nhất về FastAPI là khả năng tự động tạo các thông số kỹ thuật OpenAPI 3 mà không cần bất kỳ nỗ lực bổ sung nào từ quan điểm của nhà phát triển.

Trường hợp sử dụng API bài viết

Đối với bài viết này, ý tưởng về API bài viết đã nảy ra trong đầu tôi, cung cấp API RESTful cho phép người tiêu dùng truy xuất danh sách các bài viết được xuất bản gần đây của tôi.


Để đơn giản, giả sử một Article nhất định chứa các thuộc tính sau:

  • id - thuộc tính định danh đơn giản, duy nhất (số)
  • title – tiêu đề của bài viết (chuỗi)
  • url – URL đầy đủ của bài viết (chuỗi)
  • year – năm bài viết được xuất bản (số)


API bài viết sẽ bao gồm các URI sau:

  • GET /articles – sẽ lấy danh sách các bài viết
  • GET /articles/{article_id} – sẽ truy xuất một bài viết theo thuộc tính id
  • POST /articles – thêm một bài viết mới

FastAPI đang hoạt động

Trong thiết bị đầu cuối của mình, tôi đã tạo một dự án Python mới có tên fast-api-demo và sau đó thực hiện các lệnh sau:


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


Tôi đã tạo một tệp Python mới có tên api.py và thêm một số nội dung nhập, đồng thời thiết lập một biến app :


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


Tiếp theo, tôi đã xác định một đối tượng Article để phù hợp với trường hợp sử dụng API Article:


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


Với mô hình đã được thiết lập, tôi cần thêm các URI… việc này hóa ra khá dễ dàng:


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


Để tránh liên quan đến kho dữ liệu bên ngoài, tôi quyết định thêm một số bài viết được xuất bản gần đây của mình theo chương trình:


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


Dù bạn có tin hay không thì việc đó đã hoàn tất quá trình phát triển cho microservice Article API.


Để kiểm tra nhanh độ tỉnh táo, tôi đã triển khai dịch vụ API của mình cục bộ:


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


Sau đó, trong một cửa sổ terminal khác, tôi đã gửi một yêu cầu cuộn tròn (và chuyển nó tới 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 }


Chuẩn bị triển khai

Thay vì chỉ chạy API bài viết cục bộ, tôi nghĩ tôi sẽ thấy mình có thể triển khai microservice dễ dàng như thế nào. Vì trước đây tôi chưa bao giờ triển khai microservice Python cho Heroku nên tôi cảm thấy bây giờ là thời điểm tuyệt vời để thử.


Trước khi tìm hiểu về Heroku, tôi cần tạo một tệp requirements.txt để mô tả các phần phụ thuộc của dịch vụ. Để làm điều này, tôi đã cài đặt và thực thi pipreqs :


 $ pip install pipreqs $ pipreqs


Điều này đã tạo cho tôi một tệp requirements.txt với thông tin sau:


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


Tôi cũng cần một tệp có tên Procfile để hướng dẫn Heroku cách khởi động microservice của tôi bằng uvicorn . Nội dung của nó trông như thế này:


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


Hãy triển khai lên Heroku

Đối với những người mới làm quen với Python (cũng như tôi), tôi đã sử dụng tài liệu Bắt đầu trên Heroku với Python như một hướng dẫn hữu ích.


Vì tôi đã cài đặt Heroku CLI nên tôi chỉ cần đăng nhập vào hệ sinh thái Heroku từ thiết bị đầu cuối của mình:


 $ heroku login


Tôi đảm bảo kiểm tra tất cả các bản cập nhật của mình vào kho lưu trữ trên GitLab.


Tiếp theo, việc tạo một ứng dụng mới trong Heroku có thể được thực hiện bằng CLI thông qua lệnh sau:


 $ heroku create


CLI phản hồi bằng một tên ứng dụng duy nhất, cùng với URL của ứng dụng và kho lưu trữ dựa trên git được liên kết với ứng dụng:


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


Xin lưu ý – vào thời điểm bạn đọc bài viết này, ứng dụng của tôi sẽ không còn trực tuyến nữa.


Kiểm tra cái này. Khi tôi phát lệnh git remote, tôi có thể thấy rằng một điều khiển từ xa đã được tự động thêm vào hệ sinh thái Heroku:


 $ git remote heroku origin


Để triển khai ứng dụng fast-api-demo lên Heroku, tất cả những gì tôi phải làm là sử dụng lệnh sau:


 $ git push heroku main


Khi mọi thứ đã được thiết lập, tôi có thể xác thực rằng dịch vụ dựa trên Python mới của tôi đã hoạt động trong bảng điều khiển Heroku:


Khi dịch vụ đang chạy, có thể truy xuất Articleid = 1 từ API Bài viết bằng cách đưa ra lệnh cuộn tròn sau:


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


Lệnh Curl trả về phản hồi 200 OK và tải trọng JSON sau:


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


Tự động cung cấp thông số kỹ thuật OpenAPI 3

Việc tận dụng chức năng OpenAPI tích hợp của FastAPI cho phép người tiêu dùng nhận được đặc tả v3 đầy đủ chức năng bằng cách điều hướng đến URI /docs được tạo tự động:


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


Việc gọi URL này sẽ trả về microservice API bài viết bằng cách sử dụng giao diện người dùng Swagger được áp dụng rộng rãi:


Đối với những người đang tìm kiếm tệp openapi.json để tạo ứng dụng khách sử dụng API bài viết, có thể sử dụng URI /openapi.json :


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


Ví dụ của tôi, đặc tả OpenAPI v3 dựa trên JSON xuất hiện như dưới đây:


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


Do đó, thông số kỹ thuật sau có thể được sử dụng để tạo ứng dụng khách bằng một số ngôn ngữ khác nhau thông qua OpenAPI Generator .

Phần kết luận

Khi bắt đầu bài viết này, tôi đã sẵn sàng chiến đấu và đối mặt với bất kỳ ai không quan tâm đến việc sử dụng phương pháp tiếp cận API First. Điều tôi học được từ bài tập này là một sản phẩm như FastAPI có thể giúp xác định và tạo ra một microservice RESTful đang hoạt động một cách nhanh chóng đồng thời bao gồm cả đặc tả OpenAPI v3 hoàn toàn có thể sử dụng được… một cách tự động.


Hóa ra, FastAPI cho phép các nhóm tập trung vào mục tiêu và mục tiêu của mình bằng cách tận dụng một khuôn khổ mang lại hợp đồng tiêu chuẩn hóa để những người khác dựa vào. Kết quả là, một con đường khác đã xuất hiện để tuân thủ tuyên bố sứ mệnh cá nhân của tôi.


Trong quá trình thực hiện, lần đầu tiên tôi đã sử dụng Heroku để triển khai dịch vụ dựa trên Python. Điều này hóa ra đòi hỏi tôi phải nỗ lực rất ít ngoài việc xem xét một số tài liệu được viết tốt. Vì vậy, một phần thưởng tuyên bố sứ mệnh khác cũng cần được đề cập cho nền tảng Heroku.


Nếu bạn quan tâm đến mã nguồn của bài viết này, bạn có thể tìm thấy nó trên GitLab .


Chúc bạn có một ngày thật tuyệt vời!