Tạo tài liệu API toàn diện và chính xác là một phần quan trọng nhưng thường tẻ nhạt của quá trình phát triển phần mềm. Đặc tả OpenAPI (trước đây gọi là Swagger) đã nổi lên như một tiêu chuẩn công nghiệp để định nghĩa các API RESTful. Nó cung cấp một định dạng máy có thể đọc được, cho phép cả con người và máy tính khám phá và hiểu khả năng của một dịch vụ mà không cần truy cập mã nguồn, tài liệu hoặc thông qua việc kiểm tra lưu lượng mạng.1
Trong khi nhiều framework cung cấp các plugin để tạo đặc tả OpenAPI từ các chú thích mã (như docstrings), có những trường hợp bạn có thể cần kiểm soát trực tiếp, theo chương trình hơn đối với việc tạo đặc tả. Điều này có thể xảy ra vì bạn đang làm việc với một hệ thống cũ, một framework không chuẩn, hoặc bạn cần tạo một đặc tả cho một API được tạo thành từ nhiều microservice.
Đây là lúc pyswagger
phát huy tác dụng. Đây là một thư viện Python mạnh mẽ hoạt động như một bộ công cụ cho OpenAPI. Mặc dù nó thường được sử dụng như một API client để tiêu thụ các dịch vụ được định nghĩa bởi đặc tả OpenAPI, sức mạnh thực sự của nó nằm ở mô hình đối tượng của nó, cho phép bạn xây dựng, thao tác và xác thực một đặc tả một cách có lập trình.
Trong hướng dẫn toàn diện này, chúng ta sẽ đi sâu vào quy trình sử dụng pyswagger
để tạo thủ công, nhưng vẫn tự động, một đặc tả OpenAPI 3.0 hoàn chỉnh cho một ứng dụng web Python đơn giản được xây dựng bằng Flask. Chúng ta sẽ xây dựng đặc tả từ đầu, từng phần một, chứng minh cách các đối tượng của pyswagger
ánh xạ trực tiếp tới các thành phần của tiêu chuẩn OpenAPI. Cuối cùng, bạn sẽ không chỉ có một tệp openapi.json
được tạo ra mà còn có một giao diện người dùng tài liệu trực tiếp, tương tác được phục vụ trực tiếp từ ứng dụng của bạn.
Bạn muốn một nền tảng tích hợp, Tất cả trong Một để Đội ngũ Phát triển của bạn làm việc cùng nhau với năng suất tối đa?
Apidog đáp ứng mọi yêu cầu của bạn, và thay thế Postman với mức giá phải chăng hơn nhiều!
Phần 1: Thiết lập Môi trường Dự án
Trước khi bắt đầu tạo đặc tả của chúng ta, chúng ta cần thiết lập một môi trường phát triển phù hợp. Điều này bao gồm việc tạo một môi trường Python cô lập để quản lý các thư viện phụ thuộc và cài đặt các thư viện cần thiết.
Tạo Không gian làm việc của bạn ⚙️
Đầu tiên, hãy tạo một thư mục cho dự án của chúng ta. Mở terminal hoặc command prompt và chạy các lệnh sau:Bash
# Tạo một thư mục mới cho dự án của chúng ta
mkdir pyswagger-tutorial
cd pyswagger-tutorial
# Tạo một môi trường ảo Python
# Trên macOS/Linux
python3 -m venv venv
# Trên Windows
python -m venv venv
Môi trường ảo là một cây thư mục độc lập bao gồm một cài đặt Python và một số tệp hỗ trợ. Sử dụng môi trường ảo đảm bảo rằng các gói chúng ta cài đặt cho dự án này không xung đột với các gói được cài đặt cho các dự án khác.
Bây giờ, hãy kích hoạt môi trường ảo:Bash
# Trên macOS/Linux
source venv/bin/activate
# Trên Windows
.\venv\Scripts\activate
Sau khi được kích hoạt, dấu nhắc terminal của bạn sẽ thay đổi để hiển thị tên của môi trường ảo (ví dụ: (venv)
), cho biết rằng bạn hiện đang làm việc bên trong nó.
Cài đặt các Thư viện cần thiết
Với môi trường của chúng ta đã hoạt động, chúng ta có thể cài đặt các thư viện Python cần thiết cho hướng dẫn này. Chúng ta cần pyswagger
để xây dựng đặc tả, Flask
để tạo API web đơn giản của chúng ta, và PyYAML
vì pyswagger
sử dụng nó cho các hoạt động liên quan đến YAML.Bash
pip install "pyswagger[utils]" Flask PyYAML
Phần [utils]
khi cài đặt pyswagger
là một cách làm tốt vì nó bao gồm các tiện ích hữu ích, như trình xác thực mà chúng ta sẽ sử dụng sau này để kiểm tra đặc tả được tạo ra của chúng ta về tính đúng đắn.
Để quản lý dự án tốt, nên ghi lại các thư viện phụ thuộc của bạn vào tệp requirements.txt
.Bash
pip freeze > requirements.txt
Tệp requirements.txt
của bạn giờ đây sẽ chứa các thư viện và phiên bản cụ thể của chúng, giúp dự án của bạn dễ dàng tái tạo bởi người khác.
Tạo Ứng dụng Flask Cơ bản
Bây giờ, hãy tạo một ứng dụng Flask tối thiểu. Điều này sẽ đóng vai trò là nền tảng của API mà chúng ta sẽ tài liệu hóa.
Trong thư mục dự án của bạn, tạo một tệp mới có tên app.py
và thêm đoạn mã sau:Python
# app.py
from flask import Flask, jsonify
# Khởi tạo ứng dụng Flask
app = Flask(__name__)
@app.route("/")
def index():
""" Một endpoint đơn giản để kiểm tra xem ứng dụng có đang chạy không. """
return jsonify({"message": "API is up and running!"})
if __name__ == "__main__":
# Chạy ứng dụng Flask trên http://127.0.0.1:5000
app.run(debug=True)
Đoạn mã này thiết lập một máy chủ web rất đơn giản với một endpoint duy nhất. Để chạy nó, hãy đảm bảo môi trường ảo của bạn vẫn đang hoạt động và thực thi lệnh sau trong terminal của bạn:Bash
python app.py
Bạn sẽ thấy đầu ra cho biết máy chủ đang chạy, giống như thế này:
* Serving Flask app 'app'
* Debug mode: on
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
Bây giờ bạn có thể mở trình duyệt web hoặc sử dụng một công cụ như curl
để truy cập http://127.0.0.1:5000
. Bạn sẽ thấy phản hồi JSON: {"message": "API is up and running!"}
.
Với môi trường cơ bản và khung ứng dụng đã sẵn sàng, giờ đây chúng ta có thể đi sâu vào các khái niệm cốt lõi của pyswagger
.
Phần 2: Hiểu Mô hình Đối tượng của pyswagger
Để sử dụng pyswagger
một cách hiệu quả để tạo đặc tả, trước tiên bạn cần hiểu cách mô hình đối tượng của nó tương ứng với cấu trúc của một tài liệu OpenAPI. Đặc tả OpenAPI về cơ bản là một đối tượng JSON hoặc YAML lớn với một schema cụ thể. pyswagger
cung cấp các lớp và đối tượng Python phản ánh schema này, cho phép bạn xây dựng đặc tả một cách trực quan hơn, theo hướng đối tượng.
Các Khái niệm Cốt lõi của Đặc tả OpenAPI 3.0 📜
Một tài liệu OpenAPI 3.0 có một vài trường cấp cao chính:
openapi
: Một chuỗi chỉ định phiên bản Đặc tả OpenAPI (ví dụ:'3.0.0'
).info
: Một đối tượng cung cấp siêu dữ liệu về API. Điều này bao gồmtitle
,version
,description
, và thông tin liên hệ.servers
: Một mảng các đối tượng máy chủ, định nghĩa các URL cơ sở cho API.paths
: Trường quan trọng nhất. Đối tượng này chứa tất cả các endpoint API có sẵn (paths) và các hoạt động HTTP (GET, POST, PUT, DELETE, v.v.) có thể được thực hiện trên chúng.components
: Một đối tượng chứa một tập hợp các đối tượng có thể tái sử dụng cho các phần khác nhau của đặc tả. Điều này rất quan trọng để giữ cho đặc tả của bạn DRY (Don't Repeat Yourself - Không lặp lại chính mình). Bạn có thể định nghĩa cácschemas
(mô hình dữ liệu),responses
,parameters
,examples
, và nhiều thứ khác có thể tái sử dụng.
Ánh xạ OpenAPI sang các Đối tượng pyswagger
pyswagger
cung cấp một ánh xạ rõ ràng từ các khái niệm OpenAPI này sang các đối tượng Python. Hãy cùng khám phá những đối tượng chính mà chúng ta sẽ sử dụng.
Đối tượng trung tâm trong pyswagger
là App
. Bạn có thể coi một thể hiện App
như gốc của tài liệu OpenAPI của mình.Python
from pyswagger import App
# Gốc của tài liệu đặc tả
# Chúng ta khởi tạo nó với một phiên bản, nhưng nó cũng có thể tải từ URL hoặc tệp
root_app = App(version='3.0.0')
Khi bạn có đối tượng App
của mình, bạn có thể bắt đầu điền các thuộc tính của nó, tương ứng trực tiếp với các trường OpenAPI. pyswagger
sử dụng mẫu builder, cho phép cú pháp trôi chảy và dễ đọc.
Info và Servers
Các phần info
và servers
rất đơn giản để điền.Python
# Điền vào đối tượng 'info'
root_app.info.title = "User API"
root_app.info.version = "1.0.0"
root_app.info.description = "A simple API to manage users, used for the pyswagger tutorial."
# Điền vào mảng 'servers'
# Bạn tạo một đối tượng Server và thêm nó vào
server = root_app.prepare_obj('Server', {'url': 'http://127.0.0.1:5000', 'description': 'Local development server'})
root_app.servers.append(server)
Paths và Operations
Các đường dẫn (paths) được định nghĩa trên đối tượng App
. Bạn thêm các đường dẫn mới và sau đó định nghĩa các hoạt động (phương thức HTTP) trong chúng. Mỗi hoạt động được cấu hình với các chi tiết như summary
, description
, parameters
, requestBody
, và responses
.Python
# Định nghĩa một đường dẫn và một hoạt động
# Điều này không thực thi bất cứ điều gì; nó chỉ xây dựng cấu trúc đối tượng.
path_item = root_app.define_path('/users')
get_op = path_item.define_op('get')
get_op.summary = "Retrieve a list of all users"
Components: Schemas, Parameters, và Responses
Sức mạnh thực sự của một đặc tả OpenAPI được cấu trúc tốt đến từ các thành phần có thể tái sử dụng. Thay vì định nghĩa cấu trúc của một đối tượng "User" mỗi khi nó xuất hiện trong một phản hồi, bạn định nghĩa nó một lần trong components/schemas
và sau đó tham chiếu nó bằng cách sử dụng con trỏ $ref
. pyswagger
xử lý điều này một cách thanh lịch.
Schema
: Một đối tượng Schema
định nghĩa một mô hình dữ liệu. Bạn có thể chỉ định kiểu của nó (object
, string
, integer
) và các thuộc tính của nó.Python# Chuẩn bị một đối tượng Schema cho một User user_schema = root_app.prepare_obj('Schema', { 'type': 'object', 'properties': { 'id': {'type': 'integer', 'format': 'int64'}, 'username': {'type': 'string'}, 'email': {'type': 'string', 'format': 'email'} }, 'required': ['id', 'username', 'email'] }) # Thêm nó vào các thành phần có thể tái sử dụng root_app.components.schemas['User'] = user_schema
Parameter
: Một đối tượng Parameter
định nghĩa một tham số hoạt động duy nhất. Bạn chỉ định tên của nó, vị trí của nó (in
: 'path'
, 'query'
, 'header'
, hoặc 'cookie'
), và schema của nó.Python# Chuẩn bị một đối tượng Parameter cho ID người dùng trong đường dẫn user_id_param = root_app.prepare_obj('Parameter', { 'name': 'user_id', 'in': 'path', 'description': 'ID of the user to retrieve', 'required': True, 'schema': {'type': 'integer'} })
Response
: Một đối tượng Response
định nghĩa cấu trúc của một phản hồi cho một mã trạng thái HTTP cụ thể. Nó bao gồm một description
và content
, chỉ định loại phương tiện (ví dụ: application/json
) và schema của nó.Python# Chuẩn bị một đối tượng Response cho phản hồi 200 OK trả về một người dùng duy nhất # Lưu ý cách sử dụng '$ref' để trỏ đến schema User có thể tái sử dụng của chúng ta ok_user_response = root_app.prepare_obj('Response', { 'description': 'Successful retrieval of a user', 'content': { 'application/json': { 'schema': {'$ref': '#/components/schemas/User'} } } })
Hiểu rõ ánh xạ này là chìa khóa để xây dựng đặc tả của bạn. Về cơ bản, bạn đang xây dựng một đồ thị đối tượng Python mà pyswagger
sau này sẽ tuần tự hóa thành một tệp OpenAPI JSON hoặc YAML hợp lệ.
Phần 3: Xây dựng một API Đơn giản với Flask
Để bài tập tài liệu hóa của chúng ta trở nên thực tế, chúng ta cần một API thực tế để tài liệu hóa. Chúng ta sẽ mở rộng ứng dụng Flask đơn giản từ Phần 1 thành một API REST tối thiểu để quản lý danh sách người dùng. API này sẽ đóng vai trò là "nguồn chân lý" mà chúng ta sẽ mô tả bằng pyswagger
.
Thiết kế một API "User" Đơn giản 📝
Chúng ta sẽ triển khai bốn endpoint cơ bản đại diện cho các hoạt động CRUD (Create, Read, Update, Delete) phổ biến:
GET /users
: Truy xuất danh sách tất cả người dùng.POST /users
: Tạo một người dùng mới.GET /users/{user_id}
: Lấy một người dùng duy nhất theo ID của họ.DELETE /users/{user_id}
: Xóa một người dùng theo ID của họ.
Để đơn giản, chúng ta sẽ sử dụng một từ điển Python đơn giản làm "cơ sở dữ liệu" trong bộ nhớ của chúng ta. Trong một ứng dụng thực tế, đây sẽ là kết nối đến một cơ sở dữ liệu như PostgreSQL hoặc MongoDB.
Triển khai các Endpoint Flask
Hãy cập nhật tệp app.py
của chúng ta để bao gồm logic cho các endpoint này. Thay thế nội dung của app.py
bằng đoạn mã sau:Python
# app.py
from flask import Flask, jsonify, request, abort
app = Flask(__name__)
# --- Cơ sở dữ liệu trong bộ nhớ ---
# Một từ điển đơn giản để lưu trữ người dùng của chúng ta.
# Khóa là user_id (số nguyên), và giá trị là dữ liệu người dùng (dict).
USERS_DB = {
1: {"username": "alice", "email": "alice@example.com"},
2: {"username": "bob", "email": "bob@example.com"},
3: {"username": "charlie", "email": "charlie@example.com"},
}
# Một bộ đếm để mô phỏng ID tự tăng cho người dùng mới
LAST_INSERT_ID = 3
# --- Các Endpoint API ---
@app.route("/users", methods=["GET"])
def get_users():
""" Trả về danh sách tất cả người dùng. """
# Chúng ta cần chuyển từ điển sang danh sách các đối tượng người dùng, bao gồm cả ID của họ.
users_list = []
for user_id, user_data in USERS_DB.items():
user = {'id': user_id}
user.update(user_data)
users_list.append(user)
return jsonify(users_list)
@app.route("/users", methods=["POST"])
def create_user():
""" Tạo một người dùng mới. """
global LAST_INSERT_ID
if not request.json or 'username' not in request.json or 'email' not in request.json:
abort(400, description="Missing username or email in request body.")
LAST_INSERT_ID += 1
new_user_id = LAST_INSERT_ID
new_user = {
"username": request.json["username"],
"email": request.json["email"],
}
USERS_DB[new_user_id] = new_user
# Phản hồi nên bao gồm ID của người dùng mới được tạo
response_user = {'id': new_user_id}
response_user.update(new_user)
return jsonify(response_user), 201
@app.route("/users/<int:user_id>", methods=["GET"])
def get_user(user_id):
""" Trả về một người dùng duy nhất theo ID của họ. """
if user_id not in USERS_DB:
abort(404, description=f"User with ID {user_id} not found.")
user_data = USERS_DB[user_id]
user = {'id': user_id}
user.update(user_data)
return jsonify(user)
@app.route("/users/<int:user_id>", methods=["DELETE"])
def delete_user(user_id):
""" Xóa một người dùng theo ID của họ. """
if user_id not in USERS_DB:
abort(404, description=f"User with ID {user_id} not found.")
del USERS_DB[user_id]
# Phản hồi 204 No Content là tiêu chuẩn cho các thao tác xóa thành công
return '', 204
if __name__ == "__main__":
app.run(debug=True, port=5000)
Bây giờ, nếu bạn chạy python app.py
một lần nữa, bạn sẽ có một API hoàn chỉnh (mặc dù đơn giản). Bạn có thể kiểm tra nó bằng curl
hoặc một công cụ tương tự:
- Lấy tất cả người dùng:
curl http://127.0.0.1:5000/users
- Lấy một người dùng cụ thể:
curl http://127.0.0.1:5000/users/1
- Tạo một người dùng:
curl -X POST -H "Content-Type: application/json" -d '{"username": "david", "email": "david@example.com"}' http://127.0.0.1:5000/users
- Xóa một người dùng:
curl -X DELETE http://127.0.0.1:5000/users/3
Với API của chúng ta đã được triển khai, chúng ta có một mục tiêu cụ thể cho các nỗ lực tài liệu hóa của mình. Bước tiếp theo là sử dụng pyswagger
để mô tả chi tiết từng endpoint này.
Phần 4: Tự động Tạo Đặc tả OpenAPI với pyswagger
Đây là phần cốt lõi của hướng dẫn của chúng ta. Bây giờ chúng ta sẽ tạo một script Python riêng biệt để import pyswagger
, định nghĩa cấu trúc API của chúng ta bằng cách sử dụng mô hình đối tượng của nó, và sau đó tuần tự hóa cấu trúc đó thành một tệp openapi.json
hoàn chỉnh. Cách tiếp cận này tách biệt việc tạo đặc tả khỏi logic ứng dụng, đây có thể là một mẫu rất gọn gàng và dễ bảo trì.
Tạo Trình tạo Đặc tả
Trong thư mục dự án của bạn, tạo một tệp mới có tên generate_spec.py
. Script này sẽ chịu trách nhiệm xây dựng và lưu đặc tả OpenAPI của chúng ta.
Xây dựng Đặc tả, Từng bước một
Hãy xây dựng script generate_spec.py
từng phần một.
1. Import và Khởi tạo App
Đầu tiên, chúng ta cần import đối tượng App
từ pyswagger
và PyYAML
để giúp xuất tệp cuối cùng. Chúng ta sẽ tạo đối tượng App
gốc của mình và điền các phần info
và servers
cơ bản, giống như chúng ta đã thảo luận ở Phần 2.Python
# generate_spec.py
import json
from pyswagger import App
from pyswagger.contrib.client.requests import Client
# --- 1. Khởi tạo đối tượng App gốc ---
app = App(version='3.0.0')
# --- 2. Điền vào các phần Info & Servers ---
app.info.title = "User API"
app.info.version = "1.0.0"
app.info.description = "A simple API to manage users, for the pyswagger tutorial."
server = app.prepare_obj('Server', {
'url': 'http://127.0.0.1:5000',
'description': 'Local development server'
})
app.servers.append(server)
2. Định nghĩa các Thành phần Có thể tái sử dụng (Schemas)
Thiết kế API tốt tránh lặp lại. Chúng ta sẽ định nghĩa mô hình dữ liệu User
của mình một lần và tái sử dụng nó. Chúng ta cũng sẽ định nghĩa một schema Error
chung cho các phản hồi lỗi của chúng ta (như 404 Not Found).
Thêm đoạn mã sau vào generate_spec.py
:Python# --- 3. Định nghĩa các Thành phần Có thể tái sử dụng (Schemas) --- # Schema cho phản hồi Lỗi error_schema = app.prepare_obj('Schema', { 'type': 'object', 'properties': { 'code': {'type': 'integer', 'format': 'int32'}, 'message': {'type': 'string'} } }) app.components.schemas['Error'] = error_schema # Schema cho một User duy nhất. Lưu ý các thuộc tính khớp với cấu trúc USERS_DB của chúng ta. user_schema = app.prepare_obj('Schema', { 'type': 'object', 'properties': { 'id': { 'type': 'integer', 'description': 'Unique identifier for the user.', 'readOnly': True # Client không thể thiết lập giá trị này }, 'username': { 'type': 'string', 'description': 'The user\'s chosen username.' }, 'email': { 'type': 'string', 'description': 'The user\'s email address.', 'format': 'email' } }, 'required': ['id', 'username', 'email'] }) app.components.schemas['User'] = user_schema # Schema để tạo người dùng (không bao gồm trường 'id') new_user_schema = app.prepare_obj('Schema', { 'type': 'object', 'properties': { 'username': { 'type': 'string', 'description': 'The user\'s chosen username.' }, 'email': { 'type': 'string', 'description': 'The user\'s email address.', 'format': 'email' } }, 'required': ['username', 'email'] }) app.components.schemas['NewUser'] = new_user_schema
3. Tài liệu hóa các Endpoint /users
Bây giờ chúng ta sẽ định nghĩa đường dẫn /users
và hai hoạt động của nó: GET
và POST
.
- Đối với
GET
, phản hồi là một mảng các đối tượngUser
. - Đối với
POST
, phần thân yêu cầu sẽ mong đợi một đối tượngNewUser
, và phản hồi thành công sẽ là một đối tượngUser
duy nhất (bao gồm ID mới).
<!-- end list -->Python# --- 4. Tài liệu hóa các Đường dẫn --- # -- Đường dẫn: /users -- path_users = app.define_path('/users') # Hoạt động: GET /users op_get_users = path_users.define_op('get') op_get_users.summary = "List all users" op_get_users.description = "Returns a JSON array of all user objects." op_get_users.tags.append('Users') op_get_users.responses.A('200').description = "A list of users." op_get_users.responses.A('200').content.A('application/json').schema.A( 'array', items={'$ref': '#/components/schemas/User'} ) # Hoạt động: POST /users op_post_users = path_users.define_op('post') op_post_users.summary = "Create a new user" op_post_users.description = "Adds a new user to the database." op_post_users.tags.append('Users') op_post_users.requestBody.description = "User object that needs to be added." op_post_users.requestBody.required = True op_post_users.requestBody.content.A('application/json').schema.set_ref('#/components/schemas/NewUser') op_post_users.responses.A('201').description = "User created successfully." op_post_users.responses.A('201').content.A('application/json').schema.set_ref('#/components/schemas/User') op_post_users.responses.A('400').description = "Invalid input provided." op_post_users.responses.A('400').content.A('application/json').schema.set_ref('#/components/schemas/Error')
Lưu ý việc sử dụng set_ref
và A
(viết tắt của "access") để có cú pháp ngắn gọn hơn nhằm xây dựng cấu trúc đối tượng lồng nhau.
4. Tài liệu hóa các Endpoint /users/{user_id}
Tiếp theo, chúng ta sẽ tài liệu hóa đường dẫn để tương tác với một người dùng duy nhất. Đường dẫn này bao gồm một tham số đường dẫn, {user_id}
.
- Đối với
GET
, chúng ta sẽ cần định nghĩa tham số đường dẫn này. Phản hồi là một đối tượngUser
duy nhất hoặc lỗi404
. - Đối với
DELETE
, chúng ta cũng cần tham số đường dẫn. Phản hồi thành công là204 No Content
.
<!-- end list -->Python# -- Đường dẫn: /users/{user_id} -- path_user_id = app.define_path('/users/{user_id}') # Chúng ta có thể định nghĩa tham số một lần và tái sử dụng nó cho tất cả các hoạt động trên đường dẫn này. user_id_param = app.prepare_obj('Parameter', { 'name': 'user_id', 'in': 'path', 'description': 'ID of the user', 'required': True, 'schema': {'type': 'integer'} }) path_user_id.parameters.append(user_id_param) # Hoạt động: GET /users/{user_id} op_get_user_id = path_user_id.define_op('get') op_get_user_id.summary = "Find user by ID" op_get_user_id.description = "Returns a single user." op_get_user_id.tags.append('Users') op_get_user_id.responses.A('200').description = "Successful operation." op_get_user_id.responses.A('200').content.A('application/json').schema.set_ref('#/components/schemas/User') op_get_user_id.responses.A('404').description = "User not found." op_get_user_id.responses.A('404').content.A('application/json').schema.set_ref('#/components/schemas/Error') # Hoạt động: DELETE /users/{user_id} op_delete_user_id = path_user_id.define_op('delete') op_delete_user_id.summary = "Deletes a user" op_delete_user_id.description = "Deletes a single user from the database." op_delete_user_id.tags.append('Users') op_delete_user_id.responses.A('204').description = "User deleted successfully." op_delete_user_id.responses.A('404').description = "User not found." op_delete_user_id.responses.A('404').content.A('application/json').schema.set_ref('#/components/schemas/Error')
5. Xác thực và Lưu Đặc tả
Cuối cùng, bước thỏa mãn nhất. Chúng ta sẽ yêu cầu pyswagger
xác thực đồ thị đối tượng đã xây dựng của chúng ta dựa trên schema OpenAPI 3.0. Nếu nó hợp lệ, chúng ta sẽ xuất nó ra tệp JSON.
Thêm khối mã cuối cùng này vào generate_spec.py
:Python# --- 5. Xác thực và Lưu Đặc tả --- if __name__ == '__main__': try: # Xác thực đặc tả được tạo ra app.validate() print("Specification is valid.") # Lưu đặc tả vào tệp JSON with open('openapi.json', 'w') as f: f.write(app.dump_json(indent=2)) print("Successfully generated openapi.json") except Exception as e: print(f"Validation Error: {e}")
Tệp generate_spec.py
của bạn giờ đã hoàn chỉnh. Chạy nó từ terminal của bạn:Bash
python generate_spec.py
Nếu mọi thứ đều đúng, bạn sẽ thấy đầu ra:
Specification is valid.
Successfully generated openapi.json
Bây giờ bạn sẽ có một tệp mới, openapi.json
, trong thư mục dự án của bạn. Mở nó ra và khám phá nội dung của nó. Bạn sẽ thấy một tài liệu OpenAPI 3.0 được cấu trúc hoàn hảo mô tả API Flask của bạn một cách chi tiết.
Phần 5: Phục vụ Tài liệu
Có một tệp openapi.json
rất tốt cho máy móc và để tạo SDK client, nhưng đối với các nhà phát triển con người, một giao diện người dùng tương tác hữu ích hơn nhiều. Trong phần cuối cùng này, chúng ta sẽ tích hợp đặc tả đã tạo của chúng ta vào ứng dụng Flask và phục vụ nó bằng Swagger UI phổ biến.
Tích hợp Đặc tả vào Flask
Đầu tiên, chúng ta cần tạo một endpoint trong ứng dụng Flask của chúng ta để phục vụ tệp openapi.json
. Điều này cho phép các công cụ tài liệu hóa lấy đặc tả trực tiếp từ API đang chạy của chúng ta.
Sửa đổi app.py
để thêm một route mới:Python# app.py # ... (giữ nguyên tất cả mã Flask hiện có) ... import os # ... (tất cả các route như /users, /users/{user_id}, v.v.) ... # --- Phục vụ Đặc tả OpenAPI và UI --- @app.route('/api/docs/openapi.json') def serve_openapi_spec(): """ Phục vụ tệp openapi.json đã tạo ra. """ # Điều này giả định openapi.json nằm trong cùng thư mục với app.py # Trong một ứng dụng lớn hơn, bạn có thể muốn một cách mạnh mẽ hơn để tìm tệp return app.send_static_file('openapi.json')
Để điều này hoạt động, Flask cần biết nơi tìm các tệp tĩnh. Theo mặc định, nó tìm trong một thư mục có tên static
. Hãy tạo một thư mục và di chuyển tệp openapi.json
của chúng ta vào đó.Bash
mkdir static
mv openapi.json static/
Bây giờ, chạy python app.py
, và điều hướng đến http://127.0.0.1:5000/api/docs/openapi.json
. Bạn sẽ thấy JSON thô của đặc tả của bạn.
Phục vụ Giao diện người dùng Tương tác với Swagger UI 🎨
Swagger UI là một tập hợp độc lập các tài sản HTML,2 JavaScript và CSS tự động tạo tài liệu đẹp mắt từ một API tuân thủ OpenAPI. Chúng ta có thể dễ dàng phục vụ nó từ ứng dụng Flask của mình.
Tạo Thư mục Templates: Flask sử dụng một thư mục có tên templates
để tìm các mẫu HTML.Bash
mkdir templates
Tạo Mẫu Swagger UI: Bên trong thư mục templates
, tạo một tệp mới có tên swagger_ui.html
. Dán đoạn mã HTML sau vào đó. Đoạn mã này tải các tài sản Swagger UI từ một CDN công cộng và cấu hình nó để tải tệp đặc tả của chúng ta.HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>User API - Swagger UI</title>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.17.14/swagger-ui.min.css" >
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.17.14/swagger-ui-bundle.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.17.14/swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
// Vùng gọi Swagger3 UI bắt đầu
const ui = SwaggerUIBundle({
url: "/api/docs/openapi.json", // URL cho đặc tả của chúng ta
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset4
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
// Vùng gọi Swagger UI kết thúc
window.ui = ui
}
</script>
</body>
</html>
```
Thêm Route Flask: Cuối cùng, thêm một route vào app.py
để render mẫu HTML này. Bạn sẽ cần import render_template
từ Flask.Python# Ở đầu tệp app.py from flask import Flask, jsonify, request, abort, render_template # ... (tất cả các route khác) ... @app.route('/api/docs/') def serve_swagger_ui(): """ Phục vụ tài liệu Swagger UI tương tác. """ return render_template('swagger_ui.html')
Tổng hợp lại
Cấu trúc dự án cuối cùng của bạn sẽ trông như thế này:
pyswagger-tutorial/
├── app.py
├── generate_spec.py
├── requirements.txt
├── static/
│ └── openapi.json
├── templates/
│ └── swagger_ui.html
└── venv/
Bây giờ là kết quả cuối cùng. Đảm bảo ứng dụng Flask của bạn đang chạy (python app.py
). Mở trình duyệt web của bạn và điều hướng đến:
http://127.0.0.1:5000/api/docs/
Bạn sẽ được chào đón bằng một trang tài liệu đẹp mắt, tương tác cho API của mình. Bạn có thể mở rộng từng endpoint, xem các schema bạn đã định nghĩa, và thậm chí sử dụng nút "Try it out" để gửi các yêu cầu trực tiếp đến ứng dụng Flask đang chạy của bạn ngay từ trình duyệt.
Kết luận
Trong hướng dẫn này, chúng ta đã đi từ một thư mục trống đến một API được tài liệu hóa đầy đủ. Chúng ta đã sử dụng thành công pyswagger
để xây dựng một đặc tả OpenAPI 3.0 chi tiết một cách có lập trình bằng cách ánh xạ mô hình đối tượng của nó với cấu trúc API của chúng ta. Chúng ta đã thấy cách định nghĩa siêu dữ liệu, máy chủ, các schema có thể tái sử dụng, đường dẫn và hoạt động với các tham số và phản hồi của chúng.
Bằng cách tách biệt việc tạo đặc tả (generate_spec.py
) khỏi logic ứng dụng (app.py
), chúng ta đã tạo ra một quy trình làm việc gọn gàng: triển khai API của bạn, sau đó chạy trình tạo để tạo tài liệu. Quy trình này, mặc dù thủ công hơn các cách tiếp cận dựa trên decorator, mang lại khả năng kiểm soát và linh hoạt vô song, khiến nó trở nên lý tưởng cho các dự án phức tạp, các cơ sở mã cũ, hoặc khi các tiêu chuẩn tài liệu nghiêm ngặt.
Cuối cùng, bằng cách phục vụ đặc tả đã tạo và một thể hiện Swagger UI, chúng ta đã cung cấp một cổng tài liệu được trau chuốt, chuyên nghiệp và rất dễ sử dụng cho người dùng API của chúng ta. Giờ đây, bạn đã có một công cụ mới mạnh mẽ trong kho công cụ phát triển Python của mình để tạo ra tài liệu API đẳng cấp thế giới.
Bạn muốn một nền tảng tích hợp, Tất cả trong Một để Đội ngũ Phát triển của bạn làm việc cùng nhau với năng suất tối đa?
Apidog đáp ứng mọi yêu cầu của bạn, và thay thế Postman với mức giá phải chăng hơn nhiều!