이 글은 Armeria 1.16.0 Version을 기준으로 작성되었습니다.
이전 글 보러 가기
[Java] Armeria - Restful API 서버 구축하기 - (1) Application 생성
[Java] Armeria - Restful API 서버 구축하기 - (2) 도메인서비스 연동
이번 글에서는 Armeria Restful API Server/Client에서 사용되는 흥미로운 Annotation들에 대해서 다뤄보려고 합니다
@ExceptionHandler
Armeria Service 내부 Class, Interface, Enum, method에 사용할 수 있는 어노테이션입니다.
해당 어노테이션을 명시할 경우, 명시된 구역 내에서 발생하는 Exception들에 대한 처리가 가능합니다.
ExceptionHandler 어노테이션은 Armeria에서 제공하는 인터페이스인 ExceptionHandlerFunction의 구현체를 사용합니다.
ExceptionHandler 어노테이션 사용 예
@ExceptionHandler(NoSuchElementExceptionHandler.class) // Exception Handler
@Get("/book/:id")
public HttpResponse findById(@Param long id) {
Book book = BookRepository.findById(id);
if (book == null) {
throw new NoSuchElementException(id + " book is not found.");
}
return HttpResponse.ofJson(book);
}
NoSuchElementExceptionHandler.class
public class NoSuchElementExceptionHandler implements ExceptionHandlerFunction {
@Override
public HttpResponse handleException(ServiceRequestContext ctx, HttpRequest req, Throwable cause) {
if (cause instanceof NoSuchElementException) {
return HttpResponse.of(HttpStatus.NOT_FOUND);
}
return ExceptionHandlerFunction.fallthrough();
}
}
ExceptionHandlerFunction 인터페이스는 다른 Handler에게 제어권을 넘길 수 있는 fallthrough 라는 메서드를 제공합니다
우선순위에 기반한 Handler 명시로 자연스러운 Exception Handling 흐름을 구현할 수 있습니다
@ResponseConverters
Java의 Converter 인터페이스와 유사하게 응답 데이터에 대한 후처리를 진행할 수 있는 어노테이션입니다
여기서 눈 여겨볼 점은 Response에 대한 Converter를 여러 개 명시하여, 원하는 Converting 작업이 가능하다는 것입니다
ResponseConverters 어노테이션은 ResponseConverter 어노테이션의 배열을 포함하며,
ResponseConverter 어노테이션은 ResponseConverterFunction 인터페이스의 구현체를 사용합니다
ResponseConverters 어노테이션 사용 예
@ResponseConverters({
@ResponseConverter(BookResponseConverter.class),
@ResponseConverter(BookDeletedFailedConverter.class)
})
@Delete("/book/:id")
public HttpResponse deleteById(@Param long id) {
Book book = BookRepository.deleteById(id);
return HttpResponse.ofJson(
Objects.requireNonNullElseGet(book, () ->
new BookDeleteFailedResponse("failed",
"this is cause")));
}
BookResponseConverter.class
public class BookResponseConverter implements ResponseConverterFunction {
private final ObjectMapper mapper = new ObjectMapper();
@Override
public HttpResponse convertResponse(ServiceRequestContext ctx, ResponseHeaders headers,
@Nullable Object result, HttpHeaders trailers) throws Exception {
if (result instanceof Book) {
return HttpResponse.of(HttpStatus.OK,
MediaType.JSON_UTF_8,
"%s", mapper.writeValueAsString(result),
trailers);
}
return ResponseConverterFunction.fallthrough();
}
}
ResponseConverterFunction 인터페이스 역시 fallthrough 메서드를 통해 응답 데이터에 대한 자연스러운 Converting 흐름 구현이 가능합니다
@Produces - @Consumes
Class, Interface, method에 사용하는 어노테이션으로
Http 통신의 MediaType을 명시할 수 있습니다
Produces, Consumes 어노테이션 사용 예
@Produces(MediaTypeNames.JSON)
@Consumes(MediaTypeNames.JSON)
@Post("/book")
public HttpResponse createBook(@RequestObject Book book) {
return HttpResponse.ofJson(BookRepository.createUpdateBook(book));
}
어노테이션의 Value 값으로는 의존성 Life Cycle을 고려해
armeria.common 패키지에서 제공하는 MediaTypeNames를 사용하였습니다
@ProducesJson - @ConsumesJson
Json 데이터를 주로 사용하는 Http 통신에서, Produces, Consumes 어노테이션으로 직접 명시할 필요 없이 MediaType은 Json을 사용한다는 명시적 어노테이션입니다.
ProducesJson은 @Produces("application/json; charset=utf-8") 과 같습니다
ProducesJson, ConsumesJson 어노테이션 사용 예
@ProducesJson
@ConsumesJson
@Post("/book")
public HttpResponse createBook(@RequestObject Book book) {
return HttpResponse.ofJson(BookRepository.createUpdateBook(book));
}
ProducesJson Annotation
/**
* An alias for {@code @Produces(MediaTypeNames.JSON_UTF_8)}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Produces(MediaTypeNames.JSON_UTF_8)
public @interface ProducesJson {
}
@Param
Http 통신 PathVariable의 Key 값을 명시적으로 선언하는 곳에도 사용되고,
Request Object의 각 field 및 생성자에도 사용할 수 있는 어노테이션입니다
Param 어노테이션 사용 예
@Get("/book/:id")
public HttpResponse findById(@Param long id) { }
Request Object
public class Book {
@Param("id")
private final long id;
@Param("name")
@Default("default name") //default 값 명시
private final String name;
@Param("page")
private final long page;
}
@Blocking
Blocking Task 수행이 요구되는 Class 혹은 method에 사용할 수 있는 어노테이션으로
해당 어노테이션이 사용된 부분에서는 Event Loop Thread 대신 Blocking Thread 동작을 수행할 수 있습니다
Blocking 어노테이션 예
@Blocking
@Delete("/book/:id")
public HttpResponse deleteById(@Param long id) {
Book book = BookRepository.deleteById(id);
return HttpResponse.ofJson(
Objects.requireNonNullElseGet(book, () ->
new BookDeleteFailedResponse("failed",
"this is cause")));
}
Armeria에서 제공하는 Annotation에 대한 Reference는 이곳에서 확인할 수 있습니다
'개발 > Armeria' 카테고리의 다른 글
[Java] Armeria Documentation Service 생성하기 (0) | 2022.07.04 |
---|---|
[Java] Armeria - Restful API 서버 구축하기 - (2) 도메인서비스 연동 (0) | 2022.06.29 |
[Java] Armeria - Restful API 서버 구축하기 - (1) Application 생성 (0) | 2022.06.29 |
댓글