eyabc / req_mng

0 stars 0 forks source link

REST API #5

Closed eyabc closed 4 years ago

eyabc commented 4 years ago

https://itstory.tk/entry/%EB%8D%94-%EB%82%98%EC%9D%80-RESTful-API%EB%A5%BC-%EC%84%A4%EA%B3%84%ED%95%98%EA%B8%B0-%EC%9C%84%ED%95%9C-%EC%B5%9C%EA%B3%A0%EC%9D%98-10%EA%B0%80%EC%A7%80-%EC%97%B0%EC%8A%B5%EB%B0%A9%EB%B2%95

eyabc commented 4 years ago
  1. 동사말고 명사 사용
  2. 상태를 변경할 때 GET 메서드와 쿼리 파라미터 사용금지
  3. 복수 명사 사용
  4. 관계 형태는 하위 리소스를 사용
  5. 직렬화 포맷에는 HTTP 헤더 사용 클라이언트와 서버는 통신을 하려면 어떤 포맷의 데이터인지 알아야 합니다. HTTP 헤더에 데이터의 포맷을 명시하면 됩니다. Content-Type 은 요청 포맷을 정의합니다. Accept 는 수용가능한 포맷 목록을 정의합니다.
  6. HATEOAS 사용 하이퍼미디어의 특징을 이용하여 HTTP Response에 다음 Action이나 관계되는 리소스에 대한 HTTP Link를 함께 리턴하는 것이다.
  7. 결과반환 리스트에 필터링, 정렬, 결과요소 선택, 페이징 기능을 제공하기

필터 기능 : 모든 결과 속성에 유니크한 쿼리 파라미터를 사용하거나 필터링을 위한 쿼리 언어를 사용합니다.

정렬 기능 : 오름차순, 내림차순 정렬을 여러 결과 속성에 사용할 수 있도록 제공합니다. GET /cars?sort=-manufactorer,+model

결과요소 선택기능 : 모바일 클라이언트의 경우 결과 리스트에 있는 모든 속성들을 이용하지 않고 몇몇 속성들만 필요할 때도 있습니다. API 이용자가 몇몇 속성만 선택하여 결과를 반환받을 수 있도록 제공해야 합니다. 이는 네트워크 트래픽 감소와 API 호출 응답속도를 증가시켜 줍니다. GET /cars?fields=manufacturer,model,id,color

페이징 기능 : limit(한 페이지 나타낼 결과 갯수) 과 offset(시작점)을 이용합니다. 이는 사용자에게 유연성을 제공하고 데이터베이스에 흔히 사용되는 기법입니다 (역자첨언: 데이터베이스 LIMIT, OFFSET 연산자 참조). LIMIT=20, OFFSET=0 을 기본 값으로 설정하면 됩니다. GET /cars?offset=10&limit=5 반환 결과의 총 갯수를 사용자에게 알려주고 싶으면 X-Total-Count 라는 커스텀 HTTP 헤더를 이용하면 됩니다. HTTP Link 헤더에 이전, 다음 페이지에 대한 링크가 잘 제공되어야 합니다. 사용자가 직접 URL을 이용하는 것 보다 헤더 값에 명시된 URL을 이용하여 페이지를 이동하게 하는 것이 중요합니다.

Link: https://blog.mwaysolutions.com/sample/api/v1/cars?offset=15&limit=5; rel="next", https://blog.mwaysolutions.com/sample/api/v1/cars?offset=50&limit=3; rel="last", https://blog.mwaysolutions.com/sample/api/v1/cars?offset=0&limit=5; rel="first", https://blog.mwaysolutions.com/sample/api/v1/cars?offset=5&limit=5; rel="prev",

출처: https://itstory.tk/entry/더-나은-RESTful-API를-설계하기-위한-최고의-10가지-연습방법 [덕's IT Story]

eyabc commented 4 years ago

http://jeonghwan-kim.github.io/2016/03/29/mobile-rest-api.html

모바일 API에서는 아래 4가지 메소드만 사용한다.

POST: 리소스 추가 GET: 리소스 조회 PUT: 리소스 변경 DELETE: 리소스 삭제

user 리소스는 기본적으로 아래 5가지 API를 만들 수 있다. POST /users: 유저 추가 GET /users: 유저 목록 조회 GET /users/:id: 유저 1개 조회 PUT /users/:id: 유저 1개 수정 DELETE /users/:id: 유저 1개 삭제

POST /users 유저 리소스를 추가하는 API POST 요청이기 때문에 바디(Body)를 사용할수 있다. 유저 데이터는 이 바디를 통해 서버로 전달 리소스 생성에 성공하면 201(Created) 상태코드를 리턴 중복된 리소스가 있을 경우 409(Conflic)를 반환 데이터베이스에 UNIQUE 속성을 설정한 상태에서 중복된 리소스가 추가될 경우, 데이터베이스는 에러 실패를 발생 응답 바디에 담아 보내

GET /users, GET /users/:id 단수가 필요한 경우 리소스 식별자인 ID로 구분 유저 목록을 조회할 때는 GET /users, 특정 ID를 가진 유저 1개를 조회할 때는 GET /users/:id를 사용

PUT /users/:id ID로 유저를 찾아 리소스를 수정할때 PUT /users/:id를 사용한다. 수정할 데이터는 바디에 담아 요청한다. 수정이 완료된 데이터는 POST와 동일한 이유로 바디에 담아 응답해 준다.

DELETE /users/:id 특정 유저 리소스를 삭제 삭제에 성공했다는 데이터를 {result: "success"} 형식으로 보낼 수도 있지만 204 (No Content) 응답코드를 보내는 것이 더 심플 헤더에 담긴 상태코드에 이미 삭제 성공 메세지가 들어가있기

여러번의 API 요청을 하나로 만들고 싶을 때 여러명의 유저 데이터를 한번에 변경해야하는 상황 네이밍 일관성을 깨뜨림 여러 개 ID를 변경할 데이터와 함께 배열로 바디에 담아 요청

{
  "URL": "PUT /users",

  "BODY": {
    "ids": [1, 2, 3],
    "names": ["Chris", "Marcus", "Daniel"]
  }
}

쿼리스트링을 활용

하나의 API에 대해 다양한 조건을 설정

데이터가 너무 많으면 한정된 브라우저에서 다루기에는 버겁다. 서버단에서 최대한 데이터를 가공한 뒤 응답해 주는 것이 전체 서비스 성능에 좋다.

query: 검색어 offset, limit: 페이지네이션 sort: 정렬 fields: 필드값

GET /users?sort=-createdAt&offset=20&limit=10 GET /users?query=chris&fields=name,id 이 쿼리스트링은 서버에서 파싱되어 각 각 아래와 같은 디비 쿼리문으로 사용 SELECT * FROM users ORDER BY cratedAt DESC LIMIT 20, 10; SELECT name, id FROM users WHERE name like "%chris%";

상태코드를 활용

2xx: 성공 3xx: 미사용 4xx: 요청 오류 5xx: 서버 오류

2xx API 요청에 대해 정상적으로 로직이 수행된다면 대부분 200번 코드로 응답한다. 201(Created): 서버에 신규 리소스 생성시 사용한다. 204(No Content): 응답 바디가 없을 경우 사용한다. 리소스 삭제시 사용.

4xx 클라이언트 단에서 요청 파라매터 등의 오류가 있을 경우 400번 코드로 응답한다. 401: Unauthrized 403: Forbbiden 401과 403은 비슷한 성격의 코드다. 인증이 필요한 API에 대해 인증되지 않은 요청일 경우 401을 응답한다. OAuth를 사용할 때 엑세스 토큰(access token)이 유효하지 않을 경우다. 403은 인증시(로그인시) 사용한다. 로그인 정보가 일치하지 않을 경우 403으로 응답한다. 404: Not found. 없이 페이지 뿐만 아니라 없는 리소스일 경우에도 사용한다. 409: Conflict. 자원 추가시 기존 자원과 중복일 경우 사용한다. 위에서 이미 설명함.

5xx 모든 서버 에러에 대해서는 500번 코드를 사용한다. HTTP 스펙에는 다양한 코드들이 정의되어 있지만 서비스 에러코드로 사용하기에는 부족하다. 아니 성격이 좀 다르다. 서버에러가 발생할 경우 상태코드 500을 헤더에 넣고 자세한 에러정보는 바디에 담아 응답한다.

{
  "error": {
    "errorCode": "error code",
    "message": "error message",
    "stack": "stack trace"
  }
}

버저닝

서버단에 기능 추가를 해서 API 로직을 변경해야만 하는 상황을 생각해보자. 서버쪽에서 일방적으로 로직을 변경해버리면 이미 배포된 모바일 앱에서는 크래쉬날 가능성이 크다.

따라서 API에 대한 버전관리가 필요한다. 기존에는 get_user_v1, get_user_v2로 관리했었고 이렇게 해도 동작하는데 문제없다. 그러나 우리의 포인트는 체계적인 관리다.

GET v1/users GET v2/users 이렇게 정리하면 버전별로 계층구조가 생겨 쉽게 관리할 수 있다. 구 버전 앱에서는 GET v1/users를 여전히 사용하고, 새로 업데이트하는 버전의 앱에서는 GET v2/users를 사용하면 된다.