핵심:
docs블록에 응답 JSON을 정확히 작성하면 끝입니다.
meta {
name: API 이름
type: http
}
get /api/endpoint
headers {
Authorization: Bearer {{token}}
}
body:json {
{
"key": "value"
}
}
docs {
````json
{
"id": 1,
"username": "johndoe"
}
````
}docs 블록이 전부입니다! 이 블록의 JSON으로 타입과 스키마가 자동 생성됩니다.
올바른 예시 (단일 응답):
docs {
````json
{
"id": 1,
"username": "johndoe",
"email": "john@example.com",
"createdAt": "2025-01-01T00:00:00Z",
"profile": {
"age": 25,
"city": "Seoul"
},
"tags": ["developer", "backend"]
}
````
}올바른 예시 (상태 코드별 응답):
여러 상태 코드를 정의할 수 있지만, 200 OK만 사용됩니다:
docs {
## 200 OK
```
{
"id": 1,
"username": "johndoe",
"email": "john@example.com"
}
```
## 404 Not Found
```
{
"message": "사용자를 찾을 수 없습니다."
}
```
}200 OK 응답이 없으면 타입 생성이 실패합니다!
❌ 잘못된 예시 (200 OK 없음):
docs {
## 404 Not Found
```
{
"message": "사용자를 찾을 수 없습니다."
}
```
}✅ 올바른 예시:
docs {
## 200 OK
```
{
"id": 1,
"username": "johndoe"
}
```
## 404 Not Found
```
{
"message": "사용자를 찾을 수 없습니다."
}
```
}주의사항:
- 200 OK 응답이 여러 개 있으면 첫 번째만 사용됩니다
- 200 OK 응답의 JSON이 실제 응답과 정확히 일치해야 합니다
- 200 OK 응답이 없으면 단일 JSON 코드 블록을 찾지만, 그것도 없으면 타입 생성 실패
- ✅ 실제 응답과 동일하게 작성
- ✅ 모든 필드를 포함 (옵셔널 필드도)
- ✅ 타입이 명확한 값 사용:
- 문자열:
"hello" - 숫자:
123또는4.5 - 불린:
true/false - 배열:
[1, 2, 3](최소 1개 요소 포함) - 객체:
{ "key": "value" } - null:
null
- 문자열:
- ✅ 날짜는 ISO 8601 형식:
"2025-01-01T00:00:00Z"
❌ 잘못된 예시:
docs {
````json
{
id: 1, // 키에 따옴표 없음
"name": '홍길동' // 작은따옴표 사용
}
````
}❌ 빈 배열:
docs {
````json
{
"users": [] // 타입 추론 불가 → any[]로 추론됨
}
````
}any[]로 추론되므로, 최소 1개 요소를 포함해야 합니다.
❌ null 값으로 인한 타입 오류:
null 값이 있으면 해당 필드의 타입이 null로 고정되어 실제 사용 시 타입 오류가 발생할 수 있습니다.
docs {
````json
{
"optionalField": null // null로 추론되어 타입이 null로 고정됨
}
````
}✅ 올바른 예시 (옵셔널 필드 - 배열에서 유니온 타입 생성):
배열 응답에서 여러 아이템을 확인하여 유니온 타입을 자동 생성합니다:
docs {
````json
[
{
"status": "active",
"data": "hello",
"optionalField": "value"
},
{
"status": null,
"data": null,
"optionalField": null
}
]
````
}생성되는 타입:
export interface ResponseItem {
status: "active" | null;
data: "hello" | null;
optionalField: "value" | null;
}✅ 단일 객체에서 옵셔널 필드:
단일 객체의 경우 null 값은 null 타입으로만 추론됩니다. 옵셔널 필드를 표현하려면 배열로 작성하세요:
docs {
````json
{
"requiredField": "value",
"optionalField": "example" // 실제 값으로 작성
}
````
}✅ 올바른 예시:
docs {
````json
{
"users": [
{
"id": 1,
"name": "예시"
}
]
}
````
}파일명과 폴더명은 생성되는 코드의 구조와 이름에 직접 영향을 미칩니다. 일관된 네이밍을 위해 다음 규칙을 따르세요.
폴더명은 생성되는 도메인 디렉토리 이름이 됩니다.
-
숫자) 한글명 [영문키]형식 (권장)1) 어드민 [Admin]/ → 생성 폴더: Admin 7) 어드민 [Admin]/ → 생성 폴더: Admin 8) 사용자 [Users]/ → 생성 폴더: Users 9) 멘토 [Mentor]/ → 생성 폴더: Mentor- 대괄호 안의
영문키만 사용됩니다 - 숫자와 한글명은 가독성을 위해 사용, 실제 폴더명에는 포함되지 않음
- 대괄호 안의
-
한글명 [영문키]형식 (기존 방식, 호환)지원서 [applications]/ → 생성 폴더: applications 사용자 [users]/ → 생성 폴더: users- 대괄호 안의
영문키만 사용됩니다 - 기존 프로젝트와 호환됩니다
- 대괄호 안의
-
영문 폴더명 (가장 단순)
applications/ → 생성 폴더: applications users/ → 생성 폴더: users- 패턴이 없으면 폴더명 그대로 사용
| Bruno 폴더명 | 생성되는 폴더 | 설명 |
|---|---|---|
1) 어드민 [Admin] |
Admin |
대괄호 안의 키만 사용 |
7) 어드민 [Admin] |
Admin |
숫자는 무시됨 |
지원서 [applications] |
applications |
대괄호 안의 키만 사용 |
users |
users |
그대로 사용 |
파일명이 API 함수 이름에 직접 사용됩니다!
⚠️ 중요: 파일명에 HTTP 메서드를 포함하지 마세요. 메서드는.bru파일 내부의get,post,put,patch,delete블록에서 자동으로 인식됩니다.
-
한글명 [영문키]형식 (권장, 폴더명과 동일한 패턴)멘토 목록 조회 [mentor-list].bru → mentor-list → mentorList → getMentorList 사용자 프로필 [user-profile].bru → user-profile → userProfile → getUserProfile 지원서 생성 [create-application].bru → create-application → createApplication → postCreateApplication- 대괄호 안의
영문키만 사용됩니다 - 한글명은 가독성을 위해 사용, 실제 코드 생성에는 포함되지 않음
- HTTP 메서드 prefix는 자동으로 제거됩니다 (예:
delete-account→account)
- 대괄호 안의
-
영문 파일명 (기존 방식, 호환)
competitors.bru → competitors → getCompetitors user-profile.bru → user-profile → getUserProfile create-application.bru → create-application → postCreateApplication- 패턴이 없으면 파일명 그대로 사용
- HTTP 메서드 prefix는 자동으로 제거됩니다
✅ 올바른 예시:
멘토 목록 조회 [mentor-list].bru → mentorList → getMentorList
사용자 프로필 [user-profile].bru → userProfile → getUserProfile
지원서 생성 [create-application].bru → createApplication → postCreateApplication
프로필 수정 [update-profile].bru → updateProfile → putUpdateProfile
회원 탈퇴 [account].bru → account → deleteAccount
❌ 잘못된 예시 (HTTP 메서드 포함):
멘토 목록 조회 [get-mentor-list].bru → getMentorList → getGetMentorList (중복!)
사용자 삭제 [delete-user].bru → deleteUser → deleteDeleteUser (중복!)
-
kebab-case 사용 (하이픈으로 단어 구분)
- ✅
user-profile.bru - ❌
userProfile.bru(camelCase) - ❌
user_profile.bru(snake_case) - ❌
UserProfile.bru(PascalCase)
- ✅
-
HTTP 메서드 포함하지 않기 (필수)
- ✅
account.bru(DELETE 메서드 → deleteAccount) - ✅
sign-up.bru(POST 메서드 → postSignUp) - ✅
mentor-list.bru(GET 메서드 → getMentorList) - ❌
delete-account.bru(메서드 중복 → deleteDeleteAccount) - ❌
post-sign-up.bru(메서드 중복 → postPostSignUp)
- ✅
-
명확하고 간결한 이름
- ✅
competitors.bru(명확함) - ✅
create-application.bru(명확함) - ❌
api1.bru(불명확) - ❌
test.bru(불명확)
- ✅
-
한글 파일명 피하기
- ❌
멘토 목록 조회.bru(함수 이름 생성 시 문제 가능) - ✅
mentor-list.bru(영문 사용)
- ❌
| Bruno 파일명 | HTTP 메서드 | 추출된 키 | 함수 이름 |
|---|---|---|---|
멘토 목록 조회 [mentor-list].bru |
GET | mentor-list |
getMentorList |
사용자 프로필 [user-profile].bru |
GET | user-profile |
getUserProfile |
지원서 생성 [create].bru |
POST | create |
postCreate |
회원 탈퇴 [account].bru |
DELETE | account |
deleteAccount |
competitors.bru |
GET | competitors |
getCompetitors |
멘토 목록 조회.bru |
GET | 멘토 목록 조회 |
get멘토목록조회 ❌ |
핵심:
한글명 [영문키]형식으로 작성하면 한글 설명과 영문 코드를 모두 활용할 수 있습니다- 대괄호 안의 영문키만 kebab-case로 작성하면, 자동으로 일관된 API 함수 이름이 생성됩니다!
- HTTP 메서드는 파일명에 포함하지 마세요 -
.bru파일 내부에서 자동으로 인식됩니다!
bruno/
├── 7) 어드민 [Admin]/ # 폴더명: Admin
│ ├── 목록 조회 [list].bru # → adminApi.getList
│ ├── 생성 [create].bru # → adminApi.postCreate
│ └── 수정 [update].bru # → adminApi.putUpdate
├── 지원서 [applications]/ # 폴더명: applications
│ ├── 경쟁자 조회 [competitors].bru # → applicationsApi.getCompetitors
│ ├── 상세 조회 [details].bru # → applicationsApi.getDetails
│ └── 지원서 생성 [create].bru # → applicationsApi.postCreate
├── 사용자 [users]/ # 폴더명: users
│ ├── 프로필 조회 [profile].bru # → usersApi.getProfile
│ └── 프로필 수정 [update-profile].bru # → usersApi.putUpdateProfile
└── bruno.json
생성되는 구조:
src/apis/
├── Admin/
│ ├── api.ts # adminApi 팩토리
│ ├── apiDefinitions.ts # 타입 정의
│ └── index.ts
├── applications/
│ ├── api.ts # applicationsApi 팩토리
│ ├── apiDefinitions.ts # 타입 정의
│ └── index.ts
├── users/
│ ├── api.ts # usersApi 팩토리
│ ├── apiDefinitions.ts # 타입 정의
│ └── index.ts
meta {
name: Get Competitors
type: http
}
get /applications/competitors
headers {
Authorization: Bearer {{token}}
}
docs {
````json
{
"firstChoice": [
{
"universityId": 1,
"koreanName": "데겐도르프대학",
"studentCapacity": 150,
"applicantCount": 120
}
],
"secondChoice": [],
"thirdChoice": []
}
````
}meta {
name: Create Application
type: http
}
post /applications
headers {
Authorization: Bearer {{token}}
Content-Type: application/json
}
body:json {
{
"universityId": 1,
"choice": "first"
}
}
docs {
````json
{
"id": 123,
"status": "pending",
"submittedAt": "2025-11-12T05:30:00Z"
}
````
}meta {
name: Get Application Detail
type: http
}
get /applications/:id
headers {
Authorization: Bearer {{token}}
}
docs {
````json
{
"id": 123,
"userId": 456,
"status": "approved",
"reviewer": {
"id": 789,
"name": "심사자"
}
}
````
}MSW 핸들러는 모든 API에 대해 생성되며, 프론트엔드에서 플래그로 활성/비활성을 제어합니다.
생성된 handlers.ts 파일에서 환경 변수나 설정으로 제어할 수 있습니다:
예시 1: 환경 변수로 제어
// src/mocks/handlers.ts
import { authHandlers } from "./Auth";
import { usersHandlers } from "./Users";
const ENABLE_MSW = process.env.NEXT_PUBLIC_ENABLE_MSW === "true";
export const handlers = ENABLE_MSW ? [...authHandlers, ...usersHandlers] : [];예시 2: 특정 도메인만 활성화
export const handlers = [
...authHandlers, // Auth 도메인만 활성화
// ...usersHandlers, // Users 도메인 비활성화
];예시 3: 조건부 필터링
const enabledDomains = ["Auth", "Users"]; // 활성화할 도메인 목록
export const handlers = [
...(enabledDomains.includes("Auth") ? authHandlers : []),
...(enabledDomains.includes("Users") ? usersHandlers : []),
];새 API 엔드포인트를 만들 때:
-
meta블록 작성 (name 필수) - HTTP 메서드와 경로 명확히 표기
- 인증 필요시
headers블록에 Authorization - POST/PUT이면
body:json블록 작성 -
docs블록 반드시 작성 (가장 중요!) - JSON이 유효한가? (온라인 validator로 확인)
- 모든 필드가 포함되었나?
- 배열에 최소 1개 요소가 있나?
- 날짜는 ISO 8601 형식인가?
meta {
name: [API 이름]
type: http
}
get /[경로]
headers {
Authorization: Bearer {{token}}
}
docs {
```json
{
"id": 1,
"field": "value"
}}
### POST 템플릿
```bru
meta {
name: [API 이름]
type: http
}
post /[경로]
headers {
Authorization: Bearer {{token}}
Content-Type: application/json
}
body:json {
{
"field": "value"
}
}
docs {
```json
{
"id": 1,
"status": "success"
}
}
## 문제 해결
1. **파싱 에러**: docs 블록의 JSON을 복사해서 [JSONLint](https://jsonlint.com/)로 검증
2. **타입이 이상함**: 값의 타입 확인 (숫자는 따옴표 없이, 문자열은 따옴표)
3. **필드가 안보임**: docs 블록에 해당 필드 추가했는지 확인
---
**핵심은 `docs` 블록을 정확하게 작성하는 것!**