이 문서는 BlueTalk 서버가 WebSocket / REST API에서 사용하는
에러 응답 구조와 대표 에러 코드를 정리한 문서입니다.
API 개요와
인증 구조와 함께 보시면 전체 흐름을 이해하기 좋습니다.
BlueTalk는 성공/실패를 명확하게 구분하기 위해
응답에 공통적으로 ok 값을 사용합니다.
// 성공 응답 (예시)
{
"ok": true,
"data": { ... } // 또는 "file": { ... }, "result": { ... } 등
}
// 실패 응답 (WebSocket 기본 패턴)
{
"ok": false,
"error": {
"code": "ERROR_CODE",
"message": "사람이 읽을 수 있는 에러 메시지 (선택)"
}
}
// 실패 응답 (REST 파일 업로드: 간단한 패턴)
{
"ok": false,
"reason": "ERROR_CODE"
}
true면 성공, false면 실패입니다.
WebSocket 이벤트는 기본적으로 { ok, error: { code, message } } 패턴을 사용하며,
REST 파일 업로드(/upload/chat-file)는 현재 구현상 { ok, reason } 형태를 사용합니다.
WebSocket 이벤트에서 에러가 발생하면, 서버는 다음과 같은 형태로 응답합니다.
// 예: 채널 메시지 전송 실패
sendAck(cb, {
ok: false,
error: { code: 'PARAM_REQUIRED' }
});
// 예: 존재하지 않는 채널
sendAck(cb, {
ok: false,
error: { code: 'CHANNEL_NOT_FOUND' }
});
// 예: 내부 서버 에러
sendAck(cb, {
ok: false,
error: { code: 'INTERNAL_ERROR' }
});
DM 관련 이벤트에서도 동일한 패턴을 사용합니다.
// 예: DM 대상이 자기 자신일 경우
cb({ ok: false, error: { code: 'CANNOT_SELF' } });
// 예: 세션이 존재하지 않을 때
cb({ ok: false, error: { code: 'SESSION_NOT_FOUND' } });
// 예: 채팅금지 상태에서 전송 시도
cb({ ok: false, error: { code: 'BANNED_CHAT' } });
프론트엔드에서는 if (!res.ok) 체크 후
res.error.code 값으로 분기하여
상황별 안내 메시지나 재시도 버튼 등을 구현할 수 있습니다.
POST /upload/chat-file 엔드포인트는
현재 다음과 같은 간단한 에러 포맷을 사용합니다.
// 파일이 누락된 경우
HTTP 400
{ "ok": false, "reason": "FILE_REQUIRED" }
// 사이트 인증 실패 (등록된 site_key/도메인 조합이 아님)
HTTP 400 또는 401
{ "ok": false, "reason": "SITE_NOT_FOUND" }
// 서버 내부 오류
HTTP 500
{ "ok": false, "reason": "INTERNAL_ERROR" }
프론트엔드에서는 response.ok 또는 status를 먼저 확인하고,
JSON.reason 값을 사용해 오류 유형을 판별합니다.
향후 REST API 전반을 { ok, error: { code, message } } 패턴으로 통일할 수 있으며,
현재는 파일 업로드에 한해 reason 필드를 사용하고 있습니다.
REST API에서는 다음과 같은 Status 코드 사용을 권장합니다.
| Status | 상태 | 설명 / 예시 |
|---|---|---|
200 OK |
정상 처리 | 요청 성공. { ok:true, ... } 응답. |
400 Bad Request |
잘못된 요청 |
필수 파라미터 누락(PARAM_REQUIRED),
잘못된 포맷 등이 해당됩니다.파일 업로드에서 FILE_REQUIRED 등.
|
401 Unauthorized |
인증 실패 |
사이트 인증 실패(SITE_NOT_FOUND),
토큰/세션 만료(AUTH_REQUIRED) 등.
|
403 Forbidden |
권한 없음 |
채팅금지(BANNED_CHAT),
채널생성금지(BANNED_CREATE 등) 상황에 권장됩니다.
|
404 Not Found |
리소스 없음 |
존재하지 않는 채널(CHANNEL_NOT_FOUND),
존재하지 않는 파일/DM 세션(ATTACH_NOT_FOUND, SESSION_NOT_FOUND) 등.
|
429 Too Many Requests |
요청 과다 | 향후 속도 제한(Rate Limit) 기능 추가 시 사용 권장. |
500 Internal Server Error |
서버 오류 |
예측하지 못한 에러. 응답에는 { ok:false, reason:'INTERNAL_ERROR' } 또는
{ ok:false, error:{ code:'INTERNAL_ERROR' } } 형태를 권장합니다.
|
HTTP Status는 큰 분류를, JSON의 code/reason은 세부 분류를 담당하도록 설계하는 것이 좋습니다.
| 코드 | 설명 |
|---|---|
PARAM_REQUIRED |
필수 파라미터가 누락되었거나 값이 비어있는 경우. |
INTERNAL_ERROR |
예측하지 못한 서버 내부 오류. |
LIST_FAILED |
목록 조회 중 오류 발생 (DM 리스트 등). |
| 코드 | 설명 |
|---|---|
AUTH_FAILED |
사이트 측 회원 인증 API(auth_url) 호출 결과 인증 실패. |
AUTH_REQUIRED |
로그인이 필요하거나 세션이 만료된 상태. |
SITE_NOT_FOUND |
등록되지 않은 도메인/site_key 조합. (파일 업로드 등) |
SESSION_NOT_FOUND |
DM 세션/채팅 세션을 찾을 수 없을 때. |
| 코드 | 설명 |
|---|---|
CHANNEL_NOT_FOUND |
요청한 채널이 존재하지 않거나, 접근할 수 없는 경우. |
EMPTY_MESSAGE |
메시지 내용이 없을 때 (공백/trim 후 빈 문자열). |
NOT_PARTICIPANT |
채널 또는 세션의 참가자가 아닌 사용자가 요청할 때. |
NOT_ACTIVE |
비활성화된 채널/세션에 접근하려 할 때. |
| 코드 | 설명 |
|---|---|
TARGET_REQUIRED |
DM 대상 사용자 정보가 누락된 경우. |
CANNOT_SELF |
자기 자신에게 DM을 보내려는 경우. |
DM_KEY_REQUIRED |
DM 세션 식별자(dm_key)가 누락된 경우. |
NOT_PENDING |
대기 상태가 아닌 세션에 대해 승인/거절 등을 시도할 때. |
NOT_OWNER |
해당 DM 세션의 owner가 아닌 사용자가 owner 권한 작업을 시도할 때. |
NOT_TARGET |
대상이 아닌 사용자가 target 전용 작업을 시도할 때. |
ATTACH_NOT_FOUND |
DM 첨부파일 정보를 찾을 수 없는 경우. |
| 코드 | 설명 |
|---|---|
BANNED_CHAT |
채팅금지 상태에서 메시지를 전송하려 할 때. |
BAN_FAILED |
채팅금지/제재 설정 중 오류 발생. |
BAN_SET_FAILED |
제재 설정을 DB에 반영하는 데 실패. |
BAN_CLEAR_FAILED |
제재 해제 처리 중 오류. |
| 코드 | 설명 |
|---|---|
FILE_REQUIRED |
업로드할 파일이 포함되지 않았을 때. |
SITE_NOT_FOUND |
파일 업로드 시, 등록되지 않은 사이트(site_key)일 때. |
INTERNAL_ERROR |
업로드 처리 중 예기치 않은 서버 오류. |
※ 실제 코드에는 위 외에도 세부 에러 코드가 더 있을 수 있으며,
버전 업 과정에서 추가/변경될 수 있습니다. 공통 패턴(ok + code)만 유지되면
프론트엔드에서는 비교적 쉽게 대응할 수 있습니다.
간단한 예시 JavaScript 코드를 통해 에러 처리 패턴을 보여드립니다.
// 예: WebSocket 이벤트 콜백
socket.emit('channel:message', payload, (res) => {
if (!res || !res.ok) {
const code = res?.error?.code || 'UNKNOWN';
switch (code) {
case 'BANNED_CHAT':
alert('현재 채팅금지 상태입니다. 관리자에게 문의하세요.');
break;
case 'CHANNEL_NOT_FOUND':
alert('채널을 찾을 수 없습니다. 새로고침 후 다시 시도해 주세요.');
break;
case 'PARAM_REQUIRED':
alert('필수 입력 값이 누락되었습니다. 내용을 확인해 주세요.');
break;
default:
alert('처리 중 오류가 발생했습니다. [' + code + ']');
}
return;
}
// 성공 처리...
console.log('메시지 전송 성공');
});
// 예: 파일 업로드 (fetch)
async function uploadChatFile(file) {
const form = new FormData();
form.append('file', file);
form.append('site_key', SITE_KEY);
form.append('channel_key','global');
form.append('user_id', GLOBAL_USER_ID);
form.append('user_key', GLOBAL_USER_KEY);
const rsp = await fetch('https://server.bluetalk.kr/upload/chat-file', {
method: 'POST',
body: form
});
const json = await rsp.json();
if (!json.ok) {
const reason = json.reason || 'UNKNOWN';
if (reason === 'FILE_REQUIRED') {
alert('업로드할 파일을 선택해 주세요.');
} else if (reason === 'SITE_NOT_FOUND') {
alert('사이트 인증에 실패했습니다. 관리자에게 문의하세요.');
} else {
alert('파일 업로드 중 오류가 발생했습니다. [' + reason + ']');
}
return null;
}
return json.file; // { id, type, name, size, mime }
}
에러 처리 로직을 잘 만들어두면, 예상치 못한 상황에서도 사용자 경험(UX)을 안정적으로 유지할 수 있습니다.