使用關鍵字 model
建立模型,模型可以在不同的操作或其他模型中重複使用,編譯時模型會輸出在 components
節點,並在各個使用的地方透過 $ref
參考。
使用 model
關鍵字建立一個名為 Member
的模型,並依照各個內容欄位設定欄位名稱、型別及說明。我個人習慣將模型獨立建立一個目錄與對應的命名空間,並一個模型建立一個 TypeSpec 檔案,範例程式碼如下:
// member/model/member-model.tsp
namespace MemberService.Member.Model;
model MemberModel {
@doc("會員 ID")
id: int64;
@doc("會員姓名")
name: string;
@doc("信箱")
email: string;
@doc("手機號碼")
phone: string;
@doc("生日")
birthday?: utcDateTime;
}
若要在 member/member.tsp
中的取得單一會員 API 使用 MemberModel
,由於 MemberModel
在不同的檔案及命名空間中,需先 import <file-path>
匯入該檔案。又因 MemberModel
所屬的命名空間為 MemberService.Member.Model
,我們可以透過以下任一方式使用 MemberModel
:
MemberService.Member.Model.MemberModel
。MemberService.Member
,補上差異的命名空間 Model.MemberModel
來指定 MemberModel
。using MemberService.Model;
後使用 MemberModel
。這邊使用最後一種做法來匯入並引用,範例程式碼如下:
// member/member.tsp
import "@typespec/http";
import "./model/member-model.tsp";
using TypeSpec.Http;
using MemberService.Member.Model;
namespace MemberService.Member;
// 以下省略
接著將原本散在取得單一會員 API 中的回傳欄位移除,改使用 MemberModel
作為 Response Body,範例程式碼如下:
// member/member.tsp
import "@typespec/http";
import "./model/member-model.tsp";
using TypeSpec.Http;
using MemberService.Member.Model;
namespace MemberService.Member;
@summary("取得單一會員")
@doc("""
這個 API 用來取得單一會員的資料。
這個 API 需要提供會員 ID,並回應該會員的基本資料。
""")
@get()
@route("members/{memberId}")
op get(@path memberId: int64): {
@statusCode _: 200;
@header `x-request-id`: string;
@body body: MemberModel;
};
將這個模型也使用在註冊會員 API 的 Request Body 和 Response Body,我們先宣告註冊會員 API 的操作 register
,並設定其他參數和回傳資訊,範例程式碼如下:
// member/member.tsp
// 以上省略
@summary("註冊會員")
@doc("""
這個 API 用來註冊新的會員。
這個 API 需要提供會員 ID、會員姓名、信箱、手機號碼和生日,並回應註冊成功的會員 ID。
""")
@post()
@route("members")
op create(@body body: MemberModel): {
@statusCode _: 200;
@header `x-request-id`: string;
@body body: MemberModel;
};
這時編譯後產生的 openapi.yaml
如下:
openapi: 3.0.0
info:
title: 會員服務
version: 1.0.0
tags: []
paths:
/_hc:
get:
operationId: healthCheck
summary: 確認服務健康狀態
description: |2-
這個 API 用來確認服務是否正常運作。
這個 API 不需要任何參數,只要回應 204 即表示服務正常。
parameters: []
responses:
'204':
description: 'There is no content to send for this request, but the headers may be useful. '
/members:
post:
operationId: Member_register
summary: 註冊會員
description: |2-
這個 API 用來註冊新的會員。
這個 API 需要提供會員 ID、會員姓名、信箱、手機號碼和生日,並回應註冊成功的會員 ID。
parameters: []
responses:
'200':
description: The request has succeeded.
headers:
x-request-id:
required: true
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Member.Model.MemberModel'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Member.Model.MemberModel'
/members/{memberId}:
get:
operationId: Member_get
summary: 取得單一會員
description: |2-
這個 API 用來取得單一會員的資料。
這個 API 需要提供會員 ID,並回應該會員的基本資料。
parameters:
- name: memberId
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: The request has succeeded.
headers:
x-request-id:
required: true
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Member.Model.MemberModel'
components:
schemas:
Member.Model.MemberModel:
type: object
required:
- id
- name
- email
- phone
properties:
id:
type: integer
format: int64
description: 會員 ID
name:
type: string
description: 會員姓名
email:
type: string
description: 信箱
phone:
type: string
description: 手機號碼
birthday:
type: string
format: date-time
description: 生日
servers:
- url: https://api.staging.example.com/v1
description: 測試環境
variables: {}
- url: https://api.example.com/v1
description: 正式環境
variables: {}
可看到 components.schemas
節點下產出了 Member.Model.MemberModel
,並在不同的地方透過 $ref: '#/components/schemas/Member.Model.MemberModel'
使用。
Redoc 預覽也可看到相同的內容如下:
明天將介紹如何透過繼承與多型的方式,讓模型可更加彈性的被使用。