Hầu hết các đội API vẫn viết mã trước, rồi tạo đặc tả sau. Kết quả thường là hợp đồng API và implementation lệch nhau theo thời gian. Thiết kế API gốc Git đảo ngược quy trình đó: coi hợp đồng API như mã nguồn, quản lý phiên bản trong Git, review thay đổi qua pull request, rồi dùng đặc tả đã commit để tạo mock, kiểm thử và tài liệu.
Bài viết này tập trung vào cách triển khai quy trình đó trong thực tế: thiết kế hợp đồng trên branch, review trong PR, chạy lint trong CI, và biến OpenAPI spec thành mock, test, docs hoặc codegen. Mục tiêu là để lịch sử Git của bạn cũng chính là lịch sử API.
Nếu bạn đã quen với mô hình Spec-First và muốn xem hướng dẫn theo sản phẩm, hãy đọc thêm bài viết về quy trình làm việc API gốc Git. Bài viết này tập trung vào thực hành.
"Git-native" có nghĩa gì đối với công việc API
Git-native nghĩa là định nghĩa API của bạn nằm trong repository dưới dạng tệp văn bản thuần túy, ví dụ openapi.yaml hoặc openapi.json.
Không phải trong database riêng của một nền tảng cloud. Không phải chỉ chỉnh được qua UI của nhà cung cấp. Không phải một bản export lỗi thời được copy vào repo.
Trong mô hình gốc Git:
- Tệp spec trong
mainlà hợp đồng chính thức. - Mọi thay đổi đi qua branch, commit, pull request và merge.
- Mock, docs, test, client hoặc server stub được tạo từ spec đã commit.
Cách làm này giúp bạn có lịch sử thay đổi, trách nhiệm, rollback và review cho chính bề mặt API, giống như cách bạn đang làm với source code.
Một thiết lập Git-native tối thiểu cần có:
repo/
api/
openapi.yaml
src/
.github/
workflows/
Tệp api/openapi.yaml là nguồn sự thật duy nhất. GUI, mock server, documentation site hoặc codegen chỉ là các lớp đọc từ tệp đó.
Tại sao nên thiết kế và phát triển API trong Git
Bạn đã dùng Git để bảo vệ mã nguồn. Hợp đồng API cũng nên được quản lý tương tự.
1. Có lịch sử rõ ràng
Khi ai đó hỏi:
Chúng ta thêm tham số
cursortừ khi nào?
Bạn có thể kiểm tra ngay:
git log -p -- api/openapi.yaml
Commit liên quan sẽ có tác giả, thời gian, diff và lý do thay đổi.
2. Truy vết được trách nhiệm
Nếu một field gây nhầm lẫn, chạy:
git blame api/openapi.yaml
Bạn sẽ biết dòng đó được thêm bởi ai, trong commit nào, và thường có thể truy ngược về PR thảo luận thiết kế.
3. Rollback đơn giản
Nếu một thiết kế sai đã được merge, bạn có thể revert:
git revert <merge_commit_sha>
Sau đó, mock, docs, test và codegen được tạo lại từ spec đã revert. Không cần sửa thủ công trong một hệ thống khác.
4. Review thiết kế trước khi viết code
Pull request là nơi phù hợp để tranh luận về:
- Endpoint path
- Naming convention
- Request/response schema
- HTTP status code
- Pagination
- Breaking changes
Ví dụ: reviewer có thể bình luận trực tiếp trên dòng YAML thêm một field bắt buộc, trước khi backend hoặc frontend phụ thuộc vào nó.
5. Một nguồn sự thật duy nhất
Khi contract nằm trong main, frontend, backend, QA và documentation đều đọc cùng một file. Đây là nền tảng của một quy trình làm việc đặc tả API dựa trên Git.
Vòng lặp thiết kế API gốc Git
Một workflow đơn giản gồm 5 bước:
Thiết kế contract → Commit → Mở PR → Review → Merge
Implementation nên đi sau bước merge, không phải ngược lại.
Giả sử bạn muốn thêm endpoint lấy danh sách hóa đơn của người dùng.
Bước 1: Tạo branch
git checkout -b feat/api-invoices-list
Bước 2: Chỉnh sửa OpenAPI spec
# api/openapi.yaml
paths:
/users/{userId}/invoices:
get:
operationId: listUserInvoices
summary: List invoices for a user
parameters:
- name: userId
in: path
required: true
schema:
type: string
format: uuid
- name: status
in: query
required: false
schema:
type: string
enum: [draft, open, paid, void]
responses:
"200":
description: A page of invoices
content:
application/json:
schema:
$ref: "#/components/schemas/InvoiceList"
"404":
description: User not found
Bước 3: Commit thay đổi nhỏ và rõ ràng
git add api/openapi.yaml
git commit -m "Add GET /users/{userId}/invoices contract"
Commit nên mô tả một quyết định thiết kế cụ thể, không gom quá nhiều endpoint trong cùng một lần.
Bước 4: Mở pull request
Trong PR, reviewer sẽ thấy diff cụ thể:
- Một path mới
- Một operation mới
- Hai parameters
- Hai response cases
Đây là thời điểm tốt để thảo luận:
- Có cần pagination không?
-
statusenum đã đủ chưa? -
404có đúng khi user không tồn tại không? - Response schema có nhất quán với các endpoint khác không?
Bước 5: Merge và triển khai
Sau khi PR được duyệt, merge vào main.
git checkout main
git pull
Từ thời điểm này, contract đã được thống nhất. Backend implementation, frontend integration, mock và test có thể bám vào spec đó. Đây là ý nghĩa thực tế của phát triển API spec-first: thỏa thuận đi trước mã.
Chiến lược phân nhánh cho hợp đồng API
Hãy xử lý API contract như source code: một branch cho mỗi đơn vị thay đổi logic.
| Loại thay đổi | Tiền tố branch | Ví dụ | Mức độ review |
|---|---|---|---|
| Endpoint mới | feat/api- |
feat/api-invoices-list |
Tiêu chuẩn |
| Thêm field | feat/api- |
feat/api-invoice-currency |
Nhẹ |
| Breaking change | break/api- |
break/api-remove-legacy-id |
Nặng, cần xác nhận |
| Sửa lỗi spec | fix/api- |
fix/api-status-enum-typo |
Nhẹ |
| Refactor spec | chore/api- |
chore/api-reorder-schemas |
Nhẹ |
Tiền tố branch giúp reviewer hiểu mức độ rủi ro ngay từ tên branch.
Ví dụ:
git checkout -b break/api-remove-legacy-id
Branch này nên kích hoạt review kỹ hơn, vì có khả năng ảnh hưởng client hiện tại.
Trunk-based hay Gitflow?
| Mô hình | Phù hợp với | Đánh đổi với API |
|---|---|---|
| Trunk-based | Continuous delivery, đội nhỏ đến vừa | Contract tiến hóa theo thay đổi nhỏ, ít merge conflict |
| Gitflow | Release theo lịch, môi trường có quy định chặt | Spec có thể phân kỳ trên develop, merge lớn hơn |
Với đa số đội API, trunk-based phù hợp hơn:
- Branch ngắn hạn
- PR nhỏ
- Merge thường xuyên
- Ít xung đột YAML
Các branch tồn tại lâu dễ làm spec lệch nhau, đặc biệt khi nhiều người cùng sửa một file lớn.
Review thiết kế API trong pull request
Một PR spec không chỉ là kiểm tra cú pháp YAML. Nó là review thiết kế API.
Reviewer nên kiểm tra ít nhất 4 nhóm câu hỏi.
1. Thay đổi này có gây hỏng client hiện tại không?
Các thay đổi có thể gây hỏng gồm:
- Xóa field
- Đổi tên field
- Đổi kiểu dữ liệu
- Xóa enum value
- Biến optional field thành required
- Đổi path hoặc method
- Thắt chặt validation
Ví dụ diff an toàn hơn:
parameters:
- name: status
in: query
schema:
type: string
- enum: [draft, open, paid, void]
+ enum: [draft, open, paid, void, uncollectible]
Thêm enum value thường là thay đổi bổ sung. Nhưng nếu xóa void, client đang gửi giá trị đó có thể bị hỏng.
2. Naming có nhất quán không?
Kiểm tra các mẫu đã có:
- API dùng plural noun hay singular noun?
- Error response có field
code,messagehay cấu trúc khác? - Timestamp dùng
createdAthaycreated_at? - ID dùng
id,userIdhayuser_id?
Ví dụ nếu API hiện tại dùng camelCase:
{
"createdAt": "2026-06-01T10:00:00Z"
}
Không nên thêm field mới kiểu snake_case:
{
"created_at": "2026-06-01T10:00:00Z"
}
3. Diff có dễ review không?
Giữ YAML ổn định:
- Không format lại toàn bộ file trong cùng PR thêm endpoint.
- Sắp xếp key theo convention.
- Thêm path vào vị trí dễ đoán.
- Chia file lớn nếu cần.
Một diff 20 dòng dễ review hơn một diff 500 dòng chứa cả thay đổi thật lẫn reformat.
4. Có đủ response case không?
Đừng chỉ định nghĩa 200.
Ví dụ với endpoint tạo invoice, nên cân nhắc:
responses:
"201":
description: Invoice created
"400":
description: Invalid request
"401":
description: Unauthorized
"409":
description: Duplicate invoice
Review tốt giúp tránh sửa thiết kế sau khi implementation đã hoàn tất.
Từ thiết kế đến phát triển
Sau khi contract đã nằm trong main, hãy tạo artifact từ spec thay vì viết thủ công.
1. Tạo code từ OpenAPI
Ví dụ dùng openapi-generator:
npx @openapitools/openapi-generator-cli generate \
-i api/openapi.yaml \
-g typescript-fetch \
-o generated/client
Hoặc tạo server stub:
npx @openapitools/openapi-generator-cli generate \
-i api/openapi.yaml \
-g nodejs-express-server \
-o generated/server
Handler của bạn vẫn chứa business logic, nhưng request/response shape được ràng buộc bởi contract.
2. Tạo mock server
Mock server đọc spec và trả response mẫu. Frontend có thể bắt đầu trước khi backend hoàn tất.
Ví dụ với Prism:
npx @stoplight/prism-cli mock api/openapi.yaml
Frontend gọi mock endpoint thay vì chờ backend production-ready.
3. Chạy contract test
Contract test xác thực server đang chạy có khớp với OpenAPI spec không.
Ý tưởng cơ bản:
Gửi request thực tế → Nhận response → Validate response theo schema → Fail CI nếu lệch
Điều này biến drift giữa spec và code thành lỗi pipeline, không phải lỗi production.
4. Tạo tài liệu API
Reference docs nên được tạo từ openapi.yaml.
Khi spec thay đổi, docs thay đổi cùng commit. Không có bước cập nhật tài liệu thủ công để bị quên.
Nguyên tắc chung:
Một spec đã commit → nhiều artifact được generate
Các quy ước nhóm có thể mở rộng
Để workflow Git-native không rối khi nhóm lớn hơn, hãy thống nhất convention sớm.
1. Chọn cấu trúc spec
Với API nhỏ, một file là đủ:
api/
openapi.yaml
Với API lớn, nên tách file:
api/
openapi.yaml
paths/
users.yaml
invoices.yaml
schemas/
user.yaml
invoice.yaml
Sau đó bundle lại trong CI hoặc build step.
Ví dụ dùng Redocly CLI:
npx @redocly/cli bundle api/openapi.yaml -o dist/openapi.yaml
2. Quản lý version có chủ đích
Cập nhật info.version khi có thay đổi có ý nghĩa:
openapi: 3.1.0
info:
title: Billing API
version: 1.4.0
Gợi ý:
- Patch: sửa lỗi mô tả hoặc schema không gây ảnh hưởng
- Minor: thêm endpoint, thêm optional field
- Major: breaking change
Breaking change thường cần version mới rõ ràng, ví dụ /v2.
3. Duy trì changelog
Đặt CHANGELOG.md cạnh spec:
# Changelog
## 1.4.0
- Add `GET /users/{userId}/invoices`
- Add `status` query parameter for invoice filtering
Git log chính xác nhưng dài. Changelog giúp consumer đọc nhanh những gì thay đổi.
4. Bảo vệ spec bằng CODEOWNERS
Ví dụ với GitHub:
# .github/CODEOWNERS
/api/openapi.yaml @api-stewards
/api/paths/ @api-stewards
/api/schemas/ @api-stewards
Mọi PR sửa contract sẽ cần API steward review.
5. Chạy lint trong CI
Ví dụ workflow dùng Spectral:
# .github/workflows/api-lint.yml
name: API Lint
on:
pull_request:
paths:
- "api/**"
jobs:
spectral:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Spectral
run: npx @stoplight/spectral-cli lint api/openapi.yaml --fail-severity warn
Lint giúp bắt lỗi style, naming hoặc thiếu field trước khi con người review thiết kế.
Kết hợp tối thiểu nên có:
CODEOWNERS + API lint + PR review
Bộ ba này đủ để mở rộng từ vài kỹ sư lên nhiều team.
Các cạm bẫy phổ biến và cách tránh
1. Spec và code lệch nhau
Vấn đề:
Spec nói response có field `currency`
Server thực tế không trả `currency`
Cách tránh:
- Generate stub/client từ spec
- Chạy contract test trong CI
- Fail build nếu response không khớp schema
2. PR quá lớn
Một PR thêm 20 endpoint rất khó review. Reviewer dễ đọc lướt và bỏ sót lỗi thiết kế.
Cách tránh:
- Một endpoint hoặc một nhóm thay đổi nhỏ cho mỗi PR
- Tách refactor spec khỏi thay đổi semantic
- Không reformat toàn bộ file trong PR tính năng
3. Artifact viết tay
Nếu client, docs hoặc mock được viết tay, chúng sẽ lệch khỏi spec.
Cách tránh:
- Generate client
- Generate docs
- Generate mock
- Xem artifact viết tay như dấu hiệu cần kiểm tra lại workflow
4. Merge conflict YAML
Hai branch cùng sửa một file OpenAPI lớn có thể tạo conflict khó xử lý.
Cách tránh:
- Branch ngắn hạn
- PR nhỏ
- Thứ tự key ổn định
- Tách spec thành nhiều file theo resource
- Bundle ở build step
Mẫu chung cho cả bốn vấn đề:
Giữ thay đổi nhỏ → Generate từ spec → Dùng CI để thực thi contract
Vị trí của Apidog
Bạn có thể triển khai workflow Git-native chỉ với editor, Git và CLI. Tuy nhiên, nhiều đội vẫn muốn có giao diện trực quan để thiết kế API mà không từ bỏ Git làm nguồn sự thật.
Đó là vai trò của Chế độ Spec-First trong Apidog.
Chế độ Spec-First giữ tệp OpenAPI trong Git repository của bạn và hỗ trợ đồng bộ hai chiều. Bạn có thể chỉnh contract trong trình thiết kế trực quan của Apidog hoặc chỉnh trực tiếp trong editor. Cả hai đều nhất quán với file trong repo.
Tệp trong Git vẫn là bản chính thức, nên branch, PR, review, history và rollback vẫn hoạt động như mô tả ở trên. Apidog trở thành một giao diện thiết kế đọc và ghi vào workflow Git-native, không thay thế Git.
Xem thêm tài liệu Chế độ Spec-First để biết chi tiết cài đặt.
Câu hỏi thường gặp
Thiết kế API gốc Git chỉ dành cho OpenAPI?
Không. Nguyên tắc này áp dụng cho mọi định dạng contract dạng text có thể diff, branch và review.
Ví dụ:
- OpenAPI
- AsyncAPI
- gRPC
.proto - GraphQL SDL
OpenAPI phổ biến nhất cho REST API, nhưng Git-native là quy trình, không phải định dạng duy nhất.
Làm thế nào để xử lý breaking change?
Hãy làm breaking change thật rõ ràng:
- Dùng branch prefix
break/api- - Tăng major version
- Yêu cầu API steward phê duyệt qua
CODEOWNERS - Ghi vào
CHANGELOG.md - Nếu có thể, thêm format mới trước và deprecate format cũ sau
Ví dụ:
git checkout -b break/api-remove-legacy-id
Breaking change không nên xuất hiện như một dòng sửa nhỏ bị giấu trong PR lớn.
Spec API có nên nằm cùng repository với mã nguồn không?
Thường là có, nếu cùng một team sở hữu cả contract và implementation.
Lợi ích:
- Một PR có thể thay đổi contract và handler liên quan
- CI chạy lint và contract test trong cùng pipeline
- Dễ truy vết từ spec sang implementation
Chỉ nên tách spec sang repo riêng khi nhiều team cùng tiêu thụ một API chia sẻ và cần quản lý version độc lập.
Làm thế nào để ngăn spec và code bị lệch?
Thêm contract test vào CI.
Quy trình:
Start server → Send request → Validate response against committed spec → Fail if mismatch
Kết hợp thêm:
- Generate client từ spec
- Generate server stub từ spec
- Generate docs từ spec
- Không sửa artifact generate bằng tay
Kết luận
Thiết kế API gốc Git là một nguyên tắc triển khai: coi hợp đồng API như mã nguồn. Đặt spec trong repository, phát triển trên branch, review qua pull request, merge vào main, rồi generate artifact từ file đã commit.
Bắt đầu nhỏ:
- Di chuyển OpenAPI spec vào repo.
- Thêm API lint trong CI.
- Dùng
CODEOWNERSđể yêu cầu review. - Chia PR theo từng thay đổi nhỏ.
- Generate mock, docs, client hoặc server stub từ spec.
- Thêm contract test để chống drift.
Khi workflow này ổn định, Git history của bạn sẽ trở thành bản ghi đầy đủ về cách API tiến hóa: ai thay đổi, thay đổi gì, khi nào, vì sao, và được review như thế nào.


Top comments (0)