Spring Boot 3 & Spring Framework 6 - Section 11 : REST API 핵심 기능

이정수·2024년 8월 14일
0

Udemy학습-Spring & React

목록 보기
12/21

학습할 내용

  • REST API 핵심 기능
    • URI의 Resource에 대해 알아보기
      (ex : /users, /users/{id}/posts.. etc )

    • 상호작용하는 Http Request Method에 대해 알아보기
      (ex : GET, POST, PUT, DELETE.. etc)

    • JSON format의 RequestResponse의 구조 정의 학습하기
      Http BodyHttp Header 구조 학습

    • Request 시 알맞은 Http Status Code을 설정하여 Client에 Status Code 반환하기
      (ex : 200, 404, 500 ... etc)

    • Security , Validation, Exception Handling 학습하기.


  • REST API 고급 기능
    • Internationalization :
      Accept-Language Header를 통한 Message의 국제화( i18n, internationalization ) 기능을 제공하면서 다국어 처리하는 방법을 정의.

    • HATEOAS ( Hypermedia as the Engine of Application State )
      。API의 Response에서 Resource에 관한 link를 포함하여 Client가 동적으로 API를 탐색할 수 있도록 하는 개념.
      ▶ REST API를 이용하는 Client가 Server와 동적 상호작용이 가능하도록 하는것.

    • Versioning :
      。API가 breaking change하더라도 Client의 사용성을 유지하도록 기존 Version을 사용하거나 새로운 유형의 API가 추가될 경우 Client가 원할 때 새 버전의 API로 변경할 수 있는 유연성을 확보.

    • Documentation :
      REST API를 문서화하여 개발자가 쉽게 이해하고 테스트할 수 있도록함. ( swagger , OAS )

    • Content Negotiation :
      。Client와 Server 간 HTTP Transaction에서 Client가 header를 설정하여 원하는 Language 또는 Data format( JSON, XML , HTML 등 )을 협상하여 Server가 적절한 Response를 제공하는 과정.

    • Static Filtering
      Filtering : Spring Bean의 Field 중 Http Response Body에서 선택된 Field만 반환하도록 Customizing

      。동일한 Spring Bean에 대해 각각의 다른 REST API 에 대해서도 동일한 filtering을 적용.

    • Dynamic Filtering
      。특정 REST API의 Spring Bean에 대해서 Filtering을 Customizing.

    • Monitoring
      Spring Boot Actuator을 활용하여 API를 Monitoring.


  • REST API를 DB에 연결하는 방법
    • JPAHibernate를 활용하여 H2 , MySQL DB 연결하기


  • 번외
    • Spring SecurityAuthentication 구현
  • API ( Application Programming Interface ) :
    。Application간 원활하게 통신할 수 있도록 만든 Interface.
    ▶ 모든 접속을 표준화하므로 Platform ( OS, HW )에 관계없이 누구나 동일한 Access를 획득 가능.
    ▶ 해당 API를 활용하여 Client의 Request을 받아 이에 따라서 Server와 상호작용하여 생성된 Response를 반환하는 역할을 수행.

    。Client와 Server 간 RequestResponse를 주고받는 방식으로 동작.

    。Server와 DB에 대한 출입구 역할로서 Authorization된 User만 접근성을 부여하는 기능을 수행.
    。Client가 구현된 API의 세부기능에 대해 전혀 몰라도, API Document를 통한 간략한 사용법만 확인하여 활용 가능한 장점이 존재.
    API Document가 없는 경우 사용이 거의 불가능.
    • Web API :
      。인터넷을 통해 데이터를 주고받는 API
      ex ) REST API

    • OS API :
      。OS에서 제공하는 API로서 프로그램이 OS 기능을 활용할 수 있게함.
      ex ) Windows API , Linux API

    • Library API :
      。프로그래밍언어에서 제공하는 API로서 개발자가 프로그래밍언어에서 특정 기능을 쉽게 활용할 수 있도록 보조.
      ex ) Pythonmath Library

    • History API : React의 <BrowserRouter>
      。브라우저가 제공하는 API로서 사용자가 페이지 새로고침을 하지 않아도 브라우저의 URL을 변경 가능.
      ▶ 뒤로가기/앞으로가기 같은 탐색 기능을 사용가능.
      ▶ 해당 API로 SPA에서 페이지 리로드가 발생하지 않는 장점이 존재.
  • REST( Representational State Transfer )
    자원을 자원의 표현으로 구분하여 해당 자원의 상태를 주고 받는 모든것.
    자원(Resource) :
    。해당 소프트웨어가 관리하는 모든것.
    REST API가 다루는 대상으로서 주로 명사형태로 표현.
    ( ex: 문서 , 그림 , 데이터 등 일반적으로 교환하는 모든 정보를 포함하여 resource 라고 한다.)
    자원의 표현 : 자원을 표현하기 위한 이름
    ( ex: DB 사용자 정보가 자원이면 해당 자원의 표현으로 User이라고 명명 )
    。데이터가 요청되는 시점에서 자원의 상태(정보)를 전달하며 JSON을 통해 데이터를 주고 받는다.
    • RESTful
      REST 라는 Architecture를 구현하는 웹서비스를 지칭하는 용어
      ▶ 암묵적으로 REST 원리를 따르는 시스템에 RESTful이라는 용어를 사용한다.
      。REST API를 제공하는 웹서비스 : RESTful
  • REST API
    HTTP를 기반으로 하는 REST 형식의 API로서 Web Application에서 Data를 주고받기위한 Interface.
    ▶ 형식이므로 언어 , 프레임워크 , 기술 등에 영향을 받지 않으면서 형식을 지켜 데이터를 주고 받을 수 있다.

    REST APIJSON , XML 형식으로 데이터를 주고받는다.

    HTTP Protocol 기반으로 동작하면 Client와 Server간 통신을 쉽게하도록 설계됨.
    ▶ 별도 프로토콜 없이 사용 가능.

    REST API는 개발자 사이에서 HTTP Request를 보낼 때 어떤 URI에 어떤 HTTP method를 사용할 지에 대해 지켜지는 약속임.
    ▶ 각각의 HTTP method가 어떠한 동작이나 정보를 위한 것인지 요청의 명시적인 표현으로 쉽게 파악 가능.

    STATELESS 특징으로 매 Request 마다 인증을 요구.

    。HTTP 규약에 따라 GET / POST / PUT / DELETE / PATCH 등의 여러 HTTP method를 활용해서 요청을 보낸다.

    • Http Method
      REST API에서 Resource를 조작하기 위한 Method.
      GET을 제외한 나머지 Method는 DB에 직접적으로 영향을 주므로 CSRF Protection에 의한 제한이 존재.
      。해당 Method를 통해 Application의 CRUD 구현.
      。Request Method는 ``Web page - 검사 - Network - Doc - Headers에서 조회 가능.
      • POST : Create
        。사용자의 정보가 <Form> Data로서 전달되도록 설정.
        。새로운 Resource를 생성 시 활용.
        ( ex: 새로운 게시물을 생성 시 )

      • GET : Read
        。HTML 메소드 GET을 사용 시 사용자의 모든 정보가 URL의 일부(Query Parameter)로 전송됨.
        。특정 Resource 정보를 조회 시 활용
        ( ex: 사용자가 게시물의 상세 정보를 얻을 때 )

      • PUT / PATCH : Update
        。기존 Resource를 Update시 활용.
        ( ex: 사용자, 게시물 수정 시 )
        PUT : Resource를 일괄적으로 전체 수정시 사용
        PATCH : Resource를 일부분만 부분 수정시 사용.

      • Delete : Delete
        。기존 Resource를 삭제 시 사용.

        POST / PUT / PATCH :
        body라는 저장 공간이 존재.
        GET 보다 정보를 많이 넣을 수있으며 , 비교적 안전하게 숨겨서 전송이 가능.

        。해당 HTTP Method들의 기능이 특정 용도에 제한되어있지 않으므로 POST만을 이용해 read , update , delete가 가능하지만 , 해당 Http Request의 의도를 쉽게 파악하기 위해 목적에 따라 명시적으로 구분해서 사용.
        POST /users/1/delete가 아닌 DELETE /users/1로 표기.



    • Endpoint
      。특정 Resource를 조작하기 위한 URL 주소

      GET /users : 모든 사용자 조회
      GET /users/{id} : 특정 사용자 조회
      POST /users : 새로운 사용자 생성
      PUT /users/{id} : 특정 사용자 정보 전체 수정
      PATCH /users/{id} : 특정 사용자 정보 일부 수정
      DELETE /users/{id} : 특정 사용자 삭제
      GET /users/{id}/posts : 특정 사용자와 연결된 모든 게시물 검색
      POST /users/{id}/posts : 특정 사용자와 연결된 게시물 생성
      GET /users/{id}/posts/{post_id} : 특정 사용자와 연결된 특정 게시물 검색



    • REST API 규칙
      • HTTP Method의 적절한 사용 :
        。REST는 해당 요청의 의도를 쉽게 파악 할 수 있도록 HTTP Method를 목적에 따라 구분하여 사용.
        POST /users/1/delete가 아닌 DELETE /users/1로 표기.

      • Resource의 명사 표현 :
        。URL의 QueryParameter는 Resource이므로 동사가 아닌 명사들로 구성되어야 한다.
        REST API 설계 시 단수, 복수형을 섞어 사용하지 않으며, 모든 Resource에 대해 복수형 명사 사용!

      • 명확한 Resource URI 사용 :
        。기존 @Controller에 의한 Query Parameter/getUser?id=1이 아닌 @RestController에 의한 Path Variable/users/{id} 가 맞는 표현.

      • Http Status Code를 활용한 적절한 Response


    • REST API Background 구동 원리
      Spring 디자인 MVC 패턴 관련 정리
      • Dispatcher Servlet ( = Mapping Servlet ) :

        Model2 ArchitectureFront Controller의 역할을 수행.
        root url["/"]에 Mapping 되므로, 사용하는 url에 관계없이 모든 Request가 가장 먼저 도달한다.

        。 Spring Boot의 AutoConfiguration을 통해 class path 상의 Class를 기준으로 Web Application 또는 REST API를 Build하는 것을 감지 후 자동 설정.

        。 Application의 가장 앞단에서 Client 요청을 처리하는 Controller로서, 요청부터 응답까지의 전반적인 처리과정을 통제.
        Client로부터의 모든 Request를 전달 받아 Request의 처리에 적합한 개별 Controller로 전달.
  • Controller Method의 반환되는 Spring Bean instance가 JSON Conversion 되는 원리
    @RestController에 의해 발생한다.

    REST API 개발 시 사용되는 Annotation

    • @RestController :
      Spring MVC에서 Restful Web을 개발 시 선언하는 Annotation.
      RESTful WebController를 지정하기위한 역할로 REST API 개발 시 주로 사용.

      기존의 @Controller@ResponseBody 가 결합된 Annotation
      @Controller에 의한 Controller Method Mapping된 URL을 노출하는 역할 수행.
      @RestController 선언시 Controller Method에 자동 적용된 @ResponseBody에 의해 모든 Controller Method return type을 JSON, XML format으로 변환하여 response로 전송.

    • @RequestBody
      。Client에서 Spring Bean instance 구축에 필요한 Object type의 Data를 HTTP Request Body에 담아 SpringController Method와 Mapping된 URL로 전송할 경우, Controller Method에서는 @RequestBody가 선언된 Spring Bean의 매개변수로 선언 시 Client에서 전송하는 HTTP Request Body의 Data와 Mapping하여 전달됨.
      선언된 Controller Method의 매개변수와 HTTP Request Body와 Mapping.

      HTTP Request에서 GET Method는 사용 불가능!
      GET은 기본적으로 HTTP Request Body를 포함하지않으므로.

      Content Negotiation을 통해 HTTPRequestBody의 Data를 Client가 원하는 representation ( data type or language )로 return할 수 있다.

    • @ResponseBody
      Controller Method의 반환값을 JSON, XML format의 HTTP Response Body직렬화( Serialization )하여 Application에서 Client에게 반환.
      ▶ Server에서 Resource를 포함한 Response를 전송하기 위해 @ResponseBody를 Controller Method에 선언하여 HttpRequestBody의 객체(JSON)로 변환하여 Client에게 전송.

      Controller Method에서 Bean , List<Bean> 등의 일반 Java 객체를 반환값으로 반환 시 @ResponseBody를 선언 시 JSON으로 변환되어 HTTP Response Body에 포함.
      @RestController가 선언된 Class는 따로 Controller Method에 정의할 필요는 없다.
      • @Controller 선언된 Class의 경우
        Controller ClassController Method에 선언.
        ▶ 선언된 Controller Method가 반환하는 Data의 format을 그대로 @RequestMapping로 Mapping된 Request URL를 전송한 Client에게 반환하는 역할 수행.
        ▶ return하는 문자열 이름을 가지는 View Resolver를 통한 View의 조회를 무시하고 HTTPResponseBody에 문자열을 그대로 반환.

      • @RestController 선언된 Class의 경우
        。Class에 @RestController 선언 시 Controller Method 자동적용되므로 별도로 명시할 필요는 없다.
        Message Conversion이 발생.
        • Message Converter
          。Java Bean을 JSON 등의 다양한 Format으로 변환하는 역할을 수행.

          Message Converter가 적용되는 Annotation :
          @ResponseBody(HTTP Response), @RequestBody(HTTP Request)
          ▶ 다음 Annotation을 선언할 경우, Message Converter를 통해 HTTP Request, HTTP Response를 Message( = Body )로 변환.

          JacksonHttpMessageConverters
          。Spring Boot AutoConfiguration의 기본 Http Message Converter
          @ResponseBody에 포함되어 있음.
          ▶ 해당 Message Converter로 반환된 Spring Bean을 JSON Conversion하는 역할을 수행.

        • HTTP Message 구성 관련 정보

          Header : Http Request 또는 Http Response에 관한 metadata를 포함.
          Body : Http Request 또는 Http Response에 관한 실제 data를 포함.

        • Http Request Body :
          。Client가 Server로 Data를 전송 시 사용하는 영역
          POST , PUT , PATCH Request Method에서 주로 사용되며 JSON, XML 등의 Data를 포함할 수 있다.
          。header( Content-type )을 통한 Data type을 지정 가능.
        POST /api/user HTTP/1.1
        Host: example.com
        Content-Type: application/json // Data type 지정
        Content-Length: 45
        { 						 	//	 Http Request Body 부분
          "name": "홍길동",			
          "email": "hong@example.com"
        }

        JSON Data를 포함한 POST Request.

        • Http Response Body
          。Server가 Client의 Request에 대한 Response Data를 보내는 영역.
          GET , POST , PUT , DELETE Request Method의 Response로 주로 사용되며 HTML문서, 이미지, 영상, JSON 등 byte로 표현가능한 모든 데이터가 전송이 가능.
        HTTP/1.1 200 OK
        Content-Type: application/json
        Content-Length: 55
        {					// Http Response Body 부분
          "id": 1,
          "name": "홍길동",
          "email": "hong@example.com"
        }

        JSON 데이터를 포함한 200 OK Response

        • 비동기 ( 병렬 ) :
          특정 코드가 끝날때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 것
          。비동기 통신을 위해 Client to Server ( Http Request ) , Server to Client( Http Response )로 Body에 데이터를 담아서 전송해야한다.
  • ResponseEntity<Type> : Type : HTTP Response Body에 포함될 Data type
    Spring Framework에서 HTTP Response를 다룰 때 사용하는 객체.
    HTTP Status Code , Header , HTTP Response Body를 포함하여 임의 설정이 가능.

    。Controller Method의 반환값으로 ResponseEntity Instance를 설정 시 Spring이 자동으로 JSON등의 HTTP Response를 생성후 반환.
    @ResponseBody를 따로 선언할 필요가 없다.

    REST API에서 에러처리, Status Code , Custom Response를 쉽게 수행.
    • ResponseEntity.ok(Response Body내용) :
      ResponseEntityHTTP 200 OK Status Code와 함께 Response Body내용"문자열"을 반환.

    • ResponseEntity.noContent() :
      HTTP 204 No Content 설정.
      204 : Client의 HTTP Request를 처리했으나, HTTP Response할 데이터가 존재하지 않음.

    • ResponseEntity.badRequest() :
      HTTP 400 Bad Request 설정.

    • ResponseEnity.notFound() :
      HTTP 404 Not Found 설정.

    • ResponseEntity.internalServerError() :
      HTTP 500 Internal Server Error 설정.

    • ResponseEntity.status(HttpStatus객체.CREATED) :
      ResponseEntityHTTP Status Code를 설정.
      HttpStatus.CREATED : 201

    • ResponseEntity.headers(HttpHeaders객체) :
      HttpHeaders 객체를 Custom한 후 추가하여 Custom Header 추가 가능.

    • ResponseEntity.body(Response Body내용) :
      ResponseEntityResponse Body에 들어갈 내용을 정의.

    • ResponseEntity.build() :
      ResponseEntity의 instance를 생성.
      ResponseEntity.notFound().build() : HTTP 404 Not Found 설정된 ResponseEntity 생성.

Error Page 원리

  • Error page는 Spring Boot의 AutoConfiguration( : ErrorMvcAutoConfiguration )의 결과.

    • Controller Class에서 @ResquestMapping이 Mapping하는 url이 아닌, 다른 url을 입력 시 다음 error page가 도출.

      ErrorMvcAutoConfiguration Class에서 알 수 없는 URL이 브라우저에 입력되는 경우, 자동으로 Error page를 구성하는데 사용됨.


  • Starter Project : spring-boot-starter-web
    Spring Web을 dependency로 추가하여 사용 시
    Spring, Spring MVC, Jackson, Tomcat등이 dependency로서 포함됨.
    Error Page / Dispatcher Servlet / Spring Bean -> JSON 변환 / Tomcat WebServer등이 자동으로 AutoConfiguration됨.

    Spring Web : spring-boot-starter-web
    。Web Application 개발에 필요한 실행환경을 제공하는 Starter
    Spring MVC를 이용하여 REST API를 포함한 Restful한 Web Application을 build시 사용.
    ▶ REST API를 구축하기 위해 필요한 dependency

    。기본 embedded container로 Apache Tomcat 활용.

    Spring, Spring MVC, Jackson, Tomcat등의 수많은 JAR들을 dependency로서 Spring Boot Starter Web에 포함.

    • JAR( .jar : Java ARchive) :
      。여러 개의 Java Class 파일, 메타 데이터, Resource 파일 등을 하나의 파일로 묶은 Archive 파일.
      。필요한 기본적인 dependency들을 전부 구성하여 간편하게 사용가능하게하는 Starter Project 역할 수행.


    • Container :
      。개발자가 Library, 종속성 등 필요한 모든 것을 이용하여 Application을 Packaging하여 하나의 Package로 배포할 수 있게하는 역할을 수행.
      ▶ OS 없이, Host의 Resource를 그대로 사용하는 Application

      。서버 운영을 위한 Library만 Image에 포함하여 설치하므로, 경량화됨.
      ▶ Image : Object , Container : Instance

Spring Boot로 간단한 REST API 생성하기.

Spring Boot Project 생성하기 참고

  • Spring Boot Project 생성 (start.spring.io)
    Group ID : package 이름과 유사
    Artifact ID : class 이름과 유사
    。 Spring Boot3은 최소한 Java 17의 버전을 필요로 한다.
    。SNAPSHOT 버전은 Spring Boot Team이 현재 개발하는 버전으로서 새로운것을 배울때 사용은 부적합.
  • Dependency
    • spring-boot-starter-web :
    • spring-boot-starter-data-jpa
      。Spring Data와 Hibernate를 활용한 Java Persistence API로 SQL의 영구데이터를 저장.
    • H2 database :
      。나중에 MySQL로 대체.
    • spring-boot-devtools

#1 Spring Boot를 이용한 간단한 REST API 구축

  • REST API를 노출하는 Controller class 생성
    @RestController을 선언 및 REST API에 URL을 Mapping한 Controller method을 포함.
              // retrieveAllCourses.java
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
@RestController
public class CourseController {
    @GetMapping( path="/courses")
    public List<Course> retrieveAllCourses() {
        return Arrays.asList(
                new Course(1,"Learn AWS","wjdtn1"),
                new Course(1,"Learn DevOps","wjdtn2")
        );
    }
}

@RestController 선언으로 Controller Method에 @ResponseBody이 자동으로 적용되어 Course instance를 JSON format으로 반환.

public class Course {
    private long id;
    private String name;
    private String author;
    public Course(long id, String name, String author){
        this.id= id;
        this.name = name;
        this.author = author;
    }
    public long getId() {return id;}
    public String getName() {return name;}
    public String getAuthor(){return author;}
}

。Chrome에 json formatter chrome extension을 추가한 후 , URL에 localhost:8080/courses 검색.
。이때 Controller Method로 반환되는 Spring Bean instance은 @ResponseBody에 의해 JSON Conversion.

  • @GetMapping(path="url")
    @RequestMapping(path="url", method = RequestMethod.GET)와 비슷한 기능.
    ▶ 선언 할 경우 URL을 통해 접속 시 GET에 해당하는 Request에 대해서만 해당 Controller Method를 사용.

    REST API에 의한 Path Variable를 정의할 경우 path="URL"{Path Variable이름}을 추가해야한다.
    @GetMapping(path="/users/{id}")

    @PostMapping , @PutMapping 등의 어노테이션이 존재

  • toString() :
    。Instance에 대한 정보를 String으로 반환하여 Instance에 관한 정보를 출력 시 사용.
    。java에서 모든 객체의 상위 class인 Object에서 정의된 Method

#2 Path Parameter를 이용한 간단한 REST API 구축

  • REST API의 URL :
    /users/{id}/todos/{id} : 특정 user의 특정 todo에 접근하는 URL
    。대부분의 REST API의 URL은 Path Variable이 존재.

    Path Variable : /user/{name}
    @RestController의 해당 REST API URL에 포함되어 전달되는 변수
    Path Parameter{변수명}으로 지정.
    ▶ Controller Method의 @PathVariable 변수type 변수명으로 Mapping.

    Query Parameter /user?name=1
    @ControllerURL에 포함되어 전달되는 변수
    GET으로 Request 시 Data 정보가 URL에 포함됨.
    ▶ Controller Method의 @RequestParam 변수type 변수명으로 Mapping.
    @GetMapping( path = "/courses/path-variable/{name}")
        public Course getCourse(@PathVariable String name) {
            // /{name} : Path Variable => 변수는 {}로 구분.
            return new Course(1,name,"wjdtn1");
        }

    Controller Method의 매개변수에 @PathVariable을 선언.
    Spring MVC에서 @PathVariable이 선언된 매개변수 String name@GetMapping 으로 Mapping된 URL의 PathVariable : {name}과의 Mapping을 수행.

    REST API URL에 Path Variable : {name} 부분에 임의의 문자열을 입력 시 @PathVariable이 선언된 매개변수와 Mapping되어 값이 전달됨을 확인 가능.

    • @PathVariable :
      @RestControllerREST API URL의 Path Variable을 Controller Method의 매개변수로 Mapping.
      Query Prameter@RequestParam과 유사

REST API를 활용한 SNS Application

Application 내용

  • Key Resource :
    • 사용자(User) : id, name, birthDate
    • 게시물(Post) : id, description
  • Function
    • Request Method를 이용해 REST API에서 Resource에 관한 작업을 수행.
      。특정 User, Post를 delete / Update / Add
      。Request Method는 ``Web page - 검사 - Network - Doc - Headers에서 조회 가능.

#1 User 관련 REST API 구축하기

  • End point 구현 기능
    。 REST API 설계 시 단수, 복수형을 섞어 사용하지 않으며, 모든 Resource에 대해 복수형 명사 사용.
    。 Resource에 대해 동사는 사용하지 않는다.

    GET /users : 모든 사용자 조회
    GET /users/{id} : 특정 사용자 조회
    POST /users : 새로운 사용자 생성
    PUT /users/{id} : 특정 사용자 정보 전체 수정
    PATCH /users/{id} : 특정 사용자 정보 일부 수정
    DELETE /users/{id} : 특정 사용자 삭제
    GET /users/{id}/posts : 특정 사용자와 연결된 모든 게시물 검색
    POST /users/{id}/posts : 특정 사용자와 연결된 게시물 생성
    GET /users/{id}/posts/{post_id} : 특정 사용자와 연결된 특정 게시물 검색



  • 상세정보를 포함하는 User Class 구현
    Spring Bean의 특징을 설정.
    ▶ 해당 Class 로 Spring Bean instance 생성.
          // User.java
import java.time.LocalDate;
public class User {
    int id;
    String name;
    LocalDate birthDate;
    public User(int id, String name, LocalDate birthDate) {
        this.id = id;
        this.name = name;
        this.birthDate = birthDate;
    }
    public int getId() { return id; }
    public String getName() { return name; }
    public LocalDate getBirthDate() { return birthDate; }
    public void setId(int id) { this.id = id; }
    public void setName(String name) { this.name = name; }
    public void setBirthDate(LocalDate birthDate) { this.birthDate = birthDate; }
}
  • DB 관련 DAO( Database Access Object ) 객체를 위한 Class 생성.
    @Component 관련
    。사용자 검색 / 특정 사용자의 정보 저장
    。DAO Class를 통한 Static List를 활용. Static List 활용사례
    ▶ 나중에 JPA & Hibernate를 통한 DB를 활용
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
@Service // Spring Bean으로 제작.
public class UserDaoService {
    // static List 자료형 생성.
    private static List<User> users = new ArrayList<>();
    // User 생성 시 동적으로 할당할 id 변수
    private static int usersCount = 0;
    // List 자료형 초기화 => static 변수는 static block을 통해 초기화.
    static{
        users.add(new User(++usersCount,"Lee",LocalDate.now().minusYears(30)));
        users.add(new User(++usersCount,"Kim",LocalDate.now().minusYears(27)));
        users.add(new User(++usersCount,"Mun",LocalDate.now().minusYears(33)));
    }
    public List<User> findAll(){
        return users;
    }
    public User findById(int id){
        Predicate<? super User> userPredicate = user -> user.getId() == id;
        return users.stream().filter(userPredicate).findFirst().get();
        // List를 받아 stream으로 변환한 후 predicate를 기준으로 필터링
        // Array.stream() : 함수형 프로그래밍으로서 여러 함수를 이용하여
        // 원하는 결과를 도출.
        // predicate를 만족하는 첫번째의 todo를 추출!
    }
    public User save(User user){
        user.setId(++usersCount);
        users.add(user);
        return user;
    }
}
  • Controller class 생성하기
    @RestController 선언 후 각각의 Controller Method에서 HTTP Method 구현하기.
    @GetMapping , @PostMapping
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class UserResource {
    private UserDaoService userDaoService;
    // @Autowired  생성자 기반 의존성 주입.
    public UserResource(UserDaoService userDaoService) {
        this.userDaoService = userDaoService;
    }
    // GET Method 구현
	// GET /users : 모든 사용자 조회
    @GetMapping(path="/users")
    public List<User> ListAllUsers(){
        List<User> users = userDaoService.findAll();
        return users;
    }
	// GET /users/{id} : 특정 사용자 조회
    @GetMapping(path="/users/{id}")
    public User GetUserById(@PathVariable int id){
        User user = userDaoService.findById(id);
        return user;
    }
    // POST Method 구현
	// POST /users : 새로운 사용자 생성
    @PostMapping(path="/users")
    public void createUser(@RequestBody User user){
        // @RequestBody : HttpRequest의 Body(=JSON Format)를
        // Bean으로 변환하여 저장.
        userDaoService.save(user);
    }
}
  • Client가 REST API URL을 통해 POST Method로 HTTP Request를 Server( = Application )에 전송하는 방법
    。브라우저를 통해 REST API URL로 GET Method가 아닌 POST Method로 요청하려면 REST API Client를 이용해야한다.
    Talend API Tester

    Talend API Tester : REST API Client
    。HTTP와 REST API를 호출 및 TEST
    Chrome에 확장프로그램으로 추가.

    POST로 HTTP Method 설정 후 REST API URL을 입력한 후 Application에 전달될 Http Request MessageHttp Request Body에는 Spring Bean instance로서 생성될 User class의 Field인 name, birthDate를 반드시 JSON Format으로 입력.
    ( Id Field의 경우 ++userCount로 자동할당으로 설정했으므로 입력할 필요는 없다. )

    Content-Type : HTTP Request의 Body의 Data type을 명시.

    。다음처럼 POST Method의 Request REST API URL를 통해 HTTP Request Body를 포함한 HTTP Request Message가 Application로 전송 및 해당 REST API URL이 Mapping된 Controller Method에서 Java Bean으로 변환되어 Static List에 Add.
    localhost:8080/users로 조회가 가능하다.



  • REST API에서 알맞은 Response Status 반환하기
    REST API에서 Error 발생 시 Client에게 Error의 구조를 정확하게 정의하고 적합한 Response를 return하기 위한 목적.
    • POST Request URL로 Resource 생성 시 Http Status code201
      이 도출되게 하기.

      ResponseEntity<T>를 활용.
      Controller의 Response를 반환 시 사용.
    // Internal server error에 해당하는 ResponseEntity<Bean> instance를 생성하여 반환.
    		return new ResponseEntity<Bean>(Bean 객체, HttpStatus.INTERNAL_SERVER_ERROR);
    // created status에 해당하는 ResponseEntity 객체를 생성하여 반환.
            return ResponseEntity.created(URL_location).build();

    。알맞은( 201 : created ) Http Status에 해당하는 ResponseEntity<Bean> 객체를 ResponseEntity객체.created(URL Location).build()로 생성후 반환.

    URL Location : Response Header를 넣는곳으로, Location Header를 정의하여 input.

    。다음처럼 200이 아닌, 201이 도출.

    • Location Header를 이용해 Application에서 Spring Bean( User ) Instance 생성되었는지 알려주는 기능 추가하기.
      location header : 생성된 Resource를 Response 시 사용하는 HttpHeader
    // POST /users : 새로운 사용자 생성
        @PostMapping(path="/users")
        public ResponseEntity<User> createUser(@RequestBody User user){
            // @RequestBody : HttpRequest의 Body(=JSON Format)를 Bean으로 변환하여 저장.
            User savedUser = userDaoService.save(user);
            URI locationHeader = ServletUriComponentsBuilder.fromCurrentRequest()
                    .path("/{id}").buildAndExpand(savedUser.getId()).toUri();
            // 201 : created status에 해당하는 ResponseEntity<User> 객체를 생성하여 반환.
            return ResponseEntity.created(locationHeader).build();
        }

    ServletUriComponentsBuilder.fromCurrentRequest() :
    현재 Request에 해당하는 경로를 반환. => http://localhost:8080/users

    .path("/{id}").buildAndExpand(savedUser.getId()).toUri():
    REST API URLPath Variable /{id}를 추가하여 해당 변수를 사용자의 id로 설정한 URI로 변환하여 locationHeader 생성.
    locationHeader = http://localhost:8080/users/{id}

    。생성된 locationHeader를 사용하여 ResponseEntity.created(URL Location)의 인자( Response Header )로 적용하여 ResponseEntity instance를 생성 후 return 하는 Method 정의.

    。 이후, Http RequestPOST를 통해 Http Request Message를 전달하여 id=4의 User 생성 시, HEADERSLocation에서 http://localhost:8080/users/4로 생성된 Location Header을 표시.
    REST API의 Client는 Location HeaderURL로 생성된 해당 User의 정보를 확인 가능.

    • HttpEntity<T> :
      。Spring Framework에서 제공하는 HTTP Request , Http Response를 나타내는 Class
      ▶ Request나 Response에서 사용 가능한 Http MessageHttp Header , Http Body를 포함할 수 있음.
      ▶ 주로 Http Request Body를 포함 시 사용.

      Http Header : Http Request 또는 Http Response에 관한 metadata를 포함.
      Http Body : Http Request 또는 Http Response에 관한 실제 data를 포함.

    • ResponseEntity<T> :
      HttpEntity<T> Class를 확장한 Class로서 HTTP Response를 표현 시 사용됨.
      ▶ 기존 HttpEntity<T>headerbody를 포함하면서 추가적으로 Http Status Code를 지정 가능.

      。보통 Http Status Code를 통한 Controller의 Response를 반환 시 사용.
      badRequest, created, noContent, notFound 등의 여러가지 Response Status 별로 여럿의 Method가 존재한다.

    • HTTP Location Header :
      HTTP Response에서 Client가 이동해야할 URL을 지정하는 Header
      。주로 redirection (3xx)시 새로운 URL을 Client에게 제공하고자 사용됨.
      ▶ Client는 해당 URL로 자동 이동됨.

    • Http Status Code :
      • 1XX : Informational ( 정보제공 )
        。임시 응답
        。현재 클라이언트의 요청까지는 처리되었으므로 계속 진행을 지시

      • 2XX : Success ( 성공 )
        。클라이언트의 요청이 서버에서 성공적으로 처리
        • 200 : 전송 성공
        • 201 : Created : POST로 성공적으로 새로운 Resource가 생성됨.
        • 204 : No Content : Client의 Request를 처리했으나, Response할 데이터가 존재하지 않음.


      • 3XX : Redirection ( 리디렉션 )
        。완전한 처리를 위해 추가 동작이 필요한 경우
        。EX) 요청한 URL 웹문서가 이동했으므로 해당 주소로 다시 시도

      • 4XX : Client Error ( 클라이언트 에러 )
        。없는 페이지를 요청하는 경우
        • 400 : BadRequest : Client의 Request 구문이 문법상 오류 발생 또는 Validation Error이 발생한 경우
          ▶ EX) 요청 메시지 내용이 잘못된 경우
        • 401 : Resource에 유효한 자격 증명이 없기 때문에 HTTP Request가 적용되지 않았음
        • 403 : Client가 요청한 Resource에 대해 접근 권한이 없음을 지시
        • 404 : Resource를 발견하지 못한 경우


      • 5XX : Server Error ( 서버 에러 )
        。서버 사정으로 메시지 처리에 문제가 발생한 경우.
        。EX) 서버 부하 / DB 처리과정 오류 / Server에서 Exception이 발생한 경우.
        • 500 : Server Error : Server에서 오류발생 또는 Exception 발견.
          ex) Web Applicatin의 코드 버그 ▶ Spring JPASQL구문오류


    • URL에서 존재하지 않는 id를 검색 시, 존재하지 않는 ID라고 응답하는 Response Page 도출하기.

      UserDaoService.classfindById() 에서 findFirst().get()이 아닌, findFirst().orElse(User 객체)로 수정.

      public User findById(int id){
              Predicate<? super User> userPredicate = user -> user.getId() == id;
              return users.stream().filter(userPredicate).findFirst().orElse(null);
          }

      ▶ 브라우저에서 URL로 localhost:8080/users/101같이 Static List에서 존재하지 않는 idGET Request하는 경우 Error page가 아닌, null User 객체로서 빈 page를 도출.



    • RuntimeException 상속하는 UserNotFoundException.class 생성
      。생성자는 전달받은 String을 부모 Class( = RuntimeException )에게 전달.
      id= 101 의 Resource를 찾지못해 발생하는 Error이므로, 해당 Error에 적합한 Http Status Code인 404로 설정하기 위해 @ResponseStatus(code= HttpStatus.NOT_FOUND) 사용.
    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.ResponseStatus;
    @ResponseStatus(code = HttpStatus.NOT_FOUND)
    public class UserNotFoundException extends RuntimeException {
        public UserNotFoundException(String message) {
            super(message);
        }
    }

    .

    • Spring Bean에서 null값이 return 될 경우 예외문을 발생하는 Controller Method 구현하기.
      findById()에서 Static ListURL에 입력한 Path Variable에 해당하는 id의 값의 User instance가 존재하지 않는 경우 Spring Bean instance가 아닌, null을 반환했을 때 해당 Exception( UserNotFoundException )이 작동.
        @GetMapping(path="/users/{id}")
        public User GetUserById(@PathVariable int id){
            User user = userDaoService.findById(id);
            if (user == null){
                throw new UserNotFoundException("id :" + id);
            }
            return user;
        }

    。"id :" + id 가 RuntimeException에 전달됨.

    id=101의 Static List의 User instance가 존재하지 않아 "id= 101"의 문자열이 생성자를 통해 전달되는 RuntimeException이 발생하고 404 Http Status Code가 반환됨.

    。Page 하단의 예외 추적 로그를 생략하기 위해서는 DevTools Dependency를 제거.
    。 이때 application을 production하기 위해 .JAR을 생성 시 DevTools를 활성화해둔 상태에서 생성하더라도 해당 dependency는 자동으로 비활성화됨!
    ▶ 추적로그도 나오지 않음.

    。이때 Talend API를 통해 GET 요청을 보낸 경우, 다음처럼 JSON Format으로 구조화된 Response가 오는것을 확인 가능!

    • @ResponseStatus(code=HttpStatus.상태코드)
      Spring MVC에서 Controller에 특정 Exception이 발생한 경우 HTTP Status Code와 함께 Response를 반환하도록 설정.
      ▶ HTTP Response의 Status Code를 설정.

      。인자로 HttpStatus객체.NOT_FOUND 등의 Status Code를 설정 시 404가 반환된다.
      @ResponseStatus(code= HttpStatus.NOT_FOUND)

    • RuntimeException :
      Runtime 환경에서 발생하는 Exception.
      Compile 환경에서 해당 Exception을 인지할 수 없고, Runtime 환경에서 Exception이 발생.
      Business logic Exception 처리에 주로 사용.

      Exception : Checked Exception에 속하는 Exception.
      ▶ 개발자가 강제로 반드시 처리해야하는 Exception.

      RuntimeException : Unchecked Exception 에 속하는 Exception.
      ▶ 반드시 처리안해도 되는 Exception
      • Java에서 발생하는 예외 : Error, Exception
        Error : 코드 문제가 아닌 HW, VM, Memory등의 외적인 문제로서 비정상적 상황 발생시 발생하는 예외
        Exception : 개발자가 구현한 logic에서 발생하는 예외

      • Standard Exception :
        。Java에서 기본적으로 Exception 처리를 위해 제공하는 Exception class.
        Java의 동작 구조 : Java 원리
        .java =( Java Compiler : Compiler )=> .class(byte code) =( JVM : JIT-Compiler )=> Machine Language(~ Compile시점) => (Runtime시점 ~)

        다음 두 Exception은 Application code에서 Exception이 발생한 경우 사용.

        • Checked Exception :
          RuntimeException을 상속하지 않음!
          개발자가 반드시 예외 처리를 수행해야하는 Exception
          ▶ 이는 개발자가 Exception을 예측할 수 있으므로, 별도로 logic을 추가해 try~catch , throws 등으로 호출한 method를 통해 예외처리를 강제한다.
          Runtime Exception 이외의 모든 Exception에 해당함.

        • Unchecked Exception :
          RuntimeException을 상속.
          개발자가 예외 처리를 수행하지 않아도 되는 Exception.
          ▶ System의 비정상적인 Exception는 개발자가 미리 예측하여 처리할 수 없으므로 Application 개발 시, Exception 처리에 신경을 쓰지 않는다.

          Compile 환경에서 예외를 인지할 수 없고, 코드가 Rumtime 환경에서 실행되는 과정에서 예외 발생.


      • Custom Exception
        。Java에서 제공하는 Exception을 상속하여 제작한 Exception class.


    • 모든 예외에 대해 반환되는 HttpResponse에 대해 Custom Exception으로 Structure를 변경하기.

      。사진처럼 자동으로 Http Response Body에 6개의 field가 반환되었는데, 이를 임의로 설정하여 반환하기.
    • 예외처리에 사용할 Custom Exception ( 사용자 정의 예외 ) class 정의하기.
      field : Error message / Error Detail / Error timestamp
      => 기존 6개에서 해당 3개의 field만 반환받도록 설정하기!
    public class ErrorDetails {
        private LocalDate timestamp;
        private String message;
        private String details;
        public ErrorDetails(LocalDate timestamp, String messgae, String details) {
            this.timestamp = timestamp;
            this.message = messgae;
            this.details = details;
        }
        public LocalDate getTimestamp(){
            return timestamp;
        }
        public String getMessage() {
            return message;
        }
        public String getDetails() {
            return details;
        }
        public void setTimestamp(LocalDate timestamp){
            this.timestamp = timestamp;
        }
        public void setMessage(String message) {
            this.message = message;
        }
        public void setDetails(String details) {
            this.details = details;
        }
    }
    • ResponseEntityExceptionHandler를 상속받는 Custom Exception class 구현하기.
      @ExceptionHandler(Exception.class)를 통해 발생하는 모든 Exception에 대해 적용.
      handleException() :
      。추상클래스인 ResponseEntityExceptionHandle를 상속을 위한 구현 메소드.
      ResponseEntity를 생성하여 return.
      。발생한 error 정보는 Exception ex 인자를 통해 조회가 가능.
      ex ) ex.getFieldError() : error가 발생한 field의 정보를 return.
    	public final ResponseEntity<Object> handleException(Exception ex, WebRequest request) throws Exception {
    		if (ex instanceof HttpRequestMethodNotSupportedException subEx) {
    			return handleHttpRequestMethodNotSupported(subEx, subEx.getHeaders(), subEx.getStatusCode(), request);
    		}

    HttpStatus.INTERNAL_SERVER_ERROR 설정 시 , Http status code( 500 : Server Error )가 반환.

    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.context.request.WebRequest;
    import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
    import java.time.LocalDate;
    // Custom Exception 생성.
    @ControllerAdvice
    public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
        // 어떤 Exception을 처리할지 정의.
        // Exception.class는 모든 Exception에 대해 적용하겠다는 의미.
        @ExceptionHandler(Exception.class)
        public final ResponseEntity<ErrorDetails> handleAllException(Exception ex, WebRequest request) {
            ErrorDetails errorDetails = new ErrorDetails(
                    LocalDate.now(), ex.getMessage(), request.getDescription(false)
            );
            // ResponseEntity를 생성하여 return.
            return new ResponseEntity<ErrorDetails>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


    。이후 존재하지않는 Bean의 Id를 검색 시 HttpStatusCode:500과 HttpResponseBody에서 ErrorDetails.class를 통해 정의한 3개의 field의 JSON을 반환!
    @ExceptionHandler(Exception.class)는 해당하는 예외처리 Method가 @ControllerAdvice를 통해 전역에서 발생하는 모든 Exception에 적용한다면, @ExceptionHandler(UserNotFoundException.class)을 통해 해당 User가 존재하지 않는 특정 Exception이 발생한 상황에서만 예외처리를 수행하는 Method 생성하여 추가.

    // User이 존재하지 않는 경우에만 적용
        @ExceptionHandler(UserNotFoundException.class)
        public final ResponseEntity<ErrorDetails> handleUserNotFoundException(Exception ex, WebRequest request) {
            ErrorDetails errorDetails = new ErrorDetails(
                    LocalDate.now(), ex.getMessage(), request.getDescription(false)
            );
            return new ResponseEntity<ErrorDetails>(errorDetails, HttpStatus.NOT_FOUND);
        }


    。다음처럼 UserNotFoundException를 통해 HttpStatus.NOT_FOUND에 해당하는 404가 return.

    • @ExceptionHandler :
      。Exception을 처리하는 Method에 선언하며 하나의 class 내에서 발생하는 특정 Exception을 처리할 지를 정의하는 역할을 수행.
      @Controller, @RestController를 선언한 class에서 발생하는 Exception을 @ExceptionHandler를 선언한 메소드를 통해 처리하는 기능.
      @Service, Repository에서 발생하는 에러는 제외.
    • ResponseEntityExceptionHandler :
      。경로 : C:\Users\LG\.m2\repository\org\springframework\spring-webmvc\6.1.11\spring-webmvc-6.1.11.jar!\org\springframework\web\servlet\mvc\method\annotation\ResponseEntityExceptionHandler.class
      。특정 class에 상속 후 내부 Method에 @ExceptionHandler를 선언 시 Spring MVC의 모든 기본적인 예외처리를 자동으로 진행하는 Abstract Class
      。Method의 반환되는 객체는 ResponseEntity
    • @ControllerAdvice :
      @ExceptionHandle가 선언된 class를 위해 존재.
      @Controller가 선언된 전역의 모든 class에서 발생하는 Exception을 검출하여 @ExceptionHandle가 선언된 method를 통해 Exception을 처리하는 Annotation.


  • DELETE Method를 통해 Resource를 삭제.
    @DeleteMapping 사용하기.
        public void deleteById(int id){
            Predicate<? super User> userPredicate = user -> user.getId() == id;
            users.removeIf(userPredicate);
        }
    // DELETE Method 구현
        @DeleteMapping(path="/users/{id}")
        public void DeleteUserById(@PathVariable int id){
            userDaoService.deleteById(id);
        }


    。이후, API Tester를 통해 DELETE method로 삭제할 id를 Path Variable로 포함한 REST API URL을 전달 시 Http Status Code 200을 반환하면서 DELETE를 성공적으로 수행.



  • REST API에서 유효성(Validation) 검증하기.
    유효성 검증 참조
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

spring-boot-starter-validation dependency를 pom.xml에 추가.

  • Controller Method의 매개변수에서 Binding되는 Bean 앞에 @Valid 선언.
    @Valid :
    JSP Form 또는 HttpRequestBody와 Spring Bean간의 Binding이 되기 전 Spring Bean에 대하여 자동으로 유효성 검증을 먼저 수행.
    。주로 HttpRequestBody를 검증 시 사용됨.
@PostMapping(path="/users")
    public ResponseEntity<User> createUser(@Valid @RequestBody User user){
        User savedUser = userDaoService.save(user);
        URI locationHeader = ServletUriComponentsBuilder.fromCurrentRequest()
                .path("/{id}").buildAndExpand(savedUser.getId()).toUri();
        return ResponseEntity.created(locationHeader).build();
    }
  • Spring Bean에 대하여 Validation 설정 추가하기.
    @Size(min=2, max=8)
    private String name;
    @Past
    private LocalDate  birthDate;

Spring Bean의 검증을 수행할 field 앞에 Annotation 선언.

。브라우저에서 POST Request를 통해 HttpRequestBody에 name과 birthDate라는 field에 대하여 각각 설정된 제한범위 밖의 값을 설정 후 Request URL 전송 시 Http Status Code 400 : Bad Request가 반환.

jakarta.validation.constraints package
。ID 혹은 PW에 작성 제한(글자수, 한글, 특수문자 등)을 둘때 사용하는 유효성검사 Annotation Class를 포함하는 pacakge.

  • @Size :
    。field의 크기가 min과 max 사이인 경우에만 값을 저장하도록 유효성을 검증.
    。JPA 혹은 Hibernate로부터 독립적인 bean 생성.

  • @Past :
    。현재보다 과거의 날짜 or 시간이어야 한다.
  • Custom Exception을 통해 Error 부분을 명확하게 지시하기.
    。웹에서 반환되는 Http Status Code만으로는 어디에서 Error이 발생했는지 알 수 없기에, client에게 어느 부분에서 Error가 발생했는지 지시.
    • Custom Exception class에 구현하기.
      。기존의 Custom Exception class에 상속한 ResponseEntityExceptionHandler abstract class의 handleMethodArgumentNotValid Method를 구현 후 활용.
    	protected ResponseEntity<Object> handleMethodArgumentNotValid(
    			MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
    		return handleExceptionInternal(ex, null, headers, status, request);
    	}

    handleMethodArgumentNotValid() method 구현 시, @Override를 통해 ResponseEntityExceptionHandler abstract class의 method를 Override.

      @Override
        // ResponseEntityExceptionHandler abstract class의 method를 Override해서 사용.
        protected ResponseEntity<Object> handleMethodArgumentNotValid(
                MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
            ErrorDetails errorDetails = new ErrorDetails(
                    LocalDate.now().minusYears(19), ex.getMessage(), request.getDescription(false));
            return new ResponseEntity<Object>(errorDetails, HttpStatus.BAD_REQUEST);
        }

    。이후 API Tester에서 POST로 HttpRequestBody에 Validation 제한 범위 외의 값을 설정 후 보낼 경우, Validation Error 가 발생된 내용을 Message field에서 입력되어 response.

    • HttpResponseBody의 message field의 default message는 Bean의 Field에 선언된 Validation Annotation에 (message = "입력할 내용")으로 임의로 설정이 가능.
      @Size(min=2, message = "Name should have at least 2 characters.")
        private String name;
        @Past(message = "Birth Date should be in the past.")
        private LocalDate  birthDate;

    。 에러 내용 :
    "Validation failed for argument [0] in public org.springframework.http.ResponseEntity<com.wjdtn747.rest.webservices.restfulwebservices.user.User> com.wjdtn747.rest.webservices.restfulwebservices.user.UserResource.createUser(com.wjdtn747.rest.webservices.restfulwebservices.user.User) with 2 errors:
    [Field error in object 'user' on field 'name': rejected value []; codes [Size.user.name,Size.name,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.name,name]; arguments []; default message [name],2147483647,2]; default message [Name should have at least 2 characters.]]
    [Field error in object 'user' on field 'birthDate': rejected value [2098-03-04]; codes [Past.user.birthDate,Past.birthDate,Past.java.time.LocalDate,Past]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.birthDate,birthDate]; arguments []; default message [birthDate]]; default message [Birth Date should be in the past.]] "

    • HttpResponseBody의 message에 Bean의 Field와 관련되어 첫 번째로 발생한 Error에 관한 정보만 return
      。발생한 error에 대한 정보는 MethodArgumentNotValidException ex 인자를 통해 조회가 가능.
      ex.getFieldError().getDefaultMessage(); : 필드와 관련된 첫번째 Field Error를 조회 후 default message를 반환.
      ex.getFieldErrors() : FieldError로 이루어진 List를 반환 받음.
      ex.getErrorCount() : 발생한 Error의 갯수를 조회.
    @Override
        // ResponseEntityExceptionHandler abstract class의 method를 Override해서 사용.
        protected ResponseEntity<Object> handleMethodArgumentNotValid(
                MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
            String ex1 = "Total Error : "+ ex.getErrorCount() + " First Error : "+ ex.getFieldError().getDefaultMessage();
            // Error의 갯수와 Field와 관련된 첫 번째 Error에 관한 default message를 String으로 반환
            // 이후 errorDetails의 "message" field의 인자로 설정.
            ErrorDetails errorDetails = new ErrorDetails(
                    LocalDate.now().minusYears(19), ex1, request.getDescription(false));
            return new ResponseEntity<Object>(errorDetails, HttpStatus.BAD_REQUEST);
        }


    。이후 Error 가 발생한 field의 default message와 error count 수가 도출.

REST API 관련 Annotation

  • REST API 개발 시 사용되는 Annotation
    • @RestController :
      Spring MVC에서 Restful Web을 개발 시 선언하는 Annotation.
      RESTful WebController를 지정하기위한 역할로 REST API 개발 시 주로 사용.

      기존의 @Controller@ResponseBody 가 결합된 Annotation
      @Controller에 의한 Controller Method Mapping된 URL을 노출하는 역할 수행.
      @RestController 선언시 Controller Method에 자동 적용된 @ResponseBody에 의해 모든 Controller Method return type을 JSON, XML format으로 변환하여 response로 전송.

    • @RequestBody
      。Client가 필요한 데이터를 Request하기 위해 JSON format data를 HTTP Request Body에 담아 Server( = Application )로 전송.
      。Application에서는 @RequestBodyController Method의 매개변수로 선언하여 HTTPRequestBody의 Data를 Spring Bean instance로 변환하여 저장.
      선언된 Controller Method의 매개변수와 HTTP Request Body와 Mapping.
      Content Negotiation을 통해 HTTPRequestBody의 Data를 Client가 원하는 representation ( data type or language )로 return할 수 있다.

    • @ResponseBody
      Controller Method의 return type을 JSON, XML format의 HTTP Response Body로 변환하여 Application에서 Client에게 반환.
      ▶ Server에서 Resource를 포함한 Response를 전송하기 위해 @ResponseBody를 Controller Method에 선언하여 HttpRequestBody의 객체(JSON)로 변환하여 Client에게 전송.
      • @Controller 선언된 Class의 경우
        Controller ClassController Method에 선언.
        ▶ 선언된 Controller Method가 반환하는 Data의 format을 그대로 @RequestMapping로 Mapping된 Request URL를 전송한 Client에게 반환하는 역할 수행.
        ▶ return하는 문자열 이름을 가지는 View Resolver를 통한 View의 조회를 무시하고 HTTPResponseBody에 문자열을 그대로 반환.

      • @RestController 선언된 Class의 경우
        。Class에 @RestController 선언 시 Controller Method 자동적용되므로 별도로 명시할 필요는 없다.
        Message Conversion이 발생.


    • @GetMapping(path="url")
      @RequestMapping(path="url", method = RequestMethod.GET)와 비슷한 기능.
      ▶ 선언 할 경우 URL을 통해 접속 시 GET에 해당하는 Request에 대해서만 해당 Controller Method를 사용.

      REST API에 의한 Path Variable를 정의할 경우 path="URL"{Path Variable이름}을 추가해야한다.
      @GetMapping(path="/users/{id}")

      @PostMapping , @PutMapping 등의 어노테이션이 존재

    • @ResponseStatus(code=HttpStatus.상태코드)
      Spring MVC에서 Controller에 특정 Exception이 발생한 경우 HTTP Status Code와 함께 Response를 반환하도록 설정.
      ▶ HTTP Response의 Status Code를 설정.

      。인자로 HttpStatus객체.NOT_FOUND 등의 Status Code를 설정 시 404가 반환된다.
      @ResponseStatus(code= HttpStatus.NOT_FOUND)
    • @PathVariable :
      @RestControllerREST API URL의 Path Variable을 Controller Method의 매개변수로 Mapping.
      Query Prameter@RequestParam과 유사


  • REST API Validation 선언 시 사용
    • @Valid :
      JSP Form 또는 HttpRequestBody와 Spring Bean간의 Binding이 되기 전 Spring Bean에 대하여 자동으로 유효성 검증을 먼저 수행.
      。주로 HttpRequestBody를 검증 시 사용됨.

    • @Size :
      。field의 크기가 min과 max 사이인 경우에만 값을 저장하도록 유효성을 검증.
      。JPA 혹은 Hibernate로부터 독립적인 bean 생성.

    • @Past :
      。현재보다 과거의 날짜 or 시간이어야 한다.


  • DB Entity 연관관계 관련 Annotation
    @Entity 활용
    • @JsonProperty("JSON속성이름") :
      Jackson 라이브러리에서 제공하는 Annotation으로서 JSON과 Java 객체( field ) 간 Mapping을 Control.
      Entity Class의 field에 선언 시 JSON Format으로 직렬화( Serialization )하거나, JSON Format을 field로 역직렬화( Deserialization )를 수행할 때 @JsonProperty("JSON속성이름")을 통해 field의 JSON 속성명( key )을 임의로 설정.

      。Spring Bean에 정의된 @JsonProperty에 의해 Field명이 변경될 경우 변경된 Field명으로 Http Request Body로 전송.

    • @JsonIgnore
      Jackson 라이브러리에서 제공하는 Annotation으로서 JSON직렬화/ 역직렬화 시 특정 field를 제외하는 Annotation.
      ▶ Response할 JSON data에서 선언한 데이터를 HTTP Response에서 제외.

    • @JoinColumn(name = "Mapping 할 Entity의 외래키 Field명") :
      JPA에서 Entity간 연관관계 Mapping 시 자식 Entity의 FK를 지정하는 Annotation.
      1:N 양방향 관계 설정 시 부모 Entity에서 선언.

      @JoinColumn 예시

      @Entity
      public class Order {
          @Id
          @GeneratedValue
          private Long id;
          @ManyToOne
          @JoinColumn(name = "user_id")  // 외래 키 이름 지정
          private User user;
          // Getter, Setter 생략
      }

      。다음의 경우 Order Entity의 user field와 User Entity의 user_id field가 N:1 연관관계를 가진다.
      User Entity의 user_idFK로 활용됨.



    • @OneToMany
      DB Entity간 양방향 관계 설정 시 부모 Entity에서 1:N 관계를 Mapping할 때 자식 Entiy에 의해 참조되는 field에서 선언하는 JPA Annotation

      @OneToMany(mappedBy="자식 Entity에서 FK로서 mapping되는 Field명") :
      。해당 mappedBy속성을 설정하면 연관관계의 부모가 아닌 field임을 지시.
      ▶ 외래키를 관리하는 부모가 아니며 1:N에서 N쪽 Entity에서 설정.

      。양방향 Mapping 시 양쪽 Entity에서 FK Column을 중복생성하지 않도록 방지하는 역할 수행.



    • @ManyToOne
      DB Entity간 양방향 관계 설정 시 자식 Entity에서 1:N 관계를 Mapping할 때 부모 Entity의 외래키를 참조하는 field에 선언하는 JPA Annotation

      @ManyToOne(fetch = FetchType.LAZY) :
      。연관관계의 lazily loaded(지연로딩), eagerly fetched(즉시로딩 , 1:N에서 Default)의 여부를 결정.

      • FetchType.EAGER로 설정 시 동일한 query에서 특정 Entity를 참조하면 Mapping된 Entity도 같이 참조하는 기능 수행.

      • FetchType.LAZY의 경우 동일 query에서 특정 Entity만 참조가능하고 Mapping된 다른 DBEntity를 참조하지 못함.


    • @OneToOne 1:1

    • @ManyToMany N:M :
      。실무에서는 사용하지 않는다.
      1:N or N:1을 통해 중간에 Mapping Table을 구현하여 처리.

REST API에서 활용되는 HTTP Header 종류
Header : Http Request 또는 Http Response에 관한 metadata를 포함.

  • HTTP Location Header :
    HTTP Response에서 Client가 이동해야할 URL을 지정하는 Header
    。주로 redirection (3xx)시 새로운 URL을 Client에게 제공하고자 사용됨.
    ▶ Client는 해당 URL로 자동 이동됨.

  • HTTP Authorization Header :
    。Client가 Server에 인증정보를 전달하는 HTTP Header.
    API를 통해 HTTP Request 전달 시 권한( token 등 )을 포함하는 역할을 수행.
    ▶ Server는 Authorization Header를 확인하여 HTTP Request의 허용여부를 결정.

  • HTTP Accept header :
    。Client가 원하는 Contents type ( data type or MIME type )을 서버에 전달하는데 사용.
    JSON, XML format 등의 data type을 설정.
    application/xml 또는 application/json으로 Server에 전달 시 XML or JSON response을 받을 수 있음.

    Accept: text/html;q=0.8, application/json;q=1.0
    q값 ( [ 0.0,1.0 ] )을 설정하여 우선순위를 지정.
    JSON을 가장 선호하고 htmlJSON이 불가능할 경우 사용하여 Response.

  • HTTP Accept-Language header :
    Accept-Language: en-US,en;q=0.9,ko-KR;q=0.8,ko;q=0.7
    。Client가 원하는 Language를 Server에 전달하는 header.
    ▶ Client가 선호하는 Language( en, nl, fr )으로 설정하여 Request URL을 Server에 전달 시 Server는 해당 Language의 문서를 제공.

    。Client가 선호하는 자연어(natural language), Locale를 지시.
    Locale : 사용자의 언어, 국가 및 인터페이스에서 선호하는 사항을 지정한 매개변수의 모임.

    Accept-Language: en-US,en;q=0.9,ko-KR;q=0.8,ko;q=0.7
profile
공부기록 블로그

0개의 댓글