일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 백엔드개발자
- 프로그래밍
- 도커
- UNICON
- 체크인미팅
- 42서울
- 전국대학생게임개발동아리연합회
- CICD
- 스프링
- 프리티어
- 생활코딩
- 백엔드
- 인프라
- EC2
- 오블완
- 티스토리챌린지
- RDS
- 라피신
- 인디게임
- UNICON2023
- 배포
- AWS
- 개발공부
- UNIDEV
- 게임개발동아리
- 위키북스
- Developer
- 스프링부트
- 온라인테스트
- 자바개발자
- Today
- Total
Hyun's Wonderwall
[GDSC Study] 스프링 기반 REST API 개발 - 1주차 (섹션 0, 1) 본문
GDSC Ewha 5기_ Spring Boot 스터디
- 스터디 커리큘럼: 백기선, "스프링 기반 REST API 개발"
- 선수 학습사항: (필수) 스프링 프레임워크 핵심 기술, 스프링 부트 개념과 활용 / (선택) 스프링 데이터 JPA 의 지식 - 1주차 과제: 섹션 0. 소개, 섹션 1. REST API 및 프로젝트 소개
섹션 0. 소개
이 강좌에서는 다양한 스프링 기술을 사용하여 Self-Descriptive Message와 HATEOAS(Hypermedia as the engine of application state)를 만족하는 REST API를 개발한다.
이 두 가지를 만족해야만 진화가 가능한 REST API, -> 클라이언트와 서버 독립적으로 진화할 수 있는 성격 달성할 수 있음.
- 이 강좌에서 사용하는 스프링 기술들
- 스프링 프레임워크
- 스프링 부트
- 스프링 데이터 JPA
- 스프링 HATEOAS
- 스프링 REST Docs
- 스프링 시큐리티 OAuth2
- 테스트 주도 개발(TDD)로 진행
- EVENT라는 API 만들어 볼 것: 모임 생성, 모임 조회
REST API를 실제로 구현할 때 여러가지 문제 상황이 있음. 코드에 집중하기보다 코딩으로 무엇을 하려는가에 더 집중하기.
섹션 1. (1) REST API
API란? Application Programming Interface. API 종류 다양.
우리가 만들 것은 REST API. (웹으로 접근할 수 있는 API 중 하나)
REST? REpresentational State Transfer
인터넷 상의 서로 다른 시스템 간의 독립적인 진화를 보장하기 위한 방법(시스템 간의 상호 운용성(interoperability)을 제공)
* REST API: REST 아키텍처 스타일을 따르는 API
* 오늘날의 REST API는 대부분 REST API라고 할 수가 없다... REST API의 아키텍처 스타일을 잘 따르지 않기 때문.
REST 아키텍처 스타일
- Client-Server
- Stateless
- Cache
- Layered System
- Code-On-Demand (optional)
- Uniform Interface
- Identification of resources
- manipulation of resources through represenations
- self-descrive messages
- 메시지 스스로 메시지에 대한 설명이 가능해야 한다.
- 서버가 변해서 메시지가 변해도 클라이언트는 그 메시지를 보고 해석이 가능하다.
- 확장 가능한 커뮤니케이션
- hypermedia as the engine of appliaction state (HATEOAS)
- 하이퍼미디어(링크)를 통해 애플리케이션 상태 변화가 가능해야 한다.
- 링크 정보를 동적으로 바꿀 수 있다. (Versioning 할 필요 없이!)
- self-descrive messages, HATEOAS 이 두개를 만족하지 않는 경우들이 많음 -> 독립적인 진화를 보장하지 못함!
(불필요한 api 버저닝 등의 문제)
- 메세지가 변해도 클라이언트는 알아서 대응할 수 있어야 한다 (메세지를 해석할 수 있는 정보가 메세지 안에 담겨 있으니까)
하이퍼미디어를 통해 애플리케이션 상태 변화가 가능해야 한다. (유튜브에서 막 클릭하는 것처럼) 응답 받은 후 상태를 전이하려면 그 응답에 들어있는 링크 정보 사용해서 이동해야 함.
HATEOAS 링크 정보 이용 - 버저닝을 할 필요가 없음
Self-descriptive message 해결 방법
- 방법 1: 미디어 타입을 정의하고 IANA에 등록 후 그 미디어 타입을 리소스 리턴할 때 Content-Type으로 사용한다.
- 방법 2: profile 링크 헤더를 추가한다.
(근데 아직 브라우저들이 스펙 지원을 잘 안 함...)
대안으로 HAL의 링크 데이터에 profile 링크 추가
HATEOAS 해결 방법
- 방법1: 데이터에 링크 제공
- 링크를 어떻게 정의할 것인가? HAL - 방법2: 링크 헤더나 Location을 제공
어떤 식으로 S.D H를 만족하는 rest api를 만들 것인가? HAL 스펙을 사용해 링크를 제공해 해결할 것.
PROFILE 링크 헤더에 추가 or 응답 본문에 추가.
이중 후자의 방법을 사용하겠습니다 (아직 클라이언트가 가져오지 못할 가능성..)
좀 더 안정적으로 하기 위해 본문에 PROFILE 링크를 HAL 스펙에 따라 할것임
HATEOAS도 현재 상태->다음 상태 전이 링크를 HAL 스펙에 따라 링크 정보 추가할 것
섹션 1. (2) Event REST API
EventController 실행시 index.html 조회 가능
Event REST API: 이벤트 등록, 조회 및 수정 API
GET /api/events
이벤트 목록 조회 REST API (로그인 안 한 상태)
- 응답에 보여줘야 할 데이터
- 이벤트 목록
- 링크
- self(자신), profile(API 문서 링크), get-an-event(이벤트 하나 조회 API 링크), next(다음 페이지-optional), prev(이전 페이지-optional)
- 문서? Spring REST Docs로 만들 예정
이벤트 목록 조회 REST API (로그인 한 상태)
- 응답에 보여줘야 할 데이터
- 이벤트 목록
- 링크
- self(자신), profile(API 문서 링크), get-an-event(이벤트 하나 조회 API 링크), create-new-event(이벤트를 생성할 수 있는 API 링크), next(다음 페이지-optional), prev(이전 페이지-optional)
- 로그인 한 상태? Bearer 헤더에 유효한 AccessToken이 들어있는 경우!
link 정보들은 Spring HATEOAS
로그인 한 상태에서는 create-new-event 링크도 보여줘야 함
하이퍼미디어 정보는 현재 상태에 따라 달라짐 so 현재 상태에 적합한 링크 정보를 줘야 함
(로그인 안 한 상태에서는 create-new-event 안 보여주는게 좋은 ux)
Spring Hateoas 링크 정보들도 현재 상태 상황에 맞게끔 적합한 링크 줘야함
로그인 여부는 액세스 토큰을 사용.
POST /api/events : 이벤트 생성
GET /api/events/{id} : 이벤트 하나 조회
PUT /api/events/{id} : 이벤트 수정
섹션 1. (3) Postman & Restlet
REST API 테스트 클라이언트 애플리케이션 - postman, restlet 사용해 event api 사용해보자
restlet 크롬 플러그인 - https://restlet.talend.com/downloads/current/
~로그인 안 한 상태~
1. 아무런 헤더나 바디 없이 localhost 8080/api에 get 요청 보내보기
200으로 응답 옴, events라는 리소스가 있구나 하고 응답이 옴
리소스 요청 시 링크 입력해야 하는 게 아니라 events의 href에 해당하는 값을 가져와서 그 값으로 호출하면 됨
2. api/events로 get 요청하기 (목록 가져오기 요청)
링크 정보, 페이지 요청에 대한 정보가 나옴
self: 자기 자신의 요청
profile: self-descriptive
profile링크는 /docs/index.html#resources-... 응답 자체에 대한 설명 문서를 향하고 있다
3. 로그인을 위해 액세스 토큰을 받아와보자
post 요청, /oauth/token
Authorization 헤더에
basic assumption으로 client 앱의 id와 패스워드 넘기기(application-properties의 app-security.default-client-id, .default-client-secret)
그리고 body에는 폼 형태로
어던 유저의 계정과 아이디
grant_type으로 어떤 인증 방식을 쓸건지. OAuth 2.0 password 타입 방식을 쓸 것이다
자세한 내용은 나중에 OAuth 2.0 추가할때 설명하겠습니다~
본문에 username, password, grant_type 잘 담아 POST 요청 보내면
엑세스 토큰을 받을 수 있음
token 타입 bearer
refresh_token도 받을 수 있음
scope: 리소스로 어떤걸 할 수 있는지.. 정의하기 나름이라 항상 이런 값이 있는게 아님
4. 목록 조회해보장
HEADERS에 Authorization (아깐 Basic이었는데) "Bearer 엑세스토큰" 주고 GET 요청하면
아까랑 다르게 create-new-event 링크도 보여준다
POST 요청으로 이벤트 만들어볼게요
BODY JSON으로 데이터 보내면
응답 201 created
헤더에는 application.hal+json 나옴
바디에는 새로 만들어진 이벤트의 데이터 보임
LINK 정보 확인 가능
event, self, profile, update(헤이티오스)
5. 토큰 없이 조회 해보기
조회를 하면, 로그인 안한 상태로 조회한 것이니, 업데이트를 할 수 있는 링크는 보이지 않음.
업데이트 할 수 있는 링크도 보임.
이 유저가 이벤트 수정할수도 있으니 업데이트 보여야
6. 다른 유저로 업데이트 토큰 받아와보기
basic으로 받아볼게요
POST. HEADER 폼 편집... 다른 유저로 인증 토큰 받아 올게요
액세스 토큰 새로 받음
다시 GET으로 /api/events/3 bearer로 요청하면?
다른 유저인데 액.토 갖고있음 3번째 event 조회
이때 update 링크를 보여주면 안됨. 수정권한 없으니까
+ Postman으로 동일한 예제 해보기
No Auth 토큰 없: 만들 수 있는 링크 안보임
토큰 받아오기
Authorization에서 client id, client secret (아이디 패스워드)
한후 body에 유저네임 패스워드 그랜트타입 보내면 인증 토큰 받을 수 있음
get에서 Authorization TYPE, 헤더를 Bearer Token으로 - 새로 발급받은 토큰 설정해 요청을 보내면
인증된 사용자니까 만들 수 있는 링크 보임
이벤트 만들때는 POST 요청
Authorization 에 토큰을 주고
Body에 raw로, Text를 JSON으로 준다
요청 샘플 만들면
새로 만들어짐 events/4
토큰 안 넣고 바로 GET 요청 하면 update 안보임
토큰 넣고 GET 요청하면 update 할 수 있는 링크 보임
섹션 1. (4) Project 만들기
스프링 부트 프로젝트 만들기 (Intellij 얼티메이트 버전: Spring Initializer에서 바로 만들 수 있음)
추가할 의존성(Dependency): Web, JPA, HATEOAS, REST Docs, H2, PostgreSQL, Lombok
+ Artifact가 뭘까? https://developer-han.tistory.com/4
+ Maven pom.xml https://velog.io/@jiyounghi/SpringBoot-Maven-project-configuration-required-for-module-name-isnt-available
스프링 부트 핵심 원리
- 의존성 설정 (pom.xml)
- 자동 설정 (@EnableAutoConfiguration)
- 내장 웹 서버 (의존성과 자동 설정의 일부)
- 독립적으로 실행 가능한 JAR (pom.xml의 플러그인)
섹션 1. (5) 이벤트 도메인 구현
이벤트라는 도메인 클래스 만들어야 함
events 패키지 만들고 Event 클래스 만듬
이벤트 name, description, beginEnrollmentDateTime, closeEnrollmentDateTime, beginEventDateTime, endEventDateTime, location(optional), basePrice(optional), maxPrice(optional), limitOfEnrollment
추가: id, offline, free, eventStatus
EventStatus enum 만듬: DRAFT, PUBLISHED, BEGAN_ENROLLMENT;
도메인 대한 빌더랑 생성자로 자바 빈 스펙 맞춰서 생성할 수 있는지 (기본 생성자 있어야 하고 getter setter 있어야하고)
Test... 왜 import org.junit.Test; 가 안됐을까? import org.junit.jupiter.api.Test; 이렇게 했더니 됨...ㅎㅎ
annotation processing
target 폴더 왜 없지? 톱니바퀴 아이콘 > Tree Appearance > show excluded files
Executing pre-compile tasks...무한 로딩 이슈
targets 폴더에서 Event.class 열면 모든 파라미터 기본 생성자, static 클래스 빌더, 등등 어마어마한 코드 생성됨
builder로 손쉽게 객체 만들 수 있음. 내가 입력하는 값이 뭔지 알 수 있어 좋다.
Lombok builder is missing non nullable fields 에러 https://velog.io/@eodnjs568/Error-Builder-Annotation-%EA%B8%B0%EB%B3%B8-%EC%9E%90%EB%A3%8C%ED%98%95-%EA%B4%80%EB%A0%A8-%EC%97%90%EB%9F%AC-Lombok-%EB%A1%AC%EB%B3%B5
- Long으로 변경해 해결하고 싶은데... 우선 보류
빌더 추가하면 public 기본 생성자 생성 x라 Event.java에서 NoArgsConstructor 같은거 추가
EqualsAndHashCode(of="id") 한 이유는 스택 오버플로우 방지
account같은 다른 엔티티와의 묶음을 만드는건 좋지않음
스프링의 Meta Annotation
근데 Lombok 은 안됨
@Data: Entity에 하면 안됨 상호참조하면 스택오버플로우 위험.
섹션 1. (6) 이벤트 비즈니스 로직
# Event 생성 API
- 다음의 입력 값을 받는다.
- name
- description
- beginEnrollmentDateTime
- closeEnrollmentDateTime
- beginEventDateTime
- endEventDateTime
- location (optional) //이게 없으면 온라인 모임
- basePrice (optional)
- maxPrice (optional)
- limitOfEnrollment
# basePrice와 maxPrice 경우의 수와 각각의 로직
basePrice=0, maxPrice=100: 선착순 등록 (입장료)
basePrice=0, maxPrice=0: 무료
basePrice=100, maxPrice=0: 무제한 경매 (높은 금액 낸 순으로 등록)
basePrice=100, maxPrice=200: 제한가 선착순 등록 (처음부터 200 내면 선등록. 200이하 높은 금액 순으로.)
- 결과값
- id //event를 고유하게 식별할 수 있는 식별자
- name
- ...
- eventStatus: DRAFT, PUBLISHED, ENROLLMENT_STARTED, ... //기본 상태, 공개 상태, 접수 시작 상태
- offline //location이 있으면 offline, 없으면 online
- free //유료 or 무료
- _links //여러가지 HATEOAS정보, 하이퍼미디어 링크들 응답으로 보내줘야 함
- profile (for the self-descriptive message) //이 메세지 자체에 대한 정보를 담고 있는 문서 쪽으로 링크를 담고 있어야 함
- self //자기 자신, 이 이벤트를 조회할 수 있는 링크
- publish
- ...
이렇게 동작하는 API를 이 다음번 강좌부터 구현해볼 것!
'Study > Java, Spring' 카테고리의 다른 글
[GDSC Study] 스프링 기반 REST API 개발 - 3주차 | 섹션 3. HATEOAS와 Self-Describtive Message 적용 (0) | 2023.11.20 |
---|---|
[GDSC Study] 스프링 기반 REST API 개발 - 2주차 | 섹션 2. 이벤트 생성 API 개발 (0) | 2023.11.14 |
[백엔드] 스터디 - Spring Boot 어노테이션 몇가지 정리 (0) | 2023.05.15 |
[백엔드] 스터디 2주차 - Java (4) 배열, 버블 정렬, Arrays 클래스, Random 클래스 (0) | 2023.04.03 |
[백엔드] 스터디 1주차 - Java (3) 연산자, 조건, 반복문 (0) | 2023.03.27 |