Hợp đồng API của bạn có thể đang nằm ở ba nơi cùng lúc: một sơ đồ trong wiki, một collection Postman được export từ quý trước, và một tài liệu Markdown đã lệch khỏi service đang chạy. Khi các nguồn này không thống nhất, team phải đoán. Và đoán mò là cách nhanh nhất để làm hỏng tích hợp.
Cách xử lý là coi đặc tả API như code: viết OpenAPI spec, commit vào Git, review bằng pull request, rồi dùng chính file đó để tạo mock, test, tài liệu và SDK. Khi đó spec không còn là tài liệu phụ trợ, mà trở thành hợp đồng kỹ thuật mà frontend, backend, QA và đối tác cùng dựa vào.
Bài viết này hướng dẫn cách triển khai workflow “spec-as-code” với OpenAPI, Git và các bước kiểm soát thay đổi thực tế.
Spec-as-code nghĩa là gì
Spec-as-code nghĩa là định nghĩa API của bạn là một file văn bản thuần túy nằm trong hệ thống kiểm soát phiên bản.
Không phải:
- Một trang wiki chỉnh tay
- Một collection export rời rạc
- Một tài liệu online không có lịch sử thay đổi rõ ràng
Mà là một file có thể:
git diff- branch
- review bằng pull request
- merge
- revert
- lint trong CI
Ví dụ cấu trúc repo đơn giản:
my-service/
├── api/
│ └── openapi.yaml
├── src/
├── tests/
└── README.md
Ý tưởng này tương tự docs-as-code: tài liệu nằm cùng workflow với source code. Với spec-as-code, OpenAPI YAML hoặc JSON là sản phẩm chính. Các output như mock server, contract test, API reference và SDK đều được tạo từ file đó.
Kết quả: spec trở thành nguồn đáng tin cậy duy nhất. Khi developer muốn biết GET /users/{id} trả về gì, họ đọc spec. Khi QA viết test, họ kiểm tra theo spec. Khi đối tác tích hợp, họ dùng SDK được generate từ spec.
Một file, nhiều output.
Tại sao nên coi đặc tả API như mã nguồn
Khi OpenAPI spec nằm trong Git, bạn có thể áp dụng cùng quy trình kiểm soát đang dùng cho source code.
1. Review thay đổi bằng pull request
Mỗi thay đổi endpoint nên đi qua PR.
Ví dụ một thay đổi trong response schema:
properties:
id:
type: string
status:
type: string
+ trackingNumber:
+ type: string
Reviewer có thể thấy ngay:
- Field nào được thêm
- Response nào thay đổi
- Status code nào mới xuất hiện
- Thay đổi có phá vỡ backward compatibility không
Một breaking change không còn xuất hiện bất ngờ ở production. Nó trở thành một discussion trong PR.
Đây là cốt lõi của quy trình làm việc API Git-native.
2. Diff rõ ràng, dễ đọc
YAML thuần túy hiển thị thay đổi rất rõ trong Git.
Thay vì phải đoán “collection này đã thay đổi gì”, bạn có thể đọc diff trực tiếp:
responses:
"200":
description: The requested order
+ "404":
+ description: Order not found
Các tính năng như git blame, commit history và branch comparison đều hoạt động tốt với spec dạng text.
3. Versioning thực sự
Mỗi thay đổi spec có:
- Commit
- Tác giả
- Timestamp
- Lịch sử review
- Khả năng rollback
Ví dụ revert một thay đổi sai:
git revert <commit_sha>
Bạn cũng có thể tạo branch cho API v2:
git checkout -b api-v2-redesign
Hoặc tag một phiên bản release:
git tag api-v1.2.0
Để đi sâu hơn về chiến lược tag và branch, xem kiểm soát phiên bản OpenAPI bằng Git.
4. Một nguồn đáng tin cậy duy nhất
Khi mock, test, docs và SDK đều sinh ra từ cùng một file OpenAPI, chúng khó bị lệch nhau hơn.
Workflow nên là:
openapi.yaml
├── mock server
├── contract tests
├── API documentation
└── SDK/client libraries
Cập nhật spec, generate lại output, mọi thứ tiếp tục đồng bộ.
| Mối quan tâm | Đặc tả trong công cụ lưu trữ | Đặc tả API dưới dạng mã |
|---|---|---|
| Đánh giá thay đổi | Thủ công, dễ bỏ sót | Diff PR, đánh giá chặn |
| Lịch sử | Hạn chế hoặc bị khóa bởi nhà cung cấp | Nhật ký Git đầy đủ |
| Khôi phục | Thường thủ công | git revert |
| Nguồn đáng tin cậy duy nhất | Mơ hồ | Tệp đã được commit |
| Tích hợp CI | Gắn thêm | Bản địa |
OpenAPI như artifact chính
OpenAPI là định dạng phổ biến cho spec-as-code vì nó vừa dễ đọc với con người, vừa có thể xử lý bằng máy.
Ví dụ một file OpenAPI 3.1 tối giản:
openapi: 3.1.0
info:
title: Orders API
version: 1.2.0
paths:
/orders/{orderId}:
get:
summary: Get an order by ID
operationId: getOrder
parameters:
- name: orderId
in: path
required: true
schema:
type: string
format: uuid
responses:
"200":
description: The requested order
content:
application/json:
schema:
$ref: "#/components/schemas/Order"
"404":
description: Order not found
components:
schemas:
Order:
type: object
required:
- id
- status
- total
properties:
id:
type: string
format: uuid
status:
type: string
enum:
- pending
- shipped
- delivered
total:
type: number
format: float
File này là hợp đồng.
Nếu bạn thêm field vào Order, reviewer thấy ngay trong diff. Nếu bạn đổi enum status, CI có thể kiểm tra spec có hợp lệ không. Nếu bạn xóa response 404, team có thể thảo luận trước khi merge.
Nên đặt spec ở một đường dẫn cố định, ví dụ:
api/openapi.yaml
Điều này giúp các tool CI, mock, docs generator và SDK generator dễ tham chiếu cùng một file.
Tạo mock, test, tài liệu và SDK từ spec
Giá trị của spec-as-code không chỉ nằm ở việc có một file OpenAPI. Giá trị đến từ việc dùng file đó để tạo output thực tế.
Mock server
Mock giúp frontend hoặc mobile bắt đầu tích hợp trước khi backend hoàn tất.
Workflow:
openapi.yaml -> mock server -> frontend/mobile integration
Khi endpoint mới được định nghĩa trong spec, mock có thể phản ánh contract đó. Team client không phải chờ service thật.
Contract test
Contract test kiểm tra service đang chạy có khớp với OpenAPI spec không.
Ví dụ các lỗi nên bị phát hiện trong CI:
- API trả về field không được khai báo
- API thiếu field bắt buộc
- Status code thực tế không có trong spec
- Kiểu dữ liệu trả về khác schema
- Endpoint đã implement nhưng chưa được document
Ý tưởng là biến spec từ “tài liệu tham khảo” thành “hợp đồng được kiểm tra”.
API documentation
Thay vì viết tay bảng endpoint, bạn generate tài liệu từ OpenAPI.
Khi spec thay đổi, docs thay đổi theo. Điều này giảm nguy cơ tài liệu public khác với API thật.
SDK
Từ cùng một file OpenAPI, bạn có thể generate client SDK cho nhiều ngôn ngữ.
Ví dụ output:
openapi.yaml
├── typescript-client
├── java-client
├── python-client
└── go-client
Đối tác hoặc team nội bộ dùng SDK có kiểu dữ liệu rõ ràng và bám sát contract hiện tại.
Cách Apidog biến đặc tả thành nguồn đáng tin cậy duy nhất
Nếu tự triển khai spec-as-code hoàn toàn thủ công, bạn thường phải ghép nhiều công cụ:
- OpenAPI editor
- Mock server
- Documentation generator
- Test runner
- Git hook hoặc CI job
- Công cụ đồng bộ repo
Apidog gom các phần này vào một workflow tập trung hơn.
Chế độ Spec-First của Apidog coi file OpenAPI là định nghĩa có thẩm quyền. Bạn thiết kế endpoint dựa trên spec, sau đó dùng cùng spec đó cho mock, test và documentation.
Điểm quan trọng là đồng bộ Git hai chiều. Apidog có thể đọc OpenAPI spec từ repository và ghi thay đổi trở lại repository. Điều này giúp file trong Git và project trong Apidog tiếp tục đồng bộ.
Workflow thực tế:
Git repo/openapi.yaml
↓
Apidog
↓
mock, tests, docs
↓
changes synced back to Git
Bạn có thể:
- Chỉnh trực quan khi cần thao tác nhanh
- Chỉnh YAML trực tiếp khi cần kiểm soát chi tiết
- Vẫn giữ PR review trong Git
- Vẫn coi
openapi.yamllà nguồn đáng tin cậy duy nhất
Để xem cơ chế đẩy thay đổi spec lên upstream, đọc thêm cách đồng bộ hóa đặc tả OpenAPI của bạn với GitHub.
Kết quả: OpenAPI spec vẫn là source of truth, còn công cụ trực quan chỉ nằm trên workflow đó thay vì thay thế Git.
Những cạm bẫy thường gặp
Spec-as-code khá đơn giản, nhưng có vài lỗi triển khai dễ làm workflow mất tác dụng.
1. Spec lệch khỏi implementation
Viết spec thôi chưa đủ. Nếu không có test kiểm tra service thật, spec và implementation sẽ dần lệch nhau.
Cách xử lý:
- Thêm contract test vào CI
- Chạy test với service đang chạy
- Fail build nếu response không khớp schema
Ví dụ rule đơn giản:
Nếu API trả về field không có trong OpenAPI schema -> fail CI
Nếu API thiếu required field -> fail CI
Nếu status code không được khai báo -> fail CI
2. Trộn lẫn spec generate từ code và spec viết tay
Bạn cần chọn nguồn chính.
Có hai hướng phổ biến:
Code annotations -> generate OpenAPI
hoặc:
OpenAPI spec -> generate mocks/tests/docs/SDK
Cả hai đều có thể dùng được. Nhưng nếu vừa viết tay spec, vừa generate spec từ annotation mà không có quy tắc rõ ràng, team sẽ không biết file nào là authoritative.
Nếu chọn spec-as-code theo hướng spec-first, hãy coi openapi.yaml là nguồn chính.
3. Coi spec chỉ là tài liệu
Một spec chỉ để đọc thì vẫn là tài liệu.
Một spec dùng để tạo mock, test, docs và SDK mới là hợp đồng vận hành.
Checklist tối thiểu:
- [ ] Spec được commit vào Git
- [ ] Spec được review bằng PR
- [ ] Spec được lint trong CI
- [ ] Mock hoặc docs được generate từ spec
- [ ] Contract test kiểm tra implementation với spec
4. Bỏ qua review
Một file OpenAPI nằm trong Git nhưng được merge không review thì không khác nhiều so với tài liệu chỉnh tay.
Hãy yêu cầu review với mọi thay đổi spec, đặc biệt là:
- Xóa field
- Đổi kiểu dữ liệu
- Đổi enum
- Xóa endpoint
- Đổi status code
- Đổi request body hoặc response body
Cách bắt đầu triển khai spec-as-code
Bạn không cần chuyển toàn bộ workflow trong một lần. Có thể bắt đầu theo từng bước.
Bước 1: Commit OpenAPI spec vào repo
Đặt spec ở một đường dẫn cố định:
api/openapi.yaml
Commit file:
git add api/openapi.yaml
git commit -m "Add OpenAPI specification"
Bước 2: Bắt buộc review bằng pull request
Cấu hình branch protection để thay đổi spec phải được review trước khi merge.
Ví dụ rule:
api/openapi.yaml -> requires pull request review
Nếu repo có nhiều service, mỗi service nên có spec riêng:
services/
├── orders/
│ └── api/openapi.yaml
├── users/
│ └── api/openapi.yaml
└── billing/
└── api/openapi.yaml
Bước 3: Lint spec trong CI
Thêm bước kiểm tra OpenAPI hợp lệ trước khi merge.
Ví dụ workflow logic:
on pull request:
- validate api/openapi.yaml
- fail nếu spec không hợp lệ
Mục tiêu là bắt lỗi sớm:
- YAML sai cú pháp
-
$refbị gãy - Thiếu
operationId - Schema không hợp lệ
- Response không có description
Bước 4: Generate một output đầu tiên
Đừng cố làm mọi thứ cùng lúc. Chọn một output có giá trị nhanh nhất.
Gợi ý:
- Frontend đang chờ backend: bắt đầu với mock
- API public: bắt đầu với documentation
- Nhiều client tích hợp: bắt đầu với SDK
- Đã có production API: bắt đầu với contract test
Bước 5: Thêm contract test
Sau khi spec đã ổn định, thêm test để so sánh API thật với spec.
Workflow:
pull request
↓
validate OpenAPI
↓
run service
↓
run contract tests
↓
merge only if pass
Đây là bước biến spec thành hợp đồng được thực thi.
Kết luận
Spec-as-code là một thay đổi nhỏ về cách tổ chức, nhưng tác động lớn đến cách team phát triển API.
Thay vì để hợp đồng API rải rác trong wiki, collection và tài liệu viết tay, hãy đưa OpenAPI spec vào Git, review nó như code, và dùng nó để tạo mock, test, docs và SDK.
Workflow tối thiểu nên là:
OpenAPI spec in Git
↓
Pull request review
↓
CI validation
↓
Generated mocks/docs/tests/SDK
↓
Contract tests against implementation
Nếu bạn muốn có chỉnh sửa trực quan và đồng bộ Git tích hợp sẵn, hãy thử Chế độ Spec-First của Apidog và để file OpenAPI của bạn làm nguồn đáng tin cậy duy nhất.
Câu hỏi thường gặp
“Đặc tả API dưới dạng mã” có giống “Tài liệu dưới dạng mã” không?
Có cùng triết lý, nhưng áp dụng cho artifact khác nhau.
Docs-as-code áp dụng cho tài liệu. Spec-as-code áp dụng cho hợp đồng API. Trong thực tế, chúng bổ trợ nhau vì tài liệu API thường được generate từ OpenAPI spec đã commit trong Git.
Tệp đặc tả nên dùng định dạng nào?
OpenAPI YAML là lựa chọn phổ biến vì dễ đọc và diff rõ trong pull request.
JSON cũng hoạt động, nhưng YAML thường dễ review hơn với con người, đặc biệt khi schema lớn.
Làm sao để ngăn spec lệch khỏi API thực tế?
Thêm contract test vào CI. Test nên kiểm tra service đang chạy có trả về đúng schema, status code và field như OpenAPI spec đã commit hay không.
Nếu API thật và spec không khớp, build nên fail trước khi thay đổi được merge hoặc release.



Top comments (0)