iT邦幫忙

2024 iThome 鐵人賽

DAY 6
0
IT 管理

我要成為文件工程師── Web API 文件撰寫系列 第 6

[Day 06] OpenAPI:標準的 API 描述技術規範(五)

  • 分享至 

  • xImage
  •  

一般在做 API 設計時,都會盡量收斂設計,期望一組 API 不用太多支,每支 API 參數和欄位不要太複雜,希望這些 API 可以像最經典的樂高積木一樣小而巧,使用者可以自由組合 API 積木做出各式各樣的應用。然而現實世界中,總是會遇到種種原因出現錯綜複雜的 API 設計,同一支 API 要收幾十個參數,回傳又有百百種。

在過往經驗裡,通常是因為參數要同時有多個選項,而每個選項又有複數個子選項要一起進行設定,於是條列了大量的參數,又加上許多文字描述各種排列組合,導致文件難以閱讀。延伸前幾日的會員服務為例,會員允許多種登入方式,而透過不同的登入方式會有不同的註冊資訊組合,包含:以使用者名稱和密碼註冊(有使用者名稱和密碼兩個欄位)、以 Email 和密碼註冊(有 Email 和密碼兩個欄位)、和使用三方登入(只有一個外部 ID)。這時若條列註冊會員的參數,會得到這樣的資料結構:

components:
  schemas:
    Member:
      type: object
      properties:
        memberId:
          type: string
        account:
          type: object
          properties:
            username:
              type: string
              description: 使用者名稱,以使用者名稱註冊時必填
            email:
              type: string
              format: email
              description: 電子郵件地址,以 Email 註冊時必填
            password:
              type: string
              format: password
              description: 密碼,以使用者名稱或 Email 註冊時必填
            thirdPartyId:
              type: string
              description: 第三方服務 ID,以第三方服務註冊時必填
        name:
          type: string
        createdAt:
          type: string
          format: date-time

可以看到文件中 description 描述了各種場景對應的規則,這時我們可以視需求使用 oneOfanyOfallOf 來描述這類多型的結構。首先先說明這三個關鍵字的定義:

  • oneOf:必須符合其中一個列出的 schema,且不符合其他的 schema。
  • anyOf:必須符合其中一個以上列出的 schema。
  • allOf:必須符合所有列出的 schema。
components:
  schemas:
    A:
      type: object
      properties:
        a:
          type: string
        somethingElse:
          type: string
    B:
      type: object
      properties:
        b:
          type: string
    Example1:
      oneOf:
        - $ref: '#/components/schemas/A'
        - $ref: '#/components/schemas/B'
    Example2:
      anyOf:
        - $ref: '#/components/schemas/A'
        - $ref: '#/components/schemas/B'
    Example3:
      allOf:
        - $ref: '#/components/schemas/A'
        - $ref: '#/components/schemas/B'

在範例文件中,Example1 結構可以是 {"a":"A"}{"b":"B"},但不可以是 {"a":"A", "b":"B"}Example2 結構可以是 {"a":"A"}{"b":"B"},也可以是 {"a":"A", "b":"B"};而 Example3 結構則必須是 {"a":"A", "b":"B"},不可以是 {"a":"A"} 也不可以是 {"b":"B"}。套用到前面的會員註冊範例,我們可以使用 anyOf 將結構改寫如下:

components:
  schemas:
    UsernameAccount:
      type: object
      properties:
        username:
          type: string
        password:
          type: string
          format: password
      required:
        - username
        - password
    EmailAccount:
      type: object
      properties:
        email:
          type: string
          format: email
        password:
          type: string
          format: password
      required:
        - email
        - password
    ThirdPartyAccount:
      type: object
      properties:
        thirdPartyId:
          type: string
      required:
        - thirdPartyId
    Member:
      type: object
      properties:
        memberId:
          type: string
        account:
          anyof:
            - $ref: '#/components/schemas/UsernameAccount'
            - $ref: '#/components/schemas/EmailAccount'
            - $ref: '#/components/schemas/ThirdPartyAccount'
        name:
          type: string
        createdAt:
          type: string
          format: date-time

此時在 Redoc 上 account 欄位會呈現出三個結構名稱,點選後會切換顯示:

https://ithelp.ithome.com.tw/upload/images/20240919/20151137Qkqj5F0Y1a.png

https://ithelp.ithome.com.tw/upload/images/20240919/201511378HBctlDgwJ.png

https://ithelp.ithome.com.tw/upload/images/20240919/20151137D0awjA7bie.png

以上是 OpenAPI 的基本介紹,由於只挑選了部份我認為重要的項目出來分享,更多細節及功能請參考 OpenAPI 官網

身為懶惰工程師的一員,能少打一個字就少打一個字,手刻 yaml 或 json 寫文件實在太難以忍受!明天,將介紹如何透過 DSL 語言 TypeSpec 減輕撰寫 OpenAPI 文件的負擔。


上一篇
[Day 05] OpenAPI:標準的 API 描述技術規範(四)
下一篇
[Day 07] TypeSpec:撰寫 OpenAPI 的領域特定語言 (一)
系列文
我要成為文件工程師── Web API 文件撰寫12
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言