Cách thiết kế và phát triển API chuẩn Git-native?

Một hướng dẫn thực tế về thiết kế và phát triển API thuần Git: các hợp đồng API dựa trên nhánh, đánh giá đặc tả trong pull request và các quy ước nhóm có khả năng mở rộng.

Ashley Innocent

Ashley Innocent

3 tháng 6 2026

Cách thiết kế và phát triển API chuẩn Git-native?

Apidog cho doanh nghiệp

Triển khai tại chỗ

SSO & RBAC

Tuân thủ SOC 2

Khám phá Apidog Enterprise

Hầu hết các đội API coi hợp đồng như một điều phụ trợ. Họ viết mã trước, sau đó tạo một đặc tả, rồi chứng kiến hai thứ này dần xa nhau. Thiết kế API gốc Git đảo ngược thứ tự đó. Bạn coi hợp đồng API như mã nguồn, quản lý phiên bản nó trong Git và xem xét mọi thay đổi giống như cách bạn xem xét logic ứng dụng.

Hướng dẫn này nói về nguyên tắc, không phải một công cụ duy nhất. Bạn sẽ học cách thiết kế các hợp đồng trong các nhánh, xem xét chúng trong các pull request, và biến một đặc tả đã được commit thành các mock, kiểm thử và tài liệu. Mục tiêu là một quy trình làm việc trong đó lịch sử Git của bạn chính là lịch sử API của bạn.

Nếu bạn đã biết các công cụ Spec-First trông như thế nào và muốn xem hướng dẫn sản phẩm, hãy đọc bài viết đi kèm 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.

nút

"Git-native" có nghĩa gì đối với công việc API

Git-native có nghĩa là định nghĩa API của bạn nằm trong kho lưu trữ dưới dạng tệp văn bản thuần túy. Không phải trong cơ sở dữ liệu đám mây độc quyền. Không phải đằng sau tài khoản đăng nhập của nhà cung cấp. Một tệp .yaml hoặc .json nằm cạnh mã của bạn, được theo dõi bởi hệ thống kiểm soát phiên bản mà nhóm của bạn đã sử dụng.

Hãy so sánh điều này với các công cụ bị khóa đám mây. Nhiều nền tảng thiết kế API lưu trữ hợp đồng trong hệ thống backend của riêng họ. Bạn chỉnh sửa thông qua giao diện người dùng web, và phiên bản chính thức nằm trên máy chủ của họ. Kho lưu trữ của bạn chỉ giữ một bản xuất lỗi thời là tốt nhất. Khi cơ sở dữ liệu của nhà cung cấp là nguồn sự thật duy nhất, lịch sử Git của bạn không cho biết gì về cách API đã phát triển.

Mô hình gốc Git đảo ngược mối quan hệ đó. Tệp trong main là hợp đồng. Mọi thứ khác, bao gồm bất kỳ GUI nào, chỉ là một cái nhìn về tệp đó. Sự thay đổi đơn lẻ này mở khóa lịch sử, tính trách nhiệm, khả năng hoàn tác và xem xét cho bề mặt API của bạn.

Một thiết lập gốc Git có ba thuộc tính. Đặc tả là một tệp văn bản trong kho lưu trữ. Các thay đổi diễn ra thông qua các hoạt động Git thông thường như branch, commit và merge. Và mọi tạo phẩm phụ thuộc, từ các mock đến tài liệu, đều được tạo ra từ tệp đã được commit thay vì một cơ sở dữ liệu riêng biệt.

Tại sao nên thiết kế và phát triển API trong Git

Bạn đã tin tưởng Git với tài sản quý giá nhất của mình: mã nguồn. Hợp đồng API của bạn cũng xứng đáng được đối xử tương tự.

Lịch sử là lý do đầu tiên. Khi ai đó hỏi “chúng ta đã thêm tham số phân trang cursor khi nào?”, git log sẽ trả lời trong vài giây. Commit đã giới thiệu nó mang theo một thông báo, tác giả và ngày tháng. Không ảnh chụp màn hình, không cần "khảo cổ" changelog.

Blame là điều thứ hai. Chạy git blame trên tệp đặc tả và bạn sẽ thấy chính xác ai đã thay đổi từng dòng và tại sao. Một tên trường gây khó hiểu có thể được truy ngược về PR đã thêm nó, cùng với cuộc thảo luận đính kèm. Trách nhiệm trở nên tự động.

Rollback là điều thứ ba. Một thiết kế tồi được triển khai. Với Git, bạn git revert merge và hợp đồng trở về trạng thái trước đó. Codegen, mock và tài liệu phụ thuộc sẽ được tạo lại từ tệp đã hoàn tác. Không cần dọn dẹp thủ công trong một hệ thống riêng biệt.

Xem xét là điều thứ tư, và đây là điều mà các đội ít sử dụng. Một pull request là nơi tự nhiên để tranh luận về thiết kế API trước khi nó trở thành hiện thực. Người đánh giá bình luận trên một dòng + thêm một trường bắt buộc. Cuộc trò chuyện sẽ tồn tại mãi mãi bên cạnh sự thay đổi.

Nguồn sự thật duy nhất gắn kết mọi thứ lại với nhau. Khi hợp đồng là một tệp duy nhất trong main, không có sự mơ hồ về phiên bản nào là thật. Frontend, backend, QA và tài liệu đều đọc cùng một dòng YAML. Đây là lời hứa cốt lõi 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

Vòng lặp có năm bước: thiết kế hợp đồng, commit, mở PR, xem xét và merge. Việc triển khai theo sau bước merge, chứ không phải ngược lại.

Bắt đầu bằng cách viết hợp đồng. Giả sử bạn đang thêm một endpoint để lấy hóa đơn của người dùng. Bạn tạo một nhánh và chỉnh sửa tệp OpenAPI.

# openapi.yaml (đoạn trích được thêm vào nhánh feat/invoices-list)
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

Commit thay đổi đó với một thông báo rõ ràng: git commit -m "Add GET /users/{userId}/invoices contract". Commit nhỏ và tập trung. Nó mô tả một quyết định thiết kế.

Bây giờ hãy mở một pull request. Diff cho người đánh giá thấy chính xác những gì mới: một đường dẫn, một hoạt động, hai tham số, hai phản hồi. Đồng đội của bạn thảo luận về cách đặt tên, các giá trị enum, và liệu 404 có phải là mã phù hợp cho người dùng không tồn tại hay không. Họ có thể thúc đẩy việc phân trang theo con trỏ trước khi một dòng mã xử lý nào tồn tại.

Khi PR được chấp thuận, hãy merge nó. Hợp đồng trong main giờ đây bao gồm endpoint hóa đơn. Việc triển khai sẽ đến tiếp theo, và nó bị ràng buộc bởi đặc tả mà tất cả các bạn đã đồng ý. Thứ tự này là điều mọi người muốn nói khi nói về phát triển API spec-first: thỏa thuận đi trước mã.

Lợi ích là các cuộc tranh luận về thiết kế diễn ra với chi phí thấp. Thay đổi một trường YAML trong quá trình xem xét chỉ tốn vài phút. Thay đổi một endpoint đã được triển khai, thực hiện và ghi lại sẽ tốn nhiều ngày.

Chiến lược phân nhánh cho hợp đồng API

Xử lý các thay đổi hợp đồng như bất kỳ thay đổi nào khác: một nhánh cho mỗi đơn vị công việc logic. Một nhánh cho mỗi endpoint hoặc mỗi sửa đổi giúp PR nhỏ và diff dễ đọc.

Đặt tên nhánh sao cho ý định rõ ràng. Sử dụng tiền tố báo hiệu loại thay đổi. Điều này giúp người đánh giá và CI định tuyến công việc.

Loại thay đổi Tiền tố nhánh Ví dụ Mức độ xem xét
Endpoint mới feat/api- feat/api-invoices-list Tiêu chuẩn
Trường bổ sung feat/api- feat/api-invoice-currency Nhẹ
Thay đổi gây hỏng break/api- break/api-remove-legacy-id Nặng, cần xác nhận
Sửa lỗi trong đặc tả fix/api- fix/api-status-enum-typo Nhẹ
Chỉ refactor chore/api- chore/api-reorder-schemas Nhẹ

Tiền tố mang ý nghĩa. Một nhánh break/api- yêu cầu người đánh giá chậm lại và kiểm tra mọi bên tiêu thụ. Một nhánh chore/api- báo hiệu không có thay đổi ngữ nghĩa, do đó việc xem xét có thể diễn ra nhanh chóng.

Bạn cũng chọn một mô hình phân nhánh. Phát triển theo nhánh chính (trunk-based development) phù hợp với hầu hết các đội API. Các nhánh ngắn hạn merge vào main hàng ngày, và đặc tả luôn gần với một nguồn sự thật duy nhất. Gitflow, với các nhánh developrelease chạy dài, phù hợp với các đội nhóm gộp các thay đổi API vào các bản phát hành theo lịch trình.

Mô hình Tốt nhất cho Đánh đổi API
Trunk-based Giao hàng liên tục, đội nhỏ Hợp đồng phát triển từng bước nhỏ; ít khó khăn khi merge
Gitflow Phát hành theo lịch trình, giao hàng có quy định Đặc tả phân kỳ trên develop; merge lớn hơn, rủi ro hơn

Đối với hầu hết công việc API, hãy ưu tiên trunk-based. Các thay đổi hợp đồng nhỏ, thường xuyên tạo ra các diff nhỏ, thường xuyên. Các nhánh tồn tại lâu dài khiến đặc tả bị lệch, và các xung đột merge YAML trở nên phức tạp nhanh chóng khi hai nhánh cơ cấu lại cùng một tệp.

Xem xét thiết kế API trong pull request

Một PR đặc tả là một bản xem xét thiết kế, không phải kiểm tra cú pháp. Người đánh giá xem xét ngữ nghĩa, và một vài câu hỏi có thể bao quát hầu hết các rủi ro.

Điều này có làm hỏng các bên tiêu thụ hiện có không? Xóa một trường, đổi tên một đường dẫn, hoặc thắt chặt một kiểu dữ liệu đều là những thay đổi gây hỏng. Người đánh giá kiểm tra xem thay đổi là bổ sung hay gây hỏng, và các thay đổi gây hỏng yêu cầu tăng phiên bản hoặc một lộ trình ngừng hỗ trợ.

Cách đặt tên có nhất quán không? Nếu mọi endpoint thu thập đều sử dụng danh từ số nhiều, một đường dẫn số ít mới sẽ nổi bật. Nếu lỗi trả về trường code ở nơi khác, một endpoint mới cũng nên làm như vậy. Người đánh giá đảm bảo các mô hình mà API đã thiết lập được tuân thủ.

Có thân thiện với diff không? Giữ YAML ổn định để các diff vẫn nhỏ. Sắp xếp các khóa một cách nhất quán. Thêm các đường dẫn mới vào một vị trí dễ đoán. Người đánh giá có thể đọc một diff năm dòng trong vài giây, nhưng một tệp đã sắp xếp lại tạo ra một diff trăm dòng che giấu thay đổi thực sự.

Thay đổi gây hỏng thân thiện với người đánh giá. Các dòng - chỉ ra chính xác những gì biến mất.

# Diff mà người đánh giá thấy trong PR
 parameters:
 - name: status
 in: query
 schema:
 type: string
- enum: [draft, open, paid, void]
+ enum: [draft, open, paid, void, uncollectible]

Diff đó là bổ sung vào enum, nên nó an toàn. So sánh nó với một dòng - loại bỏ hoàn toàn void, điều này sẽ làm hỏng bất kỳ client nào gửi giá trị đó. Diff làm cho sự khác biệt hiển thị ngay lập tức.

Khuyến khích người đánh giá bình luận trực tiếp trên đặc tả, giống như cách họ bình luận trên mã nguồn. Cuộc thảo luận vẫn gắn liền với dòng đó và tồn tại trong lịch sử đã merge.

Từ thiết kế đến phát triển

Khi hợp đồng đã có trong main, nó trở thành nguồn cho mọi thứ phụ thuộc. Bạn tạo ra, không viết thủ công.

Codegen đến trước. Các công cụ như openapi-generator tạo ra các server stub và client có kiểu từ tệp đã commit. Các trình xử lý của bạn điền vào logic nghiệp vụ, nhưng cấu trúc yêu cầu và phản hồi phù hợp với hợp đồng theo thiết kế. Đặc tả và mã nguồn không thể mâu thuẫn về định dạng đường truyền.

Mock đến tiếp theo. Một máy chủ mock đọc đặc tả và trả về các phản hồi ví dụ cho mỗi endpoint. Các nhà phát triển frontend xây dựng dựa trên mock trước khi backend tồn tại. Họ bắt đầu ngay khi hợp đồng được merge, chứ không phải vài tuần sau.

Các bài kiểm thử tiếp theo. Các bài kiểm thử hợp đồng khẳng định rằng máy chủ đang chạy của bạn khớp với đặc tả. Gửi một yêu cầu, xác thực phản hồi dựa trên schema, và làm lỗi bản dựng nếu chúng khác biệt. Đây là rào chắn chống lại sự lệch pha giữa đặc tả và mã.

Tài liệu cũng được tạo ra. Tài liệu tham khảo được tạo trực tiếp từ tệp OpenAPI. Khi hợp đồng thay đổi, tài liệu cũng thay đổi trong cùng một commit. Không có bản cập nhật tài liệu riêng biệt để quên.

Nguyên tắc là nhất quán. Mọi tạo phẩm đều xuất phát từ một tệp đã commit. Tạo lại trên mỗi lần merge, và các mock, client, kiểm thử, và tài liệu của bạn sẽ luôn đồng bộ với hợp đồng.

Các quy ước nhóm có thể mở rộng

Các quy ước là điều giữ cho quy trình làm việc gốc Git không sụp đổ khi nhóm phát triển. Hãy quyết định chúng sớm và ghi lại.

Đầu tiên, chọn giữa một tệp đặc tả hoặc nhiều tệp. Một tệp openapi.yaml duy nhất đơn giản nhưng trở nên khó quản lý khi có quá vài chục endpoint. Chia thành nhiều tệp với tham chiếu $ref giúp mỗi tệp dễ đọc, đổi lại là một bước đóng gói. Một mẫu phổ biến là một tệp cho mỗi tài nguyên, được đóng gói thành một đặc tả duy nhất tại thời điểm xây dựng.

Thứ hai, quản lý phiên bản một cách có chủ đích. Tăng phiên bản info.version của OpenAPI trên mỗi thay đổi có ý nghĩa, và tuân thủ định nghĩa phiên bản ngữ nghĩa (semantic versioning). Các thay đổi bổ sung tăng phiên bản thứ cấp (minor version). Các thay đổi gây hỏng tăng phiên bản chính (major version) và thường có nghĩa là một tiền tố đường dẫn mới như /v2/.

Thứ ba, duy trì một changelog. Một tệp CHANGELOG.md bên cạnh đặc tả ghi lại những gì đã thay đổi và tại sao bằng ngôn ngữ con người. Lịch sử Git chính xác nhưng dài dòng; changelog là bản tóm tắt dễ đọc mà các bên tiêu thụ của bạn thực sự xem qua.

Thứ tư, bảo vệ đặc tả bằng CODEOWNERS. Yêu cầu những người quản lý API phê duyệt bất kỳ thay đổi nào đối với tệp hợp đồng. Điều này ngăn chặn những người đóng góp có ý tốt triển khai các thiết kế không nhất quán.

# .github/CODEOWNERS
/api/openapi.yaml @api-stewards
/api/paths/ @api-stewards

Thứ năm, chạy lint trong CI. Một linter phát hiện các vấn đề về phong cách và tính nhất quán trước khi xem xét. Chạy nó trên mỗi PR để con người xem xét thiết kế, không phải định dạng.

# .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

Với CI linting cộng với CODEOWNERS, mọi thay đổi hợp đồng đều nhận được kiểm tra tự động và một người quản lý. Sự kết hợp đó có thể mở rộng từ ba kỹ sư lên ba trăm.

Các cạm bẫy phổ biến và cách tránh chúng

Thiết kế API gốc Git có các chế độ lỗi có thể dự đoán được. Biết chúng giúp bạn thiết kế để tránh chúng.

Sự lệch pha giữa đặc tả và mã là điều tồi tệ nhất. Hợp đồng nói một đằng; máy chủ đang chạy làm một nẻo. Ngăn chặn điều đó bằng các bài kiểm thử hợp đồng trong CI để xác thực các phản hồi trực tiếp so với đặc tả đã commit. Nếu chúng khác biệt, bản dựng sẽ thất bại. Lệch pha trở thành một pipeline bị hỏng, chứ không phải một bất ngờ trong sản xuất.

Các PR khổng lồ là cạm bẫy tiếp theo. Một nhánh duy nhất thêm hai mươi endpoint tạo ra một diff không thể xem xét. Người đánh giá đọc lướt, chấp thuận và bỏ lỡ các vấn đề. Chia công việc thành một endpoint hoặc một thay đổi cho mỗi PR. Các diff nhỏ nhận được sự xem xét kỹ lưỡng.

Các tạo phẩm viết tay gây ra sự không nhất quán âm thầm. Khi ai đó viết client thủ công thay vì tạo ra nó, client sẽ lệch khỏi đặc tả. Luôn tạo client, stub và tài liệu từ tệp đã commit. Coi các tạo phẩm API viết tay là một dấu hiệu bất thường.

Xung đột merge YAML làm nản lòng các đội trên các nhánh tồn tại lâu dài. Hai nhánh cơ cấu lại cùng một tệp và Git không thể hòa giải chúng. Tránh điều này bằng cách sử dụng các nhánh ngắn hạn, một thứ tự khóa ổn định và bố cục tệp chia nhỏ để các thay đổi chạm vào các tệp khác nhau. Phát triển theo nhánh chính cộng với các PR nhỏ loại bỏ hầu hết các xung đột trước khi chúng bắt đầu.

Mô hình trên cả bốn điểm là như nhau. Giữ các thay đổi nhỏ, tạo các tạo phẩm từ đặc tả và để CI thực thi hợp đồng. Kỷ luật đánh bại những hành động anh hùng.

Vị trí của Apidog

Bạn có thể thực hiện quy trình làm việc gốc Git bằng trình soạn thảo văn bản và CLI. Nhiều nhóm muốn có GUI để thiết kế mà không từ bỏ Git là nguồn sự thật duy nhất. Đó là khoảng trống mà Chế độ Spec-First của Apidog lấp đầy.

Chế độ Spec-First giữ tệp OpenAPI trong kho lưu trữ Git của bạn và có đồng bộ hóa hai chiều. Bạn chỉnh sửa hợp đồng trong trình thiết kế trực quan của Apidog hoặc trong trình soạn thảo của bạn, và cả hai đều nhất quán với tệp trong kho lưu trữ của bạn. Tệp trong Git vẫn là bản chính thức, vì vậy các nhánh, PR và lịch sử đều hoạt động chính xác như mô tả ở đây. Bạn có được GUI mà không bị khóa vào đám mây. Xem tài liệu Chế độ Spec-First để biết chi tiết cài đặt.

Vấn đề không phải là công cụ. Mà là bạn có thể có một giao diện thiết kế trực quan và một nguyên tắc gốc Git cùng một lúc. Kho lưu trữ vẫn là nguồn sự thật duy nhất, và Apidog trở thành một góc nhìn về nó.

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 bất kỳ định dạng hợp đồng dựa trên văn bản nào. OpenAPI là phổ biến nhất, nhưng cùng một quy trình làm việc cũng có thể áp dụng cho AsyncAPI, tệp gRPC .proto hoặc GraphQL SDL. Miễn là hợp đồng là một tệp văn bản mà bạn có thể so sánh (diff), phân nhánh (branch) và xem xét (review), thì đó là git-native.

Làm thế nào để xử lý các thay đổi gây hỏng trong một quy trình làm việc gốc Git?

Làm cho các thay đổi gây hỏng trở nên rõ ràng và có chủ đích. Sử dụng tiền tố nhánh break/api-, tăng phiên bản chính, và yêu cầu người quản lý phê duyệt thông qua CODEOWNERS. Khi có thể, hãy thêm định dạng mới bên cạnh định dạng cũ và ngừng hỗ trợ đường dẫn cũ theo một lộ trình. Diff của PR và việc tăng phiên bản cùng nhau báo hiệu sự thay đổi gây hỏng cho mọi bên tiêu thụ.

Đặc tả API có nên nằm trong cùng một kho lưu trữ với mã nguồn không?

Thường thì có, khi một đội sở hữu cả hai. Đặt đặc tả và triển khai cùng một chỗ có nghĩa là một PR duy nhất có thể thay đổi hợp đồng và trình xử lý cùng nhau, và các bài kiểm thử hợp đồng chạy trong một pipeline. Chỉ đặt đặc tả trong một kho lưu trữ riêng khi nhiều đội tiêu thụ một API chia sẻ và cần quản lý phiên bản độc lập.

Làm thế nào để ngăn chặn đặc tả và mã nguồn bị lệch pha?

Thêm các bài kiểm thử hợp đồng vào CI. Chúng gửi các yêu cầu thực tế đến máy chủ đang chạy của bạn và xác thực mọi phản hồi so với đặc tả đã commit. Một sự khác biệt làm thất bại bản dựng. Kết hợp với việc tạo stub và client từ đặc tả, các bài kiểm thử hợp đồng biến sự lệch pha thành một lỗi pipeline thay vì một lỗi sản xuất.

Kết luận

Thiết kế API gốc Git là một nguyên tắc, không phải một sản phẩm. Bạn coi hợp đồng như mã nguồn, phát triển nó trong các nhánh, xem xét nó trong các pull request, và tạo ra mọi tạo phẩm phụ thuộc từ tệp đã commit. Lịch sử, tính trách nhiệm, hoàn tác và xem xét đều có sẵn miễn phí vì Git đã cung cấp chúng cho bạn.

Bắt đầu nhỏ. Di chuyển đặc tả của bạn vào kho lưu trữ, thêm bước lint, và yêu cầu xem xét các thay đổi hợp đồng. Xây dựng từ đó với codegen, mock và kiểm thử hợp đồng. Quy trình làm việc được củng cố: mỗi quy ước làm cho quy ước tiếp theo dễ dàng hơn, và lịch sử Git của bạn trở thành một bản ghi đầy đủ về cách API của bạn đã phát triển.

Nếu bạn muốn một giao diện thiết kế trực quan giữ đặc tả trong Git, hãy thử Chế độ Spec-First trong Apidog và xem cách đồng bộ hóa hai chiều phù hợp với quy trình làm việc trên.

nút

Thực hành thiết kế API trong Apidog

Khám phá cách dễ dàng hơn để xây dựng và sử dụng API