Spring RESTful Web

김기현·2022년 7월 6일
0
post-thumbnail

Spring Boot를 이용한 RESTful Web Service를 만들어보겠습니다.

Web Service와 Web Application의 개요

마이크로서비스

전통적인 방식인 하나의 큰 단위로 개발 운용되던 단위인 모너리스 개발방식이 아닌 수십, 수백개로 쪼개 운영하는 마이크로서비스를 도입해 개발 속도, 유지보수, 고객의 요구를 극대화할 수 있는 것을 말합니다.
그리고 데이터 통신을 위해서는 표준화된 HTTP 프로토콜을 사용하는 RESTful API를 많이 사용하고 있습니다.

SOAP 방식과 REST의 이해

SOAP 방식과 REST서비스를 이해하기 전에 잠시 웹 서비스와 웹 어플리케이션에 대해 짚고 넘어가겠습니다.

웹 서비스는 네트워크 상에서 서로 다른 종류의 컴퓨터들 간에 상호작용하기 위한 소프트웨어 시스템으로 정의합니다.

웹 어플리케이션은 HTML 문서를 이해해 사용자에게 보여주는 어플리케이션을 말합니다. 포털사이트, SNS, 웹메일 등을 예시로 들 수 있습니다. 그리고 웹 어플리케이션을 실행시키는 서버를 웹 서버라고 부릅니다.

웹 서비스를 개발하면서 SOAP과 REST를 사용할 수 있습니다.

  • SOAP
    SOAP은 Simple Object Access Protocol로 XML기반의 메세지를 컴퓨터 네트워크상에서 전달할 수 있는 시스템을 말합니다. 기본적인 메세지의 전송수단입니다. 간단한 데이터를 전송하는데도 앞 뒤에 부가적인 정보를 붙여야만 합니다. 복잡하고 오버헤드가 심하고 무겁다는 단점 때문에 REST 방식을 많이 사용합니다.

  • REST
    REST는 REpresemtational State Transfer로 HTTP 메서드를 통해 Resource를 처리하기 위한 아키텍쳐입니다. SOAP보다 개발하기 쉽고, 프로그램에 독립적이기에 해당 방식을 많이 사용합니다.

REST API를 제공하는 웹 서비스를 RESTful이라고 합니다.

  • Resource
    URI, 인터넷 자원을 나타내는 유일한 주소이며, 요청과 응답을 위해 XML, JSON, HTML등의 문서 포맷을 이용합니다.

Spring Boot로 개발하는 RESTful Service

JAVA, Spring 프레임워크를 사용해 RESTful API를 개발하겠습니다.

Spring Boot 개요

Spring Boot는 단독실행가능한 어플을 만들기 위한 플랫폼입니다.(실행을 위해서 별도의 서버 등을 설치할 필요가 없다는 의미입니다.) Spring Boot를 이용하면 최소한의 설정으로 프로그램과 서드파티 앱을 바로 실행할 수 있습니다.

REST API 설계

사용자를 관리하는 REST API와 사용자가 작성하는 블로그의 글이라는 시나리오를 가지고 API를 개발하겠습니다. User(사용자)와 Post(포스트)의 관계는 1:다 관계입니다.

API의 목적, HTTP Method는 다음과 같습니다.

  • Retrieve all Users
    REST API : /users
    HTTP Method :GET

  • Create a User
    REST API : /users
    HTTP Method :POST

  • Retrieve one User
    REST API : /users/{id}
    HTTP Method :GET

  • Delete a Users
    REST API : /users/{id}
    HTTP Method :DELETE

  • Retrieve all posts for a User
    REST API : /users/{id}/posts
    HTTP Method :GET

  • Create a posts for a User
    REST API : /users/{id}/posts
    HTTP Method :POST

  • Retrieve details of a User
    REST API : /users/{id}/posts/{post_id}
    HTTP Method :GET

Spring Boot Project 생성

IntelliJ IDEA Ultimate버전과 Postman 툴을 이용하겠습니다.

IntelliJ에서 Spring Initializr을 통해 프로젝트를 생성할 수 있습니다.

Name은 프로젝트의 이름이 되며, Artifact를 지정하지 않는다면 자동으로 Name과 같이 연동됩니다.
Group 아이디는 보통 도메인 주소로 사용되며, 패키지에 같이 활용됩니다.
언어는 Java, 타입은 Maven을, JDK는 13버전과 JAVA 8, 그리고 Packaging 타입은 Jar을 선택한 후 Next 버튼을 누릅니다. (맥에서 Maven을 설치하기 위한 참고 블로그입니다.)

Next 버튼을 누르면 Spring Boot 버전과 Dependencies를 선택할 수 있습니다.

참고로 Dependencies는 pom.xml파일이나 gradle파일을 통해 추가하고 삭제할 수 있습니다.

Dependencies로 Developer Tools에서 Spring Boot DevTools와 Lombok을, Web에서는 Spring Web을 선택합니다. 그리고 JPA를 통해 DB를 연동할 것이기 때문에 SQL항목에서 Spring Data JPA, 그리고 H2 Database를 사용하기 위해 선택해줍니다.

Spring Boot Project 구조 확인과 실행 방법

Maven 형태로 프로젝트를 실행하면 main과 유닛 테스트를 위한 test 폴더를 볼 수 있고, 환경변수나 설정을 관리할 수 있는 resources폴더가 있음을 확인할 수 있습니다.

그리고 아래에 pom.xml 파일이 있는데, Maven전체 프로젝트에 대한 설정 파일입니다. dependencies 정보, group 아이디 등을 설정하였는데, 해당 파일에서 볼 수 있습니다.

우측에는 Maven 탭을 볼 수 있는데, Maven 프로젝트에서 실행할 수 있는 명령어를 확인할 수 있습니다. clean, compile(클래스 코드 생성), install(패키징했던 것을 로컬 배포포), package(war or jar로 패키징) 등의 명령어를 자주 사용합니다.

Spring Boot 실행
Spring 프로젝트는 기본적으로 Tomcat이 기본적으로 embedded되어있습니다. 별도의 웹 서버를 실행하지 않고도 자바 프로그램을 실행할 때 같이 서비스를 구동할 수 있습니다.

유일하게 존재하는 RestfulWebServiceApplication이라는 본 클래스에 마우스 우측 버튼을 눌러 실행버튼 또는 control+shift+r 또는 상단의 초록 실행버튼을 눌러 실행합니다. 만약 아무것도 선택되지 않고 실행버튼도 실행되지 않는다면 pom.xml 파일을 우클릭한 후 Maven을 선택 후 프로젝트를 Reload합니다. 해당 스택오버플로우를 참고하였습니다.

실행하면 8080 포트로 정상적으로 서버가 실행됩니다.

8080포트 대신 다른 포트를 사용하기 위해 추가적으로 설정을 합니다.
application.properties파일을 우클릭>refactor>rename을 통해 application.yml으로 변경합니다. 기능을 많이 사용할 수 있고, 내용을 컴팩트하게 만들 수 있는 장점이 있습니다.

해당 파일에 포트 번호를 변경하기 위해 다음과 같이 입력합니다.

server:
  port: 8088

그리고 이미지와 같이 포트번호가 8088로 재실행하기 위해 다시 서버를 재실행합니다.

HelloWorld Controller 추가

Controller를 만들기 위해 com.example.프로젝트이름 폴더 우클릭>NEW>Java Class를 누르고 HelloWorldController라는 class를 생성합니다.

package com.example.restfulwebservice1;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloWorldController {
    // GET
    // /hello-world (end-point)
    @GetMapping(path = "/hello-world")
    public String helloWorld(){
        return "Hello World";
    }
}

@RestController를 입력하면 상단에 자동으로 import되는 것을 확인할 수 있습니다. @RestController는 Spring에서 컨트롤러를 지정해주기 위한 어노테이션으로 @Controller@ResponseBody가 추가된 것입니다. RestController의 주 용도는 JSON 형태로 객체 데이터를 반환하는 것입니다. 해당 블로그를 참고하였습니다.

GET방식의 "/hello-world" URI 엔드포인트를 사용합니다. 이 URI가 호출되면 클라이언트에서 요청한 정보를 서버에서 처리한 후 적절한 결과 메세지와 HTTP Status와 함께 다시 클라이언트에게 전달합니다. 해당 코드에서는 Hello World를 리턴합니다.

결과는 서버를 실행한 후(초록 실행 버튼 클릭) http://127.0.0.1:8088/hello-world에서 200OK의 statue와 함께 결과를 확인할 수 있습니다.

HelloWorld Bean 추가

단순한 문자 형태의 반환값이 아닌, Java Bean 형태로 반환하겠습니다.

@RestController
public class HelloWorldController {
    .
    .
    .
    
    @GetMapping(path = "/hello-world-bean")
    public HelloWorldBean helloWorldBean() {     // HelloWorldBean : 반환값
        return new HelloWorldBean("Hello World");
    }
}

HelloWorldBean는 아직 존재하지 않는 클래스이기에 붉게 표시됩니다. 빌드 시 컴파일에러도 발생합니다. 해당 클래스에 option + Enter키를 누르면 새로운 클래스를 만들 수 있는 옵션이 생깁니다. 패키지를 선택한 후 OK를 누릅니다. 그러면 com/example/restfulwebservice1/HelloWorldBean.java위치에 HelloWorldBean이라는 클래스가 생성됨을 확인할 수 있습니다.

//src/main/java/com/example/restfulwebservice1/HelloWorldBean.java
package com.example.restfulwebservice1;

public class HelloWorldBean(String message) { //메서드를 가지고 있는 생성자가 추가됨
    private String message;
}

public class HelloWorldBean(String message) 처럼 메서드를 가지고 있는 생성자가 생성되었습니다. 왜냐하면 Controller에서 return new HelloWorldBean("Hello World");처럼 String값을 포함한 채 생성자를 만들었기 때문입니다.

프로젝트를 생성할 때 lombok을 추가하였는데, 이 dependency를 이용하면 빈 클래스를 만들 때 set, get, 생성자, toString, equals등의 메서드를 자동으로 생성해주는 기능이 포함되어 개발 시간이 단축됩니다. 단순히 @Data annotation을 입력하면 됩니다. 추기로 lombok을 제대로 사용하기 위해 plugin에서 Lombok을 설치해야 합니다.

만약 lombok을 사용하지 않는다면 아래처럼 getMessage와 setMessage 메서드를 만들어주어야 합니다.

package com.example.restfulwebservice1;
			
public class HelloWorldBean {
	private String message;
    
    public String getMessage() {
    	return this.message;
    }
	public void setMessage(String msg) {
    	this.message = msg
    }
    
    public class HelloWorldBean(String message) { 
	}
}

lombok의 @data annotaion을 추가한 클래스의 structure입니다.

public class HelloWorldBean(String message) { }이라는 생성자를 사용하지 않기 위해 @AllArgsConstructor를 넣어줍니다. 모든 Argument를 가지고 있는 Constructor를 만들겠다는 의미입니다.

package com.example.restfulwebservice1;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

//lombok
@Data
@AllArgsConstructor
@NoArgsConstructor![](https://velog.velcdn.com/images/tritny6516/post/8f49e5c3-7505-488b-8fdb-6562339ddcef/image.png)

public class HelloWorldBean {
    private String message;
}

만약 annotation 기능이 정상적으로 되지 않는다면 intelliJ preference > Build, Execution, Deployment > compiler > Annotation Processors에서 Enable annotation processing 기능을 켜줍니다.

매개변수가 아무것도 없는 디폴트 생성자를 만들고 싶다면 @NoArgsConstructor annotation을 추가하면 됩니다.

그 후 Controller로 돌아오면 정상적으로 helloWorldBean()을 사용하고 있음을 확인할 수 있습니다. Bean형태로 반환하면 Spring framework는 JSON형태로 반환해서 전달해줍니다.

@RestController을 사용하면 반환되는 값이 response.body에 담기지 않더라도 JSON문서로 바뀌어져서 반환됩니다.

DispatcherServlet과 프로젝트 동작 이해

yml vs properties
application.properties는 설정이름 = 값의 형태를, application.yml은 설정이름 : 값의 형태를 지녀야 합니다. yml파일을 사용하면 적은 코드로 직관적으로 볼 수 있다는 장점이 있습니다.

아래는 로그를 확인하는 코드입니다.

server:
  port: 8088

logging:
  level:
    org.springframework: DEBUG 

이렇게 작성하면 org.springframework에 해당하는 것만 디버깅을 출력합니다.

콘솔에 출력된 항목 중에 DispatcherServletAutoConfiguration가 있는데, 사용자의 요청에 따른 로직을 처리하고 결과를 API를 다시 전달하는데, 사용자의 요청을 처리하는 일종의 GATE입니다.

dispatch는 정보를 다른 쪽으로 전달하는 것을 말합니다.

DispatcherServlet은 프레젠테이션 계층에 제일 상단에 놓여지며 중앙집중식으로 처리를 하며 사용자의 요청은 DispatcherServlet으로 시작해 DispatcherServlet으로 끝납니다.

RestController

Spring4부터 지원하는 것으로 @Controller + @ResponseBody를 포함하고 있습니다. View를 가지고 있지 않은 REST Data(JSON/XML)을 반환합니다.

Path Variable 사용

가변되는 URI를 사용하기 위해서는 {name}를 사용합니다. 이 때 변수가 가변변수로 활용하기 위해선 helloWorldBean(@PathVariable String name)클래스와 중괄호 안의 변수와 일치해야 합니다.


import org.springframework.web.bind.annotation.PathVariable;

@RestController
public class HelloWorldController {
	.
    .
    .
    @GetMapping(path = "/hello-world-bean/path-variable/{name}")
    public HelloWorldBean helloWorldBean(@PathVariable String name) {     
        return new HelloWorldBean(String.format("Hello World, %s", name));
	}
}

profile
피자, 코드, 커피를 사랑하는 피코커

0개의 댓글