URI 와 URL
URI와 URL의 차이
URI는 특정 리소스를 식별하는 통합 자원 식별자(Uniform Resource Identifier)를 의미한다.
ex.ISBN 0-486-52847-7
URL은 웹주소로, 네트워크 상에서 리소스가 어디 있는지 알려주기 위한 규약을 의미한다.
scheme(https), host(youngseo-computerblog.tistory.com), port(80), path(137), query(key=value 형식) 등으로 이루어진다.
ex. https://www.naver.com/
ex.https://youngseo-computerblog.tistory.com/137?name=restful&date=20231220
쉽게 말하면
URI는 식별하는 역할을 하고, URL은 위치를 가리키는 역할을 한다.
URI는 이름이라면, URL은 우리 집 주소를 의미한다.
이름을 언급하면 식별은 가능하나 정확히 어디인지는 알 수 없다. URL은 정확한 위치를 가리키기 때문에 정확한 위치를 특정할 수 있다.
예를 들어보자 !
https://www.tistory.com/index 은, URI이지만 URL은 아니다.
index라는 파일 자체는 웹서버에 존재하지 않기 때문이다. 이건 실제 우리집주소라고 볼 수 없다.
https://www.tistory.com/index.html 로 접근하는 게 맞을 것이다.
하지만 그냥 저렇게만 쳐도 잘 접속되는 걸 경험해볼 수 있을 것이다. 서버 내부에서 이를 index.html로 처리해주므로 URI라고 볼 수 있다. 하지만 정확한 주소값을 표현하지는 않았으므로 URL이라고 볼 수 없다.
RESTFul API
Rest API에 포함되는 것은 다음과 같다.
- URL
- 메서드 POST GET DELETE PUT
- HTTP 헤더
- Representation of Resource(자원의 표현) - json, xml 등의 리소스를 의미한다.
{
"URL": "http://example.com/api/resource",
"Method": ["POST", "GET", "DELETE", "PUT"],
"HTTP Headers": {
"Authorization": "Bearer [Token]",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Client-Version": "1.2.3"
},
"Representation of Resource": ["json", "xml"]
}
REST 특징
- Server-Client 구조 : 서버는 listen 상태로 항상 켜져 있고 Client는 이에 접근을 시도하는 구조이다. (네트워크 구조 참고)
- Stateless : Server-Client 관계에서 서버가 클라이언트의 상태를 보존하지 않는다.
- Cacheable : http 프로토콜을 사용하기 때문에 캐싱 기능을 적용할 수 있다.
- Layered System - proxy, gateway : 보안/로드 밸런싱/암호화 등 다중 계층으로 구성할 수 있고 Proxy 및 게이트웨이 등의 중간 매체를 사용할 수 있다.
REST API 설계 규칙
- URI에 행위에 대한 동사 표현이 들어가면 안된다. ex. /delete 등 포함 X
- / 슬래시는 계층 관계를 나타낼 때 표현 한다.
- 하이픈으로 가독성 높일 수 있다 (-), 밑줄(_)은 사용하지 않는다.
- 소문자로 나타낸다.
- 확장자는 URI에 포함시키지 않는다. Accept header 에 포함시킨다
- 리소스 간 연관관계가 있는 경우 → 리소스명/리소스ID/관계가 있는 다른 리소스명
- GET /users/{userId}/devices
RESTFul API로 refactoring
이 글을 쓰게 된 이유인데,, 내가 짰던 api를 RESTFul하게 바꾸어 보았다 !
기존 api 1
[GET] https://localhost:8080/sttresult?url=https://1234asdf.wav
변경된 api
{
"URL": "https://localhost:8080/sttresult?url=1234asdf"
"Method": ["GET"],
"HTTP Headers": {
"Content-Type": "audio/wav",
"Accept": "application/json",
},
"Representation of Resource": ["json"]
}
URL에 확장자를 표현하지 않기 위해 확장자는 header의 type으로 빼주었다. Content-Type은 보내는 데이터의 형식을, Accept는 이 api로 받는 데이터의 형식을 의미한다.
또한 url은 sttresult의 하위가 아니므로 /(슬래쉬)보다는 ?(key=value query)로 표현한다.
추가로 멱등성 등의 보존을 위해 POST 요청을 남발하는 것은 좋지 않다. 이 api에서는 리소스 변경 없이 데이터를 가져오는 것이므로 요청 방식을 GET 으로 할당하였다.
기존 api 2
study들 중에서 studyId를 갖는 study를 가져와, 해당 study에 참가하는 studentList를 가져오는 api이다.
@ResponseBody
@GetMapping("/student/study")
public ResponseTemplate<List<StudentRes>> getStudentListByStudyId(@RequestParam Long studyId){
try {
List<StudentRes> studentResList = studentService.getStudentListByStudyId(studyId);
return new ResponseTemplate<>(studentResList);
} catch (ResponseException e){
return new ResponseTemplate<>((e.getStatus()));
}
}
변경된 api
@ResponseBody
@GetMapping("/study/{studyId}/student")
public ResponseTemplate<List<StudentRes>> getStudentListByStudyId(@PathVariable Long studyId) {
try {
List<StudentRes> studentResList = studentService.getStudentListByStudyId(studyId);
return new ResponseTemplate<>(studentResList);
} catch (ResponseException e) {
return new ResponseTemplate<>((e.getStatus()));
}
}
@RequestParam과 @PathVariable은 mapping api에 파라미터 포함 여부에 있다. 위 api에서는 리소스 간 종속관계들을 표현하기 위해 [리소스 간 연관관계가 있는 경우 → 리소스명/리소스ID/관계가 있는 다른 리소스명] 을 참고하여 설계하였다.
전에 봤던 글 중에 패턴, 규칙을 사용하면 간단한 단어로 많은 이야기를 할 수 있고, '디자인'에 더 오랜 시간 집중할 수 있다는 문장이 있었다(디자인 패턴 공부하던 즁..) . 앞으론 간단한 것들이라 할지라도 정확히 짚고 넘어가는 게 중요할 것 같다 !
2024.01.23.. 추가 !
요즘 학교 사람들과 일주일에 한번씩 특정 주제에 대해 준비해보고 자신이 각자 이해한 내용들을 바탕으로 질문해보는 형태로 스터디를 진행하고 있다. 첫번째 주제가 바로 이 Rest API 였는데, 가장 당황스러웠던 질문들을 한 번 뽑아봤다.
1. Rest API는 Stateless하다고 말씀해주셨는데, 이 Stateless가 어떤 건지 좀 더 자세히 설명해주시겠어요?
2. Rest API를 사용하는 방향으로 리팩토링한 경험에 대해 말씀해주셨는데, 그럼 사용하기 전과 후의 차이가 뭐였나요?
이후 다시 한 번 답변을 생각해보았다.
1. stateless의 반대되는 개념은 stateful입니다. 대표적인 stateful 구조를 따르는 프로토콜로 TCP의 3-way handshaking 과정을 예로 들 수 있다. Client와 Server간 SYN, ACK 요청을 주고받는 과정은 세션 상태에 따라 서버의 응답이 달라지게 되는 것이므로 Stateful하다고 말할 수 있다. 하지만 stateful의 큰 문제는 해당 서버가 멈추거나 갑자기 못쓰게 되어 다른 서버를 사용해야 할 때이다. 예를 들어 유저가 로그인을 한 후에 글쓰기를 하려는데 다시 로그인을 해야 하는 상황이 그러하다. 로그인 정보를 들고 있는 서버가 어떤 문제가 생겨 다른 서버가 대신 역할을 이어받았는데 클라이언트의 로그인 정보가 없다.
하지만 Stateless하다면 서버는 단순히 요청이 오면 응답을 보내는 역할만을 수행하면 되고 상태관리는 전적으로 클라이언트가 맡게 됩니다. 따라서 서버 확장에 용이합니다. 하지만 Stateless는 매번 요청할 때마다 자신의 부가정보를 줘야하므로 더 많은 데이터가 소모된다는 특징이 있습니다.
그래서 stateless 특징을 유지하면서도 로그인 상태 유지를 가능하게 하기 위해 JWT 토큰을 사용하는 등의 방법으로 극복합니다.
2. 기존에는 wav 파일을 그대로 API parameter에 붙여서 전송하였습니다. 낱개의 api만을 사용했기 때문에 괜찮았지만, 여러개의 api를 사용하는 경우에는 이 wav 파일을 음성녹음 파일로 사용할 수도, 파일명 string으로 사용할 수도 있을 것입니다. 따라서 어떤 Content로 보내는지, 어떤 형식의 응답을 원하는지에 대해 명시해주면 개발자 간 소통에 더 도움이 될 것이라고 생각합니다.
'BackEnd' 카테고리의 다른 글
[ELK|Python] REST API로 ES에 데이터 색인하기 (0) | 2024.01.04 |
---|---|
[크롤링|Lambda] AWS Lambda를 이용해 백준, 티스토리 크롤링하기 (2) | 2024.01.02 |
[Java] 클린코드2 (2) | 2023.10.08 |
[Java] 클린코드1 (7) | 2023.10.04 |
[후기] 객체지향의 사실과 오해 (4) | 2023.08.04 |