Search

1. 생애 최초 API 만들기

목표

1.
스프링 프로젝트 설정하고 실행해보기
2.
서버, 네트워크와 HTTP, API, JSON 무엇이고 서버 개발에 필요한 개념 익히기.
3.
스프링 부트를 이용해서 GET API, POST API 만들기

1. 스프링 프로젝트를 시작하는 두 번째 방법

1. 이미 만들어진 스프링 프로젝트 다운

이미 수업 준비 파트에서 기존 프로젝트를 open에서 진행하는 방법을 했었다.

2. spring initalizr 사용해서 새로운 프로젝트 생성

접속해서
Maven 하고 Gradle은 프로젝트의 빌드 툴을 말한다.
최근에는 그레들를 많이 사용한다.
스프링 부트 버전인데 알파벳이 붙어있으면 아직 개발중이라는 뜻이다.
프로젝트에 존재하는 다양한 이름을 짓는 항목이다
Group : 프로젝트 그룹
Artifact : 최종 결과물의 이름
Name : 프로젝트 이름
Description : 프로젝트 설명
Package name : 패키지 이름
지금 프로젝트에 맞게 짓는다면
패키징에는 Jar 랑 War 가 있는데
스프링부터는 Tomcat이 내장되서 Jar를 선택하면 된다.
자바 버전은 11하고 17을 제일 많이 쓰고 있다.
이제 우측에
롬복은 내가 넣어둔거다. 처음엔 아무것도 없음
의존성 부분인데. 의존성이란 프로젝트에서 사용하는 라이브러리/프레임워크를 의미한다.
라이브러리란? 프로그래밍을 개발할 때 미리 만들어져 있는 기능을 사용한다. 재료를 가져다가 쓰는것
프레임워크란? 프로그래밍을 개발할 때 미리 만들어져 있는 구조에 코드를 가져다가 끼워 넣는 것! 코드를 끼워 넣는 것 마치 원데이 클래스 처럼 미리 준비되어 있는 재료들을 가지고 수업을 진행하는 것.
마지막으로 GENERATE 버튼 누르면 프로젝트가 압축되서 설치된다.
압축풀어서 인텔리제이에서 open 하면됟다
해당 LibraryAppApplication파일에서 좌측에 화살표를 누르면 서버가 실행된다.

2. @SpringBootApplication과 서버

package com.group.libraryapp; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; //@어노테이션 // 스프링을 실행시킬 때 다양한 설정이 필요. 그 설정을 다 자동으로 설정해준다. @SpringBootApplication public class LibraryAppApplication { public static void main(String[] args) { //실제 스프링 애플리케이션을 시작한다. SpringApplication.run(LibraryAppApplication.class, args); } }
Java
복사
이 코드가 이제 서버를 실행시키는 코드다.

서버란?

Server = Serve + er(~하는 사람)
제공하는 것. 기능을 제공하는 것
회원가입 기능
정보 가져오기 기능
추천 기능
이런 기능을 컴퓨터가 수행해주는데 이때 컴퓨터를 서버라고 한다.
기능하는 컴퓨터 자체를 서버라고 한다.
어떠한 기능을 제공하는 프로그램
그 프로그램을 실행시키고 있는 컴퓨터
근데 기능을 제공하기 위해서는 요청이 있어야 한다.
컴퓨터는 요청을 어떻게할까?
인터넷을 사용해서 한다.

3. 네트워크란 무엇인가?

IP

컴퓨터는 각각의 고유한 주소(IP)가 있다.
서울에 살고 있는 나는 ip가 244.77.51.9이고
미국에 사는 가족의 ip가 244.66.51.9 라는 ip를 가지고 있을 때
인터넷을 통해서 데이터를 컴퓨터끼리 주고 받을 수 있다
이제 내가 미국의 친구에게 요청을 보내고 데이터를 받을 때
데이터를 받는 컴퓨터는 이제
IP 244.66.51.9, port: 3000
port는 이제 컴퓨터안에 동작하는 여러 프로그램 중에서 특정 프로그램을 말하는거다.

Domain Name 즉, DNS 등장

ip를 외우기는 너무 어렵다.
그래서 이름을 사용하기로 했는데
도메인명 : spring.com, port : 3000
IP 244.66.51.9 랑 도메인명 : spring.com 같은거다.

4. HTTP와 API란 무엇인가?

택배를 보내려면 운송장이 필요하다.
즉, 운송장이 표준
현실 세계에서도 데이터를 주고 받는 표준이 있다.
HTTP(HyperText Transfer Protocol)
Protocol : 표준, 약속
HTTP 자체가 일종의 표준

지켜야할 규칙

HTTP GET요청 GET/protion?color=red&count=2 Host:spring.com:3000
GET
HTTP 요청을 받는 컴퓨터에게 요청하는 행위(데이터를 달라)
HTTP 메소드 중 하나.
Host:spring.com:3000
HTTP 요청을 받는 컴퓨터와 프로그램 정보
spring.com를 사용하는 3000포트 프로그램
/protion
HTTP 요청을 받는 컴퓨터에게 원하는 자원
Path
color=red
색은 빨강일때
&
다른 세부조건과 구분하기 위해서 사용
count=2
갯수는 2개
color=red&count=2
원하는 조건 = Query
자원을 요구할때 이러한 조건을 쿼리라고 한다.
HTTP POST요청 POST/oak/leather Host:spring.com:3000 오크가죽정보
POST
HTTP 요청을 받는 컴퓨터에게 요청하는 행위(저장하라)
Host:spring.com:3000
HTTP 요청을 받는 컴퓨터와 프로그램 정보
spring.com를 사용하는 3000포트 프로그램
/oak/leather
자원을 적어준다
오크가죽정보
실제 저장할 오크 가죽 정보
Body 라고 한다.
POST/oak/leather
이제 오크가죽을 저장하기 전에 공간을 미리 만들어둬야하듯이
현실세계도 HTTP 요청을 보내기전에 미리 약속을 해야한다. 상대쪽에서 받을 수 있어야지 내가 보낼 수 있다.

대표적으로 데이터를 보내는 2가지 방법

쿼리
바디

다양한 HTTP Method

GET
데이터를 줘
쿼리
POST
데이터를 저장
바디
PUT
데이터를 수정
바디
DELETE
데이터를 삭제
쿼리

API(Application Programming Interface)

정해진 규칙, 규약, 미리 정해져 있는 약속
GET/protion?color=red&count=2 Host:spring.com:3000 POST/oak/leather Host:spring.com:3000 오크 가죽 정보
Plain Text
복사
포션을 달라고 할 때나 오크 가죽을 달라고 할때
포션을 미리 줄 수 있어야하고, 가죽을 저장할 수 있게끔 되어야 있어야한다.
정해진 약속을 해서, 특정 기능을 수행하는 것.

HTTP 요청 문법

강의 참고 이미지

URL(Uniform Resource Locator)

http://spring.com:3000/portion?color=red&count=2
Plain Text
복사
http
약속 프로토콜(HTTP)
spirng.com:300
도메인 이름 : 포트
도메인 이름은 IP로 대처 가능
portion
자원이 경로 (PATH)
?
구분기호
color=red&count=2
쿼리(추가정보)

HTTP 응답

요청에 대한 응답을 해준다
HTTP 메소드를 이용해서 요청을 보내면 저장하고 응답으로 200 ok가 떨어진다.
요청에 대한 응답을 제공한 컴퓨터가 바로 서버
요청을 한 컴퓨터가 바로 클라이언트 컴퓨터다.
이 구조를 클라이언트 - 서버 구조 라고 한다

응답 상태 코드

200 성공
300 다른곳으로 이동
404 요청한걸 찾을 수 없어
500 내부 문제

응답에 바디(추가정보)를 담는다

정리

1.
웹을 통한 컴퓨터 간의 통신은 HTTP라는 표준화 방식
2.
HTTP 요청은 HTTP Method(GET, POST)와 Path(/portion)가 핵심
3.
요청에서 데이터를 전달하기 위한 2가지 방법은 쿼리와 바디
4.
HTTP 응답은 상태코드가 핵심
5.
클라이언트와 서버는 HTTP를 주고 받으며 기능을 동작. 이때 정해진 규칙을 API라고 한다.

5. GET API 개발하고 테스트

덧셈 API 만들기

만들기 전에 API Specification(명세)를 정하고 명세대로 API를 개발해야한다
줄여서 API Spec 이라고 한다
강의 참고 이미지
package com.group.libraryapp.controller.calculator; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController // CalculatorController클래스를 api진입 지점으로 만들어준다. public class CalculatorController { @GetMapping("/add") // GET /add public int addTwoNumbers(@RequestParam int number1, @RequestParam int number2) { //쿼리파라매터로 넘어올때 @RequestParam을 붙여준다 return number1 + number2; } }
Java
복사
@RestController
주어진 Class를 Controller 로 등록
@GetMapping("/add") 아래 함수가
HTTP Method가 GET
HTTP path가 /add인 API로 지정
서버를 실행시켜주고
포스트맨에서 날려주면 30이라고 응답을 받는다
200 OK라는 성공도 떨어진다.
근데 현재 지금은 number1, number2 2가지 밖에 못받는데 나중에 여러개 데이터를 받아야하는 상황이 올 수 있다. 그때 객체로 받아서 처리해주면 됨.
package com.group.libraryapp.dto.calculator.request; public class CalculatorAddRequest { private final int number1; private final int number2; public CalculatorAddRequest(int number1, int number2) { this.number1 = number1; this.number2 = number2; } public int getNumber1() { return number1; } public int getNumber2() { return number2; } }
Java
복사
객체로 생성해주고
이 객체로 바꿔준다
@GetMapping("/add") // GET /add public int addTwoNumbers(CalculatorAddRequest request) { return request.getNumber1() + request.getNumber2(); }
Java
복사
서버 재시작하고 포스트맨 날려도 성공한다.
강의 참고 이미지
스프링부트는 요청으로 들어온 값을 보고 CalculatorAddRequest 객체에다가 값을 집어넣는다.
그리고 그 객체를 컨트롤러 API 진입점에 보내준다.
그리고 정보를 전달하는 역할의 객체(CalculatorAddRequest)를 Data Transfer Object 라고 한다. DTO

6. POST API 개발하고 테스트

POST는 HTTP Body를 사용.
바디에 데이터를 넘기게 되면 API에서 바디에 있는 데이터를 열어서 정보를 가져오게 된다
이때 사용되는 문법이 JSON

JSON이란

객체 표기법, 즉 무언가를 표현하기 위한 형식
{ "name": "구구구", "age": 99 }
Java
복사
Java로 비유하면 Map<Object, Object> 느낌
{ "name": "구구구", "age": 99, "dogs": ["코코", "키키"] }
Java
복사
{ "name": "구구구", "age": 99, "house": { "address": "대한민국 서울", "hasDoor": true } }
Java
복사

곱셉 API

@PostMapping("/multiply") //POST /multiply public int multiplyTwoNumbers(@RequestBody CalculatorMultiplyRequest request){ //@RequestBody 있어야지 Post API 에서 정상적으로 HTTP body 안에 담긴 JSON을 CalculatorMultiplyRequest 객체로 변경 가능 //즉, HTTP Body로 들어오는 JSON을 CalculatorMultiplyRequest 로 바꿈 return request.getNumber1() * request.getNumber2(); }
Java
복사
package com.group.libraryapp.dto.calculator.request; public class CalculatorMultiplyRequest { private int number1; private int number2; public int getNumber1() { return number1; } public int getNumber2() { return number2; } }
Java
복사
한 Controller Class 안에 여러 API를 넣을 수 있다.

7. 유저 생성 API 개발

들어가면 이런 사이트가 나온다. ui가 제공된 상태
이제 API를 만들어야 한다.

도서관 사용자를 등록하는 API

user 컨트롤러를 위해서 user 패키지 생성
package com.group.libraryapp.controller.user; @RestController public class UserController { @PostMapping("/user") // POST /user public void saveUser() { } }
Java
복사
컨트롤러의 간단한 틀을 만들어 줬다.
바디로 잡을 dto 를 만들어 주자.
package com.group.libraryapp.dto.user.request; public class UserCreateRequest { private String name; private Integer age; public String getName() { return name; } public Integer getAge() { return age; } }
Java
복사
Integer로 잡은 이유는 null을 표현할 수 있는 자료형.
다시 컨트롤러로 와서
들어온 데이터를 @RequestBody로 이용해서 UserCreateRequest에 맵핑되게 해준다.
package com.group.libraryapp.controller.user; @RestController public class UserController { @PostMapping("/user") // POST /user public void saveUser(@RequestBody UserCreateRequest request) { } }
Java
복사
유저라는 걸 저장하기 위해서 유저라는 객체를 만들어서 저장할거다.
이 객체를 domain 패키지 안에 만들어주자.
생성자를 통해서 집어넣어주자. 그리고 null값을 예외 처리해주자.
package com.group.libraryapp.domain.user; public class User { private String name; private Integer age; public User(String name, Integer age) { if (name == null || name.isBlank()) { throw new IllegalArgumentException(String.format("잘못된 name(%s)이 들어왔습니다", name)); } this.name = name; this.age = age; } }
Java
복사
유저 클래스에 인스턴스가 생겨서 저장되게 해줘야한다.
package com.group.libraryapp.controller.user; @RestController public class UserController { private final List<User> users = new ArrayList<>(); @PostMapping("/user") // POST /user public void saveUser(@RequestBody UserCreateRequest request) { //새로운 User를 만들어서 api에 들어온 이름과 나이를 넣어준다. users.add(new User(request.getName(), request.getAge())); } }
Java
복사
이제 정상적으로 호출하면 200 OK가 떨어진다.

8. 유저 조회 API 개발과 테스트

이제 조회 API를 만들어보자

결과 반환이 JSON?

Controller 에서 getter가 있는 객체를 반환하면 JSON이 된다

테스트

package com.group.libraryapp.domain.user; public class Fruit { private String name; private int price; public Fruit(String name, int price) { this.name = name; this.price = price; } public String getName() { return name; } public int getPrice() { return price; } }
Java
복사
package com.group.libraryapp.controller.user; @RestController public class UserController { . . @GetMapping("/fruit") public Fruit fruit(){ return new Fruit("바나나", 2000); } }
Java
복사
이게 가능한 이유가 @RestController 를 붙여서 가능한거다.

Id는 무엇인가?

유저별로 겹치지 않는 유일한 번호를 말한다. 고유한 번호다
List에 담겨 있는 유저의 순서를 Id에 담아주자
@GetMapping("/user") public void getUser(){ }
Java
복사
id,나이,이름을 넣어줄건데 그러면 DTO가 하나 필요하다.
그래서 이번에는 응답 DTO니까 response 패키지를 만들어서 UserResponse 라고 만들어준다
package com.group.libraryapp.dto.user.response; public class UserResponse { private long id; private String name; private Integer age; public UserResponse(long id, String name, Integer age) { this.id = id; this.name = name; this.age = age; } public long getId() { return id; } public String getName() { return name; } public Integer getAge() { return age; } }
Java
복사
그러고 아까 잡은 api에서 반환값을 변경해주자
@GetMapping("/user") public List<UserResponse> getUser(){ List<UserResponse> responses = new ArrayList<>(); for(int i = 0; i < users.size(); i++){ responses.add(new UserResponse(i+1, users.get(i).getName(),users.get(i).getAge())); } return responses; }
Java
복사
User.java에 getter 부분도 추가해주면된다.
여기서 코드를 더 깔끔하게 하고 싶으면
UserResponse 에서 이름과 나이를 받는게 아니라 User를 직접 받는거다
변경전
public UserResponse(long id, String name, Integer age) { this.id = id; this.name = name; this.age = age; }
Java
복사
변경후
public UserResponse(long id, User user) { this.id = id; this.name = user.getName(); this.age = user.getAge(); }
Java
복사
그러면 컨트롤러도 같이 수정해주면 된다
@GetMapping("/user") public List<UserResponse> getUser(){ List<UserResponse> responses = new ArrayList<>(); for(int i = 0; i < users.size(); i++){ responses.add(new UserResponse(i+1, users.get(i))); } return responses; }
Java
복사
서버 재시작하고
해당 주소로 들어가서 사용자 등록을 해보자.
목록에 가보면

9. Section1 정리. 다음으로

서버를 재기동하고 다시 접속하면 사용자 정보가 사라진다.
유저 정보가 메모리에서만 유지되고 있기 때문이다

*참고