#การเขียน API Specification ด้วย OpenAPI

API ที่ดีไม่ควรเริ่มจากการเขียน Controller ก่อนเสมอไป แต่ควรเริ่มจากการกำหนด ข้อตกลงของ API (API Contract) ให้ชัดเจนว่า Client จะเรียกอะไร ส่งข้อมูลแบบใด และ Server จะตอบกลับอย่างไร

แนวทางที่นิยมมากที่สุดสำหรับ HTTP API คือ OpenAPI Specification (OAS) ซึ่งเป็นมาตรฐานแบบไม่ผูกกับภาษาโปรแกรมสำหรับอธิบายความสามารถและโครงสร้างของ HTTP API โดยสามารถเขียนได้ทั้ง YAML และ JSON

ณ วันที่ 21 กันยายน 2026 OpenAPI Specification รุ่นล่าสุดคือ 3.2.1 ซึ่งเผยแพร่เมื่อ 10 กันยายน 2026


#1. API Specification คืออะไร

API Specification คือเอกสารเชิงโครงสร้างที่กำหนดรายละเอียดของ API อย่างชัดเจน เช่น

  • Base URL หรือ Server URL
  • Endpoint หรือ Path
  • HTTP Method เช่น GET, POST, PUT, PATCH, DELETE
  • Path Parameter และ Query Parameter
  • Header
  • Request Body
  • Response Body
  • HTTP Status Code
  • Data Schema
  • Authentication / Authorization
  • Error Response
  • ตัวอย่าง Request และ Response

ตัวอย่าง API แบบง่าย

GET /api/users/1001

ผลลัพธ์

{
  "id": 1001,
  "name": "Somchai",
  "email": "somchai@example.com"
}

API Specification จะเพิ่มรายละเอียดว่า 1001 คือ parameter ชนิดใด, endpoint นี้ตอบ status code อะไรได้บ้าง, response มี field อะไร และ field ใดจำเป็น


#2. API Documentation กับ API Specification ต่างกันอย่างไร

หัวข้อ API Documentation API Specification
เป้าหมายหลัก อธิบายวิธีใช้ API ให้คนอ่าน กำหนด contract ที่คนและเครื่องมืออ่านได้
รูปแบบ Markdown, HTML, Wiki YAML/JSON ตามมาตรฐาน เช่น OpenAPI
ใช้สร้าง Mock Server อาจไม่ได้ ได้
ใช้สร้าง Client SDK จำกัด ได้
ใช้ตรวจสอบ Request/Response จำกัด ได้
ใช้สร้าง Interactive Docs ต้องทำเพิ่ม สร้างต่อได้จาก specification

ในระบบจริงควรมีทั้งสองส่วน โดยใช้ OpenAPI เป็น source of truth แล้วสร้าง documentation จาก specification


#3. Contract-First และ Code-First

#Contract-First / Design-First

ออกแบบ API Specification ก่อนเขียน implementation

Business Requirement
        ↓
API Design
        ↓
OpenAPI Specification
        ↓
Review Contract
        ↓
Mock / Client / Test
        ↓
Implementation

เหมาะกับทีมที่มี Frontend, Backend, Mobile, QA หรือระบบภายนอกทำงานคู่ขนานกัน

#Code-First

เขียน source code ก่อน แล้วใช้ framework สร้าง OpenAPI document จาก annotation, decorator หรือ metadata

Source Code
    ↓
Framework Metadata
    ↓
OpenAPI Specification
    ↓
API Documentation

เหมาะกับโปรเจกต์ขนาดเล็กหรือทีมที่ implementation เป็นศูนย์กลาง แต่ต้องระวัง specification กลายเป็นผลพลอยได้แทนที่จะเป็น contract ที่ได้รับการออกแบบ


#4. โครงสร้าง OpenAPI พื้นฐาน

ตัวอย่าง OpenAPI 3.2.1

openapi: 3.2.1
info:
  title: User API
  version: 1.0.0
  description: API สำหรับจัดการข้อมูลผู้ใช้

servers:
  - url: https://api.example.com/v1

paths:
  /users:
    get:
      summary: Get users
      responses:
        '200':
          description: Successful response

องค์ประกอบสำคัญ ได้แก่

openapi
info
servers
paths
components
security
webhooks

#5. openapi

กำหนดเวอร์ชันของ OpenAPI Specification ที่เอกสารนี้ใช้

openapi: 3.2.1

อย่าสับสนกับ version ของ API เช่น v1 หรือ 1.0.0


#6. info

ใช้ระบุ metadata ของ API

info:
  title: Product API
  version: 1.0.0
  summary: Product Management API
  description: |
    REST API สำหรับจัดการสินค้า

    รองรับการสร้าง อ่าน แก้ไข และลบข้อมูลสินค้า

ควรมีอย่างน้อย

  • ชื่อ API
  • เวอร์ชันของเอกสาร/API contract
  • คำอธิบายหน้าที่ของ API

#7. servers

กำหนด URL ที่สามารถเรียก API ได้

servers:
  - url: https://api.example.com/v1
    description: Production

  - url: https://staging-api.example.com/v1
    description: Staging

  - url: http://localhost:8080/api/v1
    description: Local development

ช่วยให้ Swagger UI หรือ API tools สามารถเลือก environment ได้ง่าย


#8. paths

paths คือหัวใจของ API Specification เพราะใช้กำหนด endpoint และ operation

paths:
  /users:
    get:
      summary: Get all users
    post:
      summary: Create user

  /users/{id}:
    get:
      summary: Get user by ID
    put:
      summary: Update user
    delete:
      summary: Delete user

การออกแบบ Resource URL ควรใช้คำนามมากกว่าคำกริยา

แนะนำ

GET    /users
GET    /users/{id}
POST   /users
PUT    /users/{id}
PATCH  /users/{id}
DELETE /users/{id}

หลีกเลี่ยงถ้าไม่จำเป็น

GET  /getUsers
POST /createUser
POST /deleteUser

HTTP Method มีความหมายของ action อยู่แล้ว


#9. operationId

กำหนดชื่อ operation ที่ไม่ซ้ำกัน

/users:
  get:
    operationId: listUsers
/users/{id}:
  get:
    operationId: getUserById

operationId มีประโยชน์มากสำหรับ

  • Client SDK generation
  • API testing
  • AI/Agent tool calling
  • Logging / tracing
  • การอ้างอิง operation จาก tooling

ควรตั้งชื่อให้สม่ำเสมอ เช่น

listUsers
getUserById
createUser
updateUser
patchUser
removeUser

#10. Path Parameter

ตัวอย่าง endpoint

GET /users/{id}

OpenAPI

/users/{id}:
  get:
    summary: Get user by ID
    parameters:
      - name: id
        in: path
        required: true
        description: User ID
        schema:
          type: integer
          minimum: 1

Path parameter ต้องระบุ required: true


#11. Query Parameter

ตัวอย่าง

GET /users?page=1&limit=20&status=active

Specification

parameters:
  - name: page
    in: query
    schema:
      type: integer
      minimum: 1
      default: 1

  - name: limit
    in: query
    schema:
      type: integer
      minimum: 1
      maximum: 100
      default: 20

  - name: status
    in: query
    schema:
      type: string
      enum:
        - active
        - inactive

ควรกำหนด validation constraint ให้ชัด เช่น minimum, maximum, enum, pattern


#12. Header Parameter

ตัวอย่าง custom header

parameters:
  - name: X-Correlation-ID
    in: header
    required: false
    schema:
      type: string

Correlation ID มีประโยชน์สำหรับ distributed tracing และการค้นหา request ข้าม service

Header ที่เป็นกลไก authentication โดยทั่วไปควรประกาศผ่าน securitySchemes แทนการสร้าง Authorization header เป็น parameter ธรรมดา


#13. Request Body

ตัวอย่าง API

POST /users

Request

{
  "name": "Somchai",
  "email": "somchai@example.com"
}

OpenAPI

requestBody:
  required: true
  content:
    application/json:
      schema:
        type: object
        required:
          - name
          - email
        properties:
          name:
            type: string
            minLength: 2
            maxLength: 100
          email:
            type: string
            format: email

#14. Response

ทุก operation ต้องกำหนด response ที่เป็นไปได้อย่างเหมาะสม

responses:
  '200':
    description: Successful response

  '400':
    description: Invalid request

  '401':
    description: Authentication required

  '404':
    description: Resource not found

  '500':
    description: Internal server error

อย่าระบุเพียง 200 หาก API มี failure mode ที่ผู้ใช้งานจำเป็นต้องจัดการ


#15. HTTP Status Code ที่ใช้บ่อย

Status ความหมาย ตัวอย่าง
200 OK อ่านหรือแก้ไขข้อมูลสำเร็จ
201 Created สร้าง resource สำเร็จ
202 Accepted รับงานแล้ว แต่ประมวลผลแบบ asynchronous
204 No Content สำเร็จแต่ไม่มี response body
400 Bad Request request ไม่ถูกต้อง
401 Unauthorized ยังไม่ได้ยืนยันตัวตนหรือ credential ไม่ถูกต้อง
403 Forbidden ยืนยันตัวตนแล้วแต่ไม่มีสิทธิ์
404 Not Found ไม่พบ resource
409 Conflict ข้อมูลขัดแย้งกับสถานะปัจจุบัน
422 Unprocessable Content รูปแบบอ่านได้แต่ข้อมูลไม่ผ่าน business/semantic validation
429 Too Many Requests เกิน rate limit
500 Internal Server Error server เกิดข้อผิดพลาด
503 Service Unavailable service ไม่พร้อมให้บริการชั่วคราว

#16. Response Schema

responses:
  '200':
    description: User found
    content:
      application/json:
        schema:
          type: object
          required:
            - id
            - name
            - email
          properties:
            id:
              type: integer
            name:
              type: string
            email:
              type: string
              format: email

ควรกำหนด schema ให้ละเอียดเพียงพอที่ client สามารถสร้าง model และ test ได้โดยไม่ต้องเดา


#17. components และการใช้ $ref

หาก schema ถูกใช้ซ้ำหลาย endpoint ไม่ควรเขียนซ้ำทุกจุด

components:
  schemas:
    User:
      type: object
      required:
        - id
        - name
        - email
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
          format: email

นำกลับมาใช้ด้วย $ref

schema:
  $ref: '#/components/schemas/User'

ช่วยลด duplication และลดความเสี่ยงที่ schema แต่ละ endpoint ไม่ตรงกัน


#18. แยก Request และ Response Model

ในระบบจริง UserCreate กับ User มักไม่ควรใช้ schema เดียวกัน

components:
  schemas:
    UserCreate:
      type: object
      required:
        - name
        - email
      properties:
        name:
          type: string
        email:
          type: string
          format: email

    User:
      type: object
      required:
        - id
        - name
        - email
        - createdAt
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
          format: email
        createdAt:
          type: string
          format: date-time

เพราะ Client ไม่ควรส่ง id หรือ createdAt ตอนสร้าง user หาก Server เป็นผู้กำหนดค่าเหล่านี้


#19. Error Response ที่สม่ำเสมอ

ควรกำหนดรูปแบบ error กลางของระบบ

{
  "code": "USER_NOT_FOUND",
  "message": "User was not found",
  "traceId": "01JXYZ..."
}

Schema

components:
  schemas:
    ErrorResponse:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          examples:
            - USER_NOT_FOUND
        message:
          type: string
        traceId:
          type: string

นำไปใช้

'404':
  description: User not found
  content:
    application/json:
      schema:
        $ref: '#/components/schemas/ErrorResponse'

#20. Bearer Token Authentication

กำหนด Security Scheme

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

กำหนดให้ใช้ทั้ง API

security:
  - bearerAuth: []

หรือกำหนดเฉพาะ endpoint

/users:
  get:
    security:
      - bearerAuth: []

#21. API Key

components:
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key

ใช้งาน

security:
  - apiKeyAuth: []

#22. Pagination

Specification ที่ดีควรกำหนด pagination contract ให้ชัดเจน

Request

GET /users?page=2&limit=20

Response

{
  "items": [],
  "page": 2,
  "limit": 20,
  "totalItems": 158,
  "totalPages": 8
}

OpenAPI Schema

UserListResponse:
  type: object
  required:
    - items
    - page
    - limit
    - totalItems
    - totalPages
  properties:
    items:
      type: array
      items:
        $ref: '#/components/schemas/User'
    page:
      type: integer
    limit:
      type: integer
    totalItems:
      type: integer
    totalPages:
      type: integer

สำหรับข้อมูลจำนวนมาก อาจพิจารณา cursor-based pagination เช่น cursor และ nextCursor


#23. Filtering และ Sorting

ตัวอย่าง

GET /products?category=notebook&minPrice=10000&sort=-price

ควรกำหนด semantics ให้ชัด เช่น

sort=price       → ราคาเรียงจากน้อยไปมาก
sort=-price      → ราคาเรียงจากมากไปน้อย

Specification

- name: sort
  in: query
  schema:
    type: string
    enum:
      - price
      - -price
      - name
      - -name

#24. ตัวอย่าง Request และ Response

ตัวอย่างช่วยทั้ง Developer, Tester และผู้ใช้ documentation

content:
  application/json:
    schema:
      $ref: '#/components/schemas/User'
    examples:
      - id: 1001
        name: Somchai
        email: somchai@example.com

ใน OpenAPI 3.2 การใช้ JSON Schema keyword examples เหมาะกว่าการพึ่ง field example แบบเดิมใน Schema Object


#25. API Versioning

ตัวอย่าง URL versioning

https://api.example.com/v1/users

หรือ media type / header versioning ตามสถาปัตยกรรมที่ทีมกำหนด

สิ่งสำคัญคือ กำหนด policy ให้ชัดและใช้สม่ำเสมอ รวมถึงกติกา deprecation และ migration


#26. Naming Convention

ตัวอย่างแนวทาง

/users
/users/{userId}
/orders/{orderId}/items

JSON field

{
  "firstName": "Somchai",
  "lastName": "Jaidee"
}

ควรเลือก convention เช่น camelCase หรือ snake_case เพียงแบบเดียวใน API เดียวกัน


#27. ตัวอย่าง OpenAPI Specification ฉบับใช้งานได้

openapi: 3.2.1

info:
  title: User Management API
  version: 1.0.0
  summary: REST API สำหรับจัดการข้อมูลผู้ใช้

servers:
  - url: https://api.example.com/v1
    description: Production
  - url: http://localhost:8080/api/v1
    description: Local

tags:
  - name: Users
    description: User management operations

security:
  - bearerAuth: []

paths:
  /users:
    get:
      tags: [Users]
      operationId: listUsers
      summary: Get users
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: List of users
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserListResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

    post:
      tags: [Users]
      operationId: createUser
      summary: Create user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserCreate'
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          description: Email already exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /users/{userId}:
    parameters:
      - name: userId
        in: path
        required: true
        schema:
          type: integer
          minimum: 1

    get:
      tags: [Users]
      operationId: getUserById
      summary: Get user by ID
      responses:
        '200':
          description: User found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

    patch:
      tags: [Users]
      operationId: updateUser
      summary: Update part of a user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserUpdate'
      responses:
        '200':
          description: User updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags: [Users]
      operationId: deleteUser
      summary: Delete user
      responses:
        '204':
          description: User deleted
        '404':
          $ref: '#/components/responses/NotFound'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

  schemas:
    UserCreate:
      type: object
      required:
        - name
        - email
      properties:
        name:
          type: string
          minLength: 2
          maxLength: 100
          examples:
            - Somchai Jaidee
        email:
          type: string
          format: email
          examples:
            - somchai@example.com

    UserUpdate:
      type: object
      properties:
        name:
          type: string
          minLength: 2
          maxLength: 100
        email:
          type: string
          format: email

    User:
      type: object
      required:
        - id
        - name
        - email
        - createdAt
      properties:
        id:
          type: integer
          examples:
            - 1001
        name:
          type: string
          examples:
            - Somchai Jaidee
        email:
          type: string
          format: email
          examples:
            - somchai@example.com
        createdAt:
          type: string
          format: date-time
          examples:
            - '2026-09-21T10:30:00Z'

    UserListResponse:
      type: object
      required:
        - items
        - page
        - limit
        - totalItems
        - totalPages
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/User'
        page:
          type: integer
        limit:
          type: integer
        totalItems:
          type: integer
        totalPages:
          type: integer

    ErrorResponse:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
        message:
          type: string
        traceId:
          type: string

  responses:
    BadRequest:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

    Unauthorized:
      description: Authentication required
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

#28. แยก Specification เป็นหลายไฟล์

เมื่อ API ใหญ่ขึ้น ไม่ควรรวมทุกอย่างไว้ในไฟล์เดียว

ตัวอย่างโครงสร้าง

openapi/
├── openapi.yaml
├── paths/
│   ├── users.yaml
│   ├── products.yaml
│   └── orders.yaml
├── schemas/
│   ├── user.yaml
│   ├── product.yaml
│   └── error.yaml
└── responses/
    └── common.yaml

ตัวอย่าง $ref

schema:
  $ref: './schemas/user.yaml'

เหมาะกับ API ที่มีหลาย resource และหลายทีมดูแล


#29. API Specification กับ Swagger

คำว่า OpenAPI และ Swagger มักถูกใช้ปะปนกัน

  • OpenAPI Specification = มาตรฐานสำหรับอธิบาย HTTP API
  • Swagger UI = เครื่องมือแสดง interactive API documentation
  • Swagger Editor = เครื่องมือช่วยเขียน/ตรวจ OpenAPI
  • Swagger Codegen = เครื่องมือ generate client/server code

ดังนั้นไฟล์ที่เราเขียนคือ OpenAPI document ส่วน Swagger เป็นหนึ่งใน ecosystem ของเครื่องมือที่ใช้กับ OpenAPI


#30. API Specification กับ Postman

OpenAPI document สามารถนำไปใช้เป็นต้นทางของงาน API ได้หลายด้าน เช่น

OpenAPI Specification
      │
      ├── API Documentation
      ├── Postman Collection
      ├── Mock Server
      ├── Client SDK
      ├── Contract Testing
      └── Automated Testing

ช่วยลดการเขียนข้อมูล endpoint ซ้ำในหลายระบบ


#31. API Specification กับ API Testing

หาก specification ระบุว่า

email:
  type: string
  format: email

และ

required:
  - name
  - email

Tester สามารถสร้าง test ได้ทันที เช่น

1. ไม่มี email → ต้องถูก reject
2. email format ผิด → ต้องถูก reject
3. name สั้นกว่าค่าที่กำหนด → ต้องถูก reject
4. request ถูกต้อง → ได้ 201
5. email ซ้ำ → ได้ 409

จึงสามารถใช้ API Specification เป็นฐานของ Contract Testing และ test case design ได้


#32. ใช้ใน CI/CD

ตัวอย่าง pipeline

Developer
   ↓
Modify openapi.yaml
   ↓
Git Push / Pull Request
   ↓
Lint Specification
   ↓
Validate Contract
   ↓
Run API / Contract Tests
   ↓
Generate Documentation
   ↓
Deploy

แนวคิดนี้ช่วยตรวจ breaking change ได้ก่อน deploy production


#33. Best Practices

  1. กำหนด API contract ก่อน implementation เมื่อทีมทำงานหลายส่วนร่วมกัน
  2. ใช้ resource-oriented URL เช่น /users/{id}
  3. กำหนด request และ response schema ให้ละเอียด
  4. ระบุ status code ทั้ง success และ failure ที่สำคัญ
  5. ใช้ $ref ลด schema ซ้ำ
  6. แยก Create/Update/Response model เมื่อความหมายต่างกัน
  7. กำหนด Error Response กลาง
  8. ใส่ตัวอย่างข้อมูลที่สมจริงแต่ไม่ใช้ข้อมูลลับ
  9. กำหนด security scheme อย่างชัดเจน
  10. กำหนด pagination/filtering/sorting contract ให้แน่นอน
  11. ตั้ง operationId ให้ unique และสม่ำเสมอ
  12. lint specification ใน CI
  13. เก็บ specification ใน version control
  14. review breaking changes ผ่าน Pull Request
  15. อย่าใส่ secret, production token หรือข้อมูลส่วนบุคคลจริงใน examples

#34. Checklist ก่อนเผยแพร่ API Specification

[ ] มี title และ version
[ ] ระบุ server/environment ถูกต้อง
[ ] ทุก path ใช้ resource naming ที่สม่ำเสมอ
[ ] ทุก operation มี operationId
[ ] Path parameter ระบุ required: true
[ ] Query parameter มี type และ constraint
[ ] Request body มี schema
[ ] Response มี schema
[ ] ระบุ success status code ถูกต้อง
[ ] ระบุ 4xx/5xx ที่ client ต้องจัดการ
[ ] Error format สม่ำเสมอ
[ ] Authentication/Authorization ถูกระบุ
[ ] Reusable schema ใช้ components + $ref
[ ] มี examples
[ ] ไม่มี secret หรือข้อมูลจริงที่ไม่ควรเผยแพร่
[ ] Specification ผ่าน validator/linter
[ ] Contract ตรงกับ implementation

#35. Workflow ที่แนะนำสำหรับทีมพัฒนา

Requirement
    ↓
API Contract
    ↓
OpenAPI Specification
    ↓
Team Review
    ↓
Mock API
    ↓
Frontend / Backend / QA ทำงานคู่ขนาน
    ↓
Implementation
    ↓
Contract + Integration Testing
    ↓
Documentation
    ↓
CI/CD

ข้อดีสำคัญคือ Frontend หรือ Mobile ไม่จำเป็นต้องรอ Backend เสร็จทั้งหมดก่อนเริ่มพัฒนา และ QA สามารถออกแบบ test case จาก contract ได้ตั้งแต่ต้น


#36. สรุป

การเขียน API Specification ไม่ใช่เพียงการทำเอกสารประกอบ API แต่เป็นการสร้าง สัญญาระหว่างผู้ให้บริการ API กับผู้เรียกใช้ API

OpenAPI ทำให้สัญญานี้สามารถอ่านได้ทั้งโดยมนุษย์และเครื่องมือ จึงนำไปต่อยอดได้กับ

API Design
Documentation
Mocking
Client SDK
Validation
API Testing
Contract Testing
Security Review
CI/CD
AI / Agent Tool Integration

หากทีมกำหนด specification ให้ชัดก่อนเริ่ม implementation จะช่วยลดความเข้าใจคลาดเคลื่อนระหว่าง Frontend, Backend, Mobile, QA และผู้ใช้ API ภายนอก รวมทั้งทำให้ API สามารถตรวจสอบและพัฒนาแบบอัตโนมัติได้มากขึ้น


#แหล่งอ้างอิง