우디의 개발스터디

[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

 

REST 아키텍처를 훌륭하게 적용하기 위한 몇 가지 디자인 팁

최근의 서버 프로그램은 여러 웹 브라우저는 물론이며, 아이폰, 안드로이드 애플리케이션과의 통신에 대응해야 합니다. 이번 글에선 여러 문제를 지혜롭게 대처할 수 있는 REST 아키텍처에 대해

spoqa.github.io

 

REST API 제대로 알고 사용하기 : NHN Cloud Meetup

REST API 제대로 알고 사용하기

meetup.toast.com

 

 

블로그의 정보

우디의 개발스터디

개발자 우디

활동하기