add route module
This commit is contained in:
parent
fc9b8f7f2a
commit
a5b7a9bd5d
@ -1,4 +1,5 @@
|
||||
import { createApp, listened, startApp } from './modules/core/helpers/app';
|
||||
import { createApp, startApp } from './modules/core/helpers/app';
|
||||
import { listened } from './modules/restful/utils';
|
||||
import { createOptions } from './options';
|
||||
|
||||
startApp(createApp(createOptions), listened);
|
||||
|
@ -1,11 +1,9 @@
|
||||
import { BadGatewayException, Global, Module, ModuleMetadata, Type } from '@nestjs/common';
|
||||
|
||||
import { APP_FILTER, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
|
||||
import { NestFastifyApplication } from '@nestjs/platform-fastify';
|
||||
import chalk from 'chalk';
|
||||
import { useContainer } from 'class-validator';
|
||||
|
||||
import { isNil, omit } from 'lodash';
|
||||
import { omit } from 'lodash';
|
||||
|
||||
import { ConfigModule } from '@/modules/config/config.module';
|
||||
import { Configure } from '@/modules/config/configure';
|
||||
@ -104,20 +102,3 @@ export async function startApp(
|
||||
const { port, host } = await configure.get<AppConfig>('app');
|
||||
await container.listen(port, host, listened(app, startTime));
|
||||
}
|
||||
|
||||
export async function echoApi(configure: Configure, container: NestFastifyApplication) {
|
||||
const appUrl = await configure.get<string>('app.url');
|
||||
const urlPrefix = await configure.get<string>('api.prefix', undefined);
|
||||
const apiUrl = isNil(urlPrefix)
|
||||
? appUrl
|
||||
: `${appUrl}${urlPrefix.length > 0 ? `/${urlPrefix}` : urlPrefix}`;
|
||||
console.log(`- RestAPI: ${chalk.green.underline(apiUrl)}`);
|
||||
}
|
||||
|
||||
export const listened: (app: App, startyTime: Date) => () => Promise<void> =
|
||||
({ configure, container }, startTime) =>
|
||||
async () => {
|
||||
console.log();
|
||||
await echoApi(configure, container);
|
||||
console.log('used time: ', chalk.cyan(`${new Date().getTime() - startTime.getTime()}`));
|
||||
};
|
||||
|
24
src/modules/restful/restful.module.ts
Normal file
24
src/modules/restful/restful.module.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { DynamicModule } from '@nestjs/common';
|
||||
|
||||
import { Configure } from '../config/configure';
|
||||
|
||||
import { Restful } from './restful';
|
||||
|
||||
export class RestfulModule {
|
||||
static async forRoot(configure: Configure): Promise<DynamicModule> {
|
||||
const restful = new Restful(configure);
|
||||
await restful.create(await configure.get('api'));
|
||||
return {
|
||||
module: RestfulModule,
|
||||
global: true,
|
||||
imports: restful.getModuleImports(),
|
||||
providers: [
|
||||
{
|
||||
provide: Restful,
|
||||
useValue: restful,
|
||||
},
|
||||
],
|
||||
exports: [Restful],
|
||||
};
|
||||
}
|
||||
}
|
@ -1,10 +1,18 @@
|
||||
import { Type } from '@nestjs/common';
|
||||
import { INestApplication, Type } from '@nestjs/common';
|
||||
import { RouterModule } from '@nestjs/core';
|
||||
|
||||
import { omit } from 'lodash';
|
||||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
||||
import { omit, trim } from 'lodash';
|
||||
|
||||
import { BaseRestful } from './base';
|
||||
import { ApiConfig, ApiDocOption, ApiDocSource, RouteOption, SwaggerOption } from './types';
|
||||
import {
|
||||
ApiConfig,
|
||||
ApiDocOption,
|
||||
ApiDocSource,
|
||||
RouteOption,
|
||||
SwaggerOption,
|
||||
VersionOption,
|
||||
} from './types';
|
||||
import { trimPath } from './utils';
|
||||
|
||||
export class Restful extends BaseRestful {
|
||||
@ -71,6 +79,80 @@ export class Restful extends BaseRestful {
|
||||
(module) => !excludeModules.find((emodule) => emodule === module),
|
||||
);
|
||||
}
|
||||
|
||||
protected getDocOption(name: string, voption: VersionOption, isDefault = false) {
|
||||
const docConfig: ApiDocOption = {};
|
||||
const defaultDoc = {
|
||||
title: voption.title!,
|
||||
description: voption.description!,
|
||||
tags: voption.tags ?? [],
|
||||
auth: voption.auth ?? false,
|
||||
version: name,
|
||||
path: trim(`${this.config.docuri}${isDefault ? '' : `/${name}`}`, '/'),
|
||||
};
|
||||
|
||||
const routesDoc = isDefault
|
||||
? this.getRouteDocs(defaultDoc, voption.routes ?? [])
|
||||
: this.getRouteDocs(defaultDoc, voption.routes ?? [], name);
|
||||
if (Object.keys(routesDoc).length > 0) {
|
||||
docConfig.routes = routesDoc;
|
||||
}
|
||||
const routeModules = isDefault
|
||||
? this.getRouteModules(voption.routes ?? [])
|
||||
: this.getRouteModules(voption.routes ?? [], name);
|
||||
const include = this.filterExcludeModules(routeModules);
|
||||
if (include.length > 0 || !docConfig.routes) {
|
||||
docConfig.default = { ...defaultDoc, include };
|
||||
}
|
||||
return docConfig;
|
||||
}
|
||||
|
||||
protected createDocs() {
|
||||
const versionMaps = Object.entries(this.config.versions);
|
||||
const vDocs = versionMaps.map(([name, version]) => [
|
||||
name,
|
||||
this.getDocOption(name, version),
|
||||
]);
|
||||
this._docs = Object.fromEntries(vDocs);
|
||||
const defaultVersion = this.config.versions[this._default];
|
||||
this._docs.default = this.getDocOption(this._default, defaultVersion, true);
|
||||
}
|
||||
|
||||
async factoryDocs<T extends INestApplication>(container: T) {
|
||||
const docs = Object.values(this._docs)
|
||||
.map((doc) => [doc.default, ...Object.values(doc.routes ?? [])])
|
||||
.reduce((o, n) => [...o, ...n], [])
|
||||
.filter((i) => !!i);
|
||||
|
||||
for (const voption of docs) {
|
||||
const { title, description, version, auth, include, tags } = voption!;
|
||||
const builder = new DocumentBuilder();
|
||||
if (title) {
|
||||
builder.setTitle(title);
|
||||
}
|
||||
if (description) {
|
||||
builder.setDescription(description);
|
||||
}
|
||||
if (auth) {
|
||||
builder.addBearerAuth();
|
||||
}
|
||||
if (tags) {
|
||||
tags.forEach((tag) =>
|
||||
typeof tag === 'string'
|
||||
? builder.addTag(tag)
|
||||
: builder.addTag(tag.name, tag.description, tag.externalDocs),
|
||||
);
|
||||
}
|
||||
builder.setVersion(version);
|
||||
|
||||
const document = SwaggerModule.createDocument(container, builder.build(), {
|
||||
include: include.length > 0 ? include : [() => undefined as any],
|
||||
ignoreGlobalPrefix: true,
|
||||
deepScanRoutes: true,
|
||||
});
|
||||
SwaggerModule.setup(voption!.path, container, document);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function genDocPath(routePath: string, prefix?: string, version?: string) {
|
||||
|
@ -1,14 +1,19 @@
|
||||
import { Type } from '@nestjs/common';
|
||||
import { Routes, RouteTree } from '@nestjs/core';
|
||||
import { NestFastifyApplication } from '@nestjs/platform-fastify';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import chalk from 'chalk';
|
||||
import { camelCase, isNil, omit, trim, upperFirst } from 'lodash';
|
||||
|
||||
import { Configure } from '../config/configure';
|
||||
|
||||
import { CreateModule } from '../core/helpers';
|
||||
|
||||
import { App } from '../core/types';
|
||||
|
||||
import { CONTROLLER_DEPENDS } from './constants';
|
||||
import { RouteOption } from './types';
|
||||
import { Restful } from './restful';
|
||||
import { ApiDocOption, RouteOption } from './types';
|
||||
|
||||
export const trimPath = (routePath: string, addPrefix = true) =>
|
||||
`${addPrefix ? '/' : ''}${trim(routePath.replace('//', '/'), '/')}`;
|
||||
@ -84,3 +89,53 @@ export function createRouteModuleTree(
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function echoApi(configure: Configure, container: NestFastifyApplication) {
|
||||
const appUrl = await configure.get<string>('app.url');
|
||||
const urlPrefix = await configure.get<string>('api.prefix', undefined);
|
||||
const apiUrl = isNil(urlPrefix)
|
||||
? appUrl
|
||||
: `${appUrl}${urlPrefix.length > 0 ? `/${urlPrefix}` : urlPrefix}`;
|
||||
console.log(`- RestAPI: ${chalk.green.underline(apiUrl)}`);
|
||||
console.log('- RestDocs');
|
||||
const factory = container.get(Restful);
|
||||
const { default: defaultDoc, ...docs } = factory.docs;
|
||||
await echoApiDocs('default', defaultDoc, appUrl);
|
||||
for (const [name, doc] of Object.entries(docs)) {
|
||||
console.log();
|
||||
echoApiDocs(name, doc, appUrl);
|
||||
}
|
||||
}
|
||||
|
||||
export const listened: (app: App, startyTime: Date) => () => Promise<void> =
|
||||
({ configure, container }, startTime) =>
|
||||
async () => {
|
||||
console.log();
|
||||
await echoApi(configure, container);
|
||||
console.log('used time: ', chalk.cyan(`${new Date().getTime() - startTime.getTime()}`));
|
||||
};
|
||||
|
||||
async function echoApiDocs(name: string, doc: ApiDocOption, appUrl: string) {
|
||||
const getDocPath = (path: string) => `${appUrl}/${path}`;
|
||||
if (!doc.routes && doc.default) {
|
||||
console.log(
|
||||
`[${chalk.blue(name.toUpperCase())}]:${chalk.green.underline(
|
||||
getDocPath(doc.default.path),
|
||||
)}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
console.log(`[${chalk.blue(name.toUpperCase())}]`);
|
||||
if (doc.default) {
|
||||
console.log(`default:${chalk.green.underline(getDocPath(doc.default.path))}`);
|
||||
}
|
||||
if (doc.routes) {
|
||||
Object.entries(doc.routes).forEach(([routeName, docs]) => {
|
||||
console.log(
|
||||
`<${chalk.yellowBright.bold(docs.title)}>: ${chalk.green.underline(
|
||||
getDocPath(docs.path),
|
||||
)}`,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user