Skip to Content
문서시작하기첫 번째 API

첫 번째 API

이 가이드는 최소하지만 완전한 ASAPJS API를 구축하는 과정을 안내합니다. 마지막에는 약 10분 안에 데이터베이스 테이블을 기반으로 하는 GET /api/users 엔드포인트가 작동하게 됩니다.

구축할 것: 데이터베이스 엔티티, 응답 DTO, 컨트롤러, 그리고 부트스트랩된 애플리케이션을 갖춘 User 도메인.

사전 요구사항: 설치를 완료했습니다. tsconfig.jsonexperimentalDecoratorsemitDecoratorMetadatatrue로 설정되어 있고, reflect-metadata가 설치되어 있습니다.


1단계: 애플리케이션 설정 생성

src/index.ts에 진입점을 만드세요. config 객체는 ASAPJS에게 사용할 포트, 로드할 익스텐션, JWT 및 데이터베이스 설정을 알려줍니다.

// src/index.ts import 'reflect-metadata'; import dotenv from 'dotenv'; import { Application } from '@asapjs/core'; dotenv.config(); const config = { name: 'my-api', port: Number(process.env.PORT) || 3000, basePath: 'api', // ASAPJS가 로드할 익스텐션 목록 — router와 sequelize 모두 필요합니다 extensions: ['@asapjs/router', '@asapjs/sequelize'], auth: { jwt_access_token_secret: process.env.JWT_SECRET || 'dev-secret', }, db: { username: process.env.DB_USER || 'root', password: process.env.DB_PASSWORD || '', database: process.env.DB_NAME || 'myapp', host: process.env.DB_HOST || 'localhost', port: parseInt(process.env.DB_PORT || '3306', 10), dialect: 'sqlite', // 빠른 로컬 개발에는 sqlite 사용; 프로덕션에서는 'mysql'로 변경 storage: ':memory:', // 인메모리 SQLite; 실제 데이터베이스에는 이 옵션 생략 logging: false, }, }; const app = new Application(__dirname, config); app.run(async () => { console.log(`API running at http://localhost:${config.port}/${config.basePath}`); });

팁: 데이터베이스 서버 없이 빠른 로컬 개발을 하려면 dialect: 'sqlite'storage: ':memory:'를 설정하세요. yarn add sqlite3으로 sqlite3를 설치하세요.


2단계: 데이터베이스 엔티티 생성

엔티티는 @Table로 데코레이팅된 Sequelize 모델입니다. TypeIs 데코레이터는 Sequelize 컬럼 타입과 Swagger 스키마를 한 곳에서 정의합니다.

// src/user/domain/entity/UsersTable.ts import { Model } from 'sequelize-typescript'; import { Table, TypeIs } from '@asapjs/sequelize'; @Table({ tableName: 'users', timestamps: true, }) export default class UsersTable extends Model { @TypeIs.INT({ primaryKey: true, autoIncrement: true, comment: 'User ID' }) id: number; @TypeIs.STRING({ unique: true, comment: 'Email address (unique)' }) email: string; @TypeIs.STRING({ comment: 'Display name' }) name: string; @TypeIs.DATETIME({ comment: 'Created at' }) created_at: Date; }

파일명 규칙 *Table.ts (복수형의 경우 *sTable.ts)는 중요합니다: @asapjs/sequelize는 시작 시 __dirname 아래에서 이 패턴과 일치하는 모든 파일을 자동으로 찾아 등록합니다.


3단계: 응답 DTO 생성

DTO는 API로 보내고 받는 데이터의 형태를 정의합니다. 또한 Swagger 스키마를 자동으로 생성합니다. 사용자 응답이 어떻게 생겼는지 설명하는 UserInfoDto를 만드세요:

// src/user/dto/UserInfoDto.ts import { ExtendableDto, Dto, TypeIs } from '@asapjs/sequelize'; import UsersTable from '../domain/entity/UsersTable'; @Dto({ name: 'user_info_dto', defineTable: UsersTable }) export default class UserInfoDto extends ExtendableDto { @TypeIs.INT({ comment: 'User ID' }) id: number; @TypeIs.STRING({ comment: 'Email address' }) email: string; @TypeIs.STRING({ comment: 'Display name' }) name: string; }

4단계: 애플리케이션 레이어 생성

Application 클래스는 비즈니스 로직을 담습니다. Controller와 데이터베이스 엔티티 사이에 위치합니다.

// src/user/application/UserApplication.ts import UsersTable from '../domain/entity/UsersTable'; export default class UserApplication { private users = UsersTable; async getAllUsers() { return this.users.findAll({ attributes: ['id', 'email', 'name', 'created_at'], }); } }

5단계: 컨트롤러 생성

Controller는 RouterController를 확장하고 라우트 데코레이터를 사용하여 Express 라우트를 등록합니다. 각 데코레이터는 해당 Swagger 문서 항목도 함께 생성합니다.

// src/user/controller/UserController.ts import { RouterController, Get, ExecuteArgs } from '@asapjs/router'; import UserApplication from '../application/UserApplication'; import UserInfoDto from '../dto/UserInfoDto'; export default class UserController extends RouterController { public tag = 'User'; public basePath = '/users'; private userService: UserApplication; constructor() { super(); this.registerRoutes(); this.userService = new UserApplication(); } @Get('/', { title: 'List all users', description: 'Returns all registered users', response: UserInfoDto, }) async listUsers({ }: ExecuteArgs) { return await this.userService.getAllUsers(); } }

@Get 데코레이터는 경로와 옵션 객체를 받습니다. 옵션 객체에 auth: true를 설정하면 해당 엔드포인트에 유효한 JWT 토큰이 필요합니다. auth를 생략하거나 false로 설정하면 엔드포인트가 공개됩니다.


6단계: 라우트 등록

컨트롤러 인스턴스 배열을 내보내는 src/route.ts 파일을 만드세요. ASAPJS는 이 파일을 자동으로 찾습니다 (진입점과 같은 디렉토리에서 route.ts 또는 route.js를 찾습니다):

// src/route.ts import UserController from './user/controller/UserController'; export default [new UserController()];

애플리케이션이 성장함에 따라 이 배열에 더 많은 컨트롤러를 추가하세요.


7단계: Application.run()으로 부트스트랩

1단계의 src/index.ts는 이미 완성되어 있습니다. Application 생성자는 __dirname을 받아 프레임워크가 route.ts, *Table.ts 파일 등 자동 탐색 모듈을 어디서 찾아야 하는지 알 수 있게 합니다.

이 튜토리얼에서는 첫 번째 실행 시 SQLite 테이블이 생성되도록 DB_SYNC 확인을 추가합니다:

// src/index.ts (업데이트된 run 콜백) import { getSequelize } from '@asapjs/sequelize'; app.run(async () => { const sequelize = await getSequelize(); // 아직 존재하지 않는 테이블 생성 (개발 환경에서 안전) if (process.env.DB_SYNC === 'true') { await sequelize.sync({ alter: true }); console.log('Database synced'); } console.log(`API running at http://localhost:${config.port}/${config.basePath}`); });

8단계: 실행 및 테스트

서버를 시작하세요:

DB_SYNC=true npx ts-node src/index.ts

DB_SYNC=true 플래그는 첫 번째 실행 시 users 테이블을 생성합니다. 첫 번째 실행 후에는 생략할 수 있습니다.

curl로 엔드포인트를 테스트하세요:

curl http://localhost:3000/api/users

예상 응답 (빈 데이터베이스의 경우 빈 배열):

[]

Swagger UI도 자동으로 다음 주소에서 사용할 수 있습니다:

http://localhost:3000/api-docs

전체 파일 레이아웃

모든 단계를 따른 후 프로젝트는 다음과 같은 구조여야 합니다:

src/ user/ application/ UserApplication.ts controller/ UserController.ts domain/ entity/ UsersTable.ts dto/ UserInfoDto.ts index.ts route.ts

이것이 ASAPJS가 설계된 도메인 기반 레이아웃입니다. 프로젝트 구조로 계속 진행하여 명명 규칙과 자동 탐색 메커니즘이 어떻게 작동하는지 이해하세요.

Last updated on