Існує кілька випадків використання для встановлення кодів статусу HTTP у веб-службі REST, і принаймні один не був достатньо задокументований у існуючих відповідях (тобто, коли ви використовуєте автоматичну магічну серіалізацію JSON / XML за допомогою JAXB, і ви хочете повернути об'єкт, який підлягає серіалізації, але також код статусу, відмінний від типового 200).
Тому дозвольте спробувати перерахувати різні випадки використання та рішення для кожного з них:
1. Код помилки (500, 404, ...)
Найпоширеніший випадок використання, коли потрібно повернути код статусу, інший, ніж 200 OK
коли виникає помилка.
Наприклад:
- сутність запитується, але вона не існує (404)
- запит семантично невірний (400)
- користувач не має права (401)
- є проблема з підключенням до бази даних (500)
- тощо.
а) Киньте виняток
У цьому випадку я думаю, що найчистіший спосіб вирішити проблему - це викинути виняток. Цей виняток буде оброблятися тим ExceptionMapper
, що перетворить виняток у відповідь з відповідним кодом помилки.
Ви можете використовувати за замовчуванням, ExceptionMapper
який поставляється заздалегідь налаштований з Джерсі (і, мабуть, це те саме з іншими реалізаціями), і кинути будь-який із існуючих підкласів javax.ws.rs.WebApplicationException
. Це заздалегідь визначені типи винятків, які попередньо відображені у різних кодах помилок, наприклад:
- BadRequestException (400)
- InternalServerErrorException (500)
- NotFoundException (404)
І т.д. Ви можете знайти тут список: API
Можна також визначити власні винятки та ExceptionMapper
класи та додати ці картографи до Джерсі за допомогою @Provider
анотації ( джерело цього прикладу ):
public class MyApplicationException extends Exception implements Serializable
{
private static final long serialVersionUID = 1L;
public MyApplicationException() {
super();
}
public MyApplicationException(String msg) {
super(msg);
}
public MyApplicationException(String msg, Exception e) {
super(msg, e);
}
}
Постачальник:
@Provider
public class MyApplicationExceptionHandler implements ExceptionMapper<MyApplicationException>
{
@Override
public Response toResponse(MyApplicationException exception)
{
return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();
}
}
Примітка. Ви також можете написати ExceptionMappers для існуючих типів винятків, які ви використовуєте.
b) Використовуйте конструктор відповідей
Ще один спосіб встановлення коду статусу - це використання Response
конструктора для побудови відповіді з призначеним кодом.
У такому випадку має бути тип повернення вашого методу javax.ws.rs.core.Response
. Це описується в різних інших відповідях, таких як прийнята відповідь його прокляття і виглядає так:
@GET
@Path("myresource({id}")
public Response retrieveSomething(@PathParam("id") String id) {
...
Entity entity = service.getById(uuid);
if(entity == null) {
return Response.status(Response.Status.NOT_FOUND).entity("Resource not found for ID: " + uuid).build();
}
...
}
2. Успіх, але не 200
Інший випадок, коли ви хочете встановити статус повернення, - це коли операція пройшла успішно, але ви хочете повернути код успіху, відмінний від 200, разом із вмістом, який ви повертаєте в тілі.
Частий випадок використання - це коли ви створюєте нову сутність ( POST
запит) і хочете повернути інформацію про цю нову сутність або, можливо, про саму сутність разом із 201 Created
кодом статусу.
Один із підходів полягає в тому, щоб використовувати об’єкт відповіді так, як описано вище, і самостійно встановити тіло запиту. Однак цим ви втрачаєте можливість використовувати автоматичну серіалізацію до XML або JSON, надану JAXB.
Це оригінальний метод, що повертає об'єкт сутності, який буде серіалізований в JSON JAXB:
@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public User addUser(User user){
User newuser = ... do something like DB insert ...
return newuser;
}
Це поверне JSON-представлення новоствореного користувача, але статус повернення буде 200, а не 201.
Тепер проблема полягає в тому, що якщо я хочу використовувати Response
будівельник для встановлення коду повернення, я повинен повернути Response
об'єкт у своєму методі. Як мені все-таки повернути User
об'єкт, який підлягає серіалізації?
а) Встановіть код на відповідь сервлета
Один із підходів до вирішення цього питання - отримати об’єкт запиту сервлетів і встановити код відповіді вручну самостійно, як це було продемонстровано у відповіді Гаретта Вілсона:
@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public User addUser(User user, @Context final HttpServletResponse response){
User newUser = ...
//set HTTP code to "201 Created"
response.setStatus(HttpServletResponse.SC_CREATED);
try {
response.flushBuffer();
}catch(Exception e){}
return newUser;
}
Метод як і раніше повертає об'єкт сутності, і код стану буде 201.
Зауважте, що для того, щоб це спрацювало, мені довелося стерти відповідь. Це неприємне відродження низькорівневого коду API сервлетів у нашому прекрасному ресурсі JAX_RS, і що ще гірше, це призводить до того, що заголовки після цього неможливо змінити, оскільки вони вже були відправлені на провід.
b) Використовуйте об'єкт відповіді з сутністю
Найкращим рішенням у цьому випадку є використання об’єкта Response та встановлення сутності для серіалізації на цьому об'єкті відповіді. Було б непогано зробити об’єкт Response узагальненим, щоб вказати тип сукупності корисного навантаження в цьому випадку, але наразі це не так.
@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response addUser(User user){
User newUser = ...
return Response.created(hateoas.buildLinkUri(newUser, "entity")).entity(restResponse).build();
}
У цьому випадку ми використовуємо створений метод класу Builder Response для того, щоб встановити код статусу на 201. Ми передаємо об'єкт (користувач) сутності у відповідь за допомогою методу entity ().
Результат полягає в тому, що HTTP-код - 401, як ми хотіли, а тіло відповіді - це точно такий же JSON, як і раніше, коли ми щойно повертали об'єкт User. До нього також додається заголовок місцезнаходження.
Клас відповідей має ряд методів побудови для різних статусів (stati?), Таких як:
Response.accepted () Response.ok () Response.noContent () Response.notAcceptable ()
Примітка: об’єкт hateoas - це клас помічників, який я розробив для створення URI ресурсів. Тут вам потрібно буде придумати свій власний механізм;)
Ось про це.
Я сподіваюся, що ця тривала відповідь комусь допоможе :)