본문 바로가기

Study/Spring Boot

3. REST API

*모놀리식(Monolithic) 아키텍처: 단일 코드 베이스의 애플리케이션 (모든 것을 한곳에서 실행)

*마이크로서비스 아키텍처: 애플리케이션을 작은 서비스로 분할, 각 서비스가 독립적

 

REST API

REST (Representational State Transfer)

- 생존가능성(survivability), 회복탄력성(resilience)을 향상시킴

- 무상태 애플리케이션/서비스라고도 함

- 서비스마다 자체적으로 '현재 상태'를 가짐, 다른 서비스가 자기 서비스의 '현재 상태'를 저장하리라 기대하지 않기 때문

 

*무상태: 수신자(receiver)가 이전 요청(request)의 상태를 유지하지 않는 방식

- 안정성과 확장성에 유리하지만 요청을 재사용할 수 없으므로 반복 데이터로 네트워크 성능을 저하시킴

 

• REST API는 주로 아래의 HTTP 메서드를 기반으로 함

- 생성(POST), 읽기(GET), 업데이트(PUT, PATCH), 삭제(DELETE) + OPTIONS, HEAD


*의존성은 'RESTful을 포함한 웹을 만들고, 스프링 MVC를 사용한 애플리케이션'을 만드는 기능 등 여러 기능을 포함

 

RESTful API 만들기

https://start.spring.io/

 


3.4 GET으로 시작하기

@RestController : @Controller와 @ResponseBody를 하나의 어노테이션으로 합쳐 쓴 것

 

• MVC의 여러 부분을 연결하는 데 @Controller 어노테이션이 도움됨

- @Controller (@Component의 별칭)

- @Controller가 붙은 클래스는 Model 객체를 받음

 

@RequestMapping 에 있는 편리한 어노테이션   

- @GetMapping   

- @PostMapping 

- @PutMapping 

- @PatchMapping   

- @DeleteMapping

 

@RestController
class RestApiDemoController{
	private List<Coffee> coffees = new ArrayList<>();
	
	public RestApiDemoController() {
		coffees.addAll(Arrays.asList(
						new Coffee("Cafe Cereza"),
						new Coffee("Cafe Ganador"),
						new Coffee("Cafe Lareno"),
						new Coffee("Cafe Tres Pontas")
				));
	}
	
	@RequestMapping(value = "/coffees", method = RequestMethod.GET)
	Iterable<Coffee> getCoffees(){
		return coffees;
	}
	
}

 

@RestController
@RequestMapping("/")
class RestApiDemoController{
	private List<Coffee> coffees = new ArrayList<>();
	
	public RestApiDemoController() {
		coffees.addAll(Arrays.asList(
						new Coffee("Cafe Cereza"),
						new Coffee("Cafe Ganador"),
						new Coffee("Cafe Lareno"),
						new Coffee("Cafe Tres Pontas")
				));
	}
	
	@GetMapping("/coffees")
	Iterable<Coffee> getCoffees(){
		return coffees;
	}
}

-> 위 아래 코드 동일하게 동작 .. 하는듯

3.4.2 POST로 생성하기 @PostMapping

Post는 리소스의 세부 정보(일반적으로 JSON 형식)를 제공. 해당 서비스에 POST 요청을 해서 지정된 URI에 리소스를 생성

3.4.3 PUT으로 업데이트하기 @PutMapping

일반적으로 PUT 요청은 파악된 URL를 통해 기존 리소스의 업데이트에 사용됨

✨PUT 메서드 응답 시 '상태코드'는 필수 -> ResponseEntity 반환

3.4.4 DELETE로 삭제하기 @DeleteMapping

HTTP의 DELETE의 요청은 리소스를 삭제함

 

 

 

(+) GET에는 특정 상태코드를 지정하지 않고, POST와 DELETE 메서드에는 '상태코드' 사용을 권장함


최종 코드

package com.thehecklers.sburrestdemo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class SburRestDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(SburRestDemoApplication.class, args);
	}
}

class Coffee {
	private final String id;
	private String name;

	public Coffee(String id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	public Coffee(String name) {
		this(UUID.randomUUID().toString(), name);
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getId() {
		return id;
	}
}

@RestController
@RequestMapping("/coffees")
class RestApiDemoController {
	private List<Coffee> coffees = new ArrayList<>();

	public RestApiDemoController() {
		coffees.addAll(Arrays.asList(
				new Coffee("Cafe Cereza"), 
				new Coffee("Cafe Ganador"), 
				new Coffee("Cafe Lareno"),
				new Coffee("Cafe Tres Pontas")
				));
		}
	
	//@GetMapping
	//Iterable<Coffee> getCoffees() {
	//	return coffees;
	//}
	
	@GetMapping
	Optional<Coffee> getCoffeeById(@PathVariable String id){
		for(Coffee c : coffees) {
			if(c.getId().equals(id)) {
				return Optional.of(c);
			}
		}
		return Optional.empty();
	}
	
	@PostMapping
	Coffee postCoffee(@RequestBody Coffee coffee) {
		coffees.add(coffee);
		return coffee;
	}
	
	@PutMapping("/{id}")
	ResponseEntity<Coffee> putCoffee(@PathVariable String id, @RequestBody Coffee coffee) {
		int coffeeIndex = -1;
		
		for(Coffee c : coffees) {
			if(c.getId().equals(id)) {
				coffeeIndex = coffees.indexOf(c);
				coffees.set(coffeeIndex, coffee);
			}
		}
		
		return (coffeeIndex == -1) ? 
				new ResponseEntity<>(postCoffee(coffee), HttpStatus.CREATED) : //상태코드 반환 추가
				new ResponseEntity<>(coffee, HttpStatus.OK);
	}
	
	@DeleteMapping("/{id}")
	void deleteCoffee(@PathVariable String id) {
		coffees.removeIf(c->c.getId().equals(id));
	}
}

(+) GetMapping 어노테이션이 2개 있으면 오류나서 .. 하나 지움


API 사용해보기

HTTPie 사용

GET으로 모든 커피 조회
DELETE로 커피 삭제하기

'Study > Spring Boot' 카테고리의 다른 글

6. 데이터 파고들기  (2) 2023.12.14
5. 애플리케이션 설정과 검사  (0) 2023.09.17
4. 데이터베이스 액세스  (0) 2023.09.10