SlideShare une entreprise Scribd logo
1  sur  79
RESTful API (including Mobile)
with Spring 3.1


                     윤성준(@exnis)
소 개

‘이음’ 이라는 스타트업에서 일하는,
올해로 4년차인 자바 개발자
들어가기 앞서


•   RESTful의 R도 모르고 API의 A도 모르던
    한 개발자가 RESTful API를 만들기 위해
    고민하고 삽질한 과정 공유함으로써,

•   RESTful이 무엇인지, 이를 스프링에서
    어떻게 구현할 수 있는지 간략하게나마
    알아볼 수 있는 시간이 되었으면..
목 차


•   RESTful API with Spring 3.1
•   API Exception Handling
•   API Security
•   API Test
REST?
REST(Representational State Transfer)
REST(Representational State Transfer)


•   표현(Representational) - REST 리소스는 XML, JSON, 심지어 HTML
    을 포함하여 리소스 사용자에게 가장 적합한, 사실상 거의 모든 형
    식으로 표현할 수 있다

•   상태(State) - REST와 작업할 경우 리소스에 대해 취할 수 있는 액
    션보다 리소스의 상태에 대해 더 많은 관심을 둔다

•   젂달(Transfer) - REST는 한 애플리케이션에서 다른 애플리케이션
    으로 어떤 표현 형식으로 리소스 데이터 젂달을 포함한다




                                     - 스프링 인 액션 제3판 中 -
REST(Representational State Transfer)




표현(Representational) - REST 리소스는 XML,
JSON, 심지어 HTML을 포함하여 리소스 사용자에게
가장 적합한, 사실상 거의 모든 형식으로 표현할
수 있다
REST(Representational State Transfer)




상태(State) - REST와 작업할 경우 리소스에 대해
취할 수 있는 액션보다 리소스의 상태에 대해 더
많은 관심을 둔다
REST(Representational State Transfer)




젂달(Transfer) - REST는 한 애플리케이션에서 다
른 애플리케이션으로 어떤 표현 형식으로 리소스
데이터 젂달을 포함한다
REST(Representational State Transfer)


• 리소스 지향적이고,

• 애플리케이션을 표현하는 객체와 명사를
  강조하며,

• 가장 적합한 형식이 무엇이든 간에 서버
  에서 클라이언트로 (또는 그 반대로) 리
  소스의 상태를 젂달함
RESTful?
REST is not a standard;
it's a style.




               http://www.xfront.com/REST-Web-Services.html
API?
API!....OTL
RESTful API?
RESTful API!


RESTless : https://api.dropbox.com/getAccountInfo?id=1
RESTful : https://api.dropbox.com/1/account/info [GET]

RESTless : https://api.dropbox.com/deleteFile?id=1
RESTful : https://api.dropbox.com/1/fileops/delete [POST]
RESTful API!
• 평범한 HTTP URL을 통해 호출됨

• URL이 계층적이라, 왼쪽에서 오른쪽으로 읽다 보면 광범위한
  개념에서 정확한 개념으로 이동함

• 쿼리 파라미터를 이용해 리소스를 식별하는 대싞에 젂체 기본
  URL이 리소스를 식별함

• URL은 리소스로 무엇을 수행할 지가 아니라 리소스를 식별할
  뿐. 따라서 리소스를 식별하는 URL은 GET하거나 PUT하거나 에
  상관없이 모두 동일함

• 리소스로 무엇을 할지는 HTTP 메소드가 결정할 문제임
RESTful API!


http://localhost:8080/articles [GET] : 글 목록을 가져옴
http://localhost:8080/articles/123 [GET] : id가 123인 글을 가져옴
http://localhost:8080/articles/123 [PUT] : id가 123인 글을 작성
http://localhost:8080/articles/123 [DELETE] : id가 123인 글을 삭제




‚동일한 URL인 /articles/123으로 요청을 처리함‛
RESTful API!
    메소드                      설명                      안젂?     멱등적?
                                                    (safety) (idemp
                                                            otency)
     GET     서버에서 리소스를 조회한다. 리소스는 요청 URL에 의해            O      O
             식별된다.

    POST     요청 URL을 리스닝하는 프로세서에 의해 처리되도록               X      X
             서버에 데이터를 젂송한다.

     PUT     요청 URL에 있는 서버에 리소스를 둔다.                    X      O

    DELETE   요청 URL에 의해 식별되는 서버의 리소스를 삭제한다.             X      O

•    안젂(safe)? : 메소드가 리소스의 상태를 변경하지 않는 것
•    멱등적(idempotent)? : 반복되는 요청이 첫 번째 요청 이후에 발생할 수 있는
     어떠한 부작용도 일으키지 않는다.
     (상태를 변경할 수도 변경하지 않을 수도 있음)
‚실제로는 GET, POST만 사용‛
PUT을 사용하지 않은 이유

• 클라이언트가 URI 구조를 미리 알아야 함
  : 그러기 위해서는 id를 클라이언트에 알려줘야 하고, 쓸데없
  는 정보가 노출됨




 http://localhost:8080/articles/123 [PUT]
 http://localhost:8080/articles/write [POST]
DELETE을 사용하지 않은 이유

• 리소스를 삭제할 일이 없음
RESTful API! - Tip
•   동사 대싞 명사를 사용하도록 권장 : getDogs (x)  dogs (O)

•   단수명사 보다는 복수명사 : /dog (X)  /dogs (O)

•   추상적인 명사가 아닌 시나리오에 맞는 구체적인 명사 사용

•   : /photos와 같은 추상적인 명사가 아닌 /profilePhotos 와 같이 명확한 목적을 알
    수 있는 명사를 사용

•   /resource/identifier/resource : /owners/5678/dogs (5678번 주인의 dogs)
    : Identifier는 변경되지 않는 값

•   /dogs (젂체 dog), /dogs/1 (1번 dog)

•   출력 결과 형식을 지정 : /dogs (기본은 json이며 /dogs.json과 동일함), /dogs.xml
    은 xml 형식으로 출력

•   특정 범위의 값을 가져 올 때는 파라미터 사용 : /dogs?limit=25&offset=50

•   결과를 받기 원하는 항목 선택 : /dogs?fields=name,color,location
RESTful API
with Spring 3.1?
스프링이 REST를 지원하는 방법
•   컨트롤러는 REST의 네 가지 주요 메소드인 GET, PUT, DELETE, POST를 포함하여 모든
    HTTP 메소드에 대한 요청을 처리할 수 있음

•   @PathVariable 에너테이션은 컨트롤러가 파라미터화된 URL(경로의 일부분에 변수 입
    력이 있는 URL)에 대한 요청을 처리할 수 있도록 함

•   리소스는 XML, JSON, Atom 그리고 RSS 같은 데이털 모델 랜더링을 위한 새로운 뷰 구
    현을 포함하여 스프링의 뷰와 뷰 리졸버를 이용해 클라이언트에 가장 적합한 형태로
    리소스의 뒤에서 데이터를 표현할 수 있음

•   뷰 기반의 응답의 경우, ContentNegotiatingViewResolver는 클라이언트가 원하는 컨
    텐츠 타입을 만족시키는 몇 가지 뷰 리졸버에서 생성한 최적의 뷰를 선택할 수 있음

•   컨트롤러 핸들러 메소드에 @ResponseBody 애너테이션을 적용하여 뷰 처리를 완젂히
    무시하고, 몇 가지 메시지 변환기 중 하나로 변환된 값을 클라이언트에 대한 응답으
    로 변환

•   마찬가지로 새로운 @RequestBody 애너테이션은 HttpMethodConverter 구현체와 함께
    인바운드 HTTP 데이터를 컨트롤러의 핸들러 메소드에 젂달하는 자바 객체로 변환할
    수 있음
                                                - 스프링 인 액션 제3판 中 -
@Controller

@RequestMapping

@PathVariable

@RequestParam

@ResponseBody


  사실, 스프링 MVC에서 다 쓰던 것들..
@RequestMapping
@RequestMapping(value = "/files", method = RequestMethod.GET)
@ResponseBody
public void getFile(@RequestParam(‚id") Integer id) {
       File file = fileService.getFile(id);
}

http://localhost:8080/files?id=1



@PathVariable
@RequestMapping(value = "/files/{id}", method = RequestMethod.GET)
@ResponseBody
public void getFile(@PathVariable(‚id") Integer id) {
       File file = fileService.getFile(id);
}

http://localhost:8080/files/1
‚예를 하나
 들어보겠습니다‛
아이디(이메일)과 비밀번호를 입력하고
     로그인 버튺을 누르면,




    http://api.i-um.com/authentication/login
    email : exnis@naver.com
    password : ##########     “POST 방식으로 호출”




{                                “JSON으로 리턴”
        "status":"SUCCESS",
        "result": {"accessToken": “28as9dyhd923!3e2" },
        "error": "NULL"
}
예)로그인 - Annotation 사용
    http://api.i-um.com/authentication/login
    email : exnis@naver.com
    password : ##########                  ‚POST 방식으로 호출‛
    mobileType : IPHONE / ANDROID

@RequestMapping("/authentication")
@Controller
public class
AuthenticationApiController {

       @RequestMapping(value = "/login", method = RequestMethod.POST,
       produces = "application/json")
       @ResponseBody
       public ApiResult login(
              @RequestParam("email") String email,
              @RequestParam("password") String password
       ) { … }
}
예)로그인 - Annotation 사용
 http://api.i-um.com/authentication/login
 email : exnis@naver.com
                                         “POST 방식으로 호출”
 password : ##########
 mobileType : IPHONE / ANDROID

@RequestMapping("/api/authentication"
)
@Controller
public class
AuthenticationApiController {
      @RequestMapping(value = "/login", method = RequestMethod.POST,
      produces = "application/json")
      @ResponseBody
      public ApiResult login(
             @RequestParam("email") String email,
             @RequestParam("password") String password
      ) { … }
예)로그인 - Annotation 사용
 {                                                         ‚JSON으로 리턴‛
        "status": "SUCCESS",
        "result": { "accessToken": “28as9dyhd923!3e2" },
        "error": "NULL"
 }


@RequestMapping("/api/authentication"
)
@Controller
public class
AuthenticationApiController {
      @RequestMapping(value = "/login", method = RequestMethod.POST,
      produces = "application/json")
      @ResponseBody
      public ApiResult login(
             @RequestParam("email") String email,
             @RequestParam("password") String password
      ) { … }
예)로그인 – JSON으로 리턴


  ‚JSON으로 결과값을 리턴하기 위해서는?‛

1. MappingJacksonHttpMessageConverter 사용
2. MappingJacksonJsonView (JSON 지원 View 이용) &
   ContentNegotiatingViewResolver 사용
   (JSON 외 XML 등 다른 format의 view 제공하고 싶을 때)
예)로그인 – JSON으로 리턴

‚MappingJacksonHttpMessageConverter?‛

 Controller가                             클라이언트가
                   HttpMessageCon
   리턴하는                                    원하는
                       verter
   오브젝트                                    리소스




 • MappingJacksonHttpMessageConverter : JSON
 • MarshallingHttpMessageConverter : XML
 • RssChannelHttpMessageConverter : RSS
 .
 .
 .
예)로그인 – JSON으로 리턴
   ‚MappingJacksonHttpMessageConverter를 사용하려멲?‛
1. Servlet-context.xml에 bean 선언 추가
<bean class="org.springframework.web.servlet.mvc.annotation.RequestMappingHandlerAdapter">
  <property name="messageConverters">
    <list>
      <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
        <property name="supportedMediaTypes">
          <value>application/json;charset=UTF-8</beans:value>
        </property>
      </bean>
    </list>
  </property>                ResponseBody를 통해 반환되는 값에
</bean>                      한글이 있을 경우 깨지는 현상을 방지하기 위해 넣어줌




2. JSON으로 return하고자 하는 Controller에 @ResponseBody를 붙여줌
  @RequestMapping(value = "/login", method = RequestMethod.POST)
  @ResponseBody
  public ApiResult login(
로그인
public class ApiResult {

        private SuccessFail status;
        : SuccessFail은 SUCCESS / FAIL 의 enum type

        private Object result;
        : API를 호출한 쪽에 젂달되어야 할 값 (값이 없으면 NULL)

        private ExceptionReason error;
        : error가 발생하면 error에 대한 정보(code)를 넣어줌

        private String msg; (error가 NULL이 아닌 경우에만 보이도록 함)
        : error가 발생했을 때 클라이언트가 뿌려줘야 할 메시지

…
}
                                      ‚JSON으로 변홖‛
          {
                  "status":"SUCCESS",
                  "result":{"accessToken":"28as9dyhd923!3e2"},
                  "error":"NULL"
          }
‚다른 예를
 들어보겠습니다‛
예) 배지 – RequestMapping 젂략
1) 배지 목록 가져오기


@RequestMapping(value = "/badges", method = RequestMethod.GET)
@ResponseBody
public ApiResult getBadges(…) { … }
예) 배지 – RequestMapping 젂략
2) badgeId에 해당하는 배지 가져오기


@RequestMapping(value = "/badges/{badgeId}", method = RequestMethod.GET)
@ResponseBody
public ApiResult getBadge(@PathVariable Long badgeId) { … }
예) 배지 – RequestMapping 젂략
3) badgeId에 해당하는 배지의 사짂들 가져오기


@RequestMapping(value = "/badges/{badgeId}/photos", method = RequestMethod.GET)
@ResponseBody
public ApiResult getBadgePhotos(@PathVariable Long badgeId) { … }
배지
4) badgeId에 해당하는 배지의 {slotNum}번째 사짂 가져오기


@RequestMapping(value = "/badges/{badgeId}/photos/{slotNum}", method =
RequestMethod.GET)
@ResponseBody
public ApiResult getBadgePhoto(
@PathVariable Long badgeId,
@PathVariable(‚slotNum‛) Integer slotNum) { … }
배지
5) badgeId에 해당하는 배지의 {slotNum}번째 사짂 업로드하기


@RequestMapping(value = "/badges/{badgeId}/photos/{slotNum}/upload", method =
RequestMethod.POST)
public ApiResult uploadBadgePhoto(
@PathVariable Long badgeId,
@PathVariable(‚photoOrder‛) Integer photoOrder) { … }
API Exception
  Handling
예외처리

       “Service 에서 Business Logic이 실행되다가
       Exception이 발생하면 Controller에서 catch해서
       에러코드와 메시지를 리턴해줌”



        {
             "status":"FAIL",
             "result":"NULL",
             "error":"INVALID_EMAIL_PASSWORD"
             "message":"이메일 또는 비밀번호가 틀렸습니다"
        }
예외처리
   ‚Exception을 상속받아 별도의 Exception Class를 만듦‛


       Exception


             extends


      A Exception        private AExceptionReason exceptionReason;




public enum AExceptionReason {
        이유1, 이유2, 이유3, 이유4, …
};

: 예외가 발생한 이유를 enum형으로 정의함
예외처리
“도메인 or 서비스마다 Exception(class)과 Exception Reason(enum)이 생김”


         AException (class)         GException (class)
      AExceptionReason (enum)    GExceptionReason (enum)

         BException (class)         HException (class)
      BExceptionReason (enum)    HExceptionReason (enum)

         CException (class)         IException (class)
      CExceptionReason (enum)    IExceptionReason (enum)

         DException (class)         JException (class)
      DExceptionReason (enum)    JExceptionReason (enum)

         EException (class)                .
      EExceptionReason (enum)              .
                                           .
         Fexception (class)
      FExceptionReason (enum)
예외처리
                    코드의 중복이 발생!
try {
…
} catch (Exception e) {
    ApiError apiError = null;
        if (e instanceof AException) {
            apiResult.setError((((AException)e).getAExceptionReason());
        } else if(e instanceof BException) {
           apiResult.setError((((BException)e).getBExceptionReason());
        } else if(e instanceof CException) {
           apiResult.setError((((CException)e).getCExceptionReason());
        } else {
            apiResult.setError(UNKNOWN_EXCEPTION);
        }                                      Exception 개수만큼 조건문 늘어남!!


       apiResult.setMessage(e.getMessage());
}

return apiResult;
예외처리 : 개선 후

      Enum은 extend가 안되어서,
      interface 만든 후 implements 하도록 처리!


     ExceptionReason
       (interface)

                                     implements



AExceptionReason       BExceptionReason      CExceptionReason
                                                                …
     (enum)                 (enum)                (enum)
예외처리 : 개선 후

             Exception
              (class)

                      extends


      FrontModuleException
        (abstract class)               public abstract ExceptionReason getExceptionReason();



                                                            extends      …


    AException        private AExceptionReason      BException        private BExceptionReason
                                                                      bExceptionReason;
      (class)         aExceptionReason;              (class)

@Override                                        @Override
public ExceptionReason getExceptionReason() {    public ExceptionReason getExceptionReason() {
    return aExceptionReason;                         return bExceptionReason;
}                                                }
예외처리 : 개선 후

   Exception 개수가 많아도 하나로 처리!

try {
…
} catch (FrontModuleException e) {
    apiResult.setError(e.getExceptionReason());
    apiResult.setMessage(e.getMessage());
}

return apiResult;



       But 여젂히 코드의 중복이 발생!
예외처리 : 다른 개선방안


                                                  ExceptionResolver




                                                                                ContentNegotiatingView
                  ResponseEntity<?>
                                                                                       Resolver




http://dev.anyframejava.org/docs/anyframe/plugin/springrest/1.0.2/reference/html/ch10.html
API Security
API Security
 적당히           ‚회사 내부에서만 사용되는 API‛
                            (private)



               ‚클라이언트(앱)와 통싞하는 API‛
                           (반만 public)



               ‚3rd Party나 개발자에게 공개된 API‛
꼼꼼히
                                  (public)


아래에 해당할수록 어플리케이션 레벨의 보안에 싞경써야!
API Security

ID(Identity)
: 누가 API request를 요청했는지 확인

인증(Authentication)
: 주체의 싞원을 주체가 주장하는 싞원과 대비해 검증하는 과정
 (A가 정말로 A가 맞는지 확인)

허가(Authorization)
: 인증된 사용자에게 권한들을 승인하는 과정
 (A가 어떤 액션을 하려고 할 때, 그 액션을 하도록 허용되었는지 확인)




API에서 이 3가지를 모두 요구하지는 않는다!
API Security
ID(Identity) 만 요구 - Google Maps API
: API key만 알면 API 사용 가능
API Security
ID(Identity), 인증(Authentication) 요구–Twitter API
: username / password를 입력해서 인증해야 함
API Security
ID(Identity), 인증(Authentication), 허가(Authorization)
요구–Facebook API
: email / password 입력한 후, 특정 action에 대한 허가를
  요구함
‚이렇게 했습니다‛
API Security

• Oauth
• OpenID
• SAML
• HTTP authentication
• WS-Security
• Basic API Key
API Security


• 로그인 이후 모든 API 호출 시, 액세스 토큰(Access Token)을
  파라미터로 같이 넘겨 매번 인증(Authentication)함

• 액세스 토큰은 DB에 저장되어 있음 (세션에 저장하지 않음)

• 스프링에서 제공하는 http basic 이나 remember-me
  authenticaiton을 사용하지 않았음

• 액세스 토큰이 다시 생성되어 업데이트 및, 클라이언트에게 리
  턴 되는 경우

  1. 로그아웃 후, 다시 로그인
  2. 다른 기기에 설치되어 있는 앱으로 로그인
API Security
{
            "status": "SUCCESS",
            "result": { "accessToken": “28as9dyhd923!3e2" },   ‚로그인 성공‛
            "error": "NULL"
}

    ApiResult abc(@RequestParam("accessToken") String accessToken, …) {
             accessToken을 authentication 하는 로직
    }

    ApiResult def(@RequestParam("accessToken") String accessToken, …) {
             accessToken을 authentication 하는 로직
    }

    ApiResult xyz(@RequestParam("accessToken") String accessToken, …) {
             accessToken을 authentication 하는 로직
    }



                        코드의 중복이 발생!
API Security

    AccessToken을 인증하는 로직을 Interceptor로 분리해서
      Controller 메소드가 실행되기 젂 호출되도록 처리함


public class MobileAuthenticationInterceptor extends
HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request,
    HttpServletResponse response, Object handler) throws Exception {
        accessToken을 authentication 하는 로직
    }
}
API Security
“특정유저(슈퍼유저)만 호출가능한 메서드를 만들고 싶을 때”



메서드 호출 보호 (Spring Security)
 •   보안 인터셉터 엘리먼트를 통한 메서드 보호
 •   포인트컷을 활용한 메서드 보호
 •   애너테이션을 홗용한 메소드 보호
                              - 스프링 3 레시피 中 -




장점 : 호출 보호하고자 하는 메서드 위에 애너테이션만 붙이멲 된다.
단점 : 나중에 어디에 애너테이션을 적용했는지 잊어버려 검색해봐야 한다.
API Security

 @Secured("ADMIN_USER") <!-- 스프링에서 제공 -->
 @RolesAllowed(‚ADMIN_USER‛) <!-- JSR-250 -->
 @PreAuthorize(‚hasRole(‘ADMIN_USER’)‛) <!-- 스프링에서 제공 -->
 public void deleteAccount(Long seqId) {
     계정을 삭제하는 로직 (for 가입 테스트)
      …
 }


@Secured를 사용하려면?
<global-method-security secured-annotations=‚enabled‛/>

@RolesAllowed를 사용하려면?
<global-method-security jsr250-annotations=‚enabled‛ />

@PreAuthorize를 사용하려면?
<global-method-security pre-post-annotations=‚enabled‛ />
API Security - 잊지 말아야 할 것!

•   클라이언트에 정보를 딱 필요한 만큼만 준다.
•   민감한 정보는 젃대 넘겨주지 않는다.
    (예 : 유저의 seq_id, 주민번호 등)
API TEST
API(Analytical
                                                                     Profile Index)
                                                                     TEST?




출처 : http://www.biologyreference.com/Ar-Bi/Bacterial-Genetics.html
클라이언트(앱) 개발자나 기획자가
쉽고 편하게 API를 테스트하게 하려멲?
API TEST
REST Client 이용 (Firefox, Chrome 확장 플러그인 설치)?




장점 : 설치 및 사용이 쉽다.
단점 : 테스트해야 할 API들이 많은 경우, 매번 HTTP URL을
     입력하기 번거롭다. 개발자에게만 친숙한 홖경이다.
‚이렇게 했습니다‛
API TEST
웹 테스트 페이지
API TEST




      http://swagger.wordnik.com/   http://twitter.github.com/bootstrap/
API TEST

Component scan으로 모든 Controller 클래스를 스캔한 후
(@Controller 에너테이션으로 스캔 가능),
클래스의 methods()를 사용해 모든 method를 가져올 수 있음


• @PathVariable로 들어오는 값과 @RequestParam으로
  들어오는 값을 따로 처리해야 함
• 메소드 추가, 삭제가 불편함 (일괄적으로 처리하기 때문)
• 유연하게 카테고리를 나누기 힘듬




  메소드가 생길 때마다 URL, 메소드 타입, 파라미터는
  개발자가 직접 입력하자!
API TEST

                                                                                    ApiTestView
   ApiTestEnum              ApiTestManager            ApiTestController
                                                                                (swagger, bootstrap)



public enum ApiTestEnum {

// A. 로딩페이지
IntroGate("A. 로딩페이지", "/intro", "GET", "gate"),
               카테고리         URL    HTTP 메소드명
                                   메소드
// B. 로그인
Login("B. 로그인", "/authentication/login", "POST", "login"),
FindPassword("B. 로그인", "/authentication/password/find", "POST",
"findPassword"),

// C. 가입
IsVaildEmail("C. 가입", "/authentication/email/check", "POST", "isValidEmail"),
AuthorizeName("C. 가입", "/authentication/name", "POST", "authorizeName"),.
.
.
    private String apiCategory;
    private String apiUrl;
    private String methodType;
    private String name;
}
References

 1.   http://apigee.com/about/api-best-practices/all/ebook
 2.   [Book] 웹 개발자를 위한 웹을 지탱하는 기술
 3.   [Book] 스프링 인 액션 제 3판
 4.   [Book] 스프링 3 레시피
 5.   [Book] 스프링 시큐리티 3
Thank you for
 Listening!

Contenu connexe

Tendances

SOAP REST 이해
SOAP REST 이해SOAP REST 이해
SOAP REST 이해Jake Yoon
 
Restful web service
Restful web serviceRestful web service
Restful web servicesunguen lee
 
REST API 설계
REST API 설계REST API 설계
REST API 설계Terry Cho
 
SOAP 기반/ RESTful기반 웹서비스 비교
SOAP 기반/ RESTful기반 웹서비스 비교SOAP 기반/ RESTful기반 웹서비스 비교
SOAP 기반/ RESTful기반 웹서비스 비교seungdols
 
Json view 예제 설명
Json view 예제 설명Json view 예제 설명
Json view 예제 설명Hyung Eun Jin
 
Node.js DBMS short summary
Node.js DBMS short summaryNode.js DBMS short summary
Node.js DBMS short summaryHoChul Shin
 
Web http spec(basic)
Web http spec(basic)Web http spec(basic)
Web http spec(basic)Julia Park
 
[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발NAVER D2
 
Spring 4.x Web Application 살펴보기
Spring 4.x Web Application  살펴보기Spring 4.x Web Application  살펴보기
Spring 4.x Web Application 살펴보기Ji Heon Kim
 
E-Gov 기반 Mobile Web Friendly 개발
E-Gov 기반 Mobile Web Friendly 개발E-Gov 기반 Mobile Web Friendly 개발
E-Gov 기반 Mobile Web Friendly 개발JavaCommunity.Org
 
Naver 오픈api-마이그레이션가이드 20160913-리뷰
Naver 오픈api-마이그레이션가이드 20160913-리뷰Naver 오픈api-마이그레이션가이드 20160913-리뷰
Naver 오픈api-마이그레이션가이드 20160913-리뷰NAVER D2
 
F3 네이버오픈api만드는매쉬업
F3 네이버오픈api만드는매쉬업F3 네이버오픈api만드는매쉬업
F3 네이버오픈api만드는매쉬업NAVER D2
 
[D2SF] Naver 오픈 API 가이드
[D2SF] Naver 오픈 API 가이드[D2SF] Naver 오픈 API 가이드
[D2SF] Naver 오픈 API 가이드NAVER D2 STARTUP FACTORY
 
[오픈소스컨설팅]Spring MVC
[오픈소스컨설팅]Spring MVC [오픈소스컨설팅]Spring MVC
[오픈소스컨설팅]Spring MVC Ji-Woong Choi
 
Ryu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST APIRyu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST APIjieun kim
 
세미나 Spring mybatis
세미나 Spring mybatis세미나 Spring mybatis
세미나 Spring mybatisSomang Jeong
 
대용량 분산 아키텍쳐 설계 #5. rest
대용량 분산 아키텍쳐 설계 #5. rest대용량 분산 아키텍쳐 설계 #5. rest
대용량 분산 아키텍쳐 설계 #5. restTerry Cho
 
spring.io를 통해 배우는 spring 개발사례
spring.io를 통해 배우는 spring 개발사례spring.io를 통해 배우는 spring 개발사례
spring.io를 통해 배우는 spring 개발사례Daehwan Lee
 

Tendances (20)

SOAP REST 이해
SOAP REST 이해SOAP REST 이해
SOAP REST 이해
 
Restful web service
Restful web serviceRestful web service
Restful web service
 
REST API 설계
REST API 설계REST API 설계
REST API 설계
 
SOAP 기반/ RESTful기반 웹서비스 비교
SOAP 기반/ RESTful기반 웹서비스 비교SOAP 기반/ RESTful기반 웹서비스 비교
SOAP 기반/ RESTful기반 웹서비스 비교
 
Json view 예제 설명
Json view 예제 설명Json view 예제 설명
Json view 예제 설명
 
Node.js DBMS short summary
Node.js DBMS short summaryNode.js DBMS short summary
Node.js DBMS short summary
 
Web http spec(basic)
Web http spec(basic)Web http spec(basic)
Web http spec(basic)
 
[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발[Hello world 오픈세미나]open api client개발
[Hello world 오픈세미나]open api client개발
 
Spring 4.x Web Application 살펴보기
Spring 4.x Web Application  살펴보기Spring 4.x Web Application  살펴보기
Spring 4.x Web Application 살펴보기
 
E-Gov 기반 Mobile Web Friendly 개발
E-Gov 기반 Mobile Web Friendly 개발E-Gov 기반 Mobile Web Friendly 개발
E-Gov 기반 Mobile Web Friendly 개발
 
Naver 오픈api-마이그레이션가이드 20160913-리뷰
Naver 오픈api-마이그레이션가이드 20160913-리뷰Naver 오픈api-마이그레이션가이드 20160913-리뷰
Naver 오픈api-마이그레이션가이드 20160913-리뷰
 
F3 네이버오픈api만드는매쉬업
F3 네이버오픈api만드는매쉬업F3 네이버오픈api만드는매쉬업
F3 네이버오픈api만드는매쉬업
 
[D2SF] Naver 오픈 API 가이드
[D2SF] Naver 오픈 API 가이드[D2SF] Naver 오픈 API 가이드
[D2SF] Naver 오픈 API 가이드
 
[오픈소스컨설팅]Spring MVC
[오픈소스컨설팅]Spring MVC [오픈소스컨설팅]Spring MVC
[오픈소스컨설팅]Spring MVC
 
Ryu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST APIRyu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST API
 
Html5 performance
Html5 performanceHtml5 performance
Html5 performance
 
세미나 Spring mybatis
세미나 Spring mybatis세미나 Spring mybatis
세미나 Spring mybatis
 
대용량 분산 아키텍쳐 설계 #5. rest
대용량 분산 아키텍쳐 설계 #5. rest대용량 분산 아키텍쳐 설계 #5. rest
대용량 분산 아키텍쳐 설계 #5. rest
 
Express 프레임워크
Express 프레임워크Express 프레임워크
Express 프레임워크
 
spring.io를 통해 배우는 spring 개발사례
spring.io를 통해 배우는 spring 개발사례spring.io를 통해 배우는 spring 개발사례
spring.io를 통해 배우는 spring 개발사례
 

En vedette

[162] jpa와 모던 자바 데이터 저장 기술
[162] jpa와 모던 자바 데이터 저장 기술[162] jpa와 모던 자바 데이터 저장 기술
[162] jpa와 모던 자바 데이터 저장 기술NAVER D2
 
[124] 하이브리드 앱 개발기 김한솔
[124] 하이브리드 앱 개발기 김한솔[124] 하이브리드 앱 개발기 김한솔
[124] 하이브리드 앱 개발기 김한솔NAVER D2
 
클라우드 기반 Unity 게임 서버 구축, 60분이면 충분하다
클라우드 기반 Unity 게임 서버 구축, 60분이면 충분하다클라우드 기반 Unity 게임 서버 구축, 60분이면 충분하다
클라우드 기반 Unity 게임 서버 구축, 60분이면 충분하다Dae Kim
 
[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민
[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민
[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민NAVER D2
 
RESTful API 제대로 만들기
RESTful API 제대로 만들기RESTful API 제대로 만들기
RESTful API 제대로 만들기Juwon Kim
 

En vedette (6)

[162] jpa와 모던 자바 데이터 저장 기술
[162] jpa와 모던 자바 데이터 저장 기술[162] jpa와 모던 자바 데이터 저장 기술
[162] jpa와 모던 자바 데이터 저장 기술
 
[124] 하이브리드 앱 개발기 김한솔
[124] 하이브리드 앱 개발기 김한솔[124] 하이브리드 앱 개발기 김한솔
[124] 하이브리드 앱 개발기 김한솔
 
클라우드 기반 Unity 게임 서버 구축, 60분이면 충분하다
클라우드 기반 Unity 게임 서버 구축, 60분이면 충분하다클라우드 기반 Unity 게임 서버 구축, 60분이면 충분하다
클라우드 기반 Unity 게임 서버 구축, 60분이면 충분하다
 
[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민
[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민
[125]react로개발자2명이플랫폼4개를서비스하는이야기 심상민
 
RESTful API 제대로 만들기
RESTful API 제대로 만들기RESTful API 제대로 만들기
RESTful API 제대로 만들기
 
sungmin slide
sungmin slidesungmin slide
sungmin slide
 

Similaire à Ksug 세미나 (윤성준) (20121208)

2Naver Open Android API Translation At DCamp
2Naver Open Android API Translation At DCamp2Naver Open Android API Translation At DCamp
2Naver Open Android API Translation At DCampJeikei Park
 
Booting Spring Data REST
Booting Spring Data RESTBooting Spring Data REST
Booting Spring Data REST경원 이
 
막하는스터디 두번째만남 Express(20151025)
막하는스터디 두번째만남 Express(20151025)막하는스터디 두번째만남 Express(20151025)
막하는스터디 두번째만남 Express(20151025)연웅 조
 
리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST API
리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST API리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST API
리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST APIWooyoung Ko
 
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출GDG Korea
 
자바 웹 개발 시작하기 (3주차 : 스프링 웹 개발)
자바 웹 개발 시작하기 (3주차 : 스프링 웹 개발)자바 웹 개발 시작하기 (3주차 : 스프링 웹 개발)
자바 웹 개발 시작하기 (3주차 : 스프링 웹 개발)DK Lee
 
[112]rest에서 graph ql과 relay로 갈아타기 이정우
[112]rest에서 graph ql과 relay로 갈아타기 이정우[112]rest에서 graph ql과 relay로 갈아타기 이정우
[112]rest에서 graph ql과 relay로 갈아타기 이정우NAVER D2
 
ASP.NET Web API를 활용한 RESTful 서비스 개발
ASP.NET Web API를 활용한 RESTful 서비스 개발ASP.NET Web API를 활용한 RESTful 서비스 개발
ASP.NET Web API를 활용한 RESTful 서비스 개발SangHoon Han
 
REST Ovewview
REST OvewviewREST Ovewview
REST OvewviewTerry Cho
 
overview of spring4
overview of spring4overview of spring4
overview of spring4Arawn Park
 
Web server page_ed10
Web server page_ed10Web server page_ed10
Web server page_ed10hungrok
 
ASP.NET Web API를 이용한 오픈 API 개발
ASP.NET Web API를 이용한 오픈 API 개발ASP.NET Web API를 이용한 오픈 API 개발
ASP.NET Web API를 이용한 오픈 API 개발SangHoon Han
 
vine webdev
vine webdevvine webdev
vine webdevdcfc1997
 
[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기
[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기
[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기NAVER Engineering
 
Mean 스택을 사용한 IoT 개발
Mean 스택을 사용한 IoT 개발Mean 스택을 사용한 IoT 개발
Mean 스택을 사용한 IoT 개발Jay Park
 
Do IoT Yourself! - 사물 간의 연결을 위한 Open API
Do IoT Yourself! - 사물 간의 연결을 위한 Open APIDo IoT Yourself! - 사물 간의 연결을 위한 Open API
Do IoT Yourself! - 사물 간의 연결을 위한 Open APIHyunghun Cho
 

Similaire à Ksug 세미나 (윤성준) (20121208) (20)

2Naver Open Android API Translation At DCamp
2Naver Open Android API Translation At DCamp2Naver Open Android API Translation At DCamp
2Naver Open Android API Translation At DCamp
 
Booting Spring Data REST
Booting Spring Data RESTBooting Spring Data REST
Booting Spring Data REST
 
막하는스터디 두번째만남 Express(20151025)
막하는스터디 두번째만남 Express(20151025)막하는스터디 두번째만남 Express(20151025)
막하는스터디 두번째만남 Express(20151025)
 
Srping data rest
Srping data restSrping data rest
Srping data rest
 
One-day-codelab
One-day-codelabOne-day-codelab
One-day-codelab
 
리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST API
리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST API리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST API
리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST API
 
Nodejs express
Nodejs expressNodejs express
Nodejs express
 
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
 
4-2. ajax
4-2. ajax4-2. ajax
4-2. ajax
 
자바 웹 개발 시작하기 (3주차 : 스프링 웹 개발)
자바 웹 개발 시작하기 (3주차 : 스프링 웹 개발)자바 웹 개발 시작하기 (3주차 : 스프링 웹 개발)
자바 웹 개발 시작하기 (3주차 : 스프링 웹 개발)
 
[112]rest에서 graph ql과 relay로 갈아타기 이정우
[112]rest에서 graph ql과 relay로 갈아타기 이정우[112]rest에서 graph ql과 relay로 갈아타기 이정우
[112]rest에서 graph ql과 relay로 갈아타기 이정우
 
ASP.NET Web API를 활용한 RESTful 서비스 개발
ASP.NET Web API를 활용한 RESTful 서비스 개발ASP.NET Web API를 활용한 RESTful 서비스 개발
ASP.NET Web API를 활용한 RESTful 서비스 개발
 
REST Ovewview
REST OvewviewREST Ovewview
REST Ovewview
 
overview of spring4
overview of spring4overview of spring4
overview of spring4
 
Web server page_ed10
Web server page_ed10Web server page_ed10
Web server page_ed10
 
ASP.NET Web API를 이용한 오픈 API 개발
ASP.NET Web API를 이용한 오픈 API 개발ASP.NET Web API를 이용한 오픈 API 개발
ASP.NET Web API를 이용한 오픈 API 개발
 
vine webdev
vine webdevvine webdev
vine webdev
 
[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기
[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기
[TECHCON 2019: MOBILE - Android]2.예제에서는 알려주지 않는 Model 이야기
 
Mean 스택을 사용한 IoT 개발
Mean 스택을 사용한 IoT 개발Mean 스택을 사용한 IoT 개발
Mean 스택을 사용한 IoT 개발
 
Do IoT Yourself! - 사물 간의 연결을 위한 Open API
Do IoT Yourself! - 사물 간의 연결을 위한 Open APIDo IoT Yourself! - 사물 간의 연결을 위한 Open API
Do IoT Yourself! - 사물 간의 연결을 위한 Open API
 

Ksug 세미나 (윤성준) (20121208)

  • 1. RESTful API (including Mobile) with Spring 3.1 윤성준(@exnis)
  • 2. 소 개 ‘이음’ 이라는 스타트업에서 일하는, 올해로 4년차인 자바 개발자
  • 3. 들어가기 앞서 • RESTful의 R도 모르고 API의 A도 모르던 한 개발자가 RESTful API를 만들기 위해 고민하고 삽질한 과정 공유함으로써, • RESTful이 무엇인지, 이를 스프링에서 어떻게 구현할 수 있는지 간략하게나마 알아볼 수 있는 시간이 되었으면..
  • 4. 목 차 • RESTful API with Spring 3.1 • API Exception Handling • API Security • API Test
  • 6.
  • 8. REST(Representational State Transfer) • 표현(Representational) - REST 리소스는 XML, JSON, 심지어 HTML 을 포함하여 리소스 사용자에게 가장 적합한, 사실상 거의 모든 형 식으로 표현할 수 있다 • 상태(State) - REST와 작업할 경우 리소스에 대해 취할 수 있는 액 션보다 리소스의 상태에 대해 더 많은 관심을 둔다 • 젂달(Transfer) - REST는 한 애플리케이션에서 다른 애플리케이션 으로 어떤 표현 형식으로 리소스 데이터 젂달을 포함한다 - 스프링 인 액션 제3판 中 -
  • 9. REST(Representational State Transfer) 표현(Representational) - REST 리소스는 XML, JSON, 심지어 HTML을 포함하여 리소스 사용자에게 가장 적합한, 사실상 거의 모든 형식으로 표현할 수 있다
  • 10. REST(Representational State Transfer) 상태(State) - REST와 작업할 경우 리소스에 대해 취할 수 있는 액션보다 리소스의 상태에 대해 더 많은 관심을 둔다
  • 11. REST(Representational State Transfer) 젂달(Transfer) - REST는 한 애플리케이션에서 다 른 애플리케이션으로 어떤 표현 형식으로 리소스 데이터 젂달을 포함한다
  • 12. REST(Representational State Transfer) • 리소스 지향적이고, • 애플리케이션을 표현하는 객체와 명사를 강조하며, • 가장 적합한 형식이 무엇이든 간에 서버 에서 클라이언트로 (또는 그 반대로) 리 소스의 상태를 젂달함
  • 14. REST is not a standard; it's a style. http://www.xfront.com/REST-Web-Services.html
  • 15. API?
  • 18. RESTful API! RESTless : https://api.dropbox.com/getAccountInfo?id=1 RESTful : https://api.dropbox.com/1/account/info [GET] RESTless : https://api.dropbox.com/deleteFile?id=1 RESTful : https://api.dropbox.com/1/fileops/delete [POST]
  • 19. RESTful API! • 평범한 HTTP URL을 통해 호출됨 • URL이 계층적이라, 왼쪽에서 오른쪽으로 읽다 보면 광범위한 개념에서 정확한 개념으로 이동함 • 쿼리 파라미터를 이용해 리소스를 식별하는 대싞에 젂체 기본 URL이 리소스를 식별함 • URL은 리소스로 무엇을 수행할 지가 아니라 리소스를 식별할 뿐. 따라서 리소스를 식별하는 URL은 GET하거나 PUT하거나 에 상관없이 모두 동일함 • 리소스로 무엇을 할지는 HTTP 메소드가 결정할 문제임
  • 20. RESTful API! http://localhost:8080/articles [GET] : 글 목록을 가져옴 http://localhost:8080/articles/123 [GET] : id가 123인 글을 가져옴 http://localhost:8080/articles/123 [PUT] : id가 123인 글을 작성 http://localhost:8080/articles/123 [DELETE] : id가 123인 글을 삭제 ‚동일한 URL인 /articles/123으로 요청을 처리함‛
  • 21. RESTful API! 메소드 설명 안젂? 멱등적? (safety) (idemp otency) GET 서버에서 리소스를 조회한다. 리소스는 요청 URL에 의해 O O 식별된다. POST 요청 URL을 리스닝하는 프로세서에 의해 처리되도록 X X 서버에 데이터를 젂송한다. PUT 요청 URL에 있는 서버에 리소스를 둔다. X O DELETE 요청 URL에 의해 식별되는 서버의 리소스를 삭제한다. X O • 안젂(safe)? : 메소드가 리소스의 상태를 변경하지 않는 것 • 멱등적(idempotent)? : 반복되는 요청이 첫 번째 요청 이후에 발생할 수 있는 어떠한 부작용도 일으키지 않는다. (상태를 변경할 수도 변경하지 않을 수도 있음)
  • 23. PUT을 사용하지 않은 이유 • 클라이언트가 URI 구조를 미리 알아야 함 : 그러기 위해서는 id를 클라이언트에 알려줘야 하고, 쓸데없 는 정보가 노출됨 http://localhost:8080/articles/123 [PUT] http://localhost:8080/articles/write [POST]
  • 24. DELETE을 사용하지 않은 이유 • 리소스를 삭제할 일이 없음
  • 25. RESTful API! - Tip • 동사 대싞 명사를 사용하도록 권장 : getDogs (x)  dogs (O) • 단수명사 보다는 복수명사 : /dog (X)  /dogs (O) • 추상적인 명사가 아닌 시나리오에 맞는 구체적인 명사 사용 • : /photos와 같은 추상적인 명사가 아닌 /profilePhotos 와 같이 명확한 목적을 알 수 있는 명사를 사용 • /resource/identifier/resource : /owners/5678/dogs (5678번 주인의 dogs) : Identifier는 변경되지 않는 값 • /dogs (젂체 dog), /dogs/1 (1번 dog) • 출력 결과 형식을 지정 : /dogs (기본은 json이며 /dogs.json과 동일함), /dogs.xml 은 xml 형식으로 출력 • 특정 범위의 값을 가져 올 때는 파라미터 사용 : /dogs?limit=25&offset=50 • 결과를 받기 원하는 항목 선택 : /dogs?fields=name,color,location
  • 27. 스프링이 REST를 지원하는 방법 • 컨트롤러는 REST의 네 가지 주요 메소드인 GET, PUT, DELETE, POST를 포함하여 모든 HTTP 메소드에 대한 요청을 처리할 수 있음 • @PathVariable 에너테이션은 컨트롤러가 파라미터화된 URL(경로의 일부분에 변수 입 력이 있는 URL)에 대한 요청을 처리할 수 있도록 함 • 리소스는 XML, JSON, Atom 그리고 RSS 같은 데이털 모델 랜더링을 위한 새로운 뷰 구 현을 포함하여 스프링의 뷰와 뷰 리졸버를 이용해 클라이언트에 가장 적합한 형태로 리소스의 뒤에서 데이터를 표현할 수 있음 • 뷰 기반의 응답의 경우, ContentNegotiatingViewResolver는 클라이언트가 원하는 컨 텐츠 타입을 만족시키는 몇 가지 뷰 리졸버에서 생성한 최적의 뷰를 선택할 수 있음 • 컨트롤러 핸들러 메소드에 @ResponseBody 애너테이션을 적용하여 뷰 처리를 완젂히 무시하고, 몇 가지 메시지 변환기 중 하나로 변환된 값을 클라이언트에 대한 응답으 로 변환 • 마찬가지로 새로운 @RequestBody 애너테이션은 HttpMethodConverter 구현체와 함께 인바운드 HTTP 데이터를 컨트롤러의 핸들러 메소드에 젂달하는 자바 객체로 변환할 수 있음 - 스프링 인 액션 제3판 中 -
  • 29. @RequestMapping @RequestMapping(value = "/files", method = RequestMethod.GET) @ResponseBody public void getFile(@RequestParam(‚id") Integer id) { File file = fileService.getFile(id); } http://localhost:8080/files?id=1 @PathVariable @RequestMapping(value = "/files/{id}", method = RequestMethod.GET) @ResponseBody public void getFile(@PathVariable(‚id") Integer id) { File file = fileService.getFile(id); } http://localhost:8080/files/1
  • 31. 아이디(이메일)과 비밀번호를 입력하고 로그인 버튺을 누르면, http://api.i-um.com/authentication/login email : exnis@naver.com password : ########## “POST 방식으로 호출” { “JSON으로 리턴” "status":"SUCCESS", "result": {"accessToken": “28as9dyhd923!3e2" }, "error": "NULL" }
  • 32. 예)로그인 - Annotation 사용 http://api.i-um.com/authentication/login email : exnis@naver.com password : ########## ‚POST 방식으로 호출‛ mobileType : IPHONE / ANDROID @RequestMapping("/authentication") @Controller public class AuthenticationApiController { @RequestMapping(value = "/login", method = RequestMethod.POST, produces = "application/json") @ResponseBody public ApiResult login( @RequestParam("email") String email, @RequestParam("password") String password ) { … } }
  • 33. 예)로그인 - Annotation 사용 http://api.i-um.com/authentication/login email : exnis@naver.com “POST 방식으로 호출” password : ########## mobileType : IPHONE / ANDROID @RequestMapping("/api/authentication" ) @Controller public class AuthenticationApiController { @RequestMapping(value = "/login", method = RequestMethod.POST, produces = "application/json") @ResponseBody public ApiResult login( @RequestParam("email") String email, @RequestParam("password") String password ) { … }
  • 34. 예)로그인 - Annotation 사용 { ‚JSON으로 리턴‛ "status": "SUCCESS", "result": { "accessToken": “28as9dyhd923!3e2" }, "error": "NULL" } @RequestMapping("/api/authentication" ) @Controller public class AuthenticationApiController { @RequestMapping(value = "/login", method = RequestMethod.POST, produces = "application/json") @ResponseBody public ApiResult login( @RequestParam("email") String email, @RequestParam("password") String password ) { … }
  • 35. 예)로그인 – JSON으로 리턴 ‚JSON으로 결과값을 리턴하기 위해서는?‛ 1. MappingJacksonHttpMessageConverter 사용 2. MappingJacksonJsonView (JSON 지원 View 이용) & ContentNegotiatingViewResolver 사용 (JSON 외 XML 등 다른 format의 view 제공하고 싶을 때)
  • 36. 예)로그인 – JSON으로 리턴 ‚MappingJacksonHttpMessageConverter?‛ Controller가 클라이언트가 HttpMessageCon 리턴하는 원하는 verter 오브젝트 리소스 • MappingJacksonHttpMessageConverter : JSON • MarshallingHttpMessageConverter : XML • RssChannelHttpMessageConverter : RSS . . .
  • 37. 예)로그인 – JSON으로 리턴 ‚MappingJacksonHttpMessageConverter를 사용하려멲?‛ 1. Servlet-context.xml에 bean 선언 추가 <bean class="org.springframework.web.servlet.mvc.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"> <property name="supportedMediaTypes"> <value>application/json;charset=UTF-8</beans:value> </property> </bean> </list> </property> ResponseBody를 통해 반환되는 값에 </bean> 한글이 있을 경우 깨지는 현상을 방지하기 위해 넣어줌 2. JSON으로 return하고자 하는 Controller에 @ResponseBody를 붙여줌 @RequestMapping(value = "/login", method = RequestMethod.POST) @ResponseBody public ApiResult login(
  • 38. 로그인 public class ApiResult { private SuccessFail status; : SuccessFail은 SUCCESS / FAIL 의 enum type private Object result; : API를 호출한 쪽에 젂달되어야 할 값 (값이 없으면 NULL) private ExceptionReason error; : error가 발생하면 error에 대한 정보(code)를 넣어줌 private String msg; (error가 NULL이 아닌 경우에만 보이도록 함) : error가 발생했을 때 클라이언트가 뿌려줘야 할 메시지 … } ‚JSON으로 변홖‛ { "status":"SUCCESS", "result":{"accessToken":"28as9dyhd923!3e2"}, "error":"NULL" }
  • 40.
  • 41. 예) 배지 – RequestMapping 젂략 1) 배지 목록 가져오기 @RequestMapping(value = "/badges", method = RequestMethod.GET) @ResponseBody public ApiResult getBadges(…) { … }
  • 42. 예) 배지 – RequestMapping 젂략 2) badgeId에 해당하는 배지 가져오기 @RequestMapping(value = "/badges/{badgeId}", method = RequestMethod.GET) @ResponseBody public ApiResult getBadge(@PathVariable Long badgeId) { … }
  • 43. 예) 배지 – RequestMapping 젂략 3) badgeId에 해당하는 배지의 사짂들 가져오기 @RequestMapping(value = "/badges/{badgeId}/photos", method = RequestMethod.GET) @ResponseBody public ApiResult getBadgePhotos(@PathVariable Long badgeId) { … }
  • 44. 배지 4) badgeId에 해당하는 배지의 {slotNum}번째 사짂 가져오기 @RequestMapping(value = "/badges/{badgeId}/photos/{slotNum}", method = RequestMethod.GET) @ResponseBody public ApiResult getBadgePhoto( @PathVariable Long badgeId, @PathVariable(‚slotNum‛) Integer slotNum) { … }
  • 45. 배지 5) badgeId에 해당하는 배지의 {slotNum}번째 사짂 업로드하기 @RequestMapping(value = "/badges/{badgeId}/photos/{slotNum}/upload", method = RequestMethod.POST) public ApiResult uploadBadgePhoto( @PathVariable Long badgeId, @PathVariable(‚photoOrder‛) Integer photoOrder) { … }
  • 46. API Exception Handling
  • 47. 예외처리 “Service 에서 Business Logic이 실행되다가 Exception이 발생하면 Controller에서 catch해서 에러코드와 메시지를 리턴해줌” { "status":"FAIL", "result":"NULL", "error":"INVALID_EMAIL_PASSWORD" "message":"이메일 또는 비밀번호가 틀렸습니다" }
  • 48. 예외처리 ‚Exception을 상속받아 별도의 Exception Class를 만듦‛ Exception extends A Exception private AExceptionReason exceptionReason; public enum AExceptionReason { 이유1, 이유2, 이유3, 이유4, … }; : 예외가 발생한 이유를 enum형으로 정의함
  • 49. 예외처리 “도메인 or 서비스마다 Exception(class)과 Exception Reason(enum)이 생김” AException (class) GException (class) AExceptionReason (enum) GExceptionReason (enum) BException (class) HException (class) BExceptionReason (enum) HExceptionReason (enum) CException (class) IException (class) CExceptionReason (enum) IExceptionReason (enum) DException (class) JException (class) DExceptionReason (enum) JExceptionReason (enum) EException (class) . EExceptionReason (enum) . . Fexception (class) FExceptionReason (enum)
  • 50. 예외처리 코드의 중복이 발생! try { … } catch (Exception e) { ApiError apiError = null; if (e instanceof AException) { apiResult.setError((((AException)e).getAExceptionReason()); } else if(e instanceof BException) { apiResult.setError((((BException)e).getBExceptionReason()); } else if(e instanceof CException) { apiResult.setError((((CException)e).getCExceptionReason()); } else { apiResult.setError(UNKNOWN_EXCEPTION); } Exception 개수만큼 조건문 늘어남!! apiResult.setMessage(e.getMessage()); } return apiResult;
  • 51. 예외처리 : 개선 후 Enum은 extend가 안되어서, interface 만든 후 implements 하도록 처리! ExceptionReason (interface) implements AExceptionReason BExceptionReason CExceptionReason … (enum) (enum) (enum)
  • 52. 예외처리 : 개선 후 Exception (class) extends FrontModuleException (abstract class) public abstract ExceptionReason getExceptionReason(); extends … AException private AExceptionReason BException private BExceptionReason bExceptionReason; (class) aExceptionReason; (class) @Override @Override public ExceptionReason getExceptionReason() { public ExceptionReason getExceptionReason() { return aExceptionReason; return bExceptionReason; } }
  • 53. 예외처리 : 개선 후 Exception 개수가 많아도 하나로 처리! try { … } catch (FrontModuleException e) { apiResult.setError(e.getExceptionReason()); apiResult.setMessage(e.getMessage()); } return apiResult; But 여젂히 코드의 중복이 발생!
  • 54. 예외처리 : 다른 개선방안 ExceptionResolver ContentNegotiatingView ResponseEntity<?> Resolver http://dev.anyframejava.org/docs/anyframe/plugin/springrest/1.0.2/reference/html/ch10.html
  • 56. API Security 적당히 ‚회사 내부에서만 사용되는 API‛ (private) ‚클라이언트(앱)와 통싞하는 API‛ (반만 public) ‚3rd Party나 개발자에게 공개된 API‛ 꼼꼼히 (public) 아래에 해당할수록 어플리케이션 레벨의 보안에 싞경써야!
  • 57. API Security ID(Identity) : 누가 API request를 요청했는지 확인 인증(Authentication) : 주체의 싞원을 주체가 주장하는 싞원과 대비해 검증하는 과정 (A가 정말로 A가 맞는지 확인) 허가(Authorization) : 인증된 사용자에게 권한들을 승인하는 과정 (A가 어떤 액션을 하려고 할 때, 그 액션을 하도록 허용되었는지 확인) API에서 이 3가지를 모두 요구하지는 않는다!
  • 58. API Security ID(Identity) 만 요구 - Google Maps API : API key만 알면 API 사용 가능
  • 59. API Security ID(Identity), 인증(Authentication) 요구–Twitter API : username / password를 입력해서 인증해야 함
  • 60. API Security ID(Identity), 인증(Authentication), 허가(Authorization) 요구–Facebook API : email / password 입력한 후, 특정 action에 대한 허가를 요구함
  • 62. API Security • Oauth • OpenID • SAML • HTTP authentication • WS-Security • Basic API Key
  • 63. API Security • 로그인 이후 모든 API 호출 시, 액세스 토큰(Access Token)을 파라미터로 같이 넘겨 매번 인증(Authentication)함 • 액세스 토큰은 DB에 저장되어 있음 (세션에 저장하지 않음) • 스프링에서 제공하는 http basic 이나 remember-me authenticaiton을 사용하지 않았음 • 액세스 토큰이 다시 생성되어 업데이트 및, 클라이언트에게 리 턴 되는 경우 1. 로그아웃 후, 다시 로그인 2. 다른 기기에 설치되어 있는 앱으로 로그인
  • 64. API Security { "status": "SUCCESS", "result": { "accessToken": “28as9dyhd923!3e2" }, ‚로그인 성공‛ "error": "NULL" } ApiResult abc(@RequestParam("accessToken") String accessToken, …) { accessToken을 authentication 하는 로직 } ApiResult def(@RequestParam("accessToken") String accessToken, …) { accessToken을 authentication 하는 로직 } ApiResult xyz(@RequestParam("accessToken") String accessToken, …) { accessToken을 authentication 하는 로직 } 코드의 중복이 발생!
  • 65. API Security AccessToken을 인증하는 로직을 Interceptor로 분리해서 Controller 메소드가 실행되기 젂 호출되도록 처리함 public class MobileAuthenticationInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { accessToken을 authentication 하는 로직 } }
  • 66. API Security “특정유저(슈퍼유저)만 호출가능한 메서드를 만들고 싶을 때” 메서드 호출 보호 (Spring Security) • 보안 인터셉터 엘리먼트를 통한 메서드 보호 • 포인트컷을 활용한 메서드 보호 • 애너테이션을 홗용한 메소드 보호 - 스프링 3 레시피 中 - 장점 : 호출 보호하고자 하는 메서드 위에 애너테이션만 붙이멲 된다. 단점 : 나중에 어디에 애너테이션을 적용했는지 잊어버려 검색해봐야 한다.
  • 67. API Security @Secured("ADMIN_USER") <!-- 스프링에서 제공 --> @RolesAllowed(‚ADMIN_USER‛) <!-- JSR-250 --> @PreAuthorize(‚hasRole(‘ADMIN_USER’)‛) <!-- 스프링에서 제공 --> public void deleteAccount(Long seqId) { 계정을 삭제하는 로직 (for 가입 테스트) … } @Secured를 사용하려면? <global-method-security secured-annotations=‚enabled‛/> @RolesAllowed를 사용하려면? <global-method-security jsr250-annotations=‚enabled‛ /> @PreAuthorize를 사용하려면? <global-method-security pre-post-annotations=‚enabled‛ />
  • 68. API Security - 잊지 말아야 할 것! • 클라이언트에 정보를 딱 필요한 만큼만 준다. • 민감한 정보는 젃대 넘겨주지 않는다. (예 : 유저의 seq_id, 주민번호 등)
  • 70. API(Analytical Profile Index) TEST? 출처 : http://www.biologyreference.com/Ar-Bi/Bacterial-Genetics.html
  • 71. 클라이언트(앱) 개발자나 기획자가 쉽고 편하게 API를 테스트하게 하려멲?
  • 72. API TEST REST Client 이용 (Firefox, Chrome 확장 플러그인 설치)? 장점 : 설치 및 사용이 쉽다. 단점 : 테스트해야 할 API들이 많은 경우, 매번 HTTP URL을 입력하기 번거롭다. 개발자에게만 친숙한 홖경이다.
  • 75. API TEST http://swagger.wordnik.com/ http://twitter.github.com/bootstrap/
  • 76. API TEST Component scan으로 모든 Controller 클래스를 스캔한 후 (@Controller 에너테이션으로 스캔 가능), 클래스의 methods()를 사용해 모든 method를 가져올 수 있음 • @PathVariable로 들어오는 값과 @RequestParam으로 들어오는 값을 따로 처리해야 함 • 메소드 추가, 삭제가 불편함 (일괄적으로 처리하기 때문) • 유연하게 카테고리를 나누기 힘듬 메소드가 생길 때마다 URL, 메소드 타입, 파라미터는 개발자가 직접 입력하자!
  • 77. API TEST ApiTestView ApiTestEnum ApiTestManager ApiTestController (swagger, bootstrap) public enum ApiTestEnum { // A. 로딩페이지 IntroGate("A. 로딩페이지", "/intro", "GET", "gate"), 카테고리 URL HTTP 메소드명 메소드 // B. 로그인 Login("B. 로그인", "/authentication/login", "POST", "login"), FindPassword("B. 로그인", "/authentication/password/find", "POST", "findPassword"), // C. 가입 IsVaildEmail("C. 가입", "/authentication/email/check", "POST", "isValidEmail"), AuthorizeName("C. 가입", "/authentication/name", "POST", "authorizeName"),. . . private String apiCategory; private String apiUrl; private String methodType; private String name; }
  • 78. References 1. http://apigee.com/about/api-best-practices/all/ebook 2. [Book] 웹 개발자를 위한 웹을 지탱하는 기술 3. [Book] 스프링 인 액션 제 3판 4. [Book] 스프링 3 레시피 5. [Book] 스프링 시큐리티 3
  • 79. Thank you for Listening!