필자는 기능과 데이터 전송 형태에 따라서만 API를 설계하면 된다고 생각하고 이전에 간단하게 설계를 해보았었는데, 이번 챕터를 학습해보니 어떤 상황(Form or API 메서드 사용)에서 데이터를 전송하는지도 고려해서 API 설계를 해야했던 것이었다...! 왜냐하면 상황에 따라 사용할 수 없는 HTTP 메서드가 있기 때문이다..!
그럼 어떤 상황이 존재하고 이에 맞춰서 어떻게 API를 설계해야 하는지 김영한 강사님의 강의를 통해 학습해보자.
목차
클라이언트에서 서버로 데이터 전송 4가지 상황
1. 클라이언트에서 서버로 데이터 전송 4가지 상황
(1). 정적 데이터 조회
첫 번째 상황은 정적 데이터 조회 상황이다. 이는 이미지나 정적 텍스트 문서 등과 같은 것을 요청할 때 이루어지는 상황이다. 사실 이 상황은 어려울 것도 없고 무언가를 추가로 요청하는 상황도 아니다. 즉, 쿼리 파라미터도 사용하지 않고 단순 GET요청으로 이루어지는 상황이다.
정적 데이터 조회시 요청 메시지와 응답 메시지 형태
(2). 동적 데이터 조회
두 번째 상황은 동적 데이터 조회 상황이다. 이는 클라이언트가 게시판 검색이나 목록 정렬 등을 위해 이벤트 요청을 발생시키는 상황이다. 정적인 데이터(텍스트 or 이미지 등)를 단순하게 보내주고 끝이 아니라 제공된 데이터에 대해 클라이언트쪽에서 추가로 원하는 요청(정렬, 검색 등)을 하는 동적인 상황이라고 생각하면 된다.
동적 데이터 조회는 정적 데이터 조회와 같이 GET요청으로 이루어지며 차이점은 쿼리 파라미터를 사용해서 추가적인 요청 데이터를 서버로 전달한다는 것이다.
동적 데이터 조회시 쿼리 파라미터 사용
(3). HTML Form 데이터 전송
세 번째 상황은 HTML Form 태그를 사용해 데이터를 전송하는 상황이다. 다들 웹 개발을 한 번이라도 해봤다면 Form 태그를 한 번쯤은 사용해 보았을 것이다. Form 태그 사용시 method="" 구문으로 HTTP 메서드 종류를 기입하는데, 이때 주의해야 할 점이 GET, POST만 사용할 수 있다는 점이다. 즉, Form 태그를 사용할꺼면 GET과 POST만 사용해야 한다! 이정도 상식만 알아두고 Form 태그를 사용해 데이터 저장 및 조회시 요청의 흐름을 살펴보자.
HTML Form - GET(조회 기능)
위 이미지는 Form 태그를 사용해 사용자 조회 화면을 구현한 모습이다. 클라이언트가 요청 데이터를 입력해서 method="get"을 통해 GET 요청을 서버로 보내면 웹 브라우저가 GET 요청을 확인 후 요청 데이터를 쿼리 파라미터에 넣어서 서버로 요청 메시지를 전송해준다.
※ GET 요청을 통해 쿼리 파라미터로 데이터를 전달하고 그 데이터를 저장하는데 사용해도 되지 않을까?라는 생각을 할 수 있지만 이는 필자가 알기로 보안상의 문제가 있기 때문에 그런식으로 사용하면 안된다. GET은 오로지 조회에만 사용!
HTML Form - POST(저장 기능)
위 이미지는 Form 태그를 사용해 회원가입 화면을 구현한 모습니다. 클라이언트가 요청 데이터를 입력해서 method="post"를 통해 POST 요청을 서버로 보내면 웹 브라우저가 POST 요청을 확인 후 요청 데이터를 메시지 바디에 넣어 서버로 요청 메시지를 전송해준다. 이때 메시지 바디의 데이터 타입은 application/x-www-form-urlencoded(default)로 지정되는데, 이 형식은 username=kim@age=20처럼 쿼리 파라미터랑 비슷하게 생긴 key=value 형식의 타입이다.
HTML Form으로만 회원정보 관리 API를 설계한다고 가정하면?
회원 목록 /members -> GET
회원 등록 폼 /members/new -> GET
회원 등록 /members/new -> POST
회원 조회 /members/{id} -> GET
회원 수정 폼 /members/{id}/edit -> GET
회원 수정 /members/{id}/edit -> POST
회원 삭제 /members{id}/delete => POST
위와 같이 설계할 수 있을 것이다! 이전 시간에 필자가 설계한 모습과는 많이 다를 것이다. 왜냐? Form 태그는 PUT, PATCH, DELETE 메서드를 사용하지 못하기 때문에!
이런 제약사항 때문에 기존에 리소스만으로 해결됐던 URI가 수정, 삭제 등을 수행할 때 메서드 또한 중복되므로 어쩔 수 없이 동사로 된 리소스 경로(edit, delete)를 통해 기능을 식별했다.
★ 추가내용(multipart/form=data)
우리는 이미지와 같은 바이트 단위 파일을 서버로 전송할 때가 있다. 이때, default type인 application/x-www-form-urlencoded 말고 multipart/form-data 타입으로 데이터를 전송한다. 해당 타입은 여러 종류의 데이터를 동시에 전송할 수 있게 해주는 타입(그래서 이름이 mulitpart)이라고 생각하면 된다. 여러 종류의 데이터를 전송해도 각 부분을 독립적으로 인코딩하기 때문에 텍스트와 이미지 파일을 한 번에 전송할 수 있는 것이다.
multipart/form-data 사용 및 전송 데이터 모습
왼쪽 이미지처럼 코드를 작성해서 전송하면 데이터가 오른쪽 메시지 형태로 서버에 전송 된다. 오른쪽 HTTP 메시지 내용을 자세히 보면 아까와 달리 Content-Type이 multipart/form-data; boundary=-----XXX로 되어있는 것을 확인할 수 있다. 경계선을 통해서 각 데이터를 독립적으로 나누어 인코딩을 할 수 있게 해주는 타입이다.
오른쪽 아래 빨간 박스를 확인해보면 이미지 파일을 처리하기 위해 독립적으로 Content-Type을 image/png로 타입을 지정한 것을 볼 수 있다.위와 같은 수행 덕분에 multipart/form-data를 사용하면 여러 종류의 데이터를 한 번에 처리할 수 있는 것이다!
(4). HTTP API 전송
HTTP API는 POST 기반 등록인지 PUT 기반 등록인지에 따라 API 설계가 달라진다. 상황적으로 생각하면 데이터를 수정할 때 부분 변경을 할 것이냐 완전히 덮어씌울 것이냐에 따라 다르고 개발적으로 생각하면 컬렉션 기반으로 등록할 것이냐 스토어 기반으로 등록할 것이냐에 따라 달라진다. 여기서 컬렉션과 스토어가 어떤건지 정리하고 API를 설계해보자.
컬렉션(collection)
서버가 리소스의 URI를 생성하고 관리하는 개념이다. 이전 시간에 했던 POST 예제처럼 /members URI로 요청을 보내면 서버가 새 리소스 URI를 생성하고 클라이언트에게 응답해주는 즉, 클라이언트는 새 리소스의 URI를 모르는 상태인 그런 개념을 컬렉션이라 한다.
스토어(store)
컬렉션과 반대로 클라이언트가 리소스의 URI를 알고 관리하는 개념이다. 이전 시간에 했던 PUT 예제처럼 /members/100 URI로 요청을 보내면 해당 위치의 리소스를 대체하는 즉, 클라이언트가 리소스의 URI를 알고있는 그런 개념을 스토어라고 한다.
API 설계 - POST 기반 등록
회원 목록 /members -> GET
회원 등록 /members -> POST
회원 조회 /members/{id} -> GET
회원 수정 /members/{id} -> PATCH,PUT,POST(PATCH를 지원하지 않는 환경이면 부분 변경 기능을 위해 POST사용)
회원 삭제 /members/{id} -> DELETE
API 설계 - PUT 기반 등록
PUT 기반 등록 하는 상황은 거의 없지만 게시글 관리나 파일 관리를 할 때는 충분히 PUT 사용이 가능한 상황이다.
파일 목록 /files -> GET
파일 조회 /files/{filename} -> GET
파일 등록 /files/{filename} -> PUT
파일 삭제 /files/{filename} -> DELETE
파일 대량 등록 /files -> POST
지금까지 상황별 API 설계 방법에 대해서 정리해 보았다. 근데 필자는 정리하면서 드는 생각이.. 상황은 너무 다양하고 그 상황안에 또 불가피한 상황이 생길 수 있다는 점에서 완벽히 올바른 설계 방법이 있을까..라는 생각이 든다. 그냥 HTTP 메서드에 관해 이해하고 어떤 형식으로 데이터를 전송하는지 정도만 알아도 충분히 학습한 것 아닐까?라는 생각이 드는 챕터였다.