일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- socket
- 백준
- typescript
- HTTP
- Crawling
- Nestjs
- TCP
- 수학
- 프로그래머스 레벨 2
- dp
- 자바스크립트
- HTTP 완벽 가이드
- 레벨 1
- dfs
- 문자열
- 타입 챌린지
- 쉬운 문제
- ip
- BFS
- 소켓
- javascript
- 알고리즘
- type challenge
- 크롤링
- 가천대
- Algorithm
- Node.js
- 그래프
- 프로그래머스
- 타입스크립트
- Today
- Total
kakasoo
Nestia 적용하기 본문
이 글을 찾아본 것은 이미 Nestia를 알고 온 사람들일 거라 생각되기 때문에 간단한 설명만 적자면,
Nestia란?
Node.js, TypeScript 서버의 장점인 클라이언트와 동일한 언어 사용을 극대화하는 라이브러리라고 할 수 있다.
동일한 언어를 사용한다는 것은 서버 개발자가 미리 정의한 타입의 중복 개발을 막을 수 있다는 의미가 된다.
이로 인해 프론트 개발자는 이미 개발된 타입과 SDK를 사용해 좀 더 UI/UX 측면에 집중할 수 있게 된다.
프로젝트 생성
$ npm i -g @nestjs/cli
$ nest new project-name
프로젝트 생성은 동일하게 진행해주면 된다.
Nestia를 만드신 Samchon님의 레포지토리 예제 대부분은 본인 색채가 강하지만, 아래는 참고할 만 했다.
여기서는 Samchon님의 Backend 레포지토리를 fork하지 않고, 최초 nest 프로젝트 생성부터 시작한다.
nestia 적용
$ npx nestia setup
npx nestia setup
을 입력하면 compiler, package manager, TS Config File을 묻는 질문이 나온다.
선택은 본인에 맞게 하면 되지만, 컴파일러의 경우, 모르겠다면 ts-patch를 쓰면 된다.
TS Config File은 tsconfig.json과 tsconfig.build.json 중 고르면 된다.
자동적으로 nestia 사용에 필요한 각종 모듈들이 설치되는데, typia, @nestia/core, @nestia/sdk, nestia,
이렇게 4개의 라이브러리가 설치된다.
typia는 Runtime-validator로, class-validator의 역할을 대신하며, 더 빠른 속도를 내주는 라이브러리다.
@nesita/core는 TypedRoute, TypedBody 등 Nestia의 핵심적인 코드들을 export해주며,
@Nestia/sdk는 앞서 말한 것처럼 타입이나 API 호출 함수를 내보낼 수 있게 SDK 형태로 만들어주는 기능이다.
추가로 swagger를 생성하는 것도 해준다.
nestia는 nestia github repository 설명에 따르면 단순한 cli라고 한다.
@nestia/core
import { TypedBody, TypedRoute } from '@nestia/core';
import { Controller } from '@nestjs/common';
import { AppService } from './app.service';
interface TestDto {
/**
* @format email
*/
email: string;
}
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@TypedRoute.Post('nestia')
getHello(@TypedBody() dto: TestDto): string {
console.log('work...');
return dto.email;
}
}
당신이 NestJS를 안다는 전제 하에, Nest 서버를 만들면 자동적으로 AppController가 생기는 것을 알 것이다.
AppController에 자동으로 생기는 getHello 함수의 데코레이터들을 위와 같이 변경했다.
TypedRoute.Post()
와 TypedBody()
이렇게 두 개다.
TypedRoute의 메서드들은 일반적인 Nest 메서드들보다 더 빠른 JSON.stringify 성능을 가지고 있다.
TypedBody는 마찬가지로 더 빠른, validate 기능을 수행한다.
놀라운 건 클래스가 아닌 인터페이스로도 검증이 가능하다는 점이다.
interface TestDto {
/**
* @format email
*/
email: string;
}
Nestia의 validate 규칙은 주석의 설명을 따른다.
이 부분은 typia의 comment tags에 대한 설명을 읽어보면, 어떤 태그들이 가능한지 확인할 수 있다.
nestia.config.ts
import type SDK from '@nestia/sdk';
export const NESTIA_CONFIG: SDK.INestiaConfig = {
/**
* List of files or directories containing the NestJS controller classes.
*/
input: 'src/controllers',
/**
* Output directory that SDK would be placed in.
*
* If not configured, you can't build the SDK library.
*/
output: 'src/api',
/**
* Whether to assert parameter types or not.
*
* If you configure this property to be `true`, all of the function parameters would be
* checked through the [typia](https://github.com/samchon/typia#runtime-type-checkers).
* This option would make your SDK library slower, but would enahcne the type safety even
* in the runtime level.
*
* @default false
*/
// assert: true,
/**
* Whether to optimize JSON string conversion 2x faster or not.
*
* If you configure this property to be `true`, the SDK library would utilize the
* [typia](https://github.com/samchon/typia#fastest-json-string-converter)
* and the JSON string conversion speed really be 2x faster.
*
* @default false
*/
// json: true,
/**
* Whether to wrap DTO by primitive type.
*
* If you don't configure this property as `false`, all of DTOs in the
* SDK library would be automatically wrapped by {@link Primitive} type.
*
* For refenrece, if a DTO type be capsuled by the {@link Primitive} type,
* all of methods in the DTO type would be automatically erased. Also, if
* the DTO has a `toJSON()` method, the DTO type would be automatically
* converted to return type of the `toJSON()` method.
*
* @default true
*/
// primitive: false,
/**
* Building `swagger.json` is also possible.
*
* If not specified, you can't build the `swagger.json`.
*/
swagger: {
/**
* Output path of the `swagger.json`.
*
* If you've configured only directory, the file name would be the `swagger.json`.
* Otherwise you've configured the full path with file name and extension, the
* `swagger.json` file would be renamed to it.
*/
output: 'dist/swagger.json',
},
};
export default NESTIA_CONFIG;
주석이 많아서 복잡한데, 주석을 모두 지우고 나면 별 거 없다.
input, output, 그리고 swagger의 output 이렇게 3가지만 정의하면 된다.
input은 컨트롤러가 모여 있는 폴더를 지정하고, output은 sdk가 나올 폴더를 지정하면 된다.
swagger.output도 마찬가지로, swagger.json이 생성될 위치를 지정하면 된다.
dist/swagger.json으로 설정한 이유는 프로젝트의 rootDir에 위치하게 만들기 위해 그렇게 한 것일 뿐이다.
@nestia/sdk - swagger
$ npx nestia swagger
이 명령어를 입력하면 swagger.json이 만들어진다.
import { INestApplication } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { readFileSync } from 'fs';
import path from 'path';
export const SwaggerSetting = (app: INestApplication) => {
// const config = new DocumentBuilder()
// .setTitle('server docs')
// .setDescription('The API description')
// .setVersion('1.0')
// .addTag('kakasoo')
// .addBearerAuth({ type: 'http', scheme: 'bearer', in: 'header' }, 'Bearer')
// .build();
// const document = SwaggerModule.createDocument(app, config);
// SwaggerModule.setup('api', app, document);
const swaagerConfig = readFileSync(path.join(__dirname, '../../swagger.json'), 'utf8');
SwaggerModule.setup('api', app, JSON.parse(swaagerConfig));
};
내 파일에서 dist/swagger.json을 가리키는 경로를 path.join으로 찾아준 다음 readFileSync로 읽어주었다.
순수한 string이기 때문에 이 swaggerConfig를 JSON.parse로 읽어, 자바스크립트 객체로 만들어주었다.
이를 SwaggerModule.setup에 넣어주기만 하면 nestjs 스웨거 문서 연동이 끝난다.
/**
* it's very important API.
*
* how to use? read bellow!
*
* @param id maybe you know already
* @returns true, just return true. that's all.
*/
@TypedRoute.Post(':id')
async nestiaTest(@TypedParam('id', 'number') id: number) {
console.log('id : ', id);
return true;
}
이해를 돕기 위해 이게 스웨거 상에 어떻게 표시되는지를 첨부한다.
스웨거 작성을 위한 document는 아래에서 확인할 수 있다.
@nestia/sdk - sdk(api)
$ npx nestia sdk
이 명령을 입력하면 sdk가 만들어진다.
위에 nestia.config.ts에 정의한대로 생성되기 때문에,
나의 경우 dist/api/functional/nestia/index.ts에 API SDK가 생성된 것을 볼 수 있다.
api/functional 부터는 API의 경로를 표현한 것으로 보인다.
/**
* @packageDocumentation
* @module api.functional.nestia
* @nestia Generated by Nestia - https://github.com/samchon/nestia
*/
//================================================================
import { Fetcher, Primitive } from "@nestia/fetcher";
import type { IConnection } from "@nestia/fetcher";
/**
* it's very important API.
*
* how to use? read bellow!
*
* @param connection connection Information of the remote HTTP(s) server with headers (+encryption password)
* @param id maybe you know already
* @returns true, just return true. that's all.
*
* @controller NestiaController.nestiaTest()
* @path POST /nestia/:id
* @nestia Generated by Nestia - https://github.com/samchon/nestia
*/
export function nestiaTest
(
connection: IConnection,
id: number
): Promise<nestiaTest.Output>
{
return Fetcher.fetch
(
connection,
nestiaTest.ENCRYPTED,
nestiaTest.METHOD,
nestiaTest.path(id)
);
}
export namespace nestiaTest
{
export type Output = Primitive<boolean>;
export const METHOD = "POST" as const;
export const PATH: string = "/nestia/:id";
export const ENCRYPTED: Fetcher.IEncrypted = {
request: false,
response: false,
};
export function path(id: number): string
{
return `/nestia/${encodeURIComponent(id)}`;
}
}
나의 경우 이런 형태로 생성되었는데, 사실 이게 어떻게 생긴 코드인지는 중요하지 않다.
어쨌거나 이 함수를 클라이언트가 가져가서 쓸 수 있다는 게 더 중요하다.
import { nestiaTest } from './dist/api/functional/nestia';
(async function () {
const response = await nestiaTest({ host: 'http://127.0.0.1:3000' }, 1);
})();
테스트를 위해 서버 디렉토리에서 직접 실행해보니 제대로 서버에 요청이 들어갔음을 확인할 수 있다.
참고로 IConnection은 아래와 같다.
import { IEncryptionPassword } from "./IEncryptionPassword";
/**
* Connection information.
*
* `IConnection` is a type of interface who represents connection information of the remote
* HTTP server. You can target the remote HTTP server by wring the {@link IConnection.host}
* variable down. Also, you can configure special header values by specializing the
* {@link IConnection.headers} variable.
*
* If the remote HTTP server encrypts or decrypts its body data through the AES-128/256
* algorithm, specify the {@link IConnection.encryption} with {@link IEncryptionPassword}
* or {@link IEncryptionPassword.Closure} variable.
*
* @author Jenogho Nam - https://github.com/samchon
*/
export interface IConnection {
/**
* Host address of the remote HTTP server.
*/
host: string;
/**
* Header values delivered to the remote HTTP server.
*/
headers?: Record<string, string>;
/**
* Encryption password of its closure function.
*/
encryption?: IEncryptionPassword | IEncryptionPassword.Closure;
}
IConnection을 제외하고는 우리가 만든 API를 포맷팅했기에, 파라미터가 거의 유사하다.
'프로그래밍 > NestJS' 카테고리의 다른 글
Nestia Comment Tags (0) | 2023.03.01 |
---|---|
You provided an invalid object where a stream was expected. (0) | 2023.02.24 |
동일한 400 코드에 대해서 스웨거 에러 스키마 작성하기 (0) | 2023.02.05 |
NestJS에서 S3로 이미지 업로드하기 (0) | 2023.01.31 |
NestJS 스웨거에서 에러 스키마 작성하기 (0) | 2023.01.31 |