doohong's blog

Study & Development


  • 홈

  • About

  • 태그

  • 카테고리

  • 아카이브

REST API 만들기-8

작성일 2019-01-31 | Edited on 2019-03-21 | In RESTAPI | 댓글:

스프링 기반 REST API 개발 -백기선님 인프런 강좌를 보고 작성하였습니다.

입력값이 이상한 경우 Bad Request 응답

EventController

1
2
3
4
eventValidator.validate(eventDto,errors);
if(errors.hasErrors()){
return ResponseEntity.badRequest().body(errors);
}

입력값이 이상한 경우 Bad Request 응답을 받기위해 컨트롤러 응답을 넣는것처럼
body에 errors객체를 넣으면 안된다!

이유는 event 객체는 자바빈 스펙을 준수한 객체이기 때문에 ObjectMapper가 BeanSerializer를 이용하여 json으로 변환이 가능하다.

하지만 errors 객체는 자바빈 스펙을 준수한 객체가 아니다. 그렇기 때문에 json으로 변화를 하려다 에러가 발생한다.

ErrorsSerializer

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
32
33
34
35
36
37
public class ErrorsSerializer extends JsonSerializer<Errors> {

@Override
public void serialize(Errors errors, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
gen.writeStartArray();
errors.getFieldErrors().stream().forEach(e->{

try {
gen.writeStartObject();
gen.writeStringField("field",e.getField());
gen.writeStringField("objectName",e.getObjectName());
gen.writeStringField("code",e.getCode());
gen.writeStringField("defaultMessage",e.getDefaultMessage());
Object rejectedValue = e.getRejectedValue();
if(rejectedValue !=null){
gen.writeStringField("rejectedValue",rejectedValue.toString());
}
gen.writeEndObject();
} catch (IOException e1) {
e1.printStackTrace();
}
});

errors.getGlobalErrors().forEach(e->{
try {
gen.writeStartObject();
gen.writeStringField("objectName",e.getObjectName());
gen.writeStringField("code",e.getCode());
gen.writeStringField("defaultMessage",e.getDefaultMessage());
gen.writeEndObject();
} catch (IOException e1) {
e1.printStackTrace();
}
});
gen.writeEndArray();
}
}

errors는 FieldErrors와 GlobalErrors가 있으며 json object를 두개 다 이렇게 채워주면 됩니다.

ErrorSerializer을 만들고 나서 ObjectMapper에 등록을 해줘야 하는데 @JsonComponent 어노테이션을 이용하여 등록할 수 있습니다.

Errors라는 객체를 serializer 할때 ErrorSerializer을 사용하게 됩니다.

이렇게 하여 body(errors)를 컨트롤러에서 넣으면 errors를 응답으로 주게 됩니다.

REST API 만들기-7

작성일 2019-01-30 | Edited on 2019-03-20 | In RESTAPI | 댓글:

스프링 기반 REST API 개발 -백기선님 인프런 강좌를 보고 작성하였습니다.

입력값이 이상한 경우 Bad Request 처리-2

EventValidator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Component
public class EventValidator {
public void validate(EventDto eventDto, Errors errors){
if(eventDto.getBasePrice()>eventDto.getMaxPrice()&& eventDto.getMaxPrice()>0){
errors.rejectValue("basePrice","wrongValue","BasePrice is wrong.");
errors.rejectValue("maxPrice","wrongValue","MaxPrice is wrong.");
errors.reject("wrongPrices","Values to prices are wrong");
}

LocalDateTime endEventDateTime =eventDto.getEndEventDateTime();
if(endEventDateTime.isBefore(eventDto.getBeginEventDateTime()) ||
endEventDateTime.isBefore(eventDto.getCloseEnrollmentDateTime())||
endEventDateTime.isBefore(eventDto.getBeginEnrollmentDateTime())){
errors.rejectValue("endEventDateTime","wrongValue","endEventDateTime is wrong.");
}
// TODO beginEventDateTime
// TODO CloseEnrollmentDateTime
}
}

EventValidator클래스를 만들어 준 후 검증 할 값들을 어떻게 검증할 것인지를 작성하고 검증에 실패 할경우 에러를 담아 줍니다.

EventController

작성한 validator는 빈으로 등록했기 때문에 사용하기 위해 컨트롤러에 생성자에 넣어 사용합니다.

1
2
3
4
5
6
private final EventValidator eventValidator;
public EventController(EventRepository eventRepository, ModelMapper modelMapper, EventValidator eventValidator){
this.eventRepository = eventRepository;
this.modelMapper = modelMapper;
this.eventValidator = eventValidator;
}

이렇게 컨트롤러에서 주입 받을 수 있습니다.

1
2
3
4
eventValidator.validate(eventDto,errors);
if(errors.hasErrors()){
return ResponseEntity.badRequest().build();
}

코드 추가하여 잘못된 값에 대한 검증을 할 수 있습니다.

REST API 만들기-6

작성일 2019-01-29 | Edited on 2019-03-19 | In RESTAPI | 댓글:

스프링 기반 REST API 개발 -백기선님 인프런 강좌를 보고 작성하였습니다.

입력값이 이상한 경우 Bad Request 처리-1

EventControllerTests

1
2
3
4
5
6
7
8
public void createEvent_Bad_request_Empty_Input() throws Exception { //필요 이상 입력값 입력시 400오류
EventDto eventDto = EventDto.builder().build();

this.mockMvc.perform(post("/api/events")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(this.objectMapper.writeValueAsString(eventDto)))
.andExpect(status().isBadRequest());
}

빈 값을 보내는 테스트 케이스를 하나 만듭니다.
이 테스트는 빈 값을 보내기 때문에 BadRequest가 나오길 바라지만 테스트가 깨지게 됩니다.

하지만 입력값이 이상하지만 보내는 필드가 같기 때문에 요청이 처리가 되어버린다.

이러한 경우 @Valid와 BindingResult를 이용한다.

EventController

1
2
3
public ResponseEntity createEvent(@RequestBody @Valid EventDto eventDto,Errors errors){
...
}

컨트롤러에 EventDto에 Valid어노테이션을 추가하면 EventDto에 바인딩 할때 검증을 할 수 있습니다.
검증한 결과는 Errors에 담기게 됩니다.

EventDto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class EventDto {
@NotEmpty
private String name;
@NotEmpty
private String description;
@NotNull
private LocalDateTime beginEnrollmentDateTime;
@NotNull
private LocalDateTime closeEnrollmentDateTime;
@NotNull
private LocalDateTime beginEventDateTime;
@NotNull
private LocalDateTime endEventDateTime;
private String location; // (optional) 이게 없으면 온라인 모임
@Min(0)
private int basePrice; // (optional)
@Min(0)
private int maxPrice; // (optional)
@Min(0)
private int limitOfEnrollment;
}

@NotEmpty 와 NotNull을 이용하여 검증하여 줍니다.

EventController

다시 컨트롤러로 이동하여 아래 문장을 추가하여줍니다.

1
2
3
if(errors.hasErrors()){
return ResponseEntity.badRequest().build() ;
}

검증에 에러가 존재한다면 BadRequest를 응답으로 주게 됩니다.
이렇게 테스트 케이스는 성공을 하게 됩니다.

REST API 만들기-5

작성일 2019-01-28 | Edited on 2019-03-18 | In RESTAPI | 댓글:

스프링 기반 REST API 개발 -백기선님 인프런 강좌를 보고 작성하였습니다.

입력값 이외에 에러 발생

저번 포스트에는 입력값 이외에 값이 들어오면 무시하였지만 이번 포스팅에서는 에러를 발생시키는 방법에대해 포스팅 하겠습니다.

EventControllerTests

테스트에 입력값 이외에 값을 넣는 테스트를 작성합니다.

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
public void createEvent_Bad_request() throws Exception { //필요 이상 입력값 입력시 400오류
Event event = Event.builder()
.id(100)
.name("Spring")
.description("REST API Development with Spring")
.beginEnrollmentDateTime(LocalDateTime.of(2018,11,23,14,22))
.closeEnrollmentDateTime(LocalDateTime.of(2018,11,24,14,22))
.beginEventDateTime(LocalDateTime.of(2018,11,25,14,22))
.endEventDateTime(LocalDateTime.of(2018,11,26,14,22))
.basePrice(100)
.maxPrice(200)
.limitOfEnrollment(100)
.location("강남역 D2 스타텁 팩토리")
.free(true)
.offline(false)
.eventStatus(EventStatus.PUBLISHED)
.build();

mockMvc.perform(post("/api/events")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaTypes.HAL_JSON)
.content(objectMapper.writeValueAsString(event)))
.andDo(print())
.andExpect(status().isBadRequest())
;
}

application.properties

application.properties에 아래 한줄을 추가해 줍니다.

1
spring.jackson.deserialization.fail-on-unknown-properties=true

json을 오브젝트로 변환하는 과정을 deserialization이라고 하는데
변환도중에 unknown-properties가 있으면 실패하게 하라 는 뜻입니다.

결과

이렇게 하면 받기로 한 값 이외에 id, free, offline 값 등을 같이 넘기기 때문에
Bad Request 400 에러가 발생하게 됩니다.

REST API 만들기-4

작성일 2019-01-27 | Edited on 2019-02-15 | In RESTAPI | 댓글:

스프링 기반 REST API 개발 -백기선님 인프런 강좌를 보고 작성하였습니다.

입력값 제한하기

현재 API는 입력값으로 id 또는 입력 받은 데이터를 가지고 계산해야하는 값까지도 입력으로 줄 수가 있습니다.

이번 포스팅에서는 입력으로 받으면 안되는 값들을 EventDTO를 적용하여 제한하는 방법에 대해서 알아보겠습니다.

EventDTO

Event 클래스에 어노테이션을 추가해서 DTO로 분리하는것과 같은 기능을 할 수는 있지만, 그런경우에 도메인 클래스에 너무 많은 어노테이션이 추가 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
@Builder @NoArgsConstructor @AllArgsConstructor @Data
public class EventDto {
private String name;
private String description;
private LocalDateTime beginEnrollmentDateTime;
private LocalDateTime closeEnrollmentDateTime;
private LocalDateTime beginEventDateTime;
private LocalDateTime endEventDateTime;
private String location; // (optional) 이게 없으면 온라인 모임
private int basePrice; // (optional)
private int maxPrice; // (optional)
private int limitOfEnrollment;
}

받기로 한 값들만 가지고 EventDTO 클래스를 만듭니다.

ModelMapper

입력 타입을 DTO로 바꿧으니 DTO를 다시 Event 객체로 변경해주어야 Event 타입으로 바꿔 주어야 EventRepository 를 쓸수 있습니다.

EventDTO 객체를 Event객체로 바꿔주려면 직접 옮기는 방법도 있지만 ModelMapper 를 사용해 쉽게 바꿔줄수 있습니다.

pom.xml

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.modelmapper/modelmapper -->
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.1</version>
</dependency>

빈등록

1
2
3
4
@Bean
public ModelMapper modelMapper(){
return new ModelMapper();
}

EventController

1
2
3
4
5
6
7
8
9
10
 private final ModelMapper modelMapper;

public EventController(EventRepository eventRepository, ModelMapper modelMapper){
this.eventRepository = eventRepository;
this.modelMapper = modelMapper;
}
```
생성자를 통해 ModelMapper 주입을 받습니다.
```java
Event event = modelMapper.map(eventDto,Event.class);

이렇게 ModelMapper를 통해 Event 객체로 변환할 수 있습니다.

EventControllerTests

테스트에서 더이상 테스트에서 만든 Event객체를 쓰지 않기 때문에 Mockito를 사용해서 Stubbing 하는 기능이 적용되지 않습니다.

그래서 이제 @WebMvcTest 어노테이션을 지우고 @SpringBootTest 와 SpringBootTest에서 MockMvc를 쓰기위해@AutoConfigureMock0Mvc 를 추가하여줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
mockMvc.perform(post("/api/events")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaTypes.HAL_JSON)
.content(objectMapper.writeValueAsString(event)))
.andDo(print())
.andExpect(status().isCreated())
.andExpect(jsonPath("id").exists())
.andExpect(header().exists(HttpHeaders.LOCATION))
.andExpect(header().string(HttpHeaders.CONTENT_TYPE,MediaTypes.HAL_JSON_UTF8_VALUE))
.andExpect(jsonPath("id").value(Machers.not(10)))
.andExpect(jsonPath("free").value(Machers.not(true)))
.andExpect(jsonPath("eventStatus").value(Machers.not(true)));

id, free, eventStatus 같은 입력으로 받아서 안되는 값들이 잘 제한됬는지 이렇게 코드를 추가하여 확인할 수 있습니다.

REST API 만들기-3

작성일 2019-01-26 | Edited on 2019-02-13 | In RESTAPI | 댓글:

스프링 기반 REST API 개발 -백기선님 인프런 강좌를 보고 작성하였습니다.

event 객체를 실제 DB에 저장 시키기

Event 클래스 수정

1
2
3
4
5
6
7
8
9
10
@Builder @AllArgsConstructor @NoArgsConstructor
@Getter @Setter @EqualsAndHashCode(of="id")
@Entity
public class Event {

@Id @GeneratedValue
private Integer id;
...
@Enumerated(EnumType.STRING) //string을 더 권장
private EventStatus eventStatus = EventStatus.DRAFT;

Event 클래스 각 위치에 @Entity @ID @GeneratedValue @Enumerated 어노테이션을 추가해준다.

@Entity

  • 이 어노테이션은 해당 클래스가 엔티티임을 알리기 위해 사용합니다.
  • 애플리케이션이 실행이 될 때 엔티티 자동검색을 통하여 이 어노테이션이 선언 된 클래스들은 엔티티 빈으로 등록합니다.

@Id

  • 엔티티빈의 기본키를 의미합니다. 이 어노테이션은 하나의 엔티티에는 반드시 하나가 존재해야 합니다.

@GeneratedValue

  • 데이터베이스에 의해 자동으로 생성된 값이라는 의미입니다.
  • 즉, 프로그램 상에서 조작된 데이터가 아닌, 실제 데이터베이스에 데이터가 영속(저장)될 때 생성되는 값입니다.
    @Enumerated(EnumType.STRING)
  • EnumType.ORDINAL을 이용하면 Enum 순서 값을 DB에 저장합니다
  • EnumType.STRING을 이용하면 Enum 필드가 테이블에 저장시 숫자형인 1,2,3이 아닌, Enum의 name이 저장됩니다.

    EventRepository 인터페이스 작성

    1
    2
    3

    public interface EventRepository extends JpaRepository<Event,Integer> {
    }

EventController 클래스 수정

1
2
3
4
5
6
7
8
9
10
11
12
@RequestMapping(value ="/api/events", produces = MediaTypes.HAL_JSON_UTF8_VALUE )
public class EventController{
public EventController(EventRepository eventRepository){
this.eventRepository = eventRepository;
}
@PostMapping
public ResponseEntity createEvent(@RequestMapping Event event){
Event newEvent = this.eventRepository.save(event); //JPA를 이용한 저장
URI createdUri = linkTo(EventController.class).slash(newEvent.getId()).toUri(); //DB에 저장되며 생성된 ID값을 이용
return ResponseEntity.created(createdUri).body(event);
}
}

EventControllerTests 클래스 수정

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
@RunWith(SpringRunner.class)
@WebMvcTest //web과 관련된 빈들이 등록 됨
public class EventControllerTests {
@MockBean
EventRepository eventRepository;

@Test
public void createEvent() throws Exception{
...

event.setId(10);
Mockito.when(eventRepository.save(event)).thenReturn(event);

mockMvc.perform(post("/api/events")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaTypes.HAL_JSON)
.content(objectMapper.writeValueAsString(event)))
.andDo(print())
.andExpect(status().isCreated())
.andExpect(jsonPath("id").exists())
.andExpect(header().exists(HttpHeaders.LOCATION))
.andExpect(header().string(HttpHeaders.CONTENT_TYPE,MediaTypes.HAL_JSON_UTF8_VALUE));

...
}

MockBean

  • MockBean으로 만든 eventRepository는 Mock객체이기때문에 save를 하여도 리턴 값이 null이다.
  • 그렇기 때문에 Mockito를 사용해서 Stubbing 해주었다.

REST API 만들기-2

작성일 2019-01-25 | Edited on 2019-02-13 | In RESTAPI | 댓글:

스프링 기반 REST API 개발 -백기선님 인프런 강좌를 보고 작성하였습니다.

Event 생성 API

TDD를 위한 테스트 작성

테스트 할것
입력값들을 전달하면 JSON 응답으로 201이 나오는지 확인.

  • Location 헤더에 생성된 이벤트를 조회할 수 있는 URI 담겨 있는지 확인.
  • id는 DB에 들어갈 때 자동생성된 값으로 나오는지 확인

    EventControllerTest 클래스 생성

    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
    32
    33
    34
    @RunWith(SpringRunner.class)
    @WebMvcTest //web과 관련된 빈들이 등록 됨
    public class EventControllerTests {

    @Autowired
    MockMvc mockMvc; // 가짜 요청을 만들어 DispatcherServlet 에게 보내고 응답을 확인(웹서버를 띄우진 않음)

    @Autowired
    ObjectMapper objectMapper; //자동으로 빈으로 등록해줌
    @Test
    public void createEvent(){
    Event event = Event.builder()
    .name("Spring")
    .description("REST API Development with Spring")
    .beginEnrollmentDateTime(LocalDateTime.of(2018,11,23,14,22))
    .closeEnrollmentDateTime(LocalDateTime.of(2018,11,24,14,22))
    .beginEventDateTime(LocalDateTime.of(2018,11,25,14,22))
    .endEventDateTime(LocalDateTime.of(2018,11,26,14,22))
    .basePrice(100)
    .maxPrice(200)
    .limitOfEnrollment(100)
    .location("강남역 D2 스타텁 팩토리")
    .build();

    mockMvc.perform(post("/api/events")
    .contentType((MediaType).APPLICATION_JSON_UTF8)
    .accepot(MediaTypes.HAL_JSON)
    .content(objectMapper.writeValueAsString(event)))
    .andDo(print())
    .andExpect(status().isCreated()
    .andExpect(jsonPath("id").exists());
    }

    }

@WebMvcTest

  • MockMvc 빈을 자동 설정
  • 웹 관련 빈만 등록.(슬라이스)

MockMvc

  • 스프링 MVC 테스트 핵심클래스
  • 웹 서버를 띄우지 않고도 스프링 MVC(DispatcherServlet)가 요청을 처리하는 과정을 확인할 수 있기 때문에 컨트롤러 테스트용으로 자주 쓰임

ObjectMapper

  • 스프링 부트에 mapping Jackson이 의존성주입이 되있을경우 자동 빈등록

objectMapper.writeValueAsString(event)

  • 객체를 JSON으로 변환!

EventController 클래스 작성

1
2
3
4
5
6
7
8
9
10
@RequestMapping(value ="/api/events", produces = MediaTypes.HAL_JSON_UTF8_VALUE )
public class EventController{

@PostMapping
public ResponseEntity createEvent(@RequestMapping Event event){
URI createdUri = linkTo(EventController.class).slash("{id}").toUri();
event.setID(10); //우선 임의로 아이디값을 준다.
return ResponseEntity.created(createdUri).body(event);
}
}

테스트를 진행하면 정상적으로 실행이 된다.

REST API 만들기-1

작성일 2019-01-24 | Edited on 2019-02-12 | In RESTAPI | 댓글:

스프링 기반 REST API 개발 -백기선님 인프런 강좌를 보고 작성하였습니다.

추가할 의존성 및 JDK 버전

  • Web
  • JPA
  • HATEOAS
  • REST Docs
  • H2
  • PostgreSQL
  • Lombok
  • JDK 11

    입력으로 받을 값들

  • name
  • description
  • beginEnrollmentDateTime
  • closeEnrollmentDateTime
  • beginEventDateTime
  • endEventDateTime
  • location (optional) 이게 없으면 온라인 모임
  • basePrice (optional)
  • maxPrice (optional)
  • limitOfEnrollment
basePrice maxPrice 설명
0 100 선착순등록
0 0 무료
100 0 무제한 경매(높은 금액 낸 사람이 등록)
100 200 제한가 선착순 등록

결과로 줄 값들

  • name
  • …
  • eventStatus: DRAFT, PUBLISHED, ENROLLMENT_STARTED, …
  • offline
  • free
  • _links
    • profile (for the self-descriptive message)
    • self
    • publish

      시작하기

      Event 클래스 만들기.

      패키지를 하나 만들고 그안에 Event 클래스를 생성한다.
      이벤트 클래스는 나중에 DB의 테이블과 매칭될 Entity 클래스 이다.
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      public class Event {
      private String name;
      private String description;
      private LocalDateTime beginEnrollmentDateTime;
      private LocalDateTime closeEnrollmentDateTime;
      private LocalDateTime beginEventDateTime;
      private LocalDateTime endEventDateTime;
      private String location;
      private int basePrice;
      private int maxPrice;
      private int limitOfEnrollment;
      }

EventStatus enum 클래스 생성

1
2
3
public enum EventStatus {
DRAFT, PUBLISHED, BEGEAN_ENROLLMENT;
}

Event 클래스에 lombok 어노테이션 추가

1
2
@Builder @AllArgsConstructor @NoArgsConstructor
@Getter @Setter @EqualsAndHashCode(of="id")

Test 클래스를 만들어 junit 테스트

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
@Test
public void builder(){
Event event = Event.builder()
.name("inflearn")
.description("rst API")
.build();
assertThat(event).isNotNull();

}

@Test
public void JavaBean(){
//Given
String name = "Event";
String description = "Spring";

//When
Event event = new Event();
event.setName("Event");
event.setDescription("Spring");

//Then
assertThat(event.getName()).isEqualTo(name);
assertThat(event.getDescription()).isEqualTo(description);
}

Lombok 과 AssertJ의 추가적인 설명

Lombok
AssertJ

[Spring-library]AssertJ란?

작성일 2019-01-23 | Edited on 2019-01-25 | In Spring | 댓글:

AsertJ란?

java test를 위해 좀 더 풍부한 문법을 제공하고 메서드 체이닝을 통해 직관적인 테스트 흐름을 작성할 수 있도록 개발된 오픈소스 라이브러리이다.

최근 junit에 필수로 사용되고 있는 추세이다.

공식홈페이지

시작하기

라이브러리 의존성 설정

Maven

1
2
3
4
5
6
7
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<!-- use 2.9.1 for Java 7 projects -->
<version>3.11.1</version>
<scope>test</scope>
</dependency>

Gradle

1
testCompile("org.assertj:assertj-core:3.11.1")

또는 Java 7 프로젝트의 경우 버전 2.9.1

1
testCompile("org.assertj:assertj-core:2.9.1")

AssertJ 메소드 임포트

1
import static org.assertj.core.api.Assertions.*;

실제 사용

1
assertThat(objectUnderTest). // code completion -> assertions specific to objectUnderTest

모든 테스트 코드는 assertThat() 메소드에서 시작한다.

###문자열 테스트

1
2
3
4
5
6
7
8
assertThat("Hello, world! Nice to meet you.") // 주어진 "Hello, world! Nice to meet you."라는 문자열은
.isNotEmpty() // 비어있지 않고
.contains("Nice") // "Nice"를 포함하고
.contains("world") // "world"도 포함하고
.doesNotContain("ZZZ") // "ZZZ"는 포함하지 않으며
.startsWith("Hell") // "Hell"로 시작하고
.endsWith("u.") // "u."로 끝나며
.isEqualTo("Hello, world! Nice to meet you."); // "Hello, world! Nice to meet you."과 일치합니다.

숫자 테스트

1
2
3
4
5
6
7
assertThat(3.14d) // 주어진 3.14라는 숫자는
.isPositive() // 양수이고
.isGreaterThan(3) // 3보다 크며
.isLessThan(4) // 4보다 작습니다
.isEqualTo(3, offset(1d)) // 오프셋 1 기준으로 3과 같고
.isEqualTo(3.1, offset(0.1d)) // 오프셋 0.1 기준으로 3.1과 같으며
.isEqualTo(3.14); // 오프셋 없이는 3.14와 같습니다

REST API란

작성일 2019-01-23 | Edited on 2019-01-28 | In RESTAPI | 댓글:

스프링 기반 REST API 개발 -백기선님 인프런 강좌를 보고 작성하였습니다.

API

  • Application Programming Interface
  • 응용 프로그램에서 사용할 수 있도록, 운영 체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스를 뜻한다.

REST

  • REpresentational State Treansfer
  • 인터넷 상의 시스템 간의 상호 운용성(Interoperability)을 제공하는 방법중 하나
  • 시스템 제각각의 독립적인 진화를 보장하기 위한 방법
  • REST API : REST 아키텍처 스타일을 따르는 API

그런 REST API로 괜찮은가

그런 REST API로 괜찮은가 - 이응준님 강연을 보고 작성하였습니다.

  • 오늘날 대부분의 “REST API”는 사실 REST를 따르지 않고 있다.
  • REST의 제약조건 중에서 특히 Self-descriptive와 HATEOAS를 잘 만족하지 못한다.
  • REST를 따르겠다면, Self-descriptive와 HATEOAS를 만족시켜야한다.
    • Self-descriptive는 custom media type이나 profile link relation 등으로 만족시킬 수 있다.
    • HATEOAS는 HTTP 헤더나 본문에 링크를 담아 만족시킬 수 있다.

      Self descriptive message

  • 메세지 스스로 메세지에 대한 설명이 가능해야 한다.
    • 이렇지 않으면 API문서를 항상 만들어야 한다. API만 보고 의미를 알 수 없기 때문이다.

Self descriptive message를 달성하기 위한 방법

  1. 미디어 타입을 IANA에 등록하고 그 미디어 타입을 리소스 리턴할 때 Content-Type으로 사용한다.
  2. ProFile 의미가 뭔지 정보가 담긴 문서 링크 헤더를 추가한다.

HATEOAS

  • 하이퍼미디어(링크)를 통해 애플리케이션 상태 변화가 가능해야 하며 링크 정보를 동적으로 바꿀 수 있다.
    • HATEOS는 애플리케이션 상태 전이의 late binding을 가능하게 하기 때문에 필요하다.
      어디서 어디로 전이가 가능한지 미리 결정되지 않는다. 어떤 상태로 전이가 완료되고 나서야 그 다음 전이될 수 있는 상태가 결정된다. 링크는 동적으로 변경될 수 있다. 언제나 서버가 마음대로 바꿀 수 있음.

      HATEOAS를 달성하기 위한 방법

  1. 데이터 링크 제공
  2. HTTP 헤더에 Location, Link를 활용하는 방법
1…3456
박주홍

박주홍

53 포스트
11 카테고리
112 태그
GitHub E-Mail FB Page Instagram
© 2019 박주홍
Powered by Hexo v3.8.0
|
Theme – NexT.Muse v6.7.0