tsoa setup
This commit is contained in:
+4
-1
@@ -7,5 +7,8 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"packageManager": "pnpm@10.20.0",
|
"packageManager": "pnpm@10.20.0",
|
||||||
"type": "module"
|
"type": "module",
|
||||||
|
"devDependencies": {
|
||||||
|
"tsoa": "^6.6.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
generated/
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
"typescript": "~5.9.3"
|
"typescript": "~5.9.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@tsoa/runtime": "^6.6.0",
|
||||||
"express": "^5.1.0"
|
"express": "^5.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { Controller, Get, Route, SuccessResponse } from 'tsoa';
|
||||||
|
|
||||||
|
export interface User {
|
||||||
|
email: string;
|
||||||
|
name: string;
|
||||||
|
phoneNumbers: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserCreationParams = Pick<User, "email" | "name" | "phoneNumbers">;
|
||||||
|
|
||||||
|
@Route('health')
|
||||||
|
export class HealthCheckController extends Controller {
|
||||||
|
@Get('ok')
|
||||||
|
@SuccessResponse('200', 'OK')
|
||||||
|
public async getOk(
|
||||||
|
): Promise<string> {
|
||||||
|
this.setStatus(200);
|
||||||
|
return 'Ok';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
|
import { RegisterRoutes } from './generated/routes.js';
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = 3000;
|
const port = 3000;
|
||||||
|
|
||||||
app.get('/', (_, res) => {
|
app.use(express.urlencoded({ extended: true }));
|
||||||
res.send('Hello World!');
|
app.use(express.json());
|
||||||
});
|
|
||||||
|
RegisterRoutes(app);
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Server is running at http://localhost:${port}`);
|
console.log(`Server is running at http://localhost:${port}`);
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import * as express from 'express';
|
||||||
|
|
||||||
|
export async function expressAuthentication(
|
||||||
|
request: express.Request,
|
||||||
|
securityName: string,
|
||||||
|
scopes?: string[]
|
||||||
|
): Promise<any> {
|
||||||
|
console.dir({ request, securityName, scopes });
|
||||||
|
return {};
|
||||||
|
}
|
||||||
@@ -40,6 +40,21 @@
|
|||||||
"noUncheckedSideEffectImports": true,
|
"noUncheckedSideEffectImports": true,
|
||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
// Custom Options
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"useDefineForClassFields": false,
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"incremental": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"strictFunctionTypes": true,
|
||||||
|
"strictBindCallApply": true,
|
||||||
|
"strictPropertyInitialization": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"alwaysStrict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
},
|
},
|
||||||
"files": ["./src/index.ts"],
|
"files": ["./src/index.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,3 +41,6 @@ __screenshots__/
|
|||||||
# System files
|
# System files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
|
###
|
||||||
|
src/generated-api/
|
||||||
|
|||||||
Generated
+644
-8
File diff suppressed because it is too large
Load Diff
+8
-2
@@ -1,3 +1,9 @@
|
|||||||
packages:
|
packages:
|
||||||
- 'packages/*'
|
- packages/*
|
||||||
- 'libs/*'
|
- libs/*
|
||||||
|
|
||||||
|
onlyBuiltDependencies:
|
||||||
|
- '@parcel/watcher'
|
||||||
|
- esbuild
|
||||||
|
- lmdb
|
||||||
|
- msgpackr-extract
|
||||||
|
|||||||
+223
@@ -0,0 +1,223 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
// This file was copied from https://github.com/lukeautry/tsoa/blob/v6.6.0/packages/cli/src/routeGeneration/templates/express.hbs to add the above line, please keep up to date
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
import type { TsoaRoute } from '@tsoa/runtime';
|
||||||
|
import { fetchMiddlewares, ExpressTemplateService } from '@tsoa/runtime';
|
||||||
|
{{#each controllers}}
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
import { {{name}} } from '{{modulePath}}.js';
|
||||||
|
{{/each}}
|
||||||
|
{{#if authenticationModule}}
|
||||||
|
import { expressAuthentication } from '{{authenticationModule}}.js';
|
||||||
|
// @ts-ignore - no great way to install types from subpackage
|
||||||
|
{{/if}}
|
||||||
|
{{#if iocModule}}
|
||||||
|
import { iocContainer } from '{{iocModule}}';
|
||||||
|
import type { IocContainer, IocContainerFactory } from '@tsoa/runtime';
|
||||||
|
{{/if}}
|
||||||
|
import type { Request as ExRequest, Response as ExResponse, RequestHandler, Router } from 'express';
|
||||||
|
{{#if useFileUploads}}
|
||||||
|
{{#if esm}}
|
||||||
|
import multer from 'multer';
|
||||||
|
{{else}}
|
||||||
|
const multer = require('multer');
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if authenticationModule}}
|
||||||
|
const expressAuthenticationRecasted = expressAuthentication as (req: ExRequest, securityName: string, scopes?: string[], res?: ExResponse) => Promise<any>;
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
|
||||||
|
const models: TsoaRoute.Models = {
|
||||||
|
{{#each models}}
|
||||||
|
"{{@key}}": {
|
||||||
|
{{#if enums}}
|
||||||
|
"dataType": "refEnum",
|
||||||
|
"enums": {{{json enums}}},
|
||||||
|
{{/if}}
|
||||||
|
{{#if properties}}
|
||||||
|
"dataType": "refObject",
|
||||||
|
"properties": {
|
||||||
|
{{#each properties}}
|
||||||
|
"{{@key}}": {{{json this}}},
|
||||||
|
{{/each}}
|
||||||
|
},
|
||||||
|
"additionalProperties": {{{json additionalProperties}}},
|
||||||
|
{{/if}}
|
||||||
|
{{#if type}}
|
||||||
|
"dataType": "refAlias",
|
||||||
|
"type": {{{json type}}},
|
||||||
|
{{/if}}
|
||||||
|
},
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
{{/each}}
|
||||||
|
};
|
||||||
|
const templateService = new ExpressTemplateService(models, {{{ json minimalSwaggerConfig}}});
|
||||||
|
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{{#if useFileUploads}}
|
||||||
|
export function RegisterRoutes(app: Router,opts?:{multer?:ReturnType<typeof multer>}) {
|
||||||
|
{{else}}
|
||||||
|
export function RegisterRoutes(app: Router) {
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
// ###########################################################################################################
|
||||||
|
// NOTE: If you do not see routes for all of your controllers in this file, then you might not have informed tsoa of where to look
|
||||||
|
// Please look into the "controllerPathGlobs" config option described in the readme: https://github.com/lukeautry/tsoa
|
||||||
|
// ###########################################################################################################
|
||||||
|
|
||||||
|
{{#if useFileUploads}}
|
||||||
|
const upload = opts?.multer || multer({{{json multerOpts}}});
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
|
||||||
|
{{#each controllers}}
|
||||||
|
{{#each actions}}
|
||||||
|
const args{{../name}}_{{name}}: Record<string, TsoaRoute.ParameterSchema> = {
|
||||||
|
{{#each parameters}}
|
||||||
|
{{@key}}: {{{json this}}},
|
||||||
|
{{/each}}
|
||||||
|
};
|
||||||
|
app.{{method}}('{{fullPath}}',
|
||||||
|
{{#if security.length}}
|
||||||
|
authenticateMiddleware({{json security}}),
|
||||||
|
{{/if}}
|
||||||
|
{{#if uploadFile}}
|
||||||
|
upload.fields([
|
||||||
|
{{#each uploadFileName}}
|
||||||
|
{
|
||||||
|
name: {{json name}},
|
||||||
|
{{#if maxCount}}
|
||||||
|
maxCount: {{maxCount}}
|
||||||
|
{{/if}}
|
||||||
|
}{{#if @last}}{{else}},{{/if}}
|
||||||
|
{{/each}}
|
||||||
|
]),
|
||||||
|
{{/if}}
|
||||||
|
...(fetchMiddlewares<RequestHandler>({{../name}})),
|
||||||
|
...(fetchMiddlewares<RequestHandler>({{../name}}.prototype.{{name}})),
|
||||||
|
|
||||||
|
async function {{../name}}_{{name}}(request: ExRequest, response: ExResponse, next: any) {
|
||||||
|
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
|
||||||
|
let validatedArgs: any[] = [];
|
||||||
|
try {
|
||||||
|
validatedArgs = templateService.getValidatedArgs({ args: args{{../name}}_{{name}}, request, response });
|
||||||
|
|
||||||
|
{{#if ../../iocModule}}
|
||||||
|
const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer;
|
||||||
|
|
||||||
|
const controller: any = await container.get<{{../name}}>({{../name}});
|
||||||
|
if (typeof controller['setStatus'] === 'function') {
|
||||||
|
controller.setStatus(undefined);
|
||||||
|
}
|
||||||
|
{{else}}
|
||||||
|
const controller = new {{../name}}();
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
await templateService.apiHandler({
|
||||||
|
methodName: '{{name}}',
|
||||||
|
controller,
|
||||||
|
response,
|
||||||
|
next,
|
||||||
|
validatedArgs,
|
||||||
|
successStatus: {{successStatus}},
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
{{/each}}
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
|
||||||
|
{{#if useSecurity}}
|
||||||
|
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
|
||||||
|
function authenticateMiddleware(security: TsoaRoute.Security[] = []) {
|
||||||
|
return async function runAuthenticationMiddleware(request: any, response: any, next: any) {
|
||||||
|
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
|
||||||
|
// keep track of failed auth attempts so we can hand back the most
|
||||||
|
// recent one. This behavior was previously existing so preserving it
|
||||||
|
// here
|
||||||
|
const failedAttempts: any[] = [];
|
||||||
|
const pushAndRethrow = (error: any) => {
|
||||||
|
failedAttempts.push(error);
|
||||||
|
throw error;
|
||||||
|
};
|
||||||
|
|
||||||
|
const secMethodOrPromises: Promise<any>[] = [];
|
||||||
|
for (const secMethod of security) {
|
||||||
|
if (Object.keys(secMethod).length > 1) {
|
||||||
|
const secMethodAndPromises: Promise<any>[] = [];
|
||||||
|
|
||||||
|
for (const name in secMethod) {
|
||||||
|
secMethodAndPromises.push(
|
||||||
|
expressAuthenticationRecasted(request, name, secMethod[name], response)
|
||||||
|
.catch(pushAndRethrow)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
|
||||||
|
secMethodOrPromises.push(Promise.all(secMethodAndPromises)
|
||||||
|
.then(users => { return users[0]; }));
|
||||||
|
} else {
|
||||||
|
for (const name in secMethod) {
|
||||||
|
secMethodOrPromises.push(
|
||||||
|
expressAuthenticationRecasted(request, name, secMethod[name], response)
|
||||||
|
.catch(pushAndRethrow)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
|
||||||
|
try {
|
||||||
|
request['user'] = await Promise.any(secMethodOrPromises);
|
||||||
|
|
||||||
|
// Response was sent in middleware, abort
|
||||||
|
if (response.writableEnded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
// Show most recent error as response
|
||||||
|
const error = failedAttempts.pop();
|
||||||
|
error.status = error.status || 401;
|
||||||
|
|
||||||
|
// Response was sent in middleware, abort
|
||||||
|
if (response.writableEnded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
|
}
|
||||||
|
|
||||||
|
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"entryFile": "packages/api/src/index.ts",
|
||||||
|
"noImplicitAdditionalProperties": "throw-on-extras",
|
||||||
|
"controllerPathGlobs": [
|
||||||
|
"packages/api/src/controllers/**/*.ts"
|
||||||
|
],
|
||||||
|
"routes": {
|
||||||
|
"routesDir": "packages/api/src/generated",
|
||||||
|
"middleware": "express",
|
||||||
|
"authenticationModule": "packages/api/src/middleware/authentication.ts",
|
||||||
|
"middlewareTemplate": "routes.hbs"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"outputDirectory": "packages/frontend/src/generated-api",
|
||||||
|
"specVersion": 3,
|
||||||
|
"securityDefinitions": {
|
||||||
|
"bearerAuth": {
|
||||||
|
"type": "http",
|
||||||
|
"scheme": "Bearer",
|
||||||
|
"description": "JWT token",
|
||||||
|
"bearerFormat": "JWT"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"basePath": "/api/v1",
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "https://localhost:8080/api/v1",
|
||||||
|
"description": "Development server"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tcc-member-db-4bfaysdsja-ew.a.run.app/api/v1",
|
||||||
|
"description": "Production server"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info": {
|
||||||
|
"title": "Tcc Member API",
|
||||||
|
"description": "API for the TCC Member Database",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"contact": {
|
||||||
|
"name": "TCC",
|
||||||
|
"url": "https://taekwondo-chemnitz-toni714.de/kontakt",
|
||||||
|
"email": "toniwalter.blue@gmail.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user