1. 클라이언트(Client)와 서버(Server)의 관계

클라이언트(Client)와 서버(Server)의 관계

  • WebBrower는 Frontend 서버에 content를 요청하면 Forntend 서버는 content를 찾아서 제공한다
  • Frontend 서버는 WenBrower에서 요청한 content를 필요에 따라 Backend 서버에 요청하여 제공받는다
  • 최종 Client는 WebBrower이지만 Frontend 서버는 필요에 따라 Client가 되기도 하고 Server가 되기도 한다
  • Backend도 다중의 Server를 사용하게 되면 Request Server가 Client가 되기도 한다

2. Rest API

  • Rest API 서버에 HTTP 요청을 보낼 수 있는 클라이언트 툴 또는 라이브러리를 의미한다
  • postman과 같은 프로그램은 UI가 있는 Rest API이다
  • UI가 없는 Rest API일 경우에는 Rest Client Library를 사용하면 된다
    - Server와 Server 간의 요청이 대표적이다

▶ IBM REST API : https://www.ibm.com/docs/en/integration-bus/10.0?topic=apis-rest

 

3. RestTemplate

  • Java에서 사용할 수 있는 HTTP Client 라이브러리
    - java.net.HttpURLConnection
    - Apache HttpComponents
    - OkHttp 3
    - Netty
  • Spring에서는 HTTP Client 라이브러리 중 하나를 이용해서 원격지에 있는 다른 Backend 서버에 HTTP 요청을 보낼 수 있는 RestTemplate이라는 Rest Client API를 제공한다
  • RestTemplate이라는 템플릿 클래스를 이용하여 HTTP Client 라이브러리 중 하나를 유연하게 사용할 수 있다

 

4. RestTemplate 객체 생성

  • Spring Initializr를 사용하여 프로젝트를 생성한다
package main;

public class RestClientExample01{
    public static void main(String[] args) {

        /*기본적으로 RestTemplate의 객체를 생성하기 위해서는
        RestTemplate의 생성자 파라미터로 HTTP Client 라이브러리의 구현 객체를 전달해야 한다*/

        RestTemplate restTemplate = new RestTemplate(

                /*HttpComponentsClientHttpRequestFactory 클래스를 통해 Apache HttpComponents를 전달한다*/

                new HttpComponentsClientHttpRequestFactory());
    }
}
  • 위의 코드는 객체 에러로 인하여 실행할 수 없다
  • Apache HttpComponents를 사용하기 위해서는 builde.gradle의 dependencies 항목에 아래와 같이 의존 라이브러리를 추가해야 한다
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'

	//추가한 코드
	implementation 'org.apache.httpcomponents:httpclient'
}
  • dependencies를 추가하면  객체를 import 할 수 있다
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

public class RestClientExample01{
    public static void main(String[] args) {

        /*기본적으로 RestTemplate의 객체를 생성하기 위해서는
        RestTemplate의 생성자 파라미터로 HTTP Client 라이브러리의 구현 객체를 전달해야 한다*/

        RestTemplate restTemplate = new RestTemplate(

                /*HttpComponentsClientHttpRequestFactory 클래스를 통해 Apache HttpComponents를 전달한다*/

                new HttpComponentsClientHttpRequestFactory());
    }
}

 

5. URI 생성

  • RestTemplate 객체를 생성한 후 HTTP Request를 전송할 Rest 엔드포인트 URI를 지정한다
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;

public class RestClientExample01{
    public static void main(String[] args) {

        /*기본적으로 RestTemplate의 객체를 생성하기 위해서는
        RestTemplate의 생성자 파라미터로 HTTP Client 라이브러리의 구현 객체를 전달해야 한다*/

        RestTemplate restTemplate = new RestTemplate(

                /*HttpComponentsClientHttpRequestFactory 클래스를 통해 Apache HttpComponents를 전달한다*/

                new HttpComponentsClientHttpRequestFactory());

        //URI 생성
        /*
        UriComponentsBuilder 클래스를 이용해서 UriComponents 객체를 생성하고
        UriComponents 객체를 이용해서 HTTP Request를 요청할 엔드포인트의 URI를 생성한다
        */
        UriComponents uriComponents = UriComponentsBuilder

                .newInstance() //UriComponentsBuilder 객체를 생성한다
                .scheme("http") //URI의 scheme을 설정한다
                .host("worldtimeapi.org") //호스트 정보를 입력한다
                .port(80)  //디폴트 값은 80이므로 80 포트를 사용하는 호스트라면 생략 가능하다
                .path("api/timezone/{continents}/{city}")
                /*
                URI의 경로(path)를 입력한다
                URI의 path에서 {continents}, {city} 두 개의 템플릿 변수를 사용하고 있다
                두 개의 템플릿 변수는 uriComponents.expand("Asia", "Seoul").toUri(); 에서
                expand() 메서드 파라미터의 문자열로 채워진다
                빌드 타임에 {continents}는 ‘Asia’, {city}는 ‘Seoul’로 변환됩니다.
                 */
                .encode()
                /*URI에 사용된 템플릿 변수들을 인코딩 한다
                 non-ASCII 문자와 URI에 적절하지 않은 문자를 Percent Encoding 한다는 의미이다
                 */
                .build();
                //UriComponents 객체를 생성한다

        URI uri = uriComponents.expand("Asia","Seoul").toUri();
        /* expand 메서드는 파라미터로 입력한 값을 URI 템플릿 변수의 값으로 대체한다
           toUri 메서드는 객체를 생성한다
         */
    }

 

6. Request 전송

  • 엔드포인트로 Request를 전송한다
  • getForObject(URI uri, Class<T> responseType)
    - getForObject() 메서드는 HTTP Get 요청을 통해 서버의 리소스를 조회한다
    - URI uri : Request를 전송할 엔드포인트의 URI 객체를 지정한다
    - Class responseType : 응답으로 전달 받을 클래스의 타입을 지정한다
package com.dreamfactory.restAPI;

import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;

public class RestClientExample01{
    public static void main(String[] args) {

        /*기본적으로 RestTemplate의 객체를 생성하기 위해서는
        RestTemplate의 생성자 파라미터로 HTTP Client 라이브러리의 구현 객체를 전달해야 한다*/

        RestTemplate restTemplate = new RestTemplate(

                /*HttpComponentsClientHttpRequestFactory 클래스를 통해 Apache HttpComponents를 전달한다*/

                new HttpComponentsClientHttpRequestFactory());

        //URI 생성
        /*
        UriComponentsBuilder 클래스를 이용해서 UriComponents 객체를 생성하고
        UriComponents 객체를 이용해서 HTTP Request를 요청할 엔드포인트의 URI를 생성한다
        */
        UriComponents uriComponents = UriComponentsBuilder

                .newInstance() //UriComponentsBuilder 객체를 생성한다
                .scheme("http") //URI의 scheme을 설정한다
                .host("worldtimeapi.org") //호스트 정보를 입력한다
                .port(80)  //디폴트 값은 80이므로 80 포트를 사용하는 호스트라면 생략 가능하다
                .path("api/timezone/{continents}/{city}")
                /*
                URI의 경로(path)를 입력한다
                URI의 path에서 {continents}, {city} 두 개의 템플릿 변수를 사용하고 있다
                두 개의 템플릿 변수는 uriComponents.expand("Asia", "Seoul").toUri(); 에서
                expand() 메서드 파라미터의 문자열로 채워진다
                빌드 타임에 {continents}는 ‘Asia’, {city}는 ‘Seoul’로 변환됩니다.
                 */
                .encode()
                /*URI에 사용된 템플릿 변수들을 인코딩 한다
                 non-ASCII 문자와 URI에 적절하지 않은 문자를 Percent Encoding 한다는 의미이다
                 */
                .build();
                //UriComponents 객체를 생성한다

        URI uri = uriComponents.expand("Asia","Seoul").toUri();
        /* expand 메서드는 파라미터로 입력한 값을 URI 템플릿 변수의 값으로 대체한다
           toUri 메서드는 객체를 생성한다
         */

        //Request 전송

        //getForObject() 메서드로 HTTP Get 요청을 통해 서버의 리소스를 조회한다
        //응답 데이터를 문자열로 받을 수 있도록 String.class로 지정한다
       String result = restTemplate.getForObject(uri, String.class);
        System.out.println(result);

    }
}
  • 코드를 최종적으로 실행하면 아래와 같이 출력된다

 

 1) getForObject()를 이용하여 커스텀 클래스 타입으로 원하는 정보만 응답으로 전달 받기

  • 전달 받고자하는 응답 데이터의 JSON 프로퍼티 이름과 클래스의 멤버변수 이름이 동일해야 한다
  • 해당 멤버 변수에 접근하기 위한 getter 메서드 역시 동일한 이름이어야 한다
package com.dreamfactory.restAPI;

import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;

public class RestClientExample02 {
    public static void main(String[] args) {
        RestTemplate restTemplate = new RestTemplate(
                new HttpComponentsClientHttpRequestFactory()
        );
        UriComponents uriComponents = UriComponentsBuilder
                .newInstance()
                .scheme("http")
                .host("worldtimeapi.org")
                        .port(80)
                        .path("/api/timezone/{continents}/{city}")
                        .encode()
                        .build();
        URI uri = uriComponents.expand("Asia", "Seoul").toUri();
        //WorldTime 클래스를 사용해서 전체 응답 데이터가 아니라 datetime과 timezone 정보만 전달 받는다
        WorldTime worldTime = restTemplate.getForObject(uri, WorldTime.class);

        System.out.println("# datatime: " + worldTime.getDatetime());
        System.out.println("# timezone: " + worldTime.getTimezone());
        System.out.println("# day_of_week: " + worldTime.getDay_of_week());
    }
}
  • WorldTime에 대한 클래스를 새로 생성해야 한다
package com.dreamfactory.restAPI;

public class WorldTime {
    private String datetime;
    private String timezone;
    private String day_of_week;

    public String getDatetime() {
        return datetime;
    }
    public String getTimezone() {
        return timezone;
    }
    public String getDay_of_week() {
        return day_of_week;
    }
}
  • 실행하면 지정된 데이터만 응답 전송되는 것을 확인할 수 있다

 

 

 2) getForEntity()를 사용한 Response Body(바디, 컨텐츠) + Header(헤더) 정보 전달 받기

  • 응답 데이터는 ResponseEntity 클래스로 래핑되어서 전달 된다
  • getBody(), getHeaders() 메서드 등을 이용해서 바디와 헤더 정보를 얻을 수 있다
  • 응답으로 전달 되는 모든 헤더 정보를 보고 싶다면 getHeaders().entrySet() 메서드를 이용해서 확인할 수 있다
package com.dreamfactory.restAPI;

import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;

public class RestClientExample02 {
    public static void main(String[] args) {
        RestTemplate restTemplate = new RestTemplate(
                new HttpComponentsClientHttpRequestFactory()
        );
        UriComponents uriComponents = UriComponentsBuilder
                .newInstance()
                .scheme("http")
                .host("worldtimeapi.org")
                        .port(80)
                        .path("/api/timezone/{continents}/{city}")
                        .encode()
                        .build();
        URI uri = uriComponents.expand("Asia", "Seoul").toUri();
        //WorldTime 클래스를 사용해서 전체 응답 데이터가 아니라 datetime과 timezone 정보만 전달 받는다
//        WorldTime worldTime = restTemplate.getForObject(uri, WorldTime.class);

//        System.out.println("# datatime: " + worldTime.getDatetime());
//        System.out.println("# timezone: " + worldTime.getTimezone());
//        System.out.println("# day_of_week: " + worldTime.getDay_of_week());
        
        //getForEntity()를 사용한 Response Body(바디, 컨텐츠) + Header(헤더) 정보 전달 받기
        ResponseEntity<WorldTime> response = restTemplate.getForEntity(uri, WorldTime.class);
        System.out.println("# datatime: " + response.getBody().getDatetime());
        System.out.println("# timezone: " + response.getBody().getTimezone());
        System.out.println("# day_of_week: " + response.getBody().getDay_of_week());
        System.out.println("# HTTP Status Code: " + response.getStatusCode());
        System.out.println("# HTTP Status Value: " + response.getStatusCodeValue());
        System.out.println("# Content Type: " + response.getHeaders().getContentType());
        System.out.println(response.getHeaders().entrySet());

    }
}
  • 실행하면 아래와 같은 결과 값이 출력된다

 

 3) exchange() 를 사용한 응답 데이터 받기

  • exchange() 메서드를 사용한 방식은 일반적인 HTTP Request 방식입니다.
  • HTTP Method나 HTTP Request, HTTP Response 방식을 개발자가 직접 지정해서 유연하게 사용할 수 있다
  • exchange(URI uri, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType)
    - HTTP Method, RequestEntity, ResponseEntity를 직접 지정해서 HTTP Request를 전송할 수 있는 가장 일반적인 방식이다
    URI uri : Request를 전송할 엔드포인트의 URI 객체를 지정한다
    - HttpMethod method : HTTP Method 타입을 지정한다
    - HttpEntity<?> requestEntity :
    HttpEntity 객체를 지정하며, HttpEntity 객체를 통해 헤더 및 바디, 파라미터 등을 설정해줄 수 있다
    -  Class<T> responseType : 응답으로 전달 받을 클래스의 타입을 지정한다
package com.dreamfactory.restAPI;

import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;

public class RestClientExample02 {
    public static void main(String[] args) {
        RestTemplate restTemplate = new RestTemplate(
                new HttpComponentsClientHttpRequestFactory()
        );
        UriComponents uriComponents = UriComponentsBuilder
                .newInstance()
                .scheme("http")
                .host("worldtimeapi.org")
                        .port(80)
                        .path("/api/timezone/{continents}/{city}")
                        .encode()
                        .build();
        URI uri = uriComponents.expand("Asia", "Seoul").toUri();
        //WorldTime 클래스를 사용해서 전체 응답 데이터가 아니라 datetime과 timezone 정보만 전달 받는다
//        WorldTime worldTime = restTemplate.getForObject(uri, WorldTime.class);

//        System.out.println("# datatime: " + worldTime.getDatetime());
//        System.out.println("# timezone: " + worldTime.getTimezone());
//        System.out.println("# day_of_week: " + worldTime.getDay_of_week());

        //getForEntity()를 사용한 Response Body(바디, 컨텐츠) + Header(헤더) 정보 전달 받기
//        ResponseEntity<WorldTime> response = restTemplate.getForEntity(uri, WorldTime.class);
//        System.out.println("# datatime: " + response.getBody().getDatetime());
//        System.out.println("# timezone: " + response.getBody().getTimezone());
//        System.out.println("# day_of_week: " + response.getBody().getDay_of_week());
//        System.out.println("# HTTP Status Code: " + response.getStatusCode());
//        System.out.println("# HTTP Status Value: " + response.getStatusCodeValue());
//        System.out.println("# Content Type: " + response.getHeaders().getContentType());
//        System.out.println(response.getHeaders().entrySet());

        //exchange() 를 사용한 응답 데이터 받기
        ResponseEntity<WorldTime> response = restTemplate.exchange(
                uri, HttpMethod.GET, null, WorldTime.class);
        System.out.println("# datatime: " + response.getBody().getDatetime());
        System.out.println("# timezone: " + response.getBody().getTimezone());
        System.out.println("# day_of_week: " + response.getBody().getDay_of_week());
        System.out.println("# HTTP Status Code: " + response.getStatusCode());
        System.out.println("# HTTP Status Value: " + response.getStatusCodeValue());
    }
}
  • 코드를 실행하면 아래와 같이 출력된다

 

 

※ 참조 링크

URI scheme : https://en.wikipedia.org/wiki/List_of_URI_schemes

 

List of URI schemes - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search Namespace identifier assigned by IANA This article lists common URI schemes. A Uniform Resource Identifier helps identify a source without ambiguity. Many URI schemes are registered wi

en.wikipedia.org

Percent Encoding : https://ko.wikipedia.org/wiki/%ED%8D%BC%EC%84%BC%ED%8A%B8_%EC%9D%B8%EC%BD%94%EB%94%A9

 

퍼센트 인코딩 - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

RestTemplate API : https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#rest-client-access

 

Integration

As a lightweight container, Spring is often considered an EJB replacement. We do believe that for many, if not most, applications and use cases, Spring, as a container, combined with its rich supporting functionality in the area of transactions, ORM and JD

docs.spring.io

RestTEmplate API Docs : https://docs.spring.io/spring-framework/docs/current/javadoc-api/

 

Spring Framework 5.3.22 API

 

docs.spring.io

Open API 서비스 제공 사이트

https://www.data.go.kr/dataset/3043385/openapi.do

 

공공데이터 포털

국가에서 보유하고 있는 다양한 데이터를『공공데이터의 제공 및 이용 활성화에 관한 법률(제11956호)』에 따라 개방하여 국민들이 보다 쉽고 용이하게 공유•활용할 수 있도록 공공데이터(Datase

www.data.go.kr

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

https://developers.naver.com/products/intro/plan/plan.md

 

네이버 오픈 API 목록 - INTRO

네이버 오픈 API 목록 NAVER Developers - API 소개 네이버 오픈API 목록 및 안내입니다. 네이버 오픈 API 목록 API명 설명 호출제한 검색 네이버 블로그, 이미지, 웹, 뉴스, 백과사전, 책, 카페, 지식iN 등 검

developers.naver.com

https://console.cloud.google.com/getting-started?pli=1 

 

Google Cloud console

계정이 일시적으로 차단되었습니다. Google이 네트워크에서 악성 소프트웨어, 브라우저 플러그인 또는 자동화된 요청을 전송하는 스크립트에 의해 전송되었을 수 있는 요청을 감지한 경우 계정

console.cloud.google.com

https://aiopen.etri.re.kr/

 

공공 인공지능 오픈 API·DATA 서비스 포털

과학기술정보통신부의 R&D 과제를 통해 개발한 다양한 인공지능 기술 및 데이터를 누구나 사용할 수 있도록 제공

aiopen.etri.re.kr

 

1. Controller 클래스 설계 및 구조 생성

  • API 계층을 Spring MVC 기반의 코드로 구현해 본다

 1) 애플리케이션 경계 설정

  • 커피 주문 애플리케이션으로 설정

 2) 애플리케이션 기능 요구사항 수집

  • 기능적으로 요구사항을 정리해 본다

 3) 패키지 구조 생성

  • 기능 기반 패키지 구조(package-by-feature)
    - 애플리케이션에서 구현해야 하는 기능을 기준으로 패키지를 구성하는 것을 말한다
    - 패키지를 커피 / 회원 / 주문 등 기능으로 구분할 수 있다
  • 계층 기반 패키지 구조(package-by-layer)
    - 패키지를 하나의 계층(Layer)으로 보고 클래스들을 계층별로 묶어서 관리하는 구조를 말한다
    - controller / model / repository / service 등 계층으로 구분할 수 있다
  • 테스트와 리팩토링이 용이하고, 향후에 마이크로 서비스 시스템으로의 분리가 상대적으로 용이기능 기반 패키지 구조 사용을 권장한다

 4) 애플리케이션의 기능 요구사항 및 클래스 정리

  • REST API 기반의 애플리케이션에서는 일반적으로 애플리케이션이 제공해야 될 기능을 리소스(Resource, 자원)로 분류한다
  • 리소스에 해당하는 Controller 클래스를 작성한다

 5) 엔트리포인트(Entrypoint) 클래스 작성

  • Spring Boot 기반의 애플리케이션이 정상적으로 실행되기 위해서 가장 먼저 해야될 일은 main() 메서드가 포함된 애플리케이션의 엔트리포인트(Entrypoint, 애플리케이션 시작점)를 작성하는 것이다
  • 부트스트랩(Bootstrap)은 애플리케이션이 실행되기 전에 여러가지 설정 작업을 수행하여 실행 가능한 애플리케이션으로 만드는 단계를 의미한다
  • 엔트리포인트는 spring initializr를 사용하여 프로젝트를 생성하면 자동으로 만들어 진다

  • exam_controller > src > main > java > com.dreamfactory.exam_controller > ExamControllerApplication 으로 자동 생성된다
//엔트리포인트 클래스

package com.dreamfactory.exam_controller;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
//자동구성을 활성화 해 준다
//애플리케이션 패키지 내에서 @Component가 붙은 클래스를 검색한 후(scan), Spring Bean으로 등록하는 기능을 
  활성화 해 준다
//@Configuration 이 붙은 클래스를 자동으로 찾아주고, 추가적으로 Spring Bean을 등록하는 기능을 활성화 해 준다

public class ExamControllerApplication {

	public static void main(String[] args) {
		SpringApplication.run(ExamControllerApplication.class, args);
	}
	//SpringApplication.run : Spring 애플리케이션을 부트스트랩하고, 실행하는 역할을 한다
}

 

 6) 애플리케이션의 Controller 구조 작성

  • 회원관리를 위한 MemberController 구조 작성
package com.dreamfactory.exam_controller.member;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
//@애터테이션에 의해 자동으로 import 된다

@RestController
//Spring MVC에서는 특정 클래스에 @RestController 를 추가하면 해당 클래스가 REST API의 리소스(자원, Resource)를
  처리하기 위한 API 엔드포인트로 동작함을 정의한다
//@RestController가 추가된 클래스는 애플리케이션 로딩 시, Spring Bean 으로 등록 해 준다

@RequestMapping
//@RequestMapping 은 클라이언트의 요청과 클라이언트 요청을 처리하는 핸들러 메서드(Handler Method)를 매핑해주는
  역할을 한다
//Controller 클래스 레벨에 추가하여 클래스 전체에 사용되는 공통 URL(Base URL)을 설정할 수 있다

public class MemberController {

}
  • 커피정보를 위한 CoffeeController 구조 작성
package com.dreamfactory.exam_controller.coffee;

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

@RestController
@RequestMapping("/v1/coffees")
//v1은 버젼을 의미한다. coffees는 데이터 post, get 의 조회 위치 URI를 지정한다
//Controller 클래스 레벨에 추가하여 클래스 전체에 사용되는 공통 URL(Base URL)을 설정할 수 있다.

public class CoffeeController {

}
  • 주문관리를 위한 OrderController 구조 작성
package com.dreamfactory.exam_controller.order;

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

@RestController
@RequestMapping

public class OrderController {

}

 

[참조 자료]

※ REST API란?

  • REST(Representational State Transfer)는 HTTP 네트워크 상의 리소스(Resource, 자원)를 정의하고 해당 리소스를 URI라는 고유의 주소로 접근하는 접근 방식을 의미한다
  • REST API란 REST 방식을 통해서 리소스에 접근하기 위한 서비스 API를 지칭한다

 REST에서 의미하는 리소스

  • REST에서 의미하는 자원은 데이터베이스에 저장된 데이터, 문서, 이미지, 동영상 등 HTTP 통신을 통해 주고 받을 수 있는 모든 것을 의미한다

 URI(Uniform Resource Identifier)와 URL(Uniform Resource Locator)

  • URI는 네트워크 상에 있는 특정 리소스를 식별하는 통합 자원 식별자(Uniform Resource Identifier)를 의미한다
  • URL은 인터넷에 있는 리소스를 나타내는 통합 리소스 식별자를 의미한다
  • 일상적인 웹 상의 주소는 URL을 의미한다
  • URI는 URL의 상위 개념으로 볼 수 있다
  • URI는 리소스를 식별하는 식별자 역할을 하고, URL은 리소스의 위치를 가리킨다
    - http://www.itivllage.tistory.com/manage? id = 1 에서
    - http://www.itivllage.tistory.com/manage'까지는 리소스의 위치를 가리키는 URL이고
    - http://www.itivllage.tistory.com/manage? id = 1는 리소스를 식별하기 위한 'id = 1'이라는 고유 식별자가 붙었으므로 URI이다

※ HTTP 에서 REST API 서비스를 만드는 경우의 REST API URI 작성 규칙

  • URI의 마지막이 '/' 로 끝나지 않게 한다
    - http://www.dreamfactory.com/coffees   (good)
    - http://www.dreamfactory.com/coffees/ (bad)
  • 동사 보다는 명사를 사용한다
    - http://www.dreamfactory.com/coffees             (good)
    - http://www.dreamfactory.com/coffees/update (bad) 
  • 단수형 보다는 복수형 명사를 사용한다
    - http://www.dreamfactory.com/coffees   (good)
    - http://www.dreamfactory.com/coffee     (bad)
  • URI는 기본 소문자를 사용한다
  • 언더스코어( _ ) 대신에 하이픈(-)을 사용한다
  • 파일 확장자는 URI에 포함하지 않는다

 

※ 참조 링크

 

RESTful API의 URL 작성 규칙

REST API란? REST(Representational State Transfer)는 HTTP 네트워크 상의 리소스(Resource, 자원)를 정의하고 해당 리소스를 URI라는 고유의 주소로 접근하는 접근 방식을 의미하며, REST API란 REST 방식을 통..

itvillage.tistory.com

 

@SpringBootApplication 의 역할

[코드 1-1] @SpringBootApplication public class CoffeeApplication { public static void main(String[] args) { SpringApplication.run(CoffeeApplication.class, args); } } [코드 1-1]과 같이 Spring Boot Ap..

itvillage.tistory.com

Spring Boot 애플리케이션의 부트스트랩(Bootstrap) 과정: https://itvillage.tistory.com/37

 

Spring Boot 애플리케이션의 부트스트랩(Bootstrap) 과정 알아보기

Spring Boot에서의 부트스트랩이란? 일반적으로 부트스트랩(Bootstrap)이란 어떠한 과정이 시작되어 알아서 진행되는 일련의 과정을 의미합니다. 컴퓨터의 부팅 과정을 생각해보면 이해가 쉬울것입

itvillage.tistory.com

 

2. 핸들러 메서드(Handler Method)

postman 에서 request 결과

  • MemberController에 클라이언트의 요청을 처리할 핸들러 메서드(Handler Method)가 아직 없기 때문에 localhost를 요청해도 에러가 발생한다
  • 작업 중인 애플리케이션은 REST API 기반 애플리케이션이기 때문에 응답 메시지는 JSON 형식으로 클라이언트에게 전달된다

 1) MemberController의 핸들러 메서드(Handler Method) 작성

  • 회원 이메일 주소: email
  • 회원 이름: name
  • 회원 전화번호: phoneNumber
  • 위의 정보를 기준으로 작성한다
package com.dreamfactory.exam_controller.member;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.sql.SQLOutput;
//@애터테이션에 의해 자동으로 import 된다

@RestController

@RequestMapping(value ="v1/members", produces = MediaType.APPLICATION_JSON_VALUE)
//produces애트리뷰트(Attribute)는 응답 데이터를 어떤 미디어 타입으로 클라이언트에게 전송할 지를 설정한다
//JSON 형식의 데이터를 응답 데이터로 전송하기 위해 MediaType.APPLICATION_JSON_VALUE 값을 설정했다
//이 값을 설정하지 않으면 현재 코드에서는 JSON 형식의 데이터를 응답으로 전송하지 않고, 문자열 자체를 전송한다


public class MemberController {
    @PostMapping

    //postMember() 메서드는 회원 정보를 등록해주는 핸들러 메서드이다
    //클라이언트의 요청 데이터(request body)를 서버에 생성할 때 사용하는 애너테이션이다
    //클라이언트에서 요청 전송 시 HTTP Method 타입을 동일하게 맞춰 주어야 한다(POST)
    public String postMember(@RequestParam("email")String email,
                             @RequestParam("name")String name,
                             @RequestParam("phone")String phone) {
        //@RequestParam() 핸들러 메서드의 파라미터 종류 중 하나이다
        /*클라이언트에서 전송하는 요청 데이터를 쿼리 파라미터(Query Parmeter 또는 Query String),
        폼 데이터(form-data), x-www-form-urlencoded 형식으로 전송하면 서버 쪽에서 전달 받을 때
        사용하는 애너테이션이다*/

        System.out.println("# email: " + email);
        System.out.println("# name: " + name);
        System.out.println("# phone: " + phone);

        //클라이언트 쪽에서 JSON 형식의 데이터를 전송 받아야 하기 때문에
        //응답 문자열을 JSON 형식에 맞게 작성한다
        String reponse =
                "{\"" +
                    "email\":\""+email+"\"," +
                    "\"name\":\""+name+"\",\"" +
                    "phone\":\"" + phone+
                "\"}";
        return reponse;
    }

    @GetMapping("/{member-id}")
    //@GetMapping은 클라이언트가 서버에 리소스를 조회할 때 사용하는 애너테이션이다
    //@GetMapping 애너테이션의 괄호 안에는 몇 가지 애트리뷰트(Attribute)를 사용할 수 있다
    //여기서는 전체 HTTP URI의 일부를 지정했다
    //클라이언트에서 getMember() 핸들러 메서드에 요청을 보낼 경우, 최종 URI는 형태는 아래와 같다
    // /v1/members/{member-id}
    //{member-id}는 회원 식별자를 의미한다
    //클라이언트가 요청을 보낼 때 URI로 어떤 값을 지정하느냐에 따라서 동적으로 바뀌는 값이다

    public String getMember(@PathVariable("member-id")long memberId) {
        //getMember() 메서드는 특정 회원의 정보를 클라이언트 쪽에 제공하는 핸들러 메서드이다

        //@PathVariable역시 핸들러 메서드의 파라미터 종류 중 하나이다
        //@PathVariable의 괄호 안에 입력한 문자열 값은 @GetMapping("/{member-id}") 처럼 중괄호({ }) 안의 문자열과 동일해야 한다
        //여기서는 두 문자열 모두 “member-id” 로 동일하게 지정했다
        //두 문자열이 다르면 MissingPathVariableException이 발생한다

        System.out.println("# memberId: " + memberId);

        //not implementation
        return null;
    }

    @GetMapping //별도의 URI를 지정해주지 않았기 때문에 클래스 레벨의 URI(“/v1/members”)에 매핑된다

    //getMembers() 메서드는 회원 목록을 클라이언트에게 제공하는 핸들러 메서드이다
    public String getMembers() {
        System.out.println("# get Members");

        //not implementation
        return null;
    }
}
  • 쿼리 파라미터(Query Parameter 또는 QueryString)
    - 요청 URL에서 ‘?’를 기준으로 붙는 key/value 쌍의 데이터를 말한다
    - ex) http://localhost:8080/coffees/1?page=1&size=10
  • RestController
    - Spring MVC에서 웹 요청을 하기 위한 준비가 완료되었음을 의미한다
  • RequestMapping
    - RequestMapping(value="파일경로", method={HTTP 요청값}) 의 형식으로 작성한다
    - HTTP 값을 지정하지 않으면 모든 HTTP요청에 매핑된다
    - Request에 대한 헤더 값을 지정하면 매핑 범위를 좁힐 수 있다
헤더 값을 지정하여 범위를 좁힌 예)

@RequestMapping(value = "/ex/dream", headers = "key=val", method = GET)
@ResponseBody
public String getDreamWithHeader() {
    return "Get some Dream with Header";
}
HTTP POST에 요청된 예)

@RequestMapping(value = "/ex/dream", method = POST)
@ResponseBody
public String postDream() {
    return "Post some Dream";
}
headers속성을 사용하여 헤더를 여러개 지정할 수 있다 

@RequestMapping(
  value = "/ex/dream", 
  headers = { "key1=val1", "key2=val2" }, method = GET)
@ResponseBody
public String getDreamWithHeaders() {
    return "Get some Dream with Header";
}

 

※ MemberController : postMember() 요청 및 응답

  • HTTP POST Method와 요청 URI를 입력한다
  • [Body] 탭에서 ‘x-www-form-urlencoded’ 형식의 요청 데이터를 KEY/VALUE 형태로 입력한다
  • JSON 형식의 응답 데이터를 전달 받을 수 있다
  • 우측 중간을 보면 ‘200’, ‘OK’ 라는 값을 통해서 클라이언트가 정상적으로 응답을 전달 받았음을 알 수 있다

 

 2) CoffeeController의 핸들러 메서드(Handler Method) 작성

  • 커피 식별자: coffee
  • 식별자: coffeeId
  • 커피명(영문): engName
  • 커피명(한글): korName
  • 가격: price
package com.dreamfactory.exam_controller.coffee;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(value="v1/coffees", produces = MediaType.APPLICATION_JSON_VALUE)
//v1은 버젼을 의미한다. coffees는 데이터 post, get 의 조회 위치를 의미한다

public class CoffeeController {
    @PostMapping

    //postCoffee() 메서드는 커피 정보를 등록해 준다
    public String postCoffee(@RequestParam("coffee")String coffee,
                             @RequestParam("coffeeId")String coffeeId,
                             @RequestParam("korName")String korName,
                             @RequestParam("engName")String engName,
                             @RequestParam("price")int price) {
        System.out.println("# coffee:" + coffee);
        System.out.println("# coffeeId:" + coffeeId);
        System.out.println("# korName:" + korName);
        System.out.println("# engName:" + engName);
        System.out.println("# price:" + price);

        String reponse =
                "{\"" +
                    "coffee\":\""+coffee+"\"," +
                    "\"coffeeId\":\""+coffeeId+"\"," +
                    "\"korName\":\""+korName+"\"," +
                    "\"engName\":\""+engName+"\"," +
                    "\"price\":\""+price+
                "\"}";
        return reponse;
    }

    @GetMapping("/{coffee-id}")

    //getCoffee() 메서드는 커피 정보을 클라이언트에게 제공하는 핸들러 메서드이다
    public String getCoffee(@PathVariable("coffee-id")long coffeeId) {
        System.out.println("# coffeeId: " + coffeeId);
        return null;
        }

    @GetMapping //별도의 URI를 지정해주지 않았기 때문에 클래스 레벨의 URI(“/v1/coffees”)에 매핑된다

    //getCoffees() 메서드는 커피 목록을 클라이언트에게 제공하는 핸들러 메서드이다
    public String getCoffees() {
        System.out.println("# get Coffees");
        return null;
    }
}

 

postman - v1/coffees post

 3) OrderController의 핸들러 메서드(Handler Method) 작성

  • 회원 식별자: memberId
  • 커피 식별자: coffeeId
package com.dreamfactory.exam_controller.order;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(value="v1/orders", produces = MediaType.APPLICATION_JSON_VALUE)

public class OrderController {
    @PostMapping

    //postOrder() 메서드는 주문 정보를 등록한다
    public String postOrder(@RequestParam("memberId")String memberId,
                             @RequestParam("coffeeId")String coffeeId) {
        System.out.println("# memberId:" + memberId);
        System.out.println("# coffeeId:" + coffeeId);

        String reponse =
                "{\"" +
                    "memberId\":\""+memberId+"\"," +
                    "\"coffeeId\":\""+coffeeId+
                "\"}";
        return reponse;
    }

    @GetMapping("/{order-id}")
    public String getOrder(@PathVariable("order-id")long orderId) {
        System.out.println("# orderId: " + orderId);
        return null;
    }

    @GetMapping
    public String getOrders() {
        System.out.println("# get Orders");
        return null;
    }
}

※ 식별자(Identifier)

  • 어떤 데이터를 식별할 수 있는 고유값을 의미한다
  • 기본키(Primary key)는 대표적인 식별자 중 하나이다
  •  API 계층에서 사용하는 memberId, coffeeId 등은 데이터베이스의 테이블에 저장되는 로우(row)의 식별자인 기본키(Primary key)가 된다

 

참조 링크

▶ 핸들러메서드 파라미터 : https://itvillage.tistory.com/41

 

Controller 핸들러 메서드의 Argument 알아보기

Controller의 핸들러 메서드는 다양한 유형의 Argument(인수)를 지원합니다. 그 중에서 REST API 애플리케이션에서 자주 사용되는 유형의 Argument를 간단히 살펴보도록 하겠습니다. Method Argument 설명 @Reque

itvillage.tistory.com

 미디어 타입(Media Type) : https://ko.wikipedia.org/wiki/%EB%AF%B8%EB%94%94%EC%96%B4_%ED%83%80%EC%9E%85

 

미디어 타입 - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

▶ MIME 타입 : https://developer.mozilla.org/ko/docs/Web/HTTP/Basics_of_HTTP/MIME_Types

 

MIME 타입 - HTTP | MDN

MIME 타입이란 클라이언트에게 전송된 문서의 다양성을 알려주기 위한 메커니즘입니다: 웹에서 파일의 확장자는 별  의미가 없습니다. 그러므로, 각 문서와 함께 올바른 MIME 타입을 전송하도

developer.mozilla.org

https://developer.mozilla.org/ko/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types

 

MIME 타입의 전체 목록 - HTTP | MDN

다음은 일반적인 확장자로 정렬된, 문서 타입과 관련된 MIME 타입의 포괄적인 목록입니다.

developer.mozilla.org

 HTTP POST Method의 요청 데이터 형식 : https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/POST

 

POST - HTTP | MDN

HTTP POST 메서드는 서버로 데이터를 전송합니다. 요청 본문의 유형은 Content-Type 헤더로 나타냅니다.

developer.mozilla.org

HTTP 응답 상태(Response Status) : https://developer.mozilla.org/ko/docs/Web/HTTP/Status

 

HTTP 상태 코드 - HTTP | MDN

HTTP 응답 상태 코드는 특정 HTTP 요청이 성공적으로 완료되었는지 알려줍니다. 응답은 5개의 그룹으로 나누어집니다: 정보를 제공하는 응답, 성공적인 응답, 리다이렉트, 클라이언트 에러, 그리고

developer.mozilla.org

 

1. REST API

 1) 개요

  • 웹 애플리케이션에서는 HTTP 메서드를 이용해 서버와 통신한다
    - GET을 통해 웹 페이지나 데이터를 요청한다
    - POST로 새로운 글이나 데이터를 전송한다
    - DELETE로 저장된 글이나 데이터를 삭제한다
  • 클라이언트와 서버가 HTTP 통신을 할 때는 어떤 요청을 보내고 받느냐에 따라 메서드의 사용이 달라진다
  • REST API에서 REST는 “Representational State Transfer”의 약자이다
    - 로이 필딩의 박사학위 논문에서 웹(http)의 장점을 최대한 활용할 수 있는 아키텍처로써 처음 소개되었다
  • REST API는 웹에서 사용되는 데이터나 자원(Resource)을 HTTP URI로 표현하고, HTTP 프로토콜을 통해 요청과 응답을 정의하는 방식이다

 2) 역활

  • 클라이언트와 서버 사이에는 데이터와 리소스를 요청하고 요청에 따른 응답을 전달하기 위한 도구 필요하다
  • 도구를 통해 클라이언트는 서버에 필요한 것을 요청하고, 이에 대한 응답을 다시 서버에서 클라이언트로 전송할 수 있다
  • HTTP 프로토콜 기반으로 요청과 응답에 따라 리소스를 주고받는 작업을 API가 수행해야 한다
    - 클라이언트와 서버 간에 서로 잘 알아볼 수 있도록 작성하는 것이 중요하다

 

2. REST API를 디자인하는 방법

  • REST API를 작성에는 몇 가지 지켜야 할 규칙들이 있다
  • 로이 필딩이 논문에서 제시한 REST 방법론을 보다 더 실용적으로 적용하기 위해 레오나르드 리차드슨은 REST API를 잘 적용하기 위한 4단계 모델을 만들었다
    - 로이 필딩은 이 모델의 모든 단계를 충족해야 REST API라고 부를 수 있다고 주장했다
    -  2단계까지만 적용해도 좋은 API 디자인이라고 볼 수 있고, 이런 경우 HTTP API 라고 한다
    - 리차드슨의 REST 성숙도 모델은 총 4단계(0~3단계)로 나누어진다

 1) REST 성숙도 모델 - 0단계

  • 0단계에서는 HTTP 프로토콜을 사용하기만 해도 된다
    - 0단계의 경우에는 해당 API를 REST API라고 할 수는 없다
    - 0단계는 좋은 REST API를 작성하기 위한 기본 단계이다
  • 허준이라는 의사의 예약 가능한 시간을 확인하고, 어떤 특정 시간에 예약하는 상황의 예제
    - HTTP 프로토콜을 사용하고 있다
    - 단순히 HTTP 프로토콜을 사용하는 것이 REST API의 출발점이다
요청 내용 요청 응답
예약 가능 시간 확인 POST/appointment HTTP/1.1
[헤더 생략]

{
   "date" : "2022-08-10" ,
   "doctor" : "허준"



HTTP/1.1 200 OK
[헤더 생략]

{
   " slots" : [
      { "doctor" : "허준", "start" : "09:00", "end" : "12:00"} ,
      { "doctor" : "허준", "start" : "14:00", "end" : "16:00"}
   ]
}
특정 시간 예약 POST/appointment HTTP/1.1
[헤더 생략]

{
   "doctor" : "허준" ,
   "start" : "14:00" ,
   "end" : "15:00" ,
   "patient" : "김코딩"
}
HTTP/1.1 200 OK
[헤더 생략]







 

 2) REST 성숙도 모델 - 1단계

  • 1단계에서는 개별 리소스와의 통신을 준수해야 한다
  • REST API는 웹에서 사용되는 모든 데이터나 자원(Resource)을 HTTP URI로 표현한다
    - 모든 자원은 개별 리소스에 맞는 엔드포인트(Endpoint)를 사용해야 한다
    - 모든 자원은 요청하고 받은 자원에 대한 정보를 응답으로 전달해야 한다
  • 0단계에서는 모든 요청에서 엔드포인트로 /appointment 를 사용하였다
  • 1단계에서는 요청하는 리소스가 무엇인지에 따라 각기 다른 엔드포인트로 구분하여 사용해야 한다
  • 1단계 예제
    - 예약 가능 시간 확인이라는 요청의 응답으로 받게 되는 자원(리소스)은 허준이라는 의사의 예약 가능 시간대이다
     : 예약 가능 시간 확인 요청 시 /doctors/허준이라는 엔드포인트를 사용하였다
    - 특정 시간에 예약하게 되면, 실제 slot이라는 리소스의 123이라는 id를 가진 리소스가 변경된다
     : 특정 시간 예약이라는 요청에서는 /slots/123으로 실제 변경되는 리소스를 엔드포인트로 사용하였다
요청 내용 요청 응답
예약 가능 시간 확인 POST/doctors/허준 HTTP/1.1
[헤더 생략]

{
   "date" : "2022-08-10" ,




HTTP/1.1 200 OK
[헤더 생략]

{
   " slots" : [
      { "id" : 123, "doctor" : "허준", "start" : "09:00", "end" : "12:00"} ,
      { "id" : 124, "doctor" : "허준", "start" : "14:00", "end" : "16:00"}
   ]
}
특정 시간 예약 POST/slots/123 HTTP/1.1
[헤더 생략]

{
   "patient" : "김코딩"
}



HTTP/1.1 200 OK
[헤더 생략]

{
   "appointment" : {
      "slots" : { "id" : 123, "doctor" : "허준", ... } ,
      "patient" : "김코딩"
   }
}
  • 어떤 리소스를 변화시키는지 혹은 어떤 응답이 제공되는지에 따라 각기 다른 엔드포인트를 사용해야 한다
    - 적절한 엔드포인트를 작성하는 것이 중요하다
    - 엔드포인트 작성 시에는 동사, HTTP 메서드, 어떤 행위에 대한 단어 사용은 지양한다
    - 리소스에 집중된 명사 형태의 단어로 작성하는 것이 적당하다
  • 요청에 따른 응답으로 리소스를 전달할 때에도 사용한 리소스에 대한 정보와 리소스 사용에 대한 성공/실패 여부를 반환해야 한다
    - 김코딩 환자가 허준 의사에게 9시에 예약을 진행하였으나, 해당 시간에 예약이 불가능할 경우에는 리소스 사용에 대한 실패 여부를 포함한 응답을 받아야 한다
요청 내용 요청 응답
예약 가능 시간 확인 POST/doctors/허준 HTTP/1.1
[헤더 생략]

{
   "date" : "2022-08-10" ,




HTTP/1.1 200 OK
[헤더 생략]

{
   " slots" : [
      { "id" : 123, "doctor" : "허준", "start" : "09:00", "end" : "12:00"} ,
      { "id" : 124, "doctor" : "허준", "start" : "14:00", "end" : "16:00"}
   ]
}
특정 시간 예약 POST/slots/123 HTTP/1.1
[헤더 생략]

{
   "patient" : "김코딩"
}



HTTP/1.1 200 OK
[헤더 생략]

{
   "appointmentFailure" : {
      "slots" : { "id" : 123, "doctor" : "허준", ... } ,
      "patient" : "김코딩" ,
      "reason" : "해당 시간은 이미 다른 예약이 있습니다"
   }
}

 

 3) REST 성숙도 모델 - 2단계

  • 2단계에서는 CRUD에 맞게 적절한 HTTP 메서드를 사용하는 것에 중점을 둔다
  • 0단계와 1단계 예시에서는 모든 요청을 CRUD에 상관없이 POST로 하고 있다
    - REST 성숙도 모델 2단계에 따르면 CRUD에 따른 적합한 메서드를 사용한 것이 아니다
  • 예약 가능 시간 확인은 예약 가능한 시간을 조회(READ)하는 행위를 의미한다
    - 조회(READ)하기 위해서는 GET 메서드를 사용하여 요청을 보낸다
    - GET 메서드는 body를 가지지 않기 때문에 query parameter를 사용하여 필요한 리소스를 전달한다
  • 특정 시간 예약은 해당 특정 시간에 예약을 생성(CREATE)한다는 것과 같다
    - 예약을 생성(CREATE)하기 위해서는 POST 메서드를 사용하여 요청을 보내는 것이 적당하다
  • 2단계에서는 POST 요청에 대한 응답이 어떻게 반환되는지도 중요하다
    - 응답은 새롭게 생성된 리소스를 보내주기 때문에, 응답 코드도 201 Created 로 명확하게 작성해야 한다
    - 관련 리소스를 클라이언트가 Location 헤더에 작성된 URI를 통해 확인할 수 있어야 완벽하게 REST 성숙도 모델의 2단계를 충족한 것이다
요청 내용 요청 응답
예약 가능 시간 확인 POST/doctors/허준/slots?data=2022-08-10 HTTP/1.1
[헤더 생략]






HTTP/1.1 200 OK
[헤더 생략]

{
   " slots" : [
      { "id" : 123, "doctor" : "허준", ... } ,
      { "id" : 124, "doctor" : "허준", ... }
   ]
}
특정 시간 예약 POST/slots/123 HTTP/1.1
[헤더 생략]

{
   "patient" : "김코딩"
}




HTTP/1.1 201 Created
Location : slots/123/appointment

[헤더 생략]

{
   "appointment" : {
      "slots" : { "id" : 123, "doctor" : "허준", ... } ,
      "patient" : "김코딩"
   }
}

※ 메서드 사용 규칙

  • GET 메서드는 서버의 데이터를 변화시키지 않는 요청에 사용해야 한다
  • POST 메서드는 요청마다 새로운 리소스를 생성한다
  • PUT 메서드는 요청마다 같은 리소스를 반환한다
    - 요청마다 같은 리소스를 반환하는 특징을 멱등(idempotent)하다고 한다
    - 멱등성을 가지는 메서드 PUT 과 그렇지 않은 POST는 구분하여 사용해야 한다
  • PUT 과 PATCH 도 구분하여 사용해야한다
    - PUT은 교체의 용도로 사용한다
    - PATCH는 수정의 용도로 사용한다
  • HTTP request methods : https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods 
 

HTTP request methods - HTTP | MDN

HTTP defines a set of request methods to indicate the desired action to be performed for a given resource. Although they can also be nouns, these request methods are sometimes referred to as HTTP verbs. Each of them implements a different semantic, but som

developer.mozilla.org

 

 4) REST 성숙도 모델 - 3단계

  • 3단계는 HATEOAS(Hypertext As The Engine Of Application State)라고 표현되는 하이퍼미디어 컨트롤을 적용한다
  • 3단계의 요청은 2단계와 동일하다
  • 3단계의 응답은 리소스의 URI를 포함한 링크 요소를 삽입하여 작성하는 것이 다르다
  • 응답에 들어가게 되는 링크 요소는 응답을 받은 다음에 할 수 있는 다양한 액션들을 위해 많은 하이퍼미디어 컨트롤을 포함하고 있다
요청 내용 요청 응답
예약
가능
시간
확인
POST/doctors/허준/slots?data=2022-08-10 HTTP/1.1
[헤더 생략]












HTTP/1.1 200 OK
[헤더 생략]

{
   " slots" : [
      { "id" : 123, "doctor" : "허준", ... } , ...
   ] ,
   "links" : {
      "appointment" : {
         "href" : "http://llocalhost:8080/slots/123",
         "method" : "POST"
      }
   }
}
특정
시간
예약
POST/slots/123 HTTP/1.1
[헤더 생략]

{
   "patient" : "김코딩"
}




HTTP/1.1 201 Created
Location : slots/123/appointment

[헤더 생략]

{
   "appointment" : {
      "slots" : { "id" : 123, "doctor" : "허준", ... } ,
      "patient" : "김코딩"
   } ,
   "links" : {
      "self" : {
         "href" : "http://llocalhost:8080/slots/123",
         "method" : "GET"
      }

   "cancel" : {
         "href" : { "http://llocalhost:8080/slots/123/cancel",
         "method" : "DELETE"
      }

   }
}
  • 응답 내에 새로운 링크를 넣어 새로운 기능에 접근할 수 있도록 하는 것이 3단계의 중요 포인트이다
    - 예약 가능 시간을 확인한 후에는 그 시간대에 예약을 할 수 있는 링크를 삽입할 수 있다
    - 특정 시간에 예약을 완료하고 나서 예약을 다시 확인할 수 있도록 링크를 작성할 수 있다

 

5가지의 기본적인 REST API 디자인 가이드 : https://blog.restcase.com/5-basic-rest-api-design-guidelines/

 

5 Basic REST API Design Guidelines

As soon as we start working on an API, design issues arise. Robust and strong design is a key factor for API success. A poorly designed API will indeed lead to misuse or – even worse – no use at all by its intended clients: application developers. Crea

blog.restcase.com

 호주 정부 - API 설계 표준 : https://api.gov.au/sections/definitions.html#api 

 

api.gov.au

Definitions API In the context of this API Design Standard, an API (Application Programming Interface) is defined as a RESTful API. A RESTful API is a style of communication between systems where resources are defined by URI and its operations are defined

api.gov.au

API 디자인 가이드 : https://cloud.google.com/apis/design?hl=ko 

 

API 디자인 가이드  |  Google Cloud

의견 보내기 API 디자인 가이드 2017년 2월 21일에 게시됨. 변경 로그 소개 본 문서는 네트워크 API를 위한 종합 디자인 가이드입니다. 2014년부터 Google 내부에서 사용되었으며, Cloud APIs 및 기타 Google

cloud.google.com

 Microsoft REST API Guidelines : https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md 

 

GitHub - microsoft/api-guidelines: Microsoft REST API Guidelines

Microsoft REST API Guidelines. Contribute to microsoft/api-guidelines development by creating an account on GitHub.

github.com

 

'Network' 카테고리의 다른 글

네트워크 - HTTP  (0) 2022.06.08
네트워크 - 브라우져(Browser)  (0) 2022.06.08
네트워크 - 클라이언트(Client)  (0) 2022.06.07

+ Recent posts