사용 시기
NitroStack 툴 메서드에서 요청 검증, 인가 확인, 응답 매핑, 로깅, 오류 처리 또는 성능 추적을 구현할 때 이 스킬을 사용합니다.
1. 가드 (Guard 및 @UseGuards)
가드는 인증, 인가 또는 기타 조건에 따라 툴 핸들러가 요청을 처리해야 하는지 결정합니다.
인터페이스:
import { Guard, ExecutionContext } from '@nitrostack/core';
export interface Guard {
canActivate(context: ExecutionContext): boolean | Promise<boolean>;
}
예시:
import { Guard, ExecutionContext, Injectable } from '@nitrostack/core';
@Injectable()
export class RolesGuard implements Guard {
async canActivate(context: ExecutionContext): Promise<boolean> {
const userRoles = context.clientMetadata?.roles || [];
return userRoles.includes('admin');
}
}
@UseGuards(...)를 사용하여 가드를 적용합니다:
import { Tool, UseGuards, z } from '@nitrostack/core';
import { RolesGuard } from './roles.guard.js';
export class AdminTools {
@Tool({
name: 'delete_system_logs',
description: '서버에서 모든 시스템 로그를 삭제합니다.',
inputSchema: z.object({}),
})
@UseGuards(RolesGuard)
async deleteLogs() {
return { success: true };
}
}
2. 인터셉터 (InterceptorInterface 및 @UseInterceptors)
인터셉터는 툴 메서드 실행의 입력 인수를 변환하거나 매핑된 출력을 가로챌 수 있습니다.
인터페이스:
import { ExecutionContext } from '@nitrostack/core';
export interface InterceptorInterface {
intercept(context: ExecutionContext, next: () => Promise<unknown>): Promise<unknown>;
}
예시:
import { InterceptorInterface, ExecutionContext, Injectable } from '@nitrostack/core';
@Injectable()
export class TimingInterceptor implements InterceptorInterface {
async intercept(context: ExecutionContext, next: () => Promise<unknown>): Promise<unknown> {
const start = Date.now();
const result = await next();
const duration = Date.now() - start;
context.logger.info(`실행 시간: ${duration}ms`);
return {
...result,
_meta: { durationMs: duration }
};
}
}
3. 예외 필터 (ExceptionFilterInterface 및 @UseFilters)
예외 필터는 가드, 인터셉터 또는 툴 핸들러 자체에서 발생한 모든 오류를 포착하여 사용자 친화적인 JSON 페이로드로 매핑합니다.
인터페이스:
import { ExecutionContext } from '@nitrostack/core';
export interface ExceptionFilterInterface {
catch(exception: unknown, context: ExecutionContext): unknown | Promise<unknown>;
}
예시:
import { ExceptionFilterInterface, ExecutionContext, Injectable } from '@nitrostack/core';
@Injectable()
export class CustomExceptionFilter implements ExceptionFilterInterface {
catch(exception: unknown, context: ExecutionContext) {
const message = exception instanceof Error ? exception.message : '알 수 없는 오류';
return {
error: true,
message,
timestamp: new Date().toISOString()
};
}
}
툴 메서드에 @UseFilters(...)를 사용하여 필터를 적용합니다:
import { Tool, UseFilters, z } from '@nitrostack/core';
import { CustomExceptionFilter } from './custom-exception.filter.js';
export class LoggingTools {
@Tool({
name: 'generate_report',
description: '시스템 사용 보고서를 생성합니다.',
inputSchema: z.object({}),
})
@UseFilters(CustomExceptionFilter)
async generateReport() {
throw new Error('아직 보고서 생성이 구현되지 않았습니다.');
}
}
4. 미들웨어 (MiddlewareInterface, @Middleware 및 @UseMiddleware)
미들웨어는 요청이 툴 핸들러에 도달하기 전에 실행되며, next()를 호출하여 핸들러 실행을 감쌀 수 있습니다.
인터페이스:
import { ExecutionContext } from '@nitrostack/core';
export interface MiddlewareInterface {
use(context: ExecutionContext, next: () => Promise<unknown>): Promise<unknown>;
}
예시:
import { Middleware, MiddlewareInterface, ExecutionContext } from '@nitrostack/core';
@Middleware()
export class LoggingMiddleware implements MiddlewareInterface {
async use(context: ExecutionContext, next: () => Promise<unknown>): Promise<unknown> {
context.logger.info(`툴 진입: ${context.toolName}`);
try {
const result = await next();
context.logger.info(`툴 종료: ${context.toolName}`);
return result;
} catch (error) {
context.logger.error(`툴 오류: ${error}`);
throw error;
}
}
}
툴 메서드에 @UseMiddleware(...)를 사용하여 미들웨어를 적용합니다:
import { Tool, UseMiddleware, z } from '@nitrostack/core';
import { LoggingMiddleware } from './logging.middleware.js';
export class StationTools {
@Tool({
name: 'fetch_logs',
description: '스테이션 작업 로그를 가져옵니다.',
inputSchema: z.object({}),
})
@UseMiddleware(LoggingMiddleware)
async fetchLogs() {
return { status: 'operational' };
}
}
5. 파이프 (PipeInterface, @Pipe 및 @UsePipes)
파이프는 입력 인수가 툴 핸들러 메서드에 도달하기 전에 변환하거나 검증하는 데 사용됩니다.
인터페이스:
import { ArgumentMetadata } from '@nitrostack/core';
export interface PipeInterface<T = unknown, R = unknown> {
transform(value: T, metadata: ArgumentMetadata): R | Promise<R>;
}
예시:
import { Pipe, PipeInterface, ArgumentMetadata } from '@nitrostack/core';
@Pipe()
export class TrimPipe implements PipeInterface<Record<string, unknown>, Record<string, unknown>> {
transform(value: Record<string, unknown>, metadata: ArgumentMetadata) {
const trimmed: Record<string, unknown> = {};
for (const [key, val] of Object.entries(value)) {
trimmed[key] = typeof val === 'string' ? val.trim() : val;
}
return trimmed;
}
}
툴 메서드에 @UsePipes(...)를 사용하여 파이프를 적용합니다:
import { Tool, UsePipes, z } from '@nitrostack/core';
import { TrimPipe } from './trim.pipe.js';
export class MessagingTools {
@Tool({
name: 'send_message',
description: '다른 스테이션에 메시지를 보냅니다.',
inputSchema: z.object({ text: z.string() }),
})
@UsePipes(TrimPipe)
async sendMessage(input: { text: string }) {
return { sentText: input.text };
}
}