Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn là Technical BA tại một công ty fintech ở TP.HCM. Đội của bạn vừa xây xong API thanh toán, và đối tác — một ví điện tử lớn — cần tích hợp. Họ gửi email hỏi: "Endpoint tạo giao dịch là gì? Body gửi lên ra sao? Field amount tính bằng đồng hay nghìn đồng? Nếu số dư không đủ thì trả về mã lỗi nào?". Nếu bạn không có một bản API specification rõ ràng, mỗi câu hỏi sẽ kéo theo một cuộc họp, một chuỗi email qua lại, và tích hợp lẽ ra mất 3 ngày sẽ kéo dài 3 tuần.
API Specification chính là "hợp đồng" giữa hai hệ thống. Nó mô tả chính xác: gọi cái gì, gửi gì lên, nhận gì về, và lỗi xảy ra trông như thế nào. Với Technical BA, đây là một trong những deliverable có giá trị cao nhất bạn có thể tạo ra, bởi nó biến những ý tưởng nghiệp vụ mơ hồ thành một bản đặc tả mà cả frontend, backend, QA và đối tác bên ngoài đều đọc và làm theo được.
Trong bài này, chúng ta sẽ tập trung vào việc đặc tả và lập tài liệu kỹ thuật cho API — đặc biệt là chuẩn OpenAPI/Swagger. Các nguyên tắc thiết kế REST sâu hơn, cách viết spec đầy đủ với công cụ, hay versioning sẽ được học kỹ ở các bài sau. Ở đây, mục tiêu của bạn là: hiểu một bản API spec gồm những gì, đọc và viết được nó, và biết một tài liệu kỹ thuật tốt khác một tài liệu tệ ở chỗ nào.
Khái niệm cốt lõi
API Specification là gì và khác gì với API Documentation
Hai khái niệm này thường bị nhầm lẫn. API Specification là bản mô tả mang tính kỹ thuật, chính xác, thường ở định dạng máy đọc được (YAML hoặc JSON), định nghĩa từng endpoint, tham số, cấu trúc dữ liệu, mã trạng thái. Nó là nguồn chân lý (source of truth). API Documentation là tài liệu hướng đến con người: hướng dẫn bắt đầu nhanh, ví dụ code, giải thích nghiệp vụ, sơ đồ luồng. Điều thú vị là tài liệu tốt thường được sinh tự động từ specification — viết spec đúng một lần, bạn có cả hai.
OpenAPI và Swagger — chuẩn công nghiệp
OpenAPI (trước đây gọi là Swagger Specification) là chuẩn được dùng phổ biến nhất hiện nay để đặc tả REST API. Nó cho phép bạn mô tả toàn bộ API trong một file YAML hoặc JSON theo cấu trúc chuẩn. Swagger ngày nay chỉ bộ công cụ xoay quanh OpenAPI: Swagger UI (giao diện đọc và thử API ngay trên trình duyệt), Swagger Editor (trình soạn thảo), Swagger Codegen (sinh code client/server từ spec).
Vì sao chuẩn này quan trọng với BA? Vì khi bạn viết spec theo OpenAPI, bạn nhận được rất nhiều thứ "miễn phí": tài liệu đẹp tự sinh, server giả lập (mock server) để frontend làm việc trước khi backend xong, và validation tự động giữa code và spec.
Bộ phận cấu thành một API Specification
Một đặc tả endpoint đầy đủ cần trả lời được những câu hỏi sau:
- Method và Path:
POST /api/v1/users,GET /api/v1/orders/{orderId}. - Summary và Description: Endpoint này làm gì, dùng trong nghiệp vụ nào.
- Request — Path/Query parameters:
{orderId}là gì,?status=pending&page=2nghĩa là gì, bắt buộc hay tùy chọn. - Request Body: Cấu trúc JSON gửi lên, từng field tên gì, kiểu dữ liệu gì, bắt buộc không, ràng buộc ra sao (độ dài, định dạng, giá trị hợp lệ).
- Response: Với mỗi mã trạng thái (200, 201, 400, 401, 404, 409, 500), trả về cấu trúc gì.
- Error model: Khi lỗi, body trả về có
error_code,message,detailsnhư thế nào. - Authentication: Endpoint cần token gì, header nào.
- Examples: Ví dụ request và response cụ thể — đây là phần BA hay bỏ quên nhưng lập trình viên quý nhất.
Một ví dụ OpenAPI cụ thể
Đây là cách đặc tả endpoint tạo người dùng theo OpenAPI 3.0:
paths:
/api/v1/users:
post:
summary: Tạo người dùng mới
description: Đăng ký một tài khoản người dùng vào hệ thống.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [email, full_name, phone]
properties:
email:
type: string
format: email
example: "lan.nguyen@example.com"
full_name:
type: string
minLength: 2
maxLength: 100
example: "Nguyễn Thị Lan"
phone:
type: string
pattern: '^0[0-9]{9}$'
example: "0901234567"
responses:
'201':
description: Tạo thành công
content:
application/json:
schema:
type: object
properties:
id: { type: string, example: "usr_8a2f" }
email: { type: string, example: "lan.nguyen@example.com" }
created_at: { type: string, format: date-time }
'409':
description: Email đã tồn tại
content:
application/json:
schema:
type: object
properties:
error_code: { type: string, example: "EMAIL_EXISTS" }
message: { type: string, example: "Email đã được đăng ký" }
Hãy để ý: chỉ với đoạn này, một lập trình viên frontend có thể bắt đầu làm form đăng ký, một QA có thể viết test case cho cả trường hợp thành công lẫn email trùng, mà không cần hỏi bạn câu nào. Đó là sức mạnh của một spec đầy đủ.
Tình huống thực tế
Ví dụ 1 — Ví điện tử và đối tác tích hợp
Một công ty ví điện tử ở Hà Nội (gọi là VietPay) cần mở API cho khoảng 40 đối tác merchant tích hợp thanh toán. Ban đầu, đội kỹ thuật chỉ gửi cho mỗi đối tác một file Word mô tả API. Hậu quả: mỗi đối tác hiểu một kiểu. Có đối tác gửi amount: 50000 hiểu là 50.000 đồng, có đối tác hiểu là 50.000 nghìn đồng. Một sự cố thực tế xảy ra khi một giao dịch lẽ ra 50.000đ bị xử lý thành 50 triệu vì hiểu nhầm đơn vị.
Technical BA mới vào đã chuyển toàn bộ sang OpenAPI spec, trong đó field amount được mô tả rõ: type: integer, đơn vị "đồng (VND), không có phần thập phân", kèm ví dụ 50000 nghĩa là 50.000đ và ràng buộc minimum: 1000. Họ dựng Swagger UI cho đối tác tự đọc và thử. Kết quả: thời gian onboarding một đối tác mới giảm từ trung bình 18 ngày xuống còn 5 ngày, và số ticket hỏi về API giảm khoảng 70%.
Bài học: Một spec mơ hồ về đơn vị, kiểu dữ liệu hay ràng buộc không chỉ gây phiền — nó gây ra lỗi tiền bạc thật. Hãy đặc tả đến mức không còn chỗ cho diễn giải.
Ví dụ 2 — Sàn thương mại điện tử và mock server
Một sàn TMĐT ở Đông Nam Á có đội frontend và backend làm song song. Vấn đề kinh điển: frontend luôn phải "chờ" backend làm xong API mới code được. Technical BA đề xuất quy trình "spec-first": trước mỗi sprint, BA cùng kiến trúc sư viết OpenAPI spec cho các endpoint mới và chốt với cả hai đội. Từ spec đó, họ dựng một mock server (server giả lập trả về dữ liệu mẫu đúng theo spec).
Nhờ vậy, frontend bắt đầu code ngay từ ngày đầu sprint dựa trên mock, còn backend hiện thực thật song song. Khi backend xong, hai bên ghép lại gần như không có bất ngờ, vì cả hai đều bám cùng một "hợp đồng". Đội báo cáo thời gian tích hợp cuối sprint giảm rõ rệt, và số lần frontend phải sửa lại do API "khác mô tả" gần như về 0.
Bài học: Spec-first không chỉ là tài liệu — nó là công cụ giúp các đội làm việc song song. BA viết spec tốt sẽ trực tiếp tăng tốc độ giao hàng của cả nhóm.
Ví dụ 3 — Ngân hàng và phần đặc tả lỗi bị bỏ quên
Một ngân hàng ở Việt Nam mở API truy vấn số dư cho ứng dụng đối tác. Spec mô tả rất kỹ trường hợp thành công (200) nhưng gần như không nói gì về lỗi. Khi lên production, ứng dụng đối tác liên tục crash vì gặp những phản hồi không lường trước: tài khoản bị khóa, token hết hạn, hệ thống core banking bảo trì. Mỗi tình huống trả về một cấu trúc lỗi khác nhau, và đối tác không biết phải xử lý thế nào.
Technical BA sau đó bổ sung một error model thống nhất: mọi lỗi đều trả về cùng cấu trúc { error_code, message, trace_id }, kèm bảng liệt kê đầy đủ các error_code (ví dụ ACCOUNT_LOCKED, TOKEN_EXPIRED, CORE_UNAVAILABLE) và cách đối tác nên phản ứng. Sau khi chuẩn hóa, sự cố phía đối tác giảm mạnh và việc hỗ trợ trở nên dễ vì mỗi lỗi đều có trace_id để tra cứu.
Bài học: Đặc tả "happy path" là phần dễ. Giá trị thật của một Technical BA nằm ở việc đặc tả đầy đủ các trường hợp lỗi và biên — đó mới là nơi hệ thống thật sự đổ vỡ.
Hướng dẫn từng bước
Khi bạn được giao viết API specification cho một tính năng, hãy làm theo trình tự sau:
- Hiểu nghiệp vụ trước, kỹ thuật sau. Trả lời: ai gọi API này, để làm gì trong luồng nghiệp vụ. Đừng vội nhảy vào JSON.
- Liệt kê các endpoint cần thiết. Với mỗi hành động nghiệp vụ, ánh xạ ra method và path. "Tạo đơn hàng" →
POST /orders. "Xem chi tiết đơn" →GET /orders/{orderId}. "Hủy đơn" →POST /orders/{orderId}/cancel.
- Đặc tả request cho từng endpoint. Với mỗi field: tên, kiểu dữ liệu, bắt buộc hay không, ràng buộc (độ dài, định dạng, khoảng giá trị), đơn vị (rất quan trọng với tiền, ngày giờ). Luôn ghi rõ múi giờ cho datetime — nên dùng chuẩn ISO 8601 với UTC.
- Đặc tả response cho từng mã trạng thái. Không chỉ 200/201. Hãy nghĩ tới 400 (dữ liệu sai), 401 (chưa xác thực), 403 (không có quyền), 404 (không tìm thấy), 409 (xung đột, ví dụ trùng), 422 (không hợp lệ về nghiệp vụ), 500 (lỗi server).
- Định nghĩa error model thống nhất. Một cấu trúc lỗi dùng chung cho toàn bộ API, kèm danh sách
error_code.
- Thêm ví dụ thật cho mỗi request và response. Đây là phần làm tài liệu của bạn "sống". Dùng dữ liệu giống thực tế Việt Nam: tên, số điện thoại, số tiền VND.
- Viết bằng OpenAPI và dựng Swagger UI để review. Đưa link Swagger UI cho lập trình viên và đối tác xem trực quan, thậm chí bấm "Try it out".
- Chốt spec như một hợp đồng. Khi đã thống nhất, mọi thay đổi sau đó phải đi qua quy trình kiểm soát thay đổi, vì có nhiều bên đang phụ thuộc vào nó.
Lỗi thường gặp & mẹo
Lỗi 1 — Chỉ đặc tả happy path. Đây là lỗi phổ biến nhất. BA thường mô tả rất kỹ trường hợp thành công và quên hoàn toàn các lỗi. Mẹo: với mỗi endpoint, tự hỏi "có thể sai ở đâu?" và liệt kê ít nhất 3-4 trường hợp lỗi.
Lỗi 2 — Mơ hồ về kiểu dữ liệu và đơn vị. "Số tiền" là integer hay decimal? Đơn vị là đồng hay nghìn đồng? "Ngày" theo định dạng nào, múi giờ nào? Mẹo: với mọi field tiền tệ và thời gian, luôn ghi rõ kiểu, đơn vị và định dạng. Dùng ISO 8601 cho datetime.
Lỗi 3 — Tên field không nhất quán. Chỗ thì userId, chỗ thì user_id, chỗ thì customerID. Sự không nhất quán này làm lập trình viên phát điên. Mẹo: chọn một quy ước đặt tên (ví dụ snake_case) và áp dụng cho toàn bộ API.
Lỗi 4 — Spec và code lệch nhau theo thời gian. Code đổi nhưng spec không cập nhật, dần dần tài liệu thành dối trá. Mẹo: hướng tới "spec là source of truth" — sinh tài liệu từ spec, và thiết lập kiểm tra tự động để phát hiện khi code lệch spec.
Lỗi 5 — Viết spec như một file Word tĩnh. Một bảng trong Word không thử được, không sinh mock được, dễ lỗi thời. Mẹo: dùng OpenAPI ngay từ đầu, kể cả khi ban đầu thấy "phức tạp hơn". Lợi ích về lâu dài lớn hơn nhiều.
Mẹo vàng: Hãy đọc spec của bạn dưới góc nhìn của một người chưa từng nói chuyện với bạn. Nếu họ có thể tích hợp mà không cần hỏi bạn câu nào, spec của bạn đã tốt.
Bài tập thực hành
Bài tập 1 — Đặc tả một endpoint. Cho tình huống: một ứng dụng đặt lịch khám tại phòng khám. Hãy viết OpenAPI spec cho endpoint POST /api/v1/appointments để tạo lịch hẹn, gồm các field: họ tên bệnh nhân, số điện thoại, mã bác sĩ, thời gian hẹn. Đặc tả đầy đủ request body với ràng buộc (số điện thoại đúng định dạng VN, thời gian theo ISO 8601), response 201 khi thành công, và ít nhất hai trường hợp lỗi (ví dụ bác sĩ không tồn tại, khung giờ đã kín).
Bài tập 2 — Thiết kế error model. Thiết kế một cấu trúc lỗi thống nhất cho toàn bộ API của ứng dụng trên. Liệt kê ít nhất 5 error_code kèm mã HTTP tương ứng và mô tả ngắn cách client nên xử lý từng loại.
Bài tập 3 — Soi spec tệ. Tìm một tài liệu API thật (ví dụ tài liệu công khai của một cổng thanh toán Việt Nam) và chỉ ra 3 điểm có thể gây hiểu nhầm khi tích hợp. Đề xuất cách viết lại cho rõ.
Tóm tắt
API Specification là "hợp đồng" giữa các hệ thống, và với Technical BA, đây là deliverable có giá trị rất cao. Một bản spec tốt mô tả chính xác method, path, request, response, lỗi và xác thực — đến mức người tích hợp không cần hỏi thêm câu nào.
Chuẩn công nghiệp hiện nay là OpenAPI (Swagger), cho phép viết spec ở dạng máy đọc được rồi sinh ra tài liệu đẹp, mock server và validation tự động. Spec-first giúp các đội làm việc song song và tăng tốc giao hàng.
Điều phân biệt một BA giỏi không nằm ở việc mô tả trường hợp thành công — phần đó dễ. Giá trị thật nằm ở việc đặc tả đầy đủ các trường hợp lỗi và biên, ghi rõ kiểu dữ liệu và đơn vị, giữ tên field nhất quán, và luôn kèm ví dụ thật. Như các tình huống VietPay, sàn TMĐT và ngân hàng đã cho thấy: một dòng spec mơ hồ có thể gây ra lỗi tiền tỷ, còn một spec rõ ràng có thể rút ngắn tích hợp từ vài tuần xuống vài ngày. Hãy viết spec như thể tiền và uy tín của công ty phụ thuộc vào nó — vì thường là vậy thật.