, ,

우리는 어떻게 모바일 API를 디자인하는가?

그동안 우리는 다수의 모바일 서비스를 개발해 왔다. 스텝 저널 같은 고유의 서비스 뿐만 아니라 외주로 개발한 서비스를 포함하면 대략 십여개 이상의 프로젝트를 수행한 것 같다.

초기에는 PHP로 생짜베기 코딩을 해서 서비스를 런칭했고 이후 Slim 같은 API 프레임웍을 사용했다. Node.js를 스터디한 후 기존 서비스를 처음부터 다시 갈아 엎었다. 이 후 Express.js, Hapi.js 등의 웹 프레임웍을 사용하여 모바일 서버를 개발해 왔다.

사실 어떤 개발 언어와 프레임웍을 사용하냐는 것은 백엔드 개발자만의 고민인 것 같다. 팀으로 일할 때에는 서버와 클라이언트 개발자간의 인터페이스를 맞추는 작업이 실제로 더 중요하다.

위플래닛 초창기에는 예전 웹 방식의 AJAX 호출을 사용하여 모바일 API를 구현했다. 대부분의 메쏘드는 GET으로 구현되었고 주소 체계는 get_user 같은 함수명 스타일의 네이밍을 사용했다. API 응답에는 헤더와 바디를 구분하여 전달했는데 트위터나 포스퀘어 같은 서비스를 참고한 것이다.

하지만 서비스 기능이 변경되고 점점 성장할수록 API 관리에 한계를 경험했다. 주소 체계의 일관성이 흐트러지고, 응답 형식도 주먹구구식이라 개발자간의 커뮤니케이션 횟수만 늘어났다. 문서를 꼼꼼하게 작성하지 않는한 서버 개발자 본인마져도 뭐가 뭔지 헷갈리는 상황이다.

최근에 우리는 RESTful API 구조를 일부 도입하였고 형편에 맞게 적용해서 사용하고 있다. API 주소체계, 요청 형식, 응답 형식, 에러 처리 등을 내부 표준으로 정하고 이를 개발자들이 인지한 상태에서 개발한다. 일관적인 API를 만들수 있기 때문에 문서가 거의 필요없다. 사실 스웨거(swagger-ui) 문서 하나면 충분하다.

이번 포스팅은 위플랫닛의 모바일 API 표준에 대해 소개하는 글로 진행하고자 한다.

Mobile API Guideline in WePlanet

REST API

리소스 단위로 주소체계를 사용하는 REST API를 사용을 기본으로 한다. 모든 리소스는 복수명사로 표현하되 특정 리스소를 요청할 경우 하위 주소로 식별자를 추가하여 사용할 수 있다.

HTTP 메쏘드명을 사용하여 리소스의 처리 방법을 지정할 수 있다. 총 9개 메쏘드
우리는 CRUD(Crate, Read, Update, Delete)에 해당하는 POST, GET, PUT, DELETE 네 개의 메소드만 사용한다. 하나의 리소스는 4개 메쏘드와 결합하여 최소 5개의 API로 구성된다.

유저(user) 리소스의 예:

  • POST /users: 유저 생성
  • GET /users: 유저 목록 조회
  • GET /users/{id}: 유저 조회
  • PUT /users/{id}: 유저 수정
  • DELETE /users/{id}: 유저 삭제

Request

QueryString

GET, DELETE 메쏘드는 쿼리스트링을 사용할 수 있다. 예를들어 유저 목록을 조회하는 GET /users API의 경우 검색, 페이지네이션 등의 요청을 할 수 있는데 이 경우 쿼리스트링으로 파라매터를 지정할 수 있다. 만약 쿼리스트링에 유니코드가 포함될 경우 주소 인코딩후 API를 호출해야 한다.

유저 목록 중 특정 키워드로 검색할 경우 query 파라메터를 사용한다.

유저 목록은 페이지네이션을 위해 limit, offset 파라메터를 사용한다.

데이터 전송량을 줄이기 위해 데이터베이스의 특정 컬럼만 요청할 경우 filter 파라메터를 사용한다.

위의 모든 파라매터는 &를 사용하여 AND 조합할 수 있다.

Body

POST, PUT 메쏘드는 요청 바디를 사용한다. 기본적으로 application/x-www-urlencoded를 사용하고 파일의 경우 multipart/form-data를 사용한다. 바디는 JSON 형식을 사용하고 객체나 배열을 포함할 수 있다.

Response

StatusCode

API 응답은 상태코드와 바디 두 부분으로 구성된다. 상태코드는 응답의 성공, 실패에 관한 정보를 표현하고 바디는 실제 데이터가 JSON 형식으로 담아 전달된다.

사용하는 상태코드는 크게 세 분류다.

  • 2XX: 성공
  • 4XX: 요청 에러
  • 5XX: 서버 에러

2XX는 API 성공시 응답하는 코드다.

GET, PUT 요청을 성공하면 200(Success) 코드를 응답한다.

POST 성공시 리소스 생성을 의미하는 201(Created) 코드를 응답한다.

DELETE는 삭제 성송 후 리소스가 없음을 의미하는 204(No Content)를 응답한다.

상태코드 의미 메쏘드
200 Success GET, PUT
201 Created POST
204 No Content DELETE

4XX는 API를 요청하는 클라이언트 측의 에러를 의미한다.

400은 파라메터 에러(Bad Request)를 의미하는데 파라메터가 누락되었거나 파라메터 형식이 잘못되었을 경우 발생한다.

401은 인증이 필요한 API에 대해 인증되지 않은 접근일 경우 (Unauthorize) 발생한다. 예를들어 엑세스 토큰이 잘못되었거나 엑세스 토큰의 유효기간이 지났을 경우 발생한다.

403(Forbidden)은 로그인 시도시 로그인 정보(credentials)가 잘못되었을 경우이다. 이메일이나 패스워드가 맞지 않을 경우 403으로 응답한다.

404는 리소스가 없는 경우(Not Found) 발생한다. 특정 유저를 조회하는 GET /users/1 API를 호출할 경우 아이디 1인 유저가 없을 경우 404 상태코드를 응답한다.

409는 추가할 리소스 서버에 있는 리소스와 충돌(Conflict)할 경우 발생한다. 예를 들어 POST /users API로 신규 유저를 추가한다고 했을때 이미 있는 유저일 경우 유저 생성을 중단하고 409 에러코드를 응답한다.

상태코드 의미 메쏘드
400 Bad Request GET, POST, PUT, DELETE
401 Unauthorized GET, POST, PUT, DELETE
403 Forbidden POST (로그인)
404 Not Found GET, POST, PUT, DELETE
409 Conflict POST

5XX는 서버 에러를 의미한다.

대부분의 서버 에러는 500 코드를 응답한다.

Nginx + Node.js 구성시 노드 서비스가 종료되었을 경우에는 Nginx 측에서 503 코드를 응답한다.

상태코드 의미 메쏘드
500 Internal Server Error GET, POST, PUT, DELETE
503 Service Unavailable GET, POST, PUT, DELETE

Body

2XX 상태코드는 응답 바디에 실제 전송할 데이터를 JSON 형식으로 전송한다.

목록을 조회할 경우 리소스명을 키로하는 배열을 객체에 담아 응답한다.

GET /users:

하나의 리소스를 요청할 경우 리소스명에 객체를 담아 응답한다.

GET /users/1:

모바일 화면 구성에 따라 리소스를 키로 추가하여 응답할 수 있다.

GET /users/1:

Error Handling

4XX, 5XX 상태코드 응답시 바디에 error키를 추가하여 JSON 객체로 응답한다.

errorCode는 사전 정의된 유일한 에러코드이다. 모바일에서는 이 코드를 참고하여 에러메세지 팝업 등의 에러 처리 로직을 구현할 수 있다.

message는 디버깅용 메세지를 문자열로 담는다. 경우에 따라 서버측 에러 스택 정보를 추가할 수 있다.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *