참고 사이트:
- Uniform Resource Identifiers (URI)
- Uniform Resource Locators (URL)
- Architectural Styles and the Design of Network-based Software Architectures
- REST API Tutorial
- API 디자인 지침
인터넷 검색을 할 때 웹 브라우저 URL(Uniform Resource Locator) 에 주소를 입력하면 다른 컴퓨터 또는 서버에 접속하여 정보를 받아올 수 있습니다. 이름에서 의미하듯이 URL은 인터넷 상에서 특정 자원(Resource)을 표시하는 유일한 경로라고 할 수 있는데 문법은 다음과 같습니다.
scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]
Spring 에서 어떻게 처리하는지 내용을 확인해 봅니다. IntelliJ 에서 Spring Boot – Web 프로젝트를 생성하고 아래의 파일을 생성합니다.

package com.example.demo; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class CalcController { @GetMapping("/plus") public ResponseEntity plus( @RequestParam("param1") String param1, @RequestParam("param2") String param2) { var result = Integer.parseInt(param1) + Integer.parseInt(param2); return new ResponseEntity(result, HttpStatus.OK); } @GetMapping("/minus/{param1}/{param2}") public ResponseEntity minus( @PathVariable("param1") String param1, @PathVariable("param2") String param2) { var result = Integer.parseInt(param1) - Integer.parseInt(param2); return new ResponseEntity(result, HttpStatus.OK); } }
http://localhost:8080/plus?param1=10¶m2=20
Query String 으로부터 여러 개의 값을 입력받아 결과를 출력합니다. (결과값 30)
http://localhost:8080/minus/10/20
URI 중간의 Path 의 구분을 통해 값을 입력받아 결과를 출력합니다. (결과값 -10)
Path를 구분하여 URI를 지정하는 것이 REST (REpresentational State Transfer) API를 구현하는 방식입니다. RESTFul 한 API를 구현하기 위한 지침은 참고 사이트를 보시고 아래의 문서도 정리가 잘 되어 있습니다.
여기서는 기술적으로 이 RESTFul API를 Versioning 하는 내용을 추가로 알아봅니다.
@GetMapping("/api/v1/concat/{param1}/{param2}") public ResponseEntity concatV1( @PathVariable("param1") String param1, @PathVariable("param2") String param2) { var result = param1.concat(param2); return new ResponseEntity(result, HttpStatus.OK); } @GetMapping("/api/v2/concat/{param1}/{param2}") public ResponseEntity concatV2( @PathVariable("param1") String param1, @PathVariable("param2") String param2) { var result = param2.concat(param1); return new ResponseEntity(result, HttpStatus.OK); }
도메인 명이나 서비스의 범위에 따라 URI 패턴을 정하되 API의 버전을 경로에 추가합니다. 참고로 RESTFul 하지는 않지만, YouTube API 는 이런 식의 패턴으로 관리되고 있고 보통의 경우에는 이렇게 많이 사용합니다.
- https://www.googleapis.com/youtube/v3/channels
- https://www.googleapis.com/youtube/v3/videos
이렇게 했을 때 문제는 URI 관리대상이 늘어나고 도메인 표현의 대상이 아닌 버전 내용이 Path에 포함되는 문제도 있습니다. URI는 고정시키면서 다른 버전을 호출하게 하려면 Accept Header를 이용하는 방법을 생각해 봅니다.
@GetMapping(value = "/api/concat/{param1}/{param2}", produces = "application/vnd.x1fingers-v1+json") public ResponseEntity concatV1( @PathVariable("param1") String param1, @PathVariable("param2") String param2) { var result = param1.concat(param2); return new ResponseEntity(result, HttpStatus.OK); } @GetMapping(value = "/api/concat/{param1}/{param2}", produces = "application/vnd.x1fingers-v2+json") public ResponseEntity concatV2( @PathVariable("param1") String param1, @PathVariable("param2") String param2) { var result = param2.concat(param1); return new ResponseEntity(result, HttpStatus.OK); }
$ curl -H “Accept: application/vnd.x1fingers-v1+json” http://localhost:8080/api/concat/a/b
ab
$ curl -H “Accept: application/vnd.x1fingers-v2+json” http://localhost:8080/api/concat/a/b
ba
이 방법은 웹 브라우저에서 실행할 수 없는 단점이 있습니다. 그 외에 API 버전별 문서관리의 문제도 있고 캐쉬나 HTTP 헤더의 용도에 맞지않는 등의 문제도 있습니다.
2 Responses
[…] URI 그리고 RESTFul API Versioning […]
[…] URI 그리고 RESTFul API Versioning […]