Skip to content

Commit 938430e

Browse files
committed
initiated openapi swagger integration, added license
1 parent 3c58503 commit 938430e

File tree

7 files changed

+219
-12
lines changed

7 files changed

+219
-12
lines changed

README.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,12 @@ Before you get started, make sure you have the following installed on your machi
2424
```sh
2525
docker compose up -d
2626
```
27-
2827
2. **Install Dependencies**:
2928

3029
- Use pnpm to install all the necessary dependencies:
3130
```sh
3231
pnpm i
3332
```
34-
3533
3. **Configure Environment Variables**:
3634

3735
- Create a `.env` file in the root directory.
@@ -83,3 +81,7 @@ Before you get started, make sure you have the following installed on your machi
8381
## Contributions
8482

8583
Feel free to contribute to this project by submitting issues or pull requests. Let's build something amazing together!
84+
85+
## **License**
86+
87+
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.

openapi-docs.yml

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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+
securitySchemes:
10+
bearerAuth:
11+
type: http
12+
scheme: bearer
13+
bearerFormat: JWT
14+
schemas:
15+
UserId:
16+
type: string
17+
example: "1212121"
18+
User:
19+
type: object
20+
properties:
21+
id:
22+
type: string
23+
example: "1212121"
24+
name:
25+
type: string
26+
example: John Doe
27+
age:
28+
type: number
29+
example: 42
30+
required:
31+
- id
32+
- name
33+
- age
34+
parameters:
35+
UserId:
36+
schema:
37+
$ref: "#/components/schemas/UserId"
38+
required: true
39+
name: id
40+
in: path
41+
paths:
42+
/users/{id}:
43+
get:
44+
description: Get user data by its id
45+
summary: Get a single user
46+
security:
47+
- bearerAuth: []
48+
parameters:
49+
- $ref: "#/components/parameters/UserId"
50+
responses:
51+
"200":
52+
description: Object with user data.
53+
content:
54+
application/json:
55+
schema:
56+
$ref: "#/components/schemas/User"
57+
"204":
58+
description: No content - successful operation

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"typescript-eslint": "^7.11.0"
4848
},
4949
"dependencies": {
50+
"@asteasolutions/zod-to-openapi": "^7.1.1",
5051
"@aws-sdk/client-s3": "^3.606.0",
5152
"@bull-board/api": "^5.19.0",
5253
"@bull-board/express": "^5.16.0",
@@ -88,7 +89,9 @@
8889
"pino-pretty": "^11.1.0",
8990
"redis": "^4.6.11",
9091
"socket.io": "^4.7.5",
92+
"swagger-ui-express": "^5.0.1",
9193
"validator": "^13.12.0",
94+
"yaml": "^2.5.0",
9295
"zod": "^3.21.4"
9396
},
9497
"author": "",

pnpm-lock.yaml

+48-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
File renamed without changes.

src/main.ts

+12-6
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,19 @@ import { connectDatabase } from './lib/database';
1919
import { useSocketIo } from './lib/realtime.server';
2020
import path from 'path';
2121

22+
import swaggerUi from 'swagger-ui-express';
23+
import YAML from 'yaml';
24+
import fs from 'node:fs/promises';
25+
2226
const boostrapServer = async () => {
2327
await connectDatabase();
2428

29+
const file = await fs.readFile(
30+
path.join(process.cwd(), 'openapi-docs.yml'),
31+
'utf8',
32+
);
33+
const swaggerDocument = YAML.parse(file);
34+
2535
const app = express();
2636

2737
app.set('trust proxy', true);
@@ -61,15 +71,10 @@ const boostrapServer = async () => {
6171
store: redisStore,
6272
}),
6373
);
74+
6475
// Middleware to serve static files
6576
app.use(express.static(path.join(__dirname, '..', 'public')));
6677

67-
// Route to send static file via response to socket.io
68-
app.get('/socket', (_, res) => {
69-
const filePath = path.join(__dirname, '..', 'public', 'index.html');
70-
res.sendFile(filePath);
71-
});
72-
7378
app.use(cookieParser());
7479

7580
app.use(compression());
@@ -81,6 +86,7 @@ const boostrapServer = async () => {
8186
}
8287

8388
app.use('/api', apiRoutes);
89+
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
8490

8591
const serverAdapter = new ExpressAdapter();
8692
serverAdapter.setBasePath('/admin/queues');

swagger-doc-generator.ts

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import {
2+
OpenApiGeneratorV3,
3+
OpenAPIRegistry,
4+
extendZodWithOpenApi,
5+
} from '@asteasolutions/zod-to-openapi';
6+
import { z } from 'zod';
7+
import * as yaml from 'yaml';
8+
import * as fs from 'fs';
9+
10+
extendZodWithOpenApi(z);
11+
12+
const registry = new OpenAPIRegistry();
13+
14+
const UserIdSchema = registry.registerParameter(
15+
'UserId',
16+
z.string().openapi({
17+
param: {
18+
name: 'id',
19+
in: 'path',
20+
},
21+
example: '1212121',
22+
}),
23+
);
24+
const UserSchema = z
25+
.object({
26+
id: z.string().openapi({
27+
example: '1212121',
28+
}),
29+
name: z.string().openapi({
30+
example: 'John Doe',
31+
}),
32+
age: z.number().openapi({
33+
example: 42,
34+
}),
35+
})
36+
.openapi('User');
37+
38+
const bearerAuth = registry.registerComponent('securitySchemes', 'bearerAuth', {
39+
type: 'http',
40+
scheme: 'bearer',
41+
bearerFormat: 'JWT',
42+
});
43+
44+
registry.registerPath({
45+
method: 'get',
46+
path: '/users/{id}',
47+
description: 'Get user data by its id',
48+
summary: 'Get a single user',
49+
security: [{ [bearerAuth.name]: [] }],
50+
request: {
51+
params: z.object({ id: UserIdSchema }),
52+
},
53+
responses: {
54+
200: {
55+
description: 'Object with user data.',
56+
content: {
57+
'application/json': {
58+
schema: UserSchema,
59+
},
60+
},
61+
},
62+
204: {
63+
description: 'No content - successful operation',
64+
},
65+
},
66+
});
67+
68+
function getOpenApiDocumentation() {
69+
const generator = new OpenApiGeneratorV3(registry.definitions);
70+
71+
return generator.generateDocument({
72+
openapi: '3.0.0',
73+
info: {
74+
version: '1.0.0',
75+
title: 'My API',
76+
description: 'This is the API',
77+
},
78+
servers: [{ url: 'v1' }],
79+
});
80+
}
81+
82+
function writeDocumentation() {
83+
// OpenAPI JSON
84+
const docs = getOpenApiDocumentation();
85+
86+
// YAML equivalent
87+
const fileContent = yaml.stringify(docs);
88+
89+
fs.writeFileSync(`${__dirname}/openapi-docs.yml`, fileContent, {
90+
encoding: 'utf-8',
91+
});
92+
}
93+
94+
writeDocumentation();

0 commit comments

Comments
 (0)