[Java] Jersey 활용 RESTful 웹 서비스
by 개발자 우디JAX-RS
- Restful WebServices를 위한 Java API
- Java SE5에 소개된 어노테이션을 사용하여 정의된 사양
- 대표적인 어노테이션으로 @Path, @GET, @POST 등이 있다.
Jersey
- GlassFish Project의 Sub-Project
- Web Framework
- JAX-RS(JSR 311) 스펙에 따른 구현체
Example
JAX-RS 리소스는 어노테이션된 POJO이다.
이 POJO는 리소스와 연결된 URI(@Path) 경로에 해당하는 HTTP 요청을 처리할 수 있는 리소스 메소드(spring의 컨트롤러)를 제공한다.
package com.demo;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.Produces;
@Path("helloWorld")
public class HelloWorldResource{
@GET
@Produces(MediaType.TEXT_PLAIN)
public String greet() {
return "Hello world";
}
}
Server API
@Path
Spring API에서 @GET("{path}")로 쓰던 것을 @Path와 HTTP Method(@GET)으로 분리해 사용해야한다.
@Path("/welcome")
@Component
public class MyController {
@GET
@Path("{name}")
public String callName(@PathParam("name") String name){
return "Welcome "+name;
}
@GET
@Path("/v2/{name}")
public String callName2(@PathParam(value="name") String name){
return "Welcome "+name+" (v2)";
}
}
@PathParam은 이 패스에서 {}괄호로 묶인 부분을 인수로 매핑하기 위해서 사용한다.
@PathParam("name")과 @PathParam(value="name")은 동일하다.
@Path("/classPath/{msg}")
@Component
public class ClassPathController {
@GET
public String printMsg(@PathParam("msg") String msg){
return "패스 메세지: "+msg;
}
}
@Produces
- 메소드가 생성할 출력의 타입을 지정한다.
- 클래스 수준 : 해당 리소스의 모든 메소드가 생성할 MIME 타입의 기본값을 지정한다.
- 메소드 수준 : 클래스 수준에서 지정된 MIME 타입을 재정의(오버라이드)한다.
- 클라이언트가 지정한 MIME 타입을 생성할 수 있는 리소스가 없다면 HTTP 406 오류 발생
- default는 text/html
- 여러개 정의 가능 : @Produces({"application/xml", "application/json"})
@Consumers
- 메소드가 사용할 MIME 타입을 지정
- 리소스가 클라이언트 요청의 MIME 타입을 사용할 수 없다면 HTTP 415 오류 발생
- default는 text/html
- 여러개 정의 가능
Parameter Annotation
@PathParam
가변 URI 경로의 일부를 메소드 호출에 매핑
@GET
@Path("{name}")
public String pathParamTest(@PathParam("name") String name){
return "pathParam -> "+name;
}
@QueryParam
URI 쿼리 문자열 파라미터나 URL 형식 인코딩 파라미터를 메소드 호출과 매핑해줌
@GET
@Path("query")
public String queryParamTest(@QueryParam("name") String name){
return "pathParam -> "+name;
}
@DefaultValue
옵션 파라미터를 포함하여 @DefaultValue 를 사용해 기본값을 할당해야하는 경우에 사용한다.
아래와 같은 어노테이션들과 함께 사용할 수 있다.
- @PathParam
- @QueryParam
- @MatrixParam
- @HeaderParam
- @CookieParam
- @FormParam
@GET
@Path("defaultValue")
public String defaultValueTest(
@QueryParam("name") String name,
@DefaultValue("seoul") @QueryParam("address") String address){
return "이름 : "+name+", 주소지 : "+address;
}
@MatrixParam
URI 경로에 포함된 이름-값 쌍의 집합으로 수정되며 다음과 같은 형태로 나타낸다.
../matrix;name=jason;address=seoul(QueryParam에서 ? 와 &로 구분하던 쌍을 ; 로 구분하면 된다)
@GET
@Path("matrix")
public String matrixParamTest(
@MatrixParam("name") String name,
@MatrixParam("address") String address){
return "이름 : "+name+", 주소지 : "+address;
}
@HeaderParam
Request 헤더를 메소드 파라미터와 매핑
헤더에 포함된 key:value 의 key 를 이용해 매핑해준다.
@GET
@Path("header")
public String headerParamTest(@HeaderParam("Content-Type")MediaType contentType, @HeaderParam("User-Agent")MediaType userAgent){
return "Content-Type: "+contentType+", user-agent: "+userAgent;
}
@CookieParam
특별한 유형의 HTTP 헤더이다. 리소스 구현으로 전달될 이름이나 값의 쌍으로 이뤄진다.
쿠키는 각 요청과 응답마다 제공자와 생산자 사이를 오가며 생산자만이 쿠키를 수정할 수 있다.
이 어노테이션은 쿠키의 값이나 객체를 메소드 호출에 주입할 수 있게 해준다.
@GET
@Path("cookies")
public String cookieParamTest(@CookieParam("sessionId") int sessionId){
return "Session id: "+sessionId;
}
@FormParam
요청 body 의 미디어 타입이 "application/x-www-form-urlencoded"인 경우에만 사용이 가능하다.
따라서 GET, DELETE 등 body 가 없는 요청 타입에서는 사용이 불가
@POST
@Path("form")
public String formParamTest(
@FormParam("name") String name,
@FormParam("id") String id){
return "name: "+name+", id: "+id;
}
@BeanParam
여러 파라미터를 하나의 빈에 인젝션(주입) 가능하게 해준다.
방법은 @BeanParam을 적용할 클래스를 생성하고, 각 멤버 변수에 @*Param 어노테이션을 붙여주는 것이다.
그리고 이 어노테이션에 알맞게 URI나 헤더 등을 설정해주면 된다.
컨트롤러의 메소드는 아래와 같다.
public class User {
@PathParam("id")
private long id;
@MatrixParam("name")
private String name;
@QueryParam("age")
@DefaultValue("20")
private int age;
@HeaderParam("Content-Type")
private String contentType;
public String toString(){
return "id : "+id+"\nname : "+name+"\nage : "+age+"\nContent-type : "+contentType;
}
}
@GET
@Path("bean/{id}")
public String beanParam(@BeanParam User user){
return user.toString();
}
REST
API 설계의 중심에 자원이 있고 HTTP Method를 통해 자원을 처리하도록 설계하는 것
- REpresentational State Transfer의 약자
- Resource Oriented Architecture이다.
구성요소
- Resource - URI
- /user/{userId}
- Method - 행위, HTTP Method
- GET, POST, PUT, DELETE
- Representations - 메시지, 응답 형태
- xml,json 등으로 응답
Restful
- 웹상의 자료를 HTTP위에서 SOAP(Simple Object Access Protocol) - 일반적으로 널리 알려진 HTTP, HTTPS, SMTP 등을 통해 XML 기반의 메시지를 컴퓨터 네트워크 상에서 교환하는 프로토콜 이나 쿠키를 통한 세션 트랙킹 같은 별도의 전송계층 없이 전송하기 위한 아주 간단한 인터페이스이다.
- Representational State Transfer (REST)는 일관된 인터페이스와 같은 제약 조건을 지정하는 아키텍쳐 스타일로서 웹 서비스에 적용하는 경우, 성능, 확장성 및 수정 가능성과 같은 바람직한 속성을 유도하여 웹에서 최상의 서비스 동작을 가능하게 한다.
- REST는 서버-클라이언트 아키텍쳐에 한하여 동작하며, HTTP와 같은 상태를 저장하지 않는 통신 프로토콜을 사용하도록 고안된 모델이다.
- URI (Uniform Resource Identifier)를 사용하여 접근
Rest 아키텍처 6원칙
- Uniform Interface(유니폼 인터페이스)
- URI로 지정한 리소스에 대한 조작을 통일되고 한정적인 인터페이스로 수행하는 아키텍쳐 스타일 - Stateless (무상태성)
- 작업을 위한 상태정보를 따로 저장하고 관리하지 않음- ex) 세션/쿠키정보를 별도로 저장/관리 하지 않아 API 서버는 들어오는 요청만 처리하면 됨
- 서비스 자유도 높아짐, 구현이 단순해짐
- Cacheable (캐시 가능)
- HTTP 기존 웹표준 그대로 사용하여 웹에서 사용하는 기존 인프라 그대로 활용 가능- HTTP가 가진 캐싱 기능 적용 가능
- Self-descriptiveness (자체 표현 구조)
- REST API 메시지만 보고도 이를 쉽게 이해 할 수 있는 자체 표현 구조로 되어있음 - Client-Server 구조
- REST 서버는 API 제공, 클라이언트는 사용자 인증이나 컨텍스트(세션, 로그인 정보)등을 직접 관리하는 구조
- 클라이언트/서버간 개발 내용이 명확해지고 서로간 의존성이 줄어듦
- 계층형 구조
- REST 서버는 다중 계층으로 구성될 수 있다.
- (보안, 로드 밸런싱, 암호화 계층을 추가해) 구조상의 유연성을 둘 수 있음
- (PROXY, 게이트웨이 같은) 네트워크 기반의 중간매체를 사용할 수 있게 함
RESTful한 API 소프트웨어 디자인
- 리소스와 행위 를 명시적이고 직관적으로 분리
- 리소스는 URI로 표현, 리소스 명은 명사로 표현되어야 한다.
- 행위는 분명한 목적에 따라 적절한 HTTP Method로 표현할 것
- GET(조회), POST(생성), PUT(기존 entity 전체 수정), DELETE(삭제)
- PATCH(기존 entity 일부 수정)
- Message는 Header와 Body를 명확하게 분리해서 사용
- body : Entity에 대한 내용
- header : 애플리케이션 서버가 행동할 판단의 근거가 되는 컨트롤 정보
- API 버전 정보, 응답받고자 하는 MIME 타입 등
- header와 body는 http header 와 http body로 나눌 수도 있고, http body에 들어가는 json 구조로 분리할 수도 있다.
- API 버전을 관리
- API의 signature이 변경될 수도 있음에 유의
- 특정 AI 변경시 하위호환성을 보장해야 함
- 서버와 클라이언트가 같은 방식을 사용해서 요청
- URI가 플랫폼 중립적이어야 함
- form-data든, json이든 하나로 통일한다.
참조
https://meetup.toast.com/posts/92
https://spoqa.github.io/2012/02/27/rest-introduction.html
블로그의 정보
우디의 개발스터디
개발자 우디