見通しの効く言語・フレームワークでスキーマ駆動開発をしたい
import "@typespec/http";
using TypeSpec.Http;
model Store {
name: string;
address: Address;
}
model Address {
street: string;
city: string;
}
@route("/stores")
interface Stores {
list(@query filter: string): Store[];
read(@path id: Store): Store;
}
tsp compile .
openapi: 3.0.0
info:
title: (title)
version: 0.0.0
tags: []
paths:
/stores:
get:
operationId: Stores_list
parameters:
- name: filter
in: query
required: true
schema:
type: string
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Store'
/stores/{id}:
get:
operationId: Stores_read
parameters:
- name: id
in: path
required: true
schema:
$ref: '#/components/schemas/Store'
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
$ref: '#/components/schemas/Store'
components:
schemas:
Address:
type: object
required:
- street
- city
properties:
street:
type: string
city:
type: string
Store:
type: object
required:
- name
- address
properties:
name:
type: string
address:
$ref: '#/components/schemas/Address'
類似ツールも検討 -> 生成されたファイルを編集する必要がない利点から採用
OpenAPI から
// ServerInterface represents all server handlers.
type ServerInterface interface {
// 認可レスポンスを検証してログインを実行
// (GET /auth/google/callback)
GoogleCallback(ctx echo.Context, params GoogleCallbackParams) error
// OIDC 認証を要求
// (GET /auth/google/login)
GoogleLogin(ctx echo.Context) error
// WIP: すべての授業情報を取得
// (GET /courses)
CoursesAll(ctx echo.Context) error
// StrictServerInterface represents all server handlers.
type StrictServerInterface interface {
// 認可レスポンスを検証してログインを実行
// (GET /auth/google/callback)
GoogleCallback(ctx context.Context, request GoogleCallbackRequestObject)
(GoogleCallbackResponseObject, error)
// OIDC 認証を要求
// (GET /auth/google/login)
GoogleLogin(ctx context.Context, request GoogleLoginRequestObject)
(GoogleLoginResponseObject, error)
// WIP: すべての授業情報を取得
// (GET /courses)
CoursesAll(ctx context.Context, request CoursesAllRequestObject)
(CoursesAllResponseObject, error)
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
router.GET(baseURL+"/auth/google/callback", wrapper.GoogleCallback)
router.GET(baseURL+"/auth/google/login", wrapper.GoogleLogin)
router.GET(baseURL+"/courses", wrapper.CoursesAll)
router.GET(baseURL+"/courses/filter-options", wrapper.CoursesFilterOptions)
router.GET(baseURL+"/courses/:courseId", wrapper.CoursesGet)
router.GET(baseURL+"/ping", wrapper.PingGet)
}
server/handler/ping.go
// PingGet - /api/v2/ping
func (s Server) PingGet(_ context.Context, _ openapi.PingGetRequestObject)
(openapi.PingGetResponseObject, error) {
// do something
return openapi.PingGet200JSONResponse{
Ok: true,
Pong: time.Now(),
}, nil
}
PingGet200JSONResponse
の型によってレスポンスの型が強制されている!
server/openapi/server.gen.go
type PingGet200JSONResponse struct {
Ok bool `json:"ok"`
// Pong 現在時刻
Pong time.Time `json:"pong"`
}
api-spec/main.tsp
@get
@summary("疎通確認")
op get(): {
@statusCode statusCode: 200;
@body pong: {
ok: boolean;
@doc("現在時刻") pong: offsetDateTime;
};
};
auth
ディレクティブに対応した機能があるgithub.com/oapi-codegen/echo-middleware
)必ず API 定義が先行するので、client / server の同時実装も可能
API 定義を書いたら自動で型が付くので開発体験が良い
Redocly を用いて生成し、Cf Pages にデプロイしています
@cookie
デコレータを追加
Discussion -> Issue -> Pull Request と段階を踏んで半月ほどかかった
ご清聴ありがとうございました
https://excalidraw.com/#json=OukVfJ3x1VDmes534x1CQ,wp4DK6gKWtDzAQGQz5dL6w