Skip to main content

itdoc Interface

This page comprehensively describes the itdoc interface.

describeAPI()​

The primary function for defining and documenting API endpoints.

Signature:

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

Example:

describeAPI(
HttpMethod.GET,
"/users",
{
summary: "Retrieve All Users",
tag: "User",
description: "Returns a list of all users in the system.",
},
app,
(apiDoc) => {
// Define your test cases here.
},
);

Parameters​

method​

The HTTP method of the API.

See examples here.

path​

The URL path for the API endpoint.

Example: /users

tip

If the path contains a PathVariable, define it as shown below and set values with pathParam() in req().

Example: /users/{id}

options​

Configuration options for API documentation including summary, tag, and description.

OptionDescriptionExampleRequired
summaryA brief summary of the API"User Registration API"x
tagTag for grouping the API"User"x
descriptionDetailed description of the API"Returns a list of all users in the system."x

app​

Express application instance used for testing.

info

itdoc uses supertest to simulate HTTP requests. Thus, the app parameter must be an Express instance compatible with supertest.

Example:

  • 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",
    })
    }

    // Skip user creation logic for brevity

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

    export default app
  • Test Code

    import app from "./app.js"

    describeAPI(
    HttpMethod.GET,
    "/signup",
    {
    summary: "Sign Up API",
    description: "Registers a new user with username and password.",
    },
    app,
    (apiDoc) => {},
    )

testCallback​

Callback function for defining tests for the API endpoint.

Inside this callback, you use itDoc() to create test cases.

itDoc()​

Defines individual test cases within a describeAPI block.

Signature:

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

Parameters:

  • description: Description of the test case.
  • testFn: The actual test case function.
warning

testFn must return or execute the apiDoc object received from describeAPI.

Example:

itDoc("Successfully retrieves all users", () => {
return apiDoc
.test()
.req()
.queryParam({ page: 1, limit: 10 })
.res()
.status(HttpStatus.OK)
.body({
users: field("List of users", [{ id: 1, name: "John" }]),
total: field("Total user count", 1),
});
});

apiDoc​

An object for setting up test requests and expected responses.

info

Chain methods in the following mandatory order: test() -> req() -> res().

apiDoc
.test()
.req()
.body({...}) // Request body
.header({...}) // Request headers
.pathParam({...}) // Path parameters
.queryParam({...}) // Query parameters
.res()
.status(...) // Expected response status
.header({...}) // Expected response headers
.body({...}); // Expected response body

test()​

Must be called in every test case.

  • prettyPrint(): Pretty prints the request/response for the test.

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

req()​

Defines values used in API requests.

  • body(body: object): Set JSON request body
  • file(description: string, descriptor: { path?: string; buffer?: Buffer; stream?: Readable; filename?: string; contentType?: string }): Send a single binary payload. Provide exactly one of path, buffer, or stream. Mutually exclusive with body().
  • file(requestFile: DSLRequestFile): Advanced form for custom integrations (expects the same structure as the descriptor above).
  • header(headers: object): Set request headers (Content-Type is managed automatically for .file()).
  • pathParam(params: object): Set path parameters
  • queryParam(params: object): Set query parameters
apiDoc
.test()
.req()
.file("업로드할 파일", {
stream: fs.createReadStream(filePath),
filename: "sample.bin",
contentType: "application/octet-stream",
})
.res()
.status(HttpStatus.CREATED)

res()​

Defines API response attributes. If the actual API response differs, the test will fail.

  • status(status: HttpStatus): Set expected response status
    • See all HttpStatus values here.
  • body(body: object): Set expected response body
  • header(headers: object): Set expected response headers

field()​

Used for documenting fields in request and response bodies.

Signature:

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

Parameters:

  • description: Field description
  • value: Actual value or validation callback

Example​

Using fixed values

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

Using callbacks (validation)

.res()
.body({
token: field("JWT token", 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;
}),
})
tip

You can omit field() and directly use values.

However, omitting field() means the field description won't be documented, so using field() is recommended.

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

Enumerations​

HttpMethod​

Enumeration representing HTTP methods.

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

HttpStatus​

Enumeration representing HTTP status codes.

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,
}