Skip to content

Commit dd5821c

Browse files
committed
スクラップ用にコミット
1 parent f863c8c commit dd5821c

File tree

4 files changed

+217
-10
lines changed

4 files changed

+217
-10
lines changed

package-lock.json

Lines changed: 39 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
{
2-
"name": "example-ts-open-api-with-next",
2+
"name": "example-generate-openapi3-docs",
33
"version": "0.1.0",
44
"private": true,
55
"scripts": {
66
"dev": "next dev",
77
"build": "next build",
88
"start": "next start",
9+
"generate-docs": "node src/schemas/task-schema.ts",
910
"lint": "eslint"
1011
},
1112
"dependencies": {
13+
"@asteasolutions/zod-to-openapi": "^8.1.0",
14+
"next": "16.0.0",
15+
"openapi3-ts": "^4.5.0",
1216
"react": "19.2.0",
1317
"react-dom": "19.2.0",
14-
"next": "16.0.0"
18+
"zod": "^4.1.12"
1519
},
1620
"devDependencies": {
17-
"typescript": "^5",
21+
"@tailwindcss/postcss": "^4",
1822
"@types/node": "^20",
1923
"@types/react": "^19",
2024
"@types/react-dom": "^19",
21-
"@tailwindcss/postcss": "^4",
22-
"tailwindcss": "^4",
2325
"eslint": "^9",
24-
"eslint-config-next": "16.0.0"
26+
"eslint-config-next": "16.0.0",
27+
"tailwindcss": "^4",
28+
"typescript": "^5"
2529
}
2630
}

public/openapi-docs.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
openapi: 3.0.0
2+
info:
3+
version: 1.0.0
4+
title: My API
5+
description: This is the API
6+
servers:
7+
- url: v1
8+
components:
9+
schemas:
10+
Task:
11+
type: object
12+
properties:
13+
id:
14+
type: string
15+
example: "1212121"
16+
name:
17+
type: string
18+
example: Example Task
19+
completed:
20+
type: boolean
21+
example: false
22+
required:
23+
- id
24+
- name
25+
- completed
26+
parameters: {}
27+
paths:
28+
/api/tasks:
29+
get:
30+
tags:
31+
- task
32+
summary: タスク取得
33+
description: 登録されているタスクを返却します
34+
responses:
35+
"200":
36+
description: タスクの取得成功
37+
content:
38+
application/json:
39+
schema:
40+
$ref: "#/components/schemas/Task"
41+
post:
42+
tags:
43+
- task
44+
summary: タスク登録
45+
description: タスクを登録します
46+
requestBody:
47+
content:
48+
application/json:
49+
schema:
50+
allOf:
51+
- $ref: "#/components/schemas/Task"
52+
- properties:
53+
name:
54+
type: string
55+
example: Example Task
56+
required:
57+
- name
58+
responses:
59+
"200":
60+
description: タスクの取得成功
61+
content:
62+
application/json:
63+
schema:
64+
$ref: "#/components/schemas/Task"

src/schemas/task-schema.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import {extendZodWithOpenApi, OpenApiGeneratorV3, OpenAPIRegistry} from '@asteasolutions/zod-to-openapi';
2+
import { z } from 'zod';
3+
import * as yaml from 'yaml';
4+
import * as fs from 'fs';
5+
import path from "node:path";
6+
7+
extendZodWithOpenApi(z);
8+
9+
export const registry = new OpenAPIRegistry();
10+
11+
/*
12+
- GET /api/tasks - タスク取得
13+
*/
14+
const TaskResponseSchema = z
15+
.object({
16+
id: z.string().openapi({ example: '1212121' }),
17+
name: z.string().openapi({ example: 'Example Task' }),
18+
completed: z.boolean().openapi({ example: false }),
19+
})
20+
.openapi('Task');
21+
22+
registry.registerPath({
23+
method: "get",
24+
path: "/api/tasks",
25+
tags: ["task"],
26+
summary: "タスク取得",
27+
description: "登録されているタスクを返却します",
28+
request: {},
29+
responses: {
30+
200: {
31+
description: "タスクの取得成功",
32+
content: {
33+
"application/json": {
34+
schema: TaskResponseSchema,
35+
},
36+
},
37+
},
38+
},
39+
});
40+
41+
/*
42+
- POST /api/tasks - タスク登録
43+
*/
44+
const CreateTaskSchema = z
45+
.object({
46+
name: z.string().openapi({ example: 'Example Task' }),
47+
}).openapi('Task');
48+
49+
registry.registerPath({
50+
method: "post",
51+
path: "/api/tasks",
52+
tags: ["task"],
53+
summary: "タスク登録",
54+
description: "タスクを登録します",
55+
request: {
56+
body: {
57+
content: {
58+
"application/json": {
59+
schema: CreateTaskSchema,
60+
},
61+
},
62+
},
63+
},
64+
responses: {
65+
200: {
66+
description: "タスクの取得成功",
67+
content: {
68+
"application/json": {
69+
schema: TaskResponseSchema,
70+
},
71+
},
72+
},
73+
},
74+
});
75+
76+
function getOpenApiDocumentation() {
77+
const generator = new OpenApiGeneratorV3(registry.definitions);
78+
79+
return generator.generateDocument({
80+
openapi: '3.0.0',
81+
info: {
82+
version: '1.0.0',
83+
title: 'My API',
84+
description: 'This is the API',
85+
},
86+
servers: [{ url: 'v1' }],
87+
});
88+
}
89+
90+
function writeDocumentation() {
91+
// OpenAPI JSON
92+
const docs = getOpenApiDocumentation();
93+
94+
// YAML equivalent
95+
const fileContent = yaml.stringify(docs);
96+
97+
const outPath = path.resolve(process.cwd(), "public/openapi-docs.yml");
98+
99+
fs.writeFileSync(outPath, fileContent, {
100+
encoding: 'utf-8',
101+
});
102+
}
103+
104+
writeDocumentation();

0 commit comments

Comments
 (0)