π¦ λ μμ μΈ μμ‘΄μ± μ£Όμ 컨ν μ΄λλ‘ μλ μμ‘΄μ± μ£Όμ μ ν΅ν κΉλν μν€ν μ²
Cat Frameworkλ TypeScript λ°μ½λ μ΄ν°μ νμ νμ©νμ¬ κΉλνκ³ μ§κ΄μ μΈ APIλ₯Ό μ 곡νλ μ°¨μΈλ μΉ νλ μμν¬μ λλ€. 볡μ‘ν μ€μ μμ΄ κ°λ ₯ν μμ‘΄μ± μ£Όμ μ μ§μν©λλ€.
@Controller('/api/users')
export class UserController {
@GetMapping('/')
async getUsers(): Promise<HttpResponseEntity> {
return new HttpResponseEntity({ users: await this.userService.findAll() });
}
}μμ±μ νλΌλ―Έν°λ₯Ό ν΅ν μ§κ΄μ μΈ μμ‘΄μ± μ£Όμ μΌλ‘ Spring κ°λ°μλ€μκ² μΉμν μΈν°νμ΄μ€λ₯Ό μ 곡ν©λλ€.
@Service()
export class UserService {
constructor(private readonly userRepository: UserRepository) {
}
async findAll() {
return this.userRepository.findAll();
}
}
@Controller('/users')
export class UserController {
constructor(private readonly userService: UserService) {
} // μλ μ£Όμ
!
@GetMapping('/')
async getUsers(): Promise<HttpResponseEntity> {
const users = await this.userService.findAll();
return new HttpResponseEntity({ users });
}
}μΈν°νμ΄μ€ κΈ°λ° κ°λ°κ³Ό @Inject λ°μ½λ μ΄ν°λ₯Ό ν΅ν΄ ꡬν체λ₯Ό μμ λ‘κ² κ΅μ²΄ν μ μμ΅λλ€.
// μΈν°νμ΄μ€ μ μ
interface UserRepository {
findAll(): Promise<User[]>;
findById(id: number): Promise<User>;
}
// λ€μν ꡬν체
@Repository("UserMysqlRepository")
export class UserMysqlRepository implements UserRepository {
async findAll() { /* MySQL ꡬν */
}
async findById(id: number) { /* MySQL ꡬν */
}
}
@Repository("UserMongoRepository")
export class UserMongoRepository implements UserRepository {
async findAll() { /* MongoDB ꡬν */
}
async findById(id: number) { /* MongoDB ꡬν */
}
}
// ꡬν체 μ νμ μ£Όμ
@Service()
export class UserService {
constructor(
@Inject("UserMysqlRepository") private readonly userRepository: UserRepository
) {
}
// ν
μ€νΈ νκ²½μμλ Mock μ£Όμ
κ°λ₯
// @Inject("UserMockRepository") private readonly userRepository: UserRepository
}볡μ‘ν λͺ¨λ λ±λ‘μ΄λ import κ΄λ¦¬ μμ΄, νμΌ μ€μΊλμ ν΅ν΄ μλμΌλ‘ μμ‘΄μ±μ λ°κ²¬νκ³ λ±λ‘ν©λλ€:
// μ΄λ° 볡μ‘ν μ€μ μ νμ μμ΅λλ€!
// app.module.ts β
// const app = new App([UserController, UserService, UserRepository]);
// κ·Έλ₯ λ°μ½λ μ΄ν°λ§ λΆμ΄λ©΄ λ! β
@Controller('/users') // μλ μ€μΊ & λ±λ‘
export class UserController {
...
}
@Service() // μλ μ€μΊ & λ±λ‘
export class UserService {
...
}npm install @envyw/cat-framework reflect-metadata class-transformer class-validatorλ€λ₯Έ ν¨ν€μ§ λ§€λμ λ μ¬μ©ν μ μμ΅λλ€:
yarn add @envyw/cat-framework reflect-metadata class-transformer class-validator
pnpm add @envyw/cat-framework reflect-metadata class-transformer class-validator
bun add @envyw/cat-framework reflect-metadata class-transformer class-validatorλ―Έλ€μ¨μ΄ 체μ΄λμ ν΅ν΄ λΌμ°ν°λ₯Ό λ±λ‘νμΈμ. κ·Έλ¦¬κ³ μλ²λ₯Ό μ€ν ν¨μλ₯Ό λ±λ‘νμΈμ.
import { CatServer, Injectable } from '@envyw/cat-framework';
@Injectable()
export class App {
constructor(
private readonly router: Router,
private readonly server: CatServer,
) {
}
async start() {
await this.configureServer()
await this.server.create()
await this.server.listen(3001)
}
private async configureServer() {
this.server
.use(this.router)
}
}main μ§μ μ μμ cat ν¨μλ‘ Appμ λ±λ‘νκ³ μ€ννμΈμ.
import { cat } from '@envyw/cat-framework';
cat(App).then(app => app.start())$ ts-node main.ts
Server running on port 3000// user.controller.ts
import { Controller, GetMapping, PostMapping, RequestBody, HttpResponseEntity } from '@envyw/cat-framework';
@Controller('/users')
export class UserController {
@GetMapping('/')
async getUsers(): Promise<HttpResponseEntity> {
return new HttpResponseEntity({ users: [] }, 200);
}
@PostMapping('/')
async createUser(@RequestBody() body: any): Promise<HttpResponseEntity> {
return new HttpResponseEntity({ message: 'μ¬μ©μκ° μμ±λμμ΅λλ€', user: body }, 201);
}
}// user.service.ts
import { Service } from '@envyw/cat-framework';
@Service()
export class UserService {
async findAll() {
return [{ id: 1, name: 'νκΈΈλ' }];
}
}
// user.controller.ts
@Controller('/users')
export class UserController {
constructor(private readonly userService: UserService) {
}
@GetMapping('/')
async getUsers(): Promise<HttpResponseEntity> {
const users = await this.userService.findAll();
return new HttpResponseEntity({ users }, 200);
}
}import { Injectable, Middleware, HttpRequest, HttpResponse } from '@envyw/cat-framework';
@Injectable()
export class LoggerMiddleware implements Middleware {
async handle(req: HttpRequest, res: HttpResponse, next: Function): Promise<void> {
console.log(`${req.method} ${req.path}`);
next();
}
}
// λ―Έλ€μ¨μ΄ λ±λ‘
@Injectable()
export class App {
constructor(
private readonly server: CatServer,
private readonly loggerMiddleware: LoggerMiddleware
) {
}
async start() {
this.server.use(this.loggerMiddleware);
await this.server.create();
await this.server.listen(3000);
}
}@Controller('/upload')
export class UploadController {
@PostMapping('/')
async uploadFile(@Multipart() files: any[]): Promise<HttpResponseEntity> {
return new HttpResponseEntity({
message: 'νμΌμ΄ μ
λ‘λλμμ΅λλ€',
count: files.length
});
}
}@Controller('/protected')
export class ProtectedController {
@GetMapping('/profile')
async getProfile(@Authenticated() userId: number): Promise<HttpResponseEntity> {
return new HttpResponseEntity({ userId, message: 'μΈμ¦λ μ¬μ©μ' });
}
}Cat Frameworkλ λ€μ λ°μ½λ μ΄ν°λ€μ μ 곡ν©λλ€:
@Controller(basePath?)- 컨νΈλ‘€λ¬ ν΄λμ€ μ μ@Service()- μλΉμ€ ν΄λμ€ νμ@Repository()- λ ν¬μ§ν 리 ν΄λμ€ νμ@Injectable()- μ£Όμ κ°λ₯ν ν΄λμ€ νμ
@GetMapping(path)- GET μμ² λΌμ°ν@PostMapping(path)- POST μμ² λΌμ°ν
@RequestBody()- μμ² λ³Έλ¬Έ μ£Όμ@RequestParam()- 쿼리 νλΌλ―Έν° μ£Όμ@Multipart()- λ©ν°ννΈ νμΌ μ£Όμ@Authenticated()- μΈμ¦λ μ¬μ©μ ID μ£Όμ@Inject(token)- 컀μ€ν μμ‘΄μ± μ£Όμ
const response = new HttpResponseEntity(body, status, headers);κΈ°λ³Έκ°: body = {}, status = 200, headers = {}
interface Middleware {
handle(req: HttpRequest, res: HttpResponse, next: Function, err?: Error): Promise<void>
}Cat Frameworkλ λ€μ νκ²½ λ³μλ€μ μ§μν©λλ€.
CAT_LOG_LEVEL- λ‘κΉ λ 벨 μ€μ (ERROR,WARN,INFO,DEBUG)VIEW_FILE_PATH- HTML νμΌ κ²½λ‘STATIC_FILE_PATH- μ μ νμΌ κ²½λ‘
{
"compilerOptions": {
"target": "ES2022",
"module": "CommonJS",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"strict": true
}
}κ°μ₯ κ°λ₯μ±μ΄ λμ μμΈμ 컨νΈλ‘€λ¬ νμΌμ΄ μ¬λ°λ₯Έ μμΉμ μμ§ μκΈ° λλ¬Έμ
λλ€. src/ λλ ν 리 λ΄μ μλμ§ νμΈνμΈμ.
λλ²κ·Έ λͺ¨λλ₯Ό μΌκ³ λ€μ μλν΄λ³΄μΈμ:
CAT_LOG_LEVEL=DEBUG node main.jsμ½μμ λμμ΄ λλ μ€λ₯ λ©μμ§κ° μΆλ ₯λ©λλ€.
λ―Έλ€μ¨μ΄κ° server.create() μ μ λ±λ‘λμλμ§ νμΈνμΈμ:
async
start()
{
this.server.use(this.middleware); // create() μ μ λ±λ‘
await this.server.create();
await this.server.listen(3000);
}Content-Type ν€λκ° application/jsonμΌλ‘ μ€μ λμλμ§ νμΈνμΈμ. Cat Frameworkλ νμ¬ JSON ννμ μμ² λ³Έλ¬Έλ§ μ§μν©λλ€.
reflect-metadataλ₯Ό importνλμ§ νμΈνκ³ , tsconfig.jsonμμ λ°μ½λ μ΄ν° μ€μ μ΄ νμ±νλμ΄ μλμ§ νμΈνμΈμ:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}λ€! νκ²½ λ³μλ₯Ό μ€μ νμΈμ:
STATIC_FILE_PATH=./public
VIEW_FILE_PATH=./viewsμ΄μ μ μ νμΌλ€μ΄ μλμΌλ‘ μ 곡λ©λλ€.
reflect-metadata- λ°μ½λ μ΄ν° λ©νλ°μ΄ν° (νμ)class-transformer- DTO λ³νclass-validator- μμ² κ²μ¦