Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Close #1054: add support for ApiExtension decorator #1055

Merged
merged 4 commits into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/sdk/src/analyses/ReflectHttpOperationAnalyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export namespace ReflectHttpOperationAnalyzer {
.find(({ name }) => name === "operationId")
?.text?.[0].text.split(" ")[0]
.trim(),
extensions: ReflectMetadataAnalyzer.extensions(props.function),
};

// VALIDATE PATH ARGUMENTS
Expand Down
8 changes: 8 additions & 0 deletions packages/sdk/src/analyses/ReflectMetadataAnalyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ export namespace ReflectMetadataAnalyzer {
else return value;
};

export const extensions = (value: any): Record<string, any> => {
const entire: Record<string, any>[] | undefined = Reflect.getMetadata(
"swagger/apiExtension",
value,
);
return entire ?? {};
};

export const securities = (value: any): Record<string, string[]>[] => {
const entire: Record<string, string[]>[] | undefined = Reflect.getMetadata(
"swagger/apiSecurity",
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/src/analyses/TypedHttpRouteAnalyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ export namespace TypedHttpRouteAnalyzer {
exceptions,
parameters,
success,
extensions: props.operation.extensions,
}));
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export namespace SwaggerOperationComposer {
route: props.route,
}),
security: security.length ? security : undefined,
...(props.route.extensions ?? {}),
};
};
}
1 change: 1 addition & 0 deletions packages/sdk/src/structures/IReflectHttpOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ export interface IReflectHttpOperation {
operationId: string | undefined;
description: string | null;
jsDocTags: IJsDocTagInfo[];
extensions?: Record<string, any>;
}
1 change: 1 addition & 0 deletions packages/sdk/src/structures/ITypedHttpRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ export interface ITypedHttpRoute {
description: string | null;
jsDocTags: IJsDocTagInfo[];
operationId: string | undefined;
extensions?: Record<string, any>;
}
25 changes: 25 additions & 0 deletions test/features/swagger-extensions/nestia.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { INestiaConfig } from "@nestia/sdk";

export const NESTIA_CONFIG: INestiaConfig = {
input: ["src/controllers"],
output: "src/api",
e2e: "src/test",
swagger: {
output: "swagger.json",
info: {
title: "Nestia Swagger Generation Test",
},
servers: [
{
url: "http://localhost:3000",
description: "Local Server",
},
],
security: {
bearer: {
type: "apiKey",
},
},
},
};
export default NESTIA_CONFIG;
4 changes: 4 additions & 0 deletions test/features/swagger-extensions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "@nestia/test-swagger",
"version": "1.0.3"
}
1 change: 1 addition & 0 deletions test/features/swagger-extensions/src/api/HttpError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { HttpError } from "@nestia/fetcher";
1 change: 1 addition & 0 deletions test/features/swagger-extensions/src/api/IConnection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type { IConnection } from "@nestia/fetcher";
1 change: 1 addition & 0 deletions test/features/swagger-extensions/src/api/Primitive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type { Primitive } from "@nestia/fetcher";
1 change: 1 addition & 0 deletions test/features/swagger-extensions/src/api/Resolved.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type { Resolved } from "@nestia/fetcher";
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @packageDocumentation
* @module api.functional.health
* @nestia Generated by Nestia - https://github.com/samchon/nestia
*/
//================================================================
import type { IConnection } from "@nestia/fetcher";
import { PlainFetcher } from "@nestia/fetcher/lib/PlainFetcher";

/**
* @controller HealthController.get
* @path GET /health
* @nestia Generated by Nestia - https://github.com/samchon/nestia
*/
export async function get(connection: IConnection): Promise<void> {
return PlainFetcher.fetch(connection, {
...get.METADATA,
template: get.METADATA.path,
path: get.path(),
});
}
export namespace get {
export const METADATA = {
method: "GET",
path: "/health",
request: null,
response: {
type: "application/json",
encrypted: false,
},
status: 200,
} as const;

export const path = () => "/health";
}
8 changes: 8 additions & 0 deletions test/features/swagger-extensions/src/api/functional/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @packageDocumentation
* @module api.functional
* @nestia Generated by Nestia - https://github.com/samchon/nestia
*/
//================================================================
export * as health from "./health";
export * as performance from "./performance";
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @packageDocumentation
* @module api.functional.performance
* @nestia Generated by Nestia - https://github.com/samchon/nestia
*/
//================================================================
import type { IConnection, Primitive } from "@nestia/fetcher";
import { PlainFetcher } from "@nestia/fetcher/lib/PlainFetcher";

import type { IPerformance } from "../../structures/IPerformance";

/**
* @controller PerformanceController.get
* @path GET /performance
* @nestia Generated by Nestia - https://github.com/samchon/nestia
*/
export async function get(connection: IConnection): Promise<get.Output> {
return PlainFetcher.fetch(connection, {
...get.METADATA,
template: get.METADATA.path,
path: get.path(),
});
}
export namespace get {
export type Output = Primitive<IPerformance>;

export const METADATA = {
method: "GET",
path: "/performance",
request: null,
response: {
type: "application/json",
encrypted: false,
},
status: 200,
} as const;

export const path = () => "/performance";
}
4 changes: 4 additions & 0 deletions test/features/swagger-extensions/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import * as api from "./module";

export * from "./module";
export default api;
6 changes: 6 additions & 0 deletions test/features/swagger-extensions/src/api/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type * from "./IConnection";
export type * from "./Primitive";
export type * from "./Resolved";
export * from "./HttpError";

export * as functional from "./functional";
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Performance info.
*
* @author Samchon
*/
export interface IPerformance {
cpu: NodeJS.CpuUsage;
memory: NodeJS.MemoryUsage;
resource: NodeJS.ResourceUsage;
}
81 changes: 81 additions & 0 deletions test/features/swagger-extensions/src/api/structures/ISystem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* System Information.
*
* @author Jeongho Nam
*/
export interface ISystem {
/**
* Random Unique ID.
*/
uid: number;

/**
* `process.argv`
*/
arguments: string[];

/**
* Git commit info.
*/
commit: ISystem.ICommit;

/**
* `package.json`
*/
package: ISystem.IPackage;

/**
* Creation time of this server.
*/
created_at: string;
}

export namespace ISystem {
/**
* Git commit info.
*/
export interface ICommit {
shortHash: string;
branch: string;
hash: string;
subject: string;
sanitizedSubject: string;
body: string;
author: ICommit.IUser;
committer: ICommit.IUser;
authored_at: string;
commited_at: string;
notes?: string;
tags: string[];
}
export namespace ICommit {
/**
* Git user account info.
*/
export interface IUser {
name: string;
email: string;
}
}

/**
* NPM package info.
*/
export interface IPackage {
name: string;
version: string;
description: string;
main?: string;
typings?: string;
scripts: Record<string, string>;
repository: { type: "git"; url: string };
author: string;
license: string;
bugs: { url: string };
homepage: string;
devDependencies?: Record<string, string>;
dependencies: Record<string, string>;
publishConfig?: { registry: string };
files?: string[];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import core from "@nestia/core";
import { Controller } from "@nestjs/common";

@Controller("health")
export class HealthController {
@core.TypedRoute.Get()
public get(): void {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import core from "@nestia/core";
import { Controller } from "@nestjs/common";
import { ApiExtension } from "@nestjs/swagger";

import { IPerformance } from "@api/lib/structures/IPerformance";

@Controller("performance")
export class PerformanceController {
@ApiExtension("x-visibility", "public")
@ApiExtension("x-deprecated", true)
@core.TypedRoute.Get()
public async get(): Promise<IPerformance> {
return {
cpu: process.cpuUsage(),
memory: process.memoryUsage(),
resource: process.resourceUsage(),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import typia from "typia";

import api from "../../../../api";

export const test_api_health_get = async (connection: api.IConnection) => {
const output = await api.functional.health.get(connection);
typia.assert(output);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { Primitive } from "@nestia/fetcher";
import typia from "typia";

import api from "../../../../api";
import type { IPerformance } from "../../../../api/structures/IPerformance";

export const test_api_performance_get = async (connection: api.IConnection) => {
const output: Primitive<IPerformance> =
await api.functional.performance.get(connection);
typia.assert(output);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { TestValidator } from "@nestia/e2e";

export async function test_swagger(): Promise<void> {
const { NESTIA_CONFIG } = await import(
__dirname + "/../../../../nestia.config.ts"
);
const pack = await import(__dirname + "/../../../../package.json");
const swagger = await import(__dirname + "/../../../../swagger.json");

TestValidator.equals("info.version")(pack.version)(swagger.info.version);
TestValidator.equals("info.title")(NESTIA_CONFIG.swagger.info.title)(
swagger.info.title,
);
TestValidator.equals("info.description")(
"Generated by nestia - https://github.com/samchon/nestia",
);
TestValidator.equals("servers")(NESTIA_CONFIG.swagger.servers)(
swagger.servers,
);
}
Loading