typespecでSwagger v2のファイルを作成する
typespecを利用して、Swagger v2(openAPI)のschemaを生成する取り組み。
what is typespec?
Describe your data up front and generate schemas, API specifications, client / server code, docs, and more.
schemaやcode生成のための micro soft teamが開発している言語。
global install した方が初期作業は何かと便利なので、dockerを利用して環境整備します。
0. setup project
$ mkdir schema
$ cd schema
$ touch dockerfile compose.yaml
$ tree .
.
├── README.md
├── compose.yaml
├── dockerfile
compose.yaml
services:
http_schema_container:
container_name: http_schema_container
build:
context: .
dockerfile: dockerfile
tty: true
restart: always
volumes:
- .:/usr/src/app
FROM node:23-alpine3.19
WORKDIR /usr/src/app
% docker exec -it XXX sh
あとは、dockerの中でもさもさやっていきます
1. Install depenedency
typespec Installationとおなじように、作業を進めていきます。
empty projectでいくと同じ環境を作成しやすくなります。
% npm install -g @typespec/compiler
% tsp init
Folder '/usr/src/app' is not empty. Are you sure you want to initialize a new project here? … yes
✔ Please select a template › Empty project min compiler ver: 0.61.2
Create an empty project.
✔ Project name … app
✔ Do you want to generate a .gitignore file? … yes
% tsp install
% tree . -L 2 -I node_modules
.
├── README.md
├── compose.yaml
├── dockerfile
├── tspconfig.yaml
├── package-lock.json
└── package.json
2. Swagger v2を作成できる環境を作成する
2-1. とりあえず目指す環境
6. Complete Example and Generate OpenApi 2.0 specを参考に作成していきます。
build対象になる、main.tsp
を作成していきます。
% touch main.tsp
main.tsp
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 name: string): Store;
}
% tree . -L 2 -I node_modules
.
├── README.md
├── compose.yaml
├── dockerfile
├── main.tsp
├── tspconfig.yaml
├── package-lock.json
└── package.json
2-2. @azure-tools の環境を準備する
@azure-tools/typespec-autorestをinstallして、scriptを記載していきます。
% npm install @azure-tools/typespec-autorest
package.json
...
script: {
"build:http": "tsp compile .",
"setup:vsc": "tsp code install",
"format:check": "tsp format --check \"**/*.tsp\"",
"format": "tsp format \"**/*.tsp\""
}
tspconfig.yaml
warn-as-error: true
output-dir: "{cwd}/generated"
emit:
- "@azure-tools/typespec-autorest"
2-3. buildしてみる
% npm run build
> app@0.1.0 build:http
> tsp compile .
TypeSpec compiler v0.61.2
Compilation completed successfully.
% tree . -I node_modules
.
├── README.md
├── compose.yaml
├── dockerfile
├── generated
│ └── @azure-tools
│ └── typespec-autorest
│ └── openapi.json
├── main.tsp
├── tspconfig.yaml
├── package-lock.json
└── package.json
generated/@azure-tools/typespec-autorest/openapi.json
{
"swagger": "2.0",
"info": {
"title": "(title)",
"version": "0000-00-00",
"x-typespec-generated": [
{
"emitter": "@azure-tools/typespec-autorest"
}
]
},
"schemes": [
"https"
],
"produces": [
"application/json"
],
"consumes": [
"application/json"
],
"tags": [],
"paths": {
"/stores": {
"get": {
"operationId": "Stores_List",
"parameters": [
{
"name": "filter",
"in": "query",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The request has succeeded.",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Store"
},
"x-ms-identifiers": []
}
}
}
}
},
"/stores/{name}": {
"get": {
"operationId": "Stores_Read",
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The request has succeeded.",
"schema": {
"$ref": "#/definitions/Store"
}
}
}
}
}
},
"definitions": {
"Address": {
"type": "object",
"properties": {
"street": {
"type": "string"
},
"city": {
"type": "string"
}
},
"required": [
"street",
"city"
]
},
"Store": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"address": {
"$ref": "#/definitions/Address"
}
},
"required": [
"name",
"address"
]
}
},
"parameters": {}
}