feat(server): add tsoa to generate api swaggers
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,3 +27,4 @@ build
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
/packages/server/src/routes/routes.ts
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc && tsc-alias",
|
"build": "tsoa spec-and-routes && tsc && tsc-alias",
|
||||||
"serve": "node ./build/index.js",
|
"serve": "node ./build/index.js",
|
||||||
"start": "nodemon"
|
"start": "nodemon"
|
||||||
},
|
},
|
||||||
@@ -16,10 +16,11 @@
|
|||||||
"compression": "^1.7.5",
|
"compression": "^1.7.5",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"express": "^4.21.2",
|
"express": "^4.21.2",
|
||||||
"express-oas-generator": "^1.0.48",
|
|
||||||
"nocache": "^4.0.0",
|
"nocache": "^4.0.0",
|
||||||
"sequelize": "^6.37.7",
|
"sequelize": "^6.37.7",
|
||||||
"sqlite3": "^5.1.7"
|
"sqlite3": "^5.1.7",
|
||||||
|
"tsoa": "^5.0.0",
|
||||||
|
"swagger-ui-express": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/axios": "^0.9.36",
|
"@types/axios": "^0.9.36",
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
import { Express } from "express";
|
|
||||||
import {userInfoMiddleware, groupInfoMiddleware} from "@/middleware/auth";
|
|
||||||
|
|
||||||
export const createApis = (app: Express) => {
|
|
||||||
app.get("/api/test", async (req, res) => {
|
|
||||||
res.status(200).json({
|
|
||||||
message: "success",
|
|
||||||
data: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 同时使用用户信息和群组信息中间件
|
|
||||||
app.get("/api/user-group/info", userInfoMiddleware, groupInfoMiddleware, async (req, res) => {
|
|
||||||
res.status(200).json({
|
|
||||||
message: "success",
|
|
||||||
data: {
|
|
||||||
user: req.userInfo,
|
|
||||||
group: req.groupInfo
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/** add apis here */
|
|
||||||
};
|
|
||||||
20
packages/server/src/controllers/TestController.ts
Normal file
20
packages/server/src/controllers/TestController.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { Controller, Get, Route, Response, Tags } from 'tsoa';
|
||||||
|
import { ApiResponse } from '../types/api';
|
||||||
|
|
||||||
|
@Route('api')
|
||||||
|
@Tags('Test')
|
||||||
|
export class TestController extends Controller {
|
||||||
|
/**
|
||||||
|
* 测试接口
|
||||||
|
* @summary 测试接口
|
||||||
|
* @description 用于测试API连通性的基础接口
|
||||||
|
*/
|
||||||
|
@Get('/test')
|
||||||
|
@Response<ApiResponse>(200, 'Success')
|
||||||
|
public async getTest(): Promise<ApiResponse> {
|
||||||
|
return {
|
||||||
|
message: 'success',
|
||||||
|
data: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
30
packages/server/src/controllers/UserGroupController.ts
Normal file
30
packages/server/src/controllers/UserGroupController.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { Controller, Get, Route, Response, Tags, Middlewares, Request } from 'tsoa';
|
||||||
|
import { ApiResponse, UserGroupInfo } from '../types/api';
|
||||||
|
import { userInfoMiddleware, groupInfoMiddleware } from '../middleware/auth';
|
||||||
|
import type { Request as ExpressRequest } from 'express';
|
||||||
|
|
||||||
|
@Route('api')
|
||||||
|
@Tags('User Group')
|
||||||
|
export class UserGroupController extends Controller {
|
||||||
|
/**
|
||||||
|
* 获取用户群组信息
|
||||||
|
* @summary 获取用户群组信息
|
||||||
|
* @description 获取当前用户的个人信息和所在群组的所有用户信息
|
||||||
|
*/
|
||||||
|
@Get('/user-group/info')
|
||||||
|
@Middlewares([userInfoMiddleware, groupInfoMiddleware])
|
||||||
|
@Response<ApiResponse<UserGroupInfo>>(200, 'Success')
|
||||||
|
@Response(401, 'Unauthorized')
|
||||||
|
public async getUserGroupInfo(@Request() req: ExpressRequest): Promise<ApiResponse<UserGroupInfo>> {
|
||||||
|
const userInfo = req.userInfo;
|
||||||
|
const groupInfo = req.groupInfo;
|
||||||
|
|
||||||
|
return {
|
||||||
|
message: 'success',
|
||||||
|
data: {
|
||||||
|
user: userInfo || null,
|
||||||
|
group: groupInfo || null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,16 +4,12 @@ import cors from "cors";
|
|||||||
import compression from "compression";
|
import compression from "compression";
|
||||||
import nocache from "nocache";
|
import nocache from "nocache";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import expressOasGenerator, {
|
|
||||||
OpenAPIV3,
|
|
||||||
SPEC_OUTPUT_FILE_BEHAVIOR,
|
|
||||||
} from "express-oas-generator";
|
|
||||||
|
|
||||||
dotenv.config({ path: path.resolve(__dirname, "../../../.env") });
|
dotenv.config({ path: path.resolve(__dirname, "../../../.env") });
|
||||||
|
|
||||||
import "./database";
|
import "./database";
|
||||||
import { sequelize } from "@/database/instance";
|
import { sequelize } from "@/database/instance";
|
||||||
import { createApis } from "./api";
|
import { RegisterTsoaRoutes } from "./middleware/tsoa.middleware";
|
||||||
|
|
||||||
const port = process.env.PORT || 3005;
|
const port = process.env.PORT || 3005;
|
||||||
|
|
||||||
@@ -26,29 +22,9 @@ app.use(compression());
|
|||||||
|
|
||||||
app.use(express.static(path.resolve(__dirname, "client")));
|
app.use(express.static(path.resolve(__dirname, "client")));
|
||||||
|
|
||||||
createApis(app);
|
// Register tsoa routes
|
||||||
|
RegisterTsoaRoutes(app);
|
||||||
|
|
||||||
expressOasGenerator.handleResponses(app, {
|
|
||||||
specOutputFileBehavior: SPEC_OUTPUT_FILE_BEHAVIOR.RECREATE,
|
|
||||||
swaggerDocumentOptions: {},
|
|
||||||
predefinedSpec: (spec: OpenAPIV3.Document) => {
|
|
||||||
if (spec.info) {
|
|
||||||
spec.info.description = "Egret App Server";
|
|
||||||
}
|
|
||||||
if (spec.paths) {
|
|
||||||
delete spec.paths["/v3/api-docs"];
|
|
||||||
}
|
|
||||||
return spec;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expressOasGenerator.handleRequests();
|
|
||||||
|
|
||||||
app.get("/v3/api-docs", async (req, res) => {
|
|
||||||
expressOasGenerator.getSpecV3((err, doc) => {
|
|
||||||
res.status(200).json(doc);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const host = "0.0.0.0";
|
const host = "0.0.0.0";
|
||||||
app.listen(Number(port), host, async () => {
|
app.listen(Number(port), host, async () => {
|
||||||
|
|||||||
12
packages/server/src/middleware/tsoa.middleware.ts
Normal file
12
packages/server/src/middleware/tsoa.middleware.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import swaggerUi from 'swagger-ui-express';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export function RegisterTsoaRoutes(app: any) {
|
||||||
|
// Register tsoa routes - 动态导入以避免编译时错误
|
||||||
|
const { RegisterRoutes } = require('../routes/routes');
|
||||||
|
RegisterRoutes(app);
|
||||||
|
|
||||||
|
// Serve swagger documentation - 动态导入swagger文档
|
||||||
|
const swaggerDocument = require(path.join(__dirname, '../swagger.json'));
|
||||||
|
app.use('/v3/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
|
||||||
|
}
|
||||||
14
packages/server/src/types/api.ts
Normal file
14
packages/server/src/types/api.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { UserInfo } from '../middleware/auth';
|
||||||
|
|
||||||
|
export interface ApiResponse<T = any> {
|
||||||
|
message: string;
|
||||||
|
data: T | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserGroupInfo {
|
||||||
|
user: UserInfo | null;
|
||||||
|
group: {
|
||||||
|
groupId: number;
|
||||||
|
users: UserInfo[];
|
||||||
|
} | null;
|
||||||
|
}
|
||||||
@@ -9,7 +9,10 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/*"]
|
"@/*": ["src/*"]
|
||||||
},
|
},
|
||||||
"outDir": "./build"
|
"outDir": "./build",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"useDefineForClassFields": false
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
"include": ["src"],
|
||||||
"exclude": ["node_modules", "build"],
|
"exclude": ["node_modules", "build"],
|
||||||
|
|||||||
18
packages/server/tsoa.json
Normal file
18
packages/server/tsoa.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"entryFile": "src/index.ts",
|
||||||
|
"noImplicitAdditionalProperties": "throw-on-extras",
|
||||||
|
"controllerPathGlobs": ["src/controllers/**/*Controller.ts"],
|
||||||
|
"spec": {
|
||||||
|
"outputDirectory": "build",
|
||||||
|
"specVersion": 3,
|
||||||
|
"name": "Egret App Server",
|
||||||
|
"description": "Egret App Server API Documentation",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"basePath": "/",
|
||||||
|
"schemes": ["http", "https"],
|
||||||
|
"host": "localhost:3005"
|
||||||
|
},
|
||||||
|
"routes": {
|
||||||
|
"routesDir": "src/routes"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user