typespecファイルからopen api3を生成する

# gen openapi3 from typespec

## 0. Before do

```terminal
% npm init -y
% mkdir openapi3
% tree . -L 2 -I node_modules
.
├── README.md
├── compose.yaml
├── dockerfile
├── openapi3
│   └── main.tsp
├── package-lock.json
└── package.json
```

```compose.yaml
services:
  http_schema_container:
    container_name: http_schema_container
    build:
      context: .
      dockerfile: dockerfile
    tty: true
    restart: always
    volumes:
      - .:/usr/src/app
```

```dockerfile
FROM node:23-alpine3.19

WORKDIR /usr/src/app
```

```openapi3/main.tsp
import "@typespec/http";

using TypeSpec.Http;

model Pet {
  name: string;
  age: int32;
}

model Store {
  name: string;
  address: Address;
}

model Address {
  street: string;
  city: string;
}

@route("/pets")
interface Pets {
  list(@query filter: string): Pet[];
  create(@body pet: Pet): Pet;
  read(@path id: string): Pet;
}

@route("/stores")
interface Stores {
  list(@query filter: string): Store[];
  read(@path id: string): Store;
}
```

## 1. 依存関係の設定とconfig fileの作成

### 1-1. 依存関係の設定

tspの設定とopenapi3 emitterを利用できる状況にします。

```
% npm install -D @typespec/openapi3
% npm install @typespec/compiler
```

```package.json
"scripts": {
    "cli:tsp": "tsp",
    "compile:openapi3": "tsp compile ./openapi3 --emit=@typespec/openapi3"
},
```

```terminal
% npm run compile:openapi
> app@0.1.0 compile:openapi3
> tsp compile ./openapi3 --emit=@typespec/openapi3

TypeSpec compiler v0.61.2

Compilation completed successfully.

% tree . -L 2 -I node_modules
.
├── README.md
├── compose.yaml
├── dockerfile
├── openapi3
│   └── main.tsp
├── package-lock.json
├── package.json
└── tsp-output
    └── @typespec
        └── openapi3
            └── openapi.yaml
```

```tsp-output/@typespec/openapi3/openapi.yaml
openapi: 3.0.0
info:
  title: (title)
  version: 0.0.0
tags: []
paths:
  /pets:
    get:
      operationId: Pets_list
      parameters:
        - name: filter
          in: query
          required: true
          schema:
            type: string
          explode: false
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Pet'
    post:
      operationId: Pets_create
      parameters: []
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Pet'
  /pets/{id}:
    get:
      operationId: Pets_read
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
  /stores:
    get:
      operationId: Stores_list
      parameters:
        - name: filter
          in: query
          required: true
          schema:
            type: string
          explode: false
      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:
            type: string
      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
    Pet:
      type: object
      required:
        - name
        - age
      properties:
        name:
          type: string
        age:
          type: integer
          format: int32
    Store:
      type: object
      required:
        - name
        - address
      properties:
        name:
          type: string
        address:
          $ref: '#/components/schemas/Address'
```

### 1-2. config fileの設定

```terminal
% touch openapi3/tspconfig.yaml
```

```openapi3/tspconfig.yaml
emit:
  - "@typespec/openapi3"
```

```package.json
"scripts": {
    "compile:openapi3": "tsp compile ./openapi3"
  },
```

```terminal
% npm run compile:openapi3
```

[OpenAPI3 Emitter Usage](https://typespec.io/docs/emitters/openapi3/reference/emitter)
[Configuration](https://typespec.io/docs/handbook/configuration#built-in-variables)