Open4
sqlc (go) 利用時に ts の型情報を生成してほしい
モチベーション
- sqlc を使うと SQL で書いた内容を API の JSON として返してしまう場合が多い
- emit_json_tags を true にする前提
- TODO:
omitempty
や-
の機能が欲しい
- ブラウザ -> Cloudflare Workers (TS) -> Go という構成だと、そのまま返して特に困らない
- BFF (Backend for Frontend) として Cloudflare Workers を利用する場合は SQL からの出力そのまま出すことが多い
- Buf/Connect 調べたが自分には合わなかった
何が嬉しくなるか
- Go で書かれた API を呼ぶ側、つまり TypeScript 側で型情報が利用できるようになる
課題
- バリデーションが未解決
- ReqParams 部分は SQL に直接渡せるものもあれば、渡せないモノもあるので微妙
出力イメージ
sqlc generate したタイミングで go とは別に ts の型情報を出力する。
type GetProjectFromIdParams struct {
ID string `json:"id"`
}
type GetProjectFromIdRow struct {
Pk int64 `json:"pk"`
ID string `json:"id"`
OrgPk int32 `json:"org_pk"`
OrgID uuid.UUID `json:"org_id"`
DisplayName string `json:"display_name"`
Disabled bool `json:"disabled"`
Deleted bool `json:"deleted"`
CreatedAt time.Time `json:"created_at"`
}
という struct がある場合、これらの TS の型をそのまま定義して欲しい。
type GetProjectFromIdParams = {
id: string
}
type GetProjectFromIdRow = {
pk: number
id: string
orgPk number
orgId: string
displayName: string
disabled: boolean
deleted: boolean
createdAt: string
}
- plugin では types の出力場所を指定できるようにして欲しい
- types.d.ts に全部入ってしまえば良さそう
利用イメージ
- type.d.ts をインポートして利用する。typescript の types に指定して利用するイメージか
- イメージはシンプルなワーカー実装にしているが実際は Remix などのフレームワークを利用している
- fetch で API を取ってきて、色々処理してから、React でレンダリングする
// from は適当
import type {
GetProjectFromIdParams,
GetProjectFromIdRow
} from '~/gen/sqlc/types'
import type {
Request as WorkerRequest,
ExecutionContext,
} from '@cloudflare/workers-types/experimental'
export default {
async fetch(request: WorkerRequest, env: Env, context: ExecutionContext): Promise<Response> {
return handleRequest(request, env)
},
}
const handleRequest = async (request: WorkerRequest, env: Env): Promise<Response> => {
const reqParams: GetProjectFromIdParams = { id: 'spam' }
const res = await fetch('/api/get-project-from-id', {
method: 'POST',
body: JSON.stringify(reqParams),
})
const { id, orgId } = await res.json<GetProjectFromIdRow>()
return new Response(JSON.stringify({ id, orgId }), { status: 200 })
}
sqlc-rpc
かなり雑な妄想
- 一歩進めれば sqlc-rpc が作れそう
- あくまで BFF がある前提になる
-
DynamoDB や Route53 などの AWS API が独特な仕様なので紹介
- ヘッダーベースを利用すれば URL を考えなくて良くなる
- Go 側どうするんだ、という話がある
export const getProjectFromId = async (reqParams: GetProjectFromIdParams): Promise<GetProjectFromIdRow> => {
const resp = await fetch("/rpc", {method: "POST", headers: {
"content-type": "application/json",
"x-sqlc-target": "SpamRPC_20230814.GetProjectFromId"
}, body: JSON.stringify(reqParams)})
return await resp.json<GetProjectFromIdRow>()
}
const { id, orgId } = await rpc.getProjectFromId({id: 'spam'})