본문으로 건너뛰기

itdoc 인터페이스

이 페이지에서는 itdoc의 인터페이스에 대해 포괄적으로 설명합니다.

describeAPI()

API 엔드포인트를 정의하고 문서화하는 주요 함수입니다.

시그니처:

function describeAPI(
method: HttpMethod,
path: string,
options: ApiDocOptions,
app: Express.Application | any,
testCallback: (apiDoc: RootBuilder) => void,
): void

예시:

describeAPI(
HttpMethod.GET,
"/users",
{
summary: "모든 사용자 조회",
tag: "사용자",
description: "시스템의 모든 사용자 목록을 반환합니다",
},
app,
(apiDoc) => {
// 여기에 테스트 케이스를 정의합니다.
},
)

매개변수 설명

method

API의 HTTP 메소드입니다.

값 예시는 여기를 참조하세요.

path

API 엔드포인트의 URL 경로입니다.

예시: /users

만일 PathVariable을 포함하는 경로라면, 예시와 같이 정의하고 req()에서 pathParam()으로 값을 설정하세요.

예시: /users/{id}

options

API 문서화에 필요한 요약, 태그, 설명을 포함한 구성 옵션입니다.

옵션설명예시 값필수 여부
summaryAPI의 간략한 요약 설명"사용자 등록 API"x
tagAPI를 그룹화하기 위한 태그"사용자"x
descriptionAPI에 대한 자세한 설명"시스템에 등록된 모든 사용자 목록을 반환합니다."x

app

테스트할 Express 애플리케이션 인스턴스입니다.

정보

itdocsupertest를 사용하여 HTTP 요청을 시뮬레이션합니다. 따라서 app 매개변수는 supertest와 호환되는 Express 인스턴스여야 합니다.

예시:

  • app.js

    import express from "express";

    const app = express()

    app.use(express.json())

    app.post("/signup", function (req, res) {
    const { username, password } = req.body

    if (!username || !password) {
    return res.status(400).json({
    error: "username and password are required",
    })
    }

    if (password.length < 8) {
    return res.status(400).json({
    error: "password must be at least 8 characters",
    })
    }

    // (회원 가입 코드는 생략)

    return res.status(201).json()
    })

    export default app
  • 테스트 코드

    import app from "./app.js"

    describeAPI(
    HttpMethod.GET,
    "/signup",
    {
    summary: "회원가입 API",
    description: "아이디와 패스워드를 받아 회원가입을 수행합니다.",
    },
    app,
    (apiDoc) => {},
    )

testCallback

API 엔드포인트 테스트를 정의하는 콜백 함수입니다.

이 콜백 내부에서 itDoc()을 사용하여 테스트 케이스를 작성합니다.

itDoc()

describeAPI 블록 내에서 개별 테스트 케이스를 정의합니다.

시그니처:

function itDoc(description: string, testFn: () => RootBuilder | Promise<RootBuilder>): void

매개변수:

  • description: 테스트 케이스에 대한 설명입니다.
  • testFn: 실제 테스트 케이스 정의 함수입니다.
경고

testFn에서는 반드시 describeAPI에서 전달받은 apiDoc 객체를 반환하거나 실행해야 합니다.

예시:

itDoc("모든 사용자를 성공적으로 검색합니다", () => {
return apiDoc
.test()
.req()
.queryParam({ page: 1, limit: 10 })
.res()
.status(HttpStatus.OK)
.body({
users: field("사용자 목록", [{ id: 1, name: "John" }]),
total: field("총 사용자 수", 1),
});
});

apiDoc

테스트 요청 및 예상 응답을 설정하는 객체입니다.

정보

무조건 test() -> req() -> res() 순서로 체이닝해야 합니다.

apiDoc
.test()
.req()
.body({...}) // 요청 본문
.header({...}) // 요청 헤더
.pathParam({...}) // 경로 매개변수
.queryParam({...}) // 쿼리 매개변수
.res()
.status(...) // 예상하는 응답 상태
.header({...}) // 예상하는 응답 헤더
.body({...}); // 예상하는 응답 본문

test()

모든 테스트 케이스에서 반드시 호출해야 합니다.

  • prettyPrint(): 테스트의 request/response를 예쁘게 출력합니다.

    apiDoc
    .test()
    .prettyPrint()
    .req()
    ...

req()

여기서 정의한 값이 API 요청에 사용됩니다.

  • body(body: object): 요청 본문 설정
  • header(headers: object): 요청 헤더 설정
  • pathParam(params: object): 경로 매개변수 설정
  • queryParam(params: object): 쿼리 매개변수 설정
  • expectStatus(status: HttpStatus): 예상 응답 상태 설정 (필수 호출)

res()

API 응답 속성을 정의합니다. 여기서 정의한 값과 실제 API 응답이 다르면, 테스트가 실패합니다.

  • status(status: HttpStatus): 예상 응답 상태 코드 설정
    • 여기서 사용되는 HttpStatus여기에서 확인할 수 있습니다.
  • body(body: object): 예상 응답 본문 설정
  • header(headers: object): 예상 응답 헤더 설정

field()

요청 및 응답 본문의 필드를 문서화할 때 사용합니다.

시그니처:

function field<T>(description: string, value: T | ((val: any) => T)): T

매개변수:

  • description: 필드 설명
  • value: 실제 값 또는 값 검증 함수

예시

고정된 값 사용

.res()
.body({
token: field("JWT 토큰", "eyJhbGciOi...")
})

콜백 사용 (응답 검증)

.res()
.body({
token: field("JWT 토큰", val => {
const jwtPattern = /^([A-Za-z0-9\-_]+)\.([A-Za-z0-9\-_]+)\.([A-Za-z0-9\-_]+)$/;
if (!jwtPattern.test(val)) throw new Error(`Invalid JWT token format: ${val}`);
return val;
}),
})

field()를 생략하고 값을 직접 사용할 수 있습니다.

다만 이 경우엔 필드에 대한 설명이 문서화 되지 않으므로, 가능한 field()를 사용하는 것이 좋습니다.

.req()
.body({ username: "john_doe" });

열거형

HttpMethod

HTTP 메소드를 나타내는 열거형입니다.

enum HttpMethod {
GET = "GET",
POST = "POST",
PUT = "PUT",
DELETE = "DELETE",
PATCH = "PATCH",
HEAD = "HEAD",
OPTIONS = "OPTIONS",
TRACE = "TRACE",
CONNECT = "CONNECT",
}

HttpStatus

HTTP 상태 코드를 나타내는 열거형입니다.

export enum HttpStatus {
CONTINUE = 100,
SWITCHING_PROTOCOLS = 101,
PROCESSING = 102,
EARLY_HINTS = 103,

OK = 200,
CREATED = 201,
ACCEPTED = 202,
NON_AUTHORITATIVE_INFORMATION = 203,
NO_CONTENT = 204,
RESET_CONTENT = 205,
PARTIAL_CONTENT = 206,
MULTI_STATUS = 207,
ALREADY_REPORTED = 208,
IM_USED = 226,

MULTIPLE_CHOICES = 300,
MOVED_PERMANENTLY = 301,
FOUND = 302,
SEE_OTHER = 303,
NOT_MODIFIED = 304,
USE_PROXY = 305,
TEMPORARY_REDIRECT = 307,
PERMANENT_REDIRECT = 308,

BAD_REQUEST = 400,
UNAUTHORIZED = 401,
PAYMENT_REQUIRED = 402,
FORBIDDEN = 403,
NOT_FOUND = 404,
METHOD_NOT_ALLOWED = 405,
NOT_ACCEPTABLE = 406,
PROXY_AUTHENTICATION_REQUIRED = 407,
REQUEST_TIMEOUT = 408,
CONFLICT = 409,
GONE = 410,
LENGTH_REQUIRED = 411,
PRECONDITION_FAILED = 412,
PAYLOAD_TOO_LARGE = 413,
URI_TOO_LONG = 414,
UNSUPPORTED_MEDIA_TYPE = 415,
RANGE_NOT_SATISFIABLE = 416,
EXPECTATION_FAILED = 417,
IM_A_TEAPOT = 418,
MISDIRECTED_REQUEST = 421,
UNPROCESSABLE_ENTITY = 422,
LOCKED = 423,
FAILED_DEPENDENCY = 424,
TOO_EARLY = 425,
UPGRADE_REQUIRED = 426,
PRECONDITION_REQUIRED = 428,
TOO_MANY_REQUESTS = 429,
REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
UNAVAILABLE_FOR_LEGAL_REASONS = 451,

INTERNAL_SERVER_ERROR = 500,
NOT_IMPLEMENTED = 501,
BAD_GATEWAY = 502,
SERVICE_UNAVAILABLE = 503,
GATEWAY_TIMEOUT = 504,
HTTP_VERSION_NOT_SUPPORTED = 505,
VARIANT_ALSO_NEGOTIATES = 506,
INSUFFICIENT_STORAGE = 507,
LOOP_DETECTED = 508,
NOT_EXTENDED = 510,
NETWORK_AUTHENTICATION_REQUIRED = 511,
}