Возвращение JSON и HTTP-статуса вместе в JAX-RS: гид

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Чтобы вернуть JSON и HTTP-статус-код одновременно в JAX-RS, используйте строителя Response:

Java
Скопировать код
return Response
    .status(Response.Status.OK) // Всё в порядке? Ваш статус-код на подходе.
    .entity(jsonEntity) // Ваш JSON подан горячим!
    .build();

Таким образом, вы получите структурированный HTTP-ответ, который будет полезен пользователям вашего API.

Кинга Идем в IT: пошаговый план для смены профессии

Создание и возврат JSON-ответов

Для создания ответа в формате JSON, не забудьте пометить ваш JAX-RS метод аннотацией @Produces("application/json"). Это обязательно для отправки ответа клиентам в формате JSON, так же, как шеф-повар подает свое фирменное блюдо:

Java
Скопировать код
@GET
@Produces("application/json")
public Response makeJson() {
    MySpecialObject jsonObj = new MySpecialObject();
    return Response.ok(jsonObj).build(); // Сервируем горячий JSON с кодом 200.
}

Передача настраиваемых HTTP-кодов статуса

В ходе формирования ответов может потребоваться уточнить HTTP-код статуса с использованием перечисления Response.Status или числового значения. Если вы хотите возвратить статус 201 Created с JSON-содержимым, достаточно написать:

Java
Скопировать код
return Response
    .status(Response.Status.CREATED) // Код 201, свежий как с монетного двора!
    .entity(jsonEntity)
    .build();

Обработка исключений с настраиваемыми сообщениями об ошибках

Для корректной обработки исключений и генерации точных ответов с описанием ошибок применяйте ExceptionMapper. Это поможет предоставить пользователям максимально информативные сообщения об ошибках:

Java
Скопировать код
@Provider
public class MyExceptionMapper implements ExceptionMapper<MyException> {
    @Override
    public Response toResponse(MyException exception) {
        return Response
            .status(Response.Status.BAD_REQUEST)
            .entity(new ErrorMessage(exception.getMessage())) // Ответ с сообщением об ошибке для анализа
            .build();
    }
}

Использование строителя Response для создания идеальных ответов

Строитель Response предлагает множество методов для формирования идеального HTTP-ответа. Например, вы можете установить заголовок Location и добавить пользовательские заголовки при отправке статуса 201 Created:

Java
Скопировать код
return Response
    .created(new URI("http://example.com/myresource"))
    .header("X-Custom-Header", "Дополнительный пользовательский заголовок")
    .entity(jsonEntity)
    .build();

Обработка отсутствующих и нулевых данных

Будьте готовы к ситуации, когда конечные точки вашего API могут получить null или пустые данные. Внедрите необходимые проверки, чтобы избежать непредвиденных ошибок, и при необходимости возвращайте резервный ответ или сообщение об ошибке с соответствующим HTTP-кодом:

Java
Скопировать код
if(input == null || input.trim().isEmpty()) {
    return Response
            .status(Response.Status.BAD_REQUEST) // Упс, кажется, в запросе произошло недопонимание
            .entity("Пустые запросы не принимаются!")
            .build();
}

Удовлетворение ожиданий клиента

Ответы, которые вы отправляете, вызывают у клиентов определённые "ожидания", которые мотивируют их на выполнение определённых действий на стороне JavaScript. Это подобно описанию нюансов вашего блюда гурманом:

JS
Скопировать код
if (response.status === 200) {
    console.log('Вкус успеха:', response.payload);
} else {
    console.error('Неудача:', response.statusText);
}

Продвинутые приёмы создания ответов

Продвинутые методы работы с Response предполагают создание пользовательских аннотаций и использование фильтров ContainerResponseFilter для автоматизации некоторых аспектов работы ответов и лучшего разделения логики.

Визуализация

Презентация ответа от вашего API-сервиса можно сравнить с подачей блюда из двух компонентов:

КомпонентПредставляет
🍽 БлюдоHTTP-код статуса
🥗 СалатJSON-нагрузка

Отправка такого ответа равносильна подаче комплексного обеда:

http
Скопировать код
Response🍽 = HTTP-код статуса (200 OK) + JSON-салат ({"ключ":"значение"})

Ваше блюдо обозначает СТАТУС, который является индикатором качества сервиса, а в «сыром салате» представлена ИНФОРМАЦИЯ — суть запроса клиента. Такая комбинация гарантирует полное удовлетворение потребностей наших пользователей.

Курирование пользовательских фильтров ответов

Для достижения оптимального результата рекомендуется использовать пользовательские аннотации в паре с ContainerResponseFilter, что позволит правильно задавать HTTP-коды статуса и не перегружать основную логику сервиса.

Пример аннотации:

Java
Скопировать код
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface CustomStatus {
    Response.Status value() default Response.Status.OK;
}

И соответствующий фильтр:

Java
Скопировать код
@Provider
@CustomStatus
public class CustomStatusFilter implements ContainerResponseFilter {
    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
        CustomStatus annotation = findAnnotation(requestContext); // Найдём скрытую аннотацию!
        if (annotation != null) {
            responseContext.setStatus(annotation.value().getStatusCode());
        }
    }
}

Работа с параметрами URL

Если ваш API применяет параметры URL, используйте @PathParam для гибкой работы с ними. Таким образом, вы создадите ответ, который максимально соответствует запросу клиента:

Java
Скопировать код
@GET
@Path("/{id}")
@Produces("application/json")
public Response getRecord(@PathParam("id") String id) {
    MyObject jsonEntity = findEntityById(id);
    if (jsonEntity == null) {
        return Response.status(Response.Status.NOT_FOUND).build(); // Печально, когда клиент не может найти то, что искал…
    }
    return Response.ok(jsonEntity).build(); // Ваш заказ готов к подаче!
}

Искусство формирования сообщений об ошибках

Важно создавать сообщения об ошибках так, чтобы они оставляли у клиента ощущение профессионализма. Сопоставьте их с HTTP-кодами статуса для создания впечатляющего ответа:

Java
Скопировать код
return Response
    .status(Response.Status.INTERNAL_SERVER_ERROR)
    .entity(new ApiError("Кажется, я забыл выключить духовку!", e.toString())) // Сохраняйте спокойствие даже в стрессовых ситуациях
    .build();

Ошибки, возвращаемые через такие классы как ApiError, обеспечивают консистентность в ответах об ошибках и значительно упрощают обработку ошибок со стороны клиентов.

Учет ожиданий клиентов

Важно помнить, что клиенты ожидают от ваших ответов определённого поведения. Удостоверьтесь, что ваши HTTP-коды статуса преобразуются браузерами и прокси-серверами корректно. К примеру, коды 204 No Content и 205 Reset Content могут вызвать неожиданные реакции. Следование спецификации API поможет обеспечить плавное взаимодействие с клиентами.

Полезные материалы

  1. Response (Java(TM) EE 7 Specification APIs) — детальнее ознакомьтесь со всеми возможностями строителя Response в официальной документации Java EE.
  2. 29 Построение RESTful Web Services с JAX-RS (Релиз 7) — изучите методологии от Oracle и расширьте свои знания в работе с JAX-RS.
  3. java – JAX-RS — Как вернуть JSON и HTTP-код статуса одновременно? – Stack Overflow — присоединяйтесь к обсуждению этой темы на Stack Overflow в сообществе разработчиков.
  4. Jersey — официальный сайт проекта Jersey, который предлагает реализацию JAX-RS со всеми необходимыми для разработки инструментами.
  5. REST с Java (JAX-RS) используя Jersey – учебник — комплексное руководство по созданию современных RESTful-сервисов на Java с использованием Jersey.