DEV Community

Cover image for การออกแบบและพัฒนา API แบบ Git-Native ทำอย่างไร?
Thanawat Wongchai
Thanawat Wongchai

Posted on • Originally published at apidog.com

การออกแบบและพัฒนา API แบบ Git-Native ทำอย่างไร?

ทีม API จำนวนมากเขียนโค้ดก่อน แล้วค่อยสร้างสเปกภายหลัง ทำให้ contract และ implementation คลาดเคลื่อนกันได้ง่าย การออกแบบ API แบบ Git-native แก้ปัญหานี้โดยปฏิบัติต่อสัญญา API เหมือนซอร์สโค้ด: เก็บเป็นไฟล์ใน repo, แตก branch, review ผ่าน PR และ merge เหมือนโค้ดแอปพลิเคชัน

ลองใช้ Apidog วันนี้

คู่มือนี้เน้นวิธีทำงานจริง ไม่ใช่การขายเครื่องมือ คุณจะเห็นวิธีออกแบบ contract ใน branch, ตรวจสอบ diff ใน pull request และใช้สเปกที่ commit แล้วสร้าง mocks, tests, clients และ docs เป้าหมายคือให้ประวัติ Git ของคุณกลายเป็นประวัติ API ของคุณ

หากคุณต้องการดูภาพรวมของผลิตภัณฑ์และตัวอย่าง workflow เพิ่มเติม อ่านบทความเสริมเกี่ยวกับ เวิร์กโฟลว์ API แบบ Git-native

“Git-native” หมายถึงอะไรสำหรับงาน API

Git-native หมายถึง contract ของ API อยู่ใน repository เป็นไฟล์ข้อความธรรมดา เช่น .yaml, .json, .proto หรือ GraphQL SDL ไม่ได้ถูกเก็บเป็นข้อมูลหลักในระบบคลาวด์ของ vendor

ใน workflow นี้ ไฟล์ใน main คือแหล่งความจริงหลัก ส่วน UI, mock server, code generator และเอกสารเป็นเพียง artifact ที่อ่านหรือสร้างจากไฟล์นั้น

Git-native API workflow

คุณสมบัติหลักของ API workflow แบบ Git-native มี 3 ข้อ:

  1. สเปก API อยู่ใน repo เป็นไฟล์ข้อความ
  2. ทุกการเปลี่ยนแปลงผ่าน Git operation ปกติ เช่น branch, commit, pull request และ merge
  3. artifacts ปลายน้ำ เช่น mocks, clients, tests และ docs สร้างจากไฟล์ที่ commit แล้ว

ผลลัพธ์คือคุณได้ change history, blame, rollback และ review สำหรับ API contract เหมือนกับที่มีในโค้ด

ทำไมต้องออกแบบและพัฒนา API ใน Git

Git ให้ประโยชน์ที่ตรงกับปัญหาของ API contract โดยตรง

1. ดูประวัติการเปลี่ยนแปลงได้

เมื่อมีคนถามว่า “เราเพิ่ม query parameter cursor เมื่อไหร่” ให้ใช้:

git log -p api/openapi.yaml
Enter fullscreen mode Exit fullscreen mode

คุณจะเห็น commit, ผู้เขียน, วันที่ และ diff ของการเปลี่ยนแปลงนั้นทันที

2. ระบุผู้รับผิดชอบได้

หากมี field ที่ตั้งชื่อไม่ชัดเจน ใช้:

git blame api/openapi.yaml
Enter fullscreen mode Exit fullscreen mode

จากนั้นย้อนกลับไปดู PR ที่เพิ่ม field นั้น พร้อม context และการสนทนาที่เกิดขึ้นตอน review

3. Rollback ได้

ถ้า contract ใหม่ทำให้ consumer ใช้งานไม่ได้ คุณสามารถ revert merge commit ได้:

git revert <merge-commit-sha>
Enter fullscreen mode Exit fullscreen mode

จากนั้น mocks, generated clients, tests และ docs สามารถสร้างใหม่จากสเปกที่ rollback แล้ว

4. Review ก่อนเขียนโค้ดจริง

Pull request เป็นจุดที่เหมาะที่สุดในการถกเถียง API design ก่อน implementation จะถูกสร้างขึ้น ผู้ตรวจสอบสามารถ comment บนบรรทัดที่เพิ่ม required field, response schema หรือ path ใหม่ได้โดยตรง

แนวคิดนี้สอดคล้องกับ เวิร์กโฟลว์การกำหนด API ด้วย Git: contract ใน Git คือ single source of truth

วงจรการออกแบบ API แบบ Git-native

workflow พื้นฐานมี 5 ขั้นตอน:

  1. สร้าง branch
  2. แก้ไข contract
  3. commit สเปก
  4. เปิด pull request
  5. review และ merge

ตัวอย่าง: เพิ่ม endpoint สำหรับดึง invoice ของ user

git checkout -b feat/api-invoices-list
Enter fullscreen mode Exit fullscreen mode

แก้ไข openapi.yaml:

# 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
Enter fullscreen mode Exit fullscreen mode

commit ด้วยข้อความที่ชัดเจน:

git add api/openapi.yaml
git commit -m "Add GET /users/{userId}/invoices contract"
Enter fullscreen mode Exit fullscreen mode

จากนั้นเปิด PR ให้ทีมตรวจสอบ:

  • path เหมาะสมหรือไม่
  • operationId สอดคล้องกับ convention หรือไม่
  • status enum ครบหรือเกินจำเป็นหรือไม่
  • response 404 เหมาะกับกรณี user ไม่พบหรือไม่
  • ต้องมี pagination หรือไม่

เมื่อ PR ถูก approve และ merge แล้ว implementation จึงค่อยตามมา นี่คือแกนของ การพัฒนา API แบบ spec-first: ตกลง contract ก่อนเขียนโค้ด

กลยุทธ์การแตก branch สำหรับ API contract

ใช้ branch ขนาดเล็ก หนึ่ง branch ควรแทนหนึ่งการเปลี่ยนแปลงเชิงตรรกะ เช่น endpoint ใหม่หนึ่งตัว หรือ schema change หนึ่งชุด

ประเภทการเปลี่ยนแปลง คำนำหน้า branch ตัวอย่าง น้ำหนักการ review
Endpoint ใหม่ feat/api- feat/api-invoices-list มาตรฐาน
เพิ่ม field feat/api- feat/api-invoice-currency เบา
Breaking change break/api- break/api-remove-legacy-id หนัก ต้องมี approval
แก้ typo หรือ bug ในสเปก fix/api- fix/api-status-enum-typo เบา
จัดระเบียบไฟล์เท่านั้น chore/api- chore/api-reorder-schemas เบา

คำนำหน้าช่วยบอก intent ให้ reviewer และ CI pipeline ได้ เช่น branch ที่ขึ้นต้นด้วย break/api- ควรถูกตรวจเข้มกว่า branch chore/api-

สำหรับทีมส่วนใหญ่ ควรใช้ trunk-based development:

โมเดล เหมาะสำหรับ ข้อแลกเปลี่ยนของ API
Trunk-based Continuous delivery, ทีมขนาดเล็กถึงกลาง diff เล็ก, merge conflict น้อย
Gitflow release เป็นรอบ, governance เข้ม branch อายุยาว, spec drift ง่าย, merge ใหญ่กว่า

ถ้าใช้ YAML ไฟล์เดียว branch อายุยาวจะทำให้ merge conflict เกิดเร็วมาก โดยเฉพาะเมื่อหลาย branch แก้ path หรือ schema ใกล้กัน

วิธี review API design ใน pull request

PR ของสเปกไม่ใช่แค่ syntax review แต่คือ design review ให้ผู้ตรวจสอบดูคำถามเหล่านี้เป็นหลัก

1. เป็น breaking change หรือไม่

ตัวอย่าง breaking change:

  • ลบ field
  • เปลี่ยนชื่อ path
  • เปลี่ยน type จาก string เป็น integer
  • ลบ enum value
  • เปลี่ยน optional field เป็น required field

ถ้าเป็น breaking change ให้เพิ่ม version, กำหนด deprecation path และขอ approval จาก API steward

2. Naming สอดคล้องหรือไม่

ตรวจสอบ convention เช่น:

  • collection path ใช้คำนามพหูพจน์หรือไม่ เช่น /invoices
  • error response ใช้ field เดียวกับ endpoint อื่นหรือไม่ เช่น code, message
  • operationId ใช้รูปแบบเดียวกันหรือไม่ เช่น listUserInvoices

3. Diff อ่านง่ายหรือไม่

จัด format ให้เสถียร:

  • เรียง key ให้เหมือนกันทุก endpoint
  • อย่า reorder ทั้งไฟล์โดยไม่จำเป็น
  • แยก ref/schema เป็นไฟล์ย่อยเมื่อไฟล์ใหญ่เกินไป
  • อย่ารวม refactor กับ semantic change ใน PR เดียวกัน

ตัวอย่าง diff ที่ reviewer อ่านได้ง่าย:

 parameters:
   - name: status
     in: query
     schema:
       type: string
-      enum: [draft, open, paid, void]
+      enum: [draft, open, paid, void, uncollectible]
Enter fullscreen mode Exit fullscreen mode

การเพิ่ม enum value มักปลอดภัยกว่า แต่ถ้า diff ลบ void ออก จะเป็น breaking change ทันทีสำหรับ client ที่ส่งค่านั้นอยู่

จาก design สู่ development

เมื่อ contract อยู่ใน main แล้ว ให้ใช้มันเป็นแหล่งสร้าง artifact ทั้งหมด

From API design to development

1. สร้าง code จากสเปก

ตัวอย่างใช้ openapi-generator:

npx @openapitools/openapi-generator-cli generate \
  -i api/openapi.yaml \
  -g typescript-fetch \
  -o generated/api-client
Enter fullscreen mode Exit fullscreen mode

หรือสร้าง server stub:

npx @openapitools/openapi-generator-cli generate \
  -i api/openapi.yaml \
  -g nodejs-express-server \
  -o generated/server
Enter fullscreen mode Exit fullscreen mode

handler ของคุณเติม business logic ส่วน shape ของ request/response ถูกกำหนดจาก contract

2. สร้าง mock server

mock server อ่าน OpenAPI แล้วตอบตาม schema/example ทำให้ frontend เริ่มทำงานได้ก่อน backend เสร็จ

แนวทางที่ดี:

  • merge contract ก่อน
  • frontend ใช้ mock จากสเปก
  • backend implement ตามสเปกเดียวกัน
  • CI ตรวจว่าทั้งสองฝั่งไม่ drift

3. เพิ่ม contract tests

contract tests ควรส่ง request จริงไปยัง server แล้ว validate response กับ schema ใน OpenAPI

สิ่งที่ควรตรวจ:

  • status code
  • response headers ที่สำคัญ
  • response body schema
  • required fields
  • enum values
  • error response format

ถ้า implementation ไม่ตรงกับสเปก ให้ pipeline fail ทันที

4. สร้างเอกสารจากสเปก

เอกสาร reference ควรถูกสร้างจาก openapi.yaml โดยตรง ไม่ควรเขียนซ้ำด้วยมือ เพราะจะ drift ได้ง่าย

หลักการคือ artifacts ทุกตัวต้องมาจากไฟล์ contract เดียวกันที่ commit แล้ว

แนวปฏิบัติที่ช่วยให้ทีม scale ได้

1. เลือกโครงสร้างไฟล์ให้เหมาะ

สำหรับ API ขนาดเล็ก ไฟล์เดียวอาจพอ:

api/
  openapi.yaml
Enter fullscreen mode Exit fullscreen mode

สำหรับ API ที่ใหญ่ขึ้น ให้แยกเป็นหลายไฟล์:

api/
  openapi.yaml
  paths/
    users.yaml
    invoices.yaml
  components/
    schemas/
      User.yaml
      Invoice.yaml
Enter fullscreen mode Exit fullscreen mode

จากนั้น bundle เป็นไฟล์เดียวในขั้นตอน build

2. ใช้ semantic versioning

อัปเดต info.version เมื่อ contract เปลี่ยนอย่างมีนัยสำคัญ:

info:
  title: Billing API
  version: 1.4.0
Enter fullscreen mode Exit fullscreen mode

แนวทางทั่วไป:

  • additive change → minor version
  • bug fix หรือ documentation fix → patch version
  • breaking change → major version และมักต้องมี path ใหม่ เช่น /v2

3. เก็บ changelog

เพิ่ม CHANGELOG.md ข้างสเปก:

# Changelog

## 1.4.0

- Add GET /users/{userId}/invoices
- Add status filter for invoices
Enter fullscreen mode Exit fullscreen mode

Git history แม่นยำ แต่ changelog อ่านง่ายกว่าสำหรับ consumer

4. ป้องกัน contract ด้วย CODEOWNERS

# .github/CODEOWNERS
/api/openapi.yaml @api-stewards
/api/paths/ @api-stewards
/api/components/ @api-stewards
Enter fullscreen mode Exit fullscreen mode

เมื่อมีคนแก้ไฟล์ contract ต้องให้ API steward approve ก่อน merge

5. ทำ lint ใน CI

ตัวอย่าง GitHub Actions ด้วย 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
Enter fullscreen mode Exit fullscreen mode

lint ช่วยจับปัญหา style และ consistency ก่อนถึง reviewer ทำให้ reviewer โฟกัสที่ design decision ได้มากขึ้น

ข้อผิดพลาดทั่วไปและวิธีหลีกเลี่ยง

1. สเปกกับโค้ดคลาดเคลื่อนกัน

ปัญหา: contract บอกอย่างหนึ่ง แต่ server ทำอีกอย่างหนึ่ง

วิธีแก้:

  • สร้าง stubs/clients จากสเปก
  • เพิ่ม contract tests ใน CI
  • fail build เมื่อ response จริงไม่ตรง schema

2. PR ใหญ่เกินไป

ปัญหา: branch เดียวเพิ่ม 20 endpoints ทำให้ reviewer อ่านไม่ไหว

วิธีแก้:

  • หนึ่ง endpoint หรือหนึ่ง behavior change ต่อ PR
  • แยก refactor ออกจาก semantic change
  • ใช้ branch อายุสั้น

3. เขียน artifacts ด้วยมือ

ปัญหา: client, docs หรือ mock ที่เขียนด้วยมือ drift จากสเปก

วิธีแก้:

  • generate clients
  • generate docs
  • generate mocks
  • ถือว่า artifact ที่เขียนมือเป็น exception ไม่ใช่ default

4. YAML merge conflict บ่อย

ปัญหา: หลาย branch แก้ไฟล์เดียวกันนานเกินไป

วิธีแก้:

  • ใช้ trunk-based workflow
  • แยกไฟล์ตาม resource
  • รักษา key order ให้เสถียร
  • merge บ่อยและเร็ว

Apidog เข้ามามีบทบาทอย่างไร

คุณสามารถทำ Git-native API workflow ได้ด้วย text editor, CLI และ CI ตามปกติ แต่บางทีมต้องการ visual designer สำหรับออกแบบ API โดยยังให้ Git เป็นแหล่งความจริงหลัก

Spec-First Mode ของ Apidog ถูกออกแบบมาเพื่อ workflow นี้: เก็บไฟล์ OpenAPI ไว้ใน Git repository และซิงค์แบบสองทาง คุณสามารถแก้ contract ใน visual designer หรือแก้ไฟล์ใน editor ก็ได้ โดยไฟล์ใน repo ยังเป็นแหล่งความจริงสำหรับ branch, PR และ history

อ่านรายละเอียดการตั้งค่าได้ที่ เอกสาร Spec-First Mode

ประเด็นสำคัญคือ GUI ไม่ควรแทนที่ Git แต่ควรเป็นอีกมุมมองหนึ่งของ contract ที่อยู่ใน repo

คำถามที่พบบ่อย

การออกแบบ API แบบ Git-native ใช้ได้กับ OpenAPI เท่านั้นหรือไม่?

ไม่จำเป็น OpenAPI เป็นรูปแบบที่พบบ่อยที่สุด แต่หลักการเดียวกันใช้ได้กับ AsyncAPI, gRPC .proto และ GraphQL SDL ตราบใดที่ contract เป็นไฟล์ข้อความที่ diff, branch และ review ได้

จะจัดการ breaking change อย่างไร?

ทำให้มองเห็นชัดเจน:

  • ใช้ branch prefix break/api-
  • เพิ่ม major version
  • ให้ API steward approve ผ่าน CODEOWNERS
  • เพิ่ม endpoint หรือ schema ใหม่ควบคู่ของเก่าเมื่อทำได้
  • กำหนด deprecation timeline

สเปกควรอยู่ repo เดียวกับโค้ดหรือไม่?

โดยทั่วไปควรอยู่ repo เดียวกัน ถ้าทีมเดียวดูแลทั้ง contract และ implementation เพราะ PR เดียวสามารถเปลี่ยนสเปกและโค้ดที่เกี่ยวข้องได้ และ contract tests ทำงานใน pipeline เดียวกัน

ใช้ repo แยกเมื่อ API เป็น shared platform ที่หลายทีม consume และต้องการ versioning แยกจาก implementation

จะป้องกัน spec/code drift ได้อย่างไร?

เพิ่ม contract tests ใน CI และสร้าง artifacts จากสเปก:

  • server stubs
  • typed clients
  • mock server
  • API docs

เมื่อสเปกกับโค้ดไม่ตรงกัน pipeline ต้อง fail ก่อน deploy

บทสรุป

การออกแบบ API แบบ Git-native คือการปฏิบัติต่อ contract เหมือนซอร์สโค้ด: เก็บใน repo, เปลี่ยนผ่าน branch, review ผ่าน PR และสร้าง artifacts จากไฟล์ที่ commit แล้ว

เริ่มจากขั้นตอนเล็ก ๆ:

  1. ย้ายสเปกเข้า repo
  2. เพิ่ม API lint ใน CI
  3. ใช้ CODEOWNERS สำหรับ contract review
  4. สร้าง clients, mocks และ docs จากสเปก
  5. เพิ่ม contract tests เพื่อกัน spec/code drift

เมื่อทำครบ ประวัติ Git ของคุณจะไม่ใช่แค่ประวัติโค้ด แต่เป็นบันทึกที่ตรวจสอบได้ว่า API เติบโตและเปลี่ยนแปลงอย่างไร לאורךเวลา

Top comments (0)