제5장: 2단계 - API 인터페이스

弘益人間 (홍익인간) - 널리 인간을 이롭게 하라

5.1 2단계의 목적

2단계 명세(PHASE-2-API, v1.0.0)는 청소 로봇을 제어하고 모니터링하기 위한 RESTful HTTP API와 WebSocket 인터페이스를 정의한다. 명세는 모든 엔드포인트가 인증과 요청 속도 제한(rate limiting)을 구현해야 한다(MUST)고 규정한다. API가 주고받는 데이터는 제4장의 1단계 형식(RobotState, OccupancyGrid, CleaningSession 등)을 그대로 사용한다.

5.2 기본 URL과 버전

API는 로봇 자체(또는 로봇을 대리하는 게이트웨이)가 제공하며, 기본 URL은 다음과 같다. 기본 포트는 8080이다.

http://{robot_ip}:{port}/api/v1

API 버전은 URL 경로(/api/v1/)에 표시하며, 호환성을 깨는 변경이 생기면 새 버전 번호를 부여해야 한다. 명세 예시의 기본 URL은 http로 적혀 있지만, 3단계는 모든 네트워크 통신에 TLS 1.3을 요구하므로 실제 배치에서는 HTTPS를 사용해야 한다(제6장 참조).

5.3 인증

토큰 발급

클라이언트는 POST /auth/token에 사용자 이름과 비밀번호를 보내 JWT 접근 토큰과 갱신 토큰을 받는다. 접근 토큰의 유효 시간은 expires_in(초)으로 알려 주며, 명세 예시는 3600초(1시간)다.

POST /auth/token
Content-Type: application/json

{
  "username": "string",
  "password": "string"
}

Response:
{
  "access_token": "JWT token",
  "refresh_token": "string",
  "expires_in": 3600
}

토큰 사용

이후 모든 요청은 Authorization 헤더에 Bearer 토큰을 실어 보낸다.

Authorization: Bearer {access_token}

3단계 명세는 인증 방식으로 JWT(권장), OAuth 2.0, 단순 통합용 API 키를 허용한다. 서드파티 서비스가 사용자를 대신해 로봇에 접근할 때는 OAuth 2.0(RFC 6749)이 적합하다.

5.4 핵심 엔드포인트

명세 4절이 정의하는 핵심 엔드포인트는 다음과 같다. 모든 경로는 기본 URL(/api/v1) 아래에 붙는다.

메서드경로기능
GET/robot/status로봇 상태 조회
POST/robot/clean청소 시작
POST/robot/stop청소 정지
POST/robot/dock도크 복귀
GET/robot/map?floor={floor_number}지도 조회
PUT/robot/map/rooms/{room_id}방 정보 수정
GET/robot/history?limit=10&offset=0청소 이력 조회
POST/robot/schedule청소 일정 등록

상태 조회

GET /robot/status

Response:
{
  "robotId": "string",
  "state": "RobotState object",
  "uptime": "integer (seconds)",
  "lastUpdate": "ISO8601 datetime"
}

응답의 state는 제4장의 RobotState 문서다.

청소 시작

POST /robot/clean
Content-Type: application/json

{
  "mode": "auto|spot|edge|custom",
  "rooms": ["room_id1", "room_id2"],
  "powerLevel": 0-100,
  "waterLevel": 0-100
}

Response:
{
  "sessionId": "UUID",
  "status": "started",
  "estimatedDuration": "integer (seconds)"
}

응답의 sessionId는 이 청소 작업에 해당하는 CleaningSession의 식별자다. 특정 방만 청소하려면 rooms에 지도의 방 ID를 넣는다.

청소 정지와 도크 복귀

POST /robot/stop
Response: { "status": "stopped", "sessionId": "UUID", "areaCleaned": "float (m²)" }

POST /robot/dock
Response: { "status": "returning", "distance": "float (meters)", "estimatedTime": "integer (seconds)" }

지도 조회와 방 정보 수정

GET /robot/map?floor={floor_number}
Response: { "map": "OccupancyGrid object", "lastUpdated": "ISO8601 datetime" }

PUT /robot/map/rooms/{room_id}
Content-Type: application/json

{
  "name": "Living Room",
  "surfaceType": "hardwood",
  "cleaningPriority": 1-10
}

Response: { "status": "updated", "room": "Room object" }

청소 이력과 일정

GET /robot/history?limit=10&offset=0
Response: { "sessions": ["CleaningSession", "array"], "total": "integer", "hasMore": "boolean" }

POST /robot/schedule
Content-Type: application/json

{
  "enabled": true,
  "schedule": [
    { "day": "monday|tuesday|...", "time": "HH:MM", "mode": "auto", "rooms": ["array (optional)"] }
  ]
}

Response: { "scheduleId": "UUID", "status": "created" }

5.5 WebSocket API

실시간 상태 변화는 WebSocket으로 받는다. 연결 주소는 ws://{robot_ip}:{port}/ws이며, 실제 배치에서는 TLS를 적용한 WSS를 사용한다. 모든 메시지는 종류(type)와 채널(channel)을 가진다.

{
  "type": "subscribe|unsubscribe|command|event",
  "channel": "status|sensors|map|logs",
  "data": {}
}

클라이언트가 상태 채널을 1000ms 간격으로 구독하면, 로봇은 event 메시지로 변화를 알린다.

// 구독 요청
{ "type": "subscribe", "channel": "status", "interval": 1000 }

// 실시간 이벤트
{
  "type": "event",
  "channel": "status",
  "timestamp": "ISO8601",
  "data": { "battery": 75, "position": {"x": 2.5, "y": 3.1}, "mode": "cleaning" }
}

5.6 오류 처리

오류 응답은 다음 형식을 따른다.

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human readable message",
    "details": {},
    "timestamp": "ISO8601 datetime"
  }
}
오류 코드의미
ROBOT_BUSY로봇이 이미 청소 중이다
LOW_BATTERY배터리가 부족해 작업할 수 없다
INVALID_COMMAND명령 매개변수가 올바르지 않다
NOT_CONNECTED로봇이 네트워크에 연결되어 있지 않다
SENSOR_ERROR센서 이상이 감지되었다
NAVIGATION_ERROR주행할 수 없다
DOCK_NOT_FOUND충전 도크를 찾을 수 없다

명세 부속서 B는 HTTP API 오류 표현의 국제 표준으로 RFC 9457(Problem Details)을 참조 표준으로 열거한다. 위 오류 형식과 RFC 9457 형식을 어떻게 대응시킬지는 구현체가 문서화해 두는 것이 좋다.

5.7 요청 속도 제한

5.8 페이지 나누기와 필터

목록을 돌려주는 모든 엔드포인트는 표준 페이지 나누기 매개변수를 지원한다.

GET /robot/history?limit=20&offset=40&sort=startTime&order=desc

- limit:  페이지당 항목 수 (기본 10, 최대 100)
- offset: 건너뛸 항목 수
- sort:   정렬 기준 필드
- order:  asc 또는 desc

명세는 필터 예시로 GET /robot/history?mode=auto&minDuration=300, GET /robot/map/rooms?surfaceType=carpet, GET /robot/events?level=error&category=navigation을 든다.

5.9 일괄 처리와 부가 기능

일괄 처리

POST /robot/batch는 여러 요청을 한 번에 보내고, 요청 순서대로 결과 배열을 돌려받는다.

POST /robot/batch
{
  "operations": [
    { "method": "POST", "path": "/robot/clean",  "body": {"mode": "spot"} },
    { "method": "PUT",  "path": "/robot/config", "body": {"language": "ko"} }
  ]
}

Response:
{ "results": [ {"status": 200, "data": {}}, {"status": 200, "data": {}} ] }

모니터링과 고급 기능

엔드포인트기능
GET /robot/metricsCPU·메모리 사용률, 온도, 네트워크 송수신량, 가동 시간
POST /robot/control/joystick원격 수동 조작(선속도 m/s, 각속도 rad/s)
GET /robot/camera/streamMJPEG 카메라 스트림
GET /robot/map/export?format=png|svg|json지도 내보내기

카메라 스트림과 원격 조작은 사생활과 안전에 직접 영향을 주므로, 인증된 사용자에게만 허용하고 사용 중임을 사용자가 알 수 있게 하는 것이 바람직하다.

5.10 참조 SDK로 호출하기

WIA 공개 저장소(cleaning-robot/api/typescript)의 TypeScript SDK 골격은 위 엔드포인트를 감싼 WiaCleaningRobot 클래스를 제공한다. 이 SDK는 공개 패키지 저장소에 배포되어 있지 않으므로 저장소에서 직접 받아 사용한다(제3장 3.9절 참조).

import { WiaCleaningRobot } from 'wia-rob-011';

const robot = new WiaCleaningRobot({
  host: '192.168.1.100',
  token: 'your_token_here'
});

await robot.connect();                         // GET /health
const status = await robot.getStatus();        // GET /robot/status
await robot.startCleaning({ mode: 'auto' });   // POST /robot/clean

핵심 요약

복습 문제

  1. 2단계 API의 기본 URL과 버전 표시 방식을 설명하라.
  2. JWT 접근 토큰을 발급받고 사용하는 과정을 설명하라.
  3. 거실과 주방만 흡입력 60으로 청소하도록 요청하는 POST /robot/clean 본문을 작성하라.
  4. REST API와 WebSocket API는 각각 어떤 용도에 적합한가?
  5. 표준 오류 코드 일곱 가지 중 세 가지를 들고 의미를 설명하라.
  6. 속도 제한을 넘은 클라이언트는 어떤 응답을 받는가?
  7. 일괄 처리 엔드포인트는 어떤 상황에서 유용한가?

📐 시뮬레이터 패널 4