Упрощение REST URL с помощью параметров JSON - PullRequest
0 голосов
/ 07 февраля 2019

Мне дали задание, и я действительно не знаю, как его решить, поэтому любая помощь будет принята с благодарностью.Рассмотрим следующий пример:

@Path("/v1/{server}:{port}/instance")  
public class WSInstance {
        private static final Log        log = LogFactory.getLog(WSInstance.class);

        private final String    PLANNING_PROPNAME = "**PLNG_NAME**";
        private final String    PLANNING_PROPVAL = "**CALENDAR_NAME**";

        @GET
        @Path("/{instanceName}")
        @Produces("text/plain")
        public String getInstanceStatus(@Context HttpHeaders headers, 
                @PathParam("server")String server, 
                @PathParam("port")int port,
                @PathParam("instanceName") String instName,
                @DefaultValue("") @QueryParam("date") String date,
                @DefaultValue("") @QueryParam("instnum") String numexec)
        {
            return getInstanceStatus(Utils.extractUserInfo(headers), server, port, instName, numexec, date);    
        }

Пример вызова вышеупомянутого метода будет выглядеть следующим образом:

/v1/serverName:portNumber/instance/toto?date=21090207&instnum=0000

Задача состоит в том, чтобы заменить все переменныев этом URL (serverName, portNumber, toto, date и instnum) с параметрами JSON.Это предназначено для упрощения REST URL.

Есть идеи, с чего начать?


** РЕДАКТИРОВАТЬ : Спасибо всем за ответы, вы, безусловно, мне очень помогли.Вот что я сделал до сих пор:

Я решил взять «более простой» класс и метод, чтобы ознакомиться с процедурой.Итак, я взял это:

@Path("/v2/{server}:{port}/admin/")
public class WSAdmin {
    private static final Log log    = LogFactory.getLog(WSAdmin.class);

    @PUT
    @Path("/device")
    @Produces("text/plain")
    @Consumes("application/json")
    public String putDevice(String jsonObject, @Context HttpHeaders headers,
                                    @PathParam("server")String server,
                                    @PathParam("port")int port)
    {
        ObjectMapper mapper = new ObjectMapper();

        try
        {
            return updateDevice(mapper.readTree(jsonObject), Utils.extractUserInfo(headers), server, port);
        }
        catch (JsonProcessingException e)
        {
            return e.getMessage();
        }
        catch (IOException e)
        {
            return e.getMessage();
        }
    }

Я изменил его так:

@Path("/v2/admin/")
public class WSAdmin {
    private static final Log log    = LogFactory.getLog(WSAdmin.class);

    @POST
    @Path("/device")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response putDevice(Admin admin)
    {
            String output = admin.toString();
            return Response.status(200).entity(output).build();
    }

Затем я создал соответствующий POJO:

@XmlRootElement
public class Admin {

    private String server;
    private int port;
    private Date date;
    private String instnum;

// Constructors + getters + setters

    @Override
    public String toString() {
        return new StringBuffer("Server: ").append(this.server)
                .append("Port: ").append(this.port).append("Date: ")
                .append(this.date).append("InstNum: ")
                .append(this.instnum).toString();
    }
}

Затем я отредактировал web.xml файл для возможности маршалирования и демаршализации Java-объектов:

<init-param>
    <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
    <param-value>true</param-value>
</init-param>

Но по какой-то причине я получаю следующую ошибку при звонке от почтальона:

GRAVE [http-nio-8080-exec-5] com.sun.jersey.spi.container.ContainerRequest.getEntity A message body reader for Java class com.ws.v3.models.Admin, and Java type class com.ws.v3.models.Admin, and MIME media type application/json was not found.
The registered message body readers compatible with the MIME media type are:
application/json ->
  com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$App
  com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$App
  com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$App
*/* ->
  com.sun.jersey.core.impl.provider.entity.FormProvider
  com.sun.jersey.core.impl.provider.entity.StringProvider
  com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
  com.sun.jersey.core.impl.provider.entity.FileProvider
  com.sun.jersey.core.impl.provider.entity.InputStreamProvider
  com.sun.jersey.core.impl.provider.entity.DataSourceProvider
  com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General
  com.sun.jersey.core.impl.provider.entity.ReaderProvider
  com.sun.jersey.core.impl.provider.entity.DocumentProvider
  com.sun.jersey.core.impl.provider.entity.SourceProvider$StreamSourceReader
  com.sun.jersey.core.impl.provider.entity.SourceProvider$SAXSourceReader
  com.sun.jersey.core.impl.provider.entity.SourceProvider$DOMSourceReader
  com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$General
  com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General
  com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General
  com.sun.jersey.core.impl.provider.entity.XMLRootObjectProvider$General
  com.sun.jersey.core.impl.provider.entity.EntityHolderReader
  com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$General
  com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$General

Те, у кого была похожая ошибка, исчезли, добавив gerson или jersey-json в pom.xml.Я добавил их, но проблема не была решена.

Есть идеи?

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

Подумайте об использовании Джексона.Джексон отображает JSON <-> объекты.Прочитайте о том, как вы можете использовать его с Джерси (REST) ​​здесь: https://www.mkyong.com/webservices/jax-rs/json-example-with-jersey-jackson/

0 голосов
/ 07 февраля 2019

Per спецификация полезная нагрузка запроса GET не определена.Поэтому вы должны воздерживаться от отправки тела с запросом GET.Как уже указывал Давиде, вам следует вместо этого переключиться на POST, поскольку здесь семантика полученной полезной нагрузки определяется вами, сопровождающим сервера / API.

Однако, поскольку вы пометили свой пост вам, вероятно, следует подумать о копировании концепций, используемых в Интернете уже более 2 десятилетий, и преобразовании их в свой дизайн API.Во-первых, архитектура REST не заботится о структуре вашего URI.Сам URI является просто указателем на ресурс, и клиентам не нужно ни интерпретировать его, ни взламывать его.Вся информация, необходимая клиенту для выбора, должна быть предоставлена ​​сервером для начала.Поскольку клиенты не должны анализировать и интерпретировать URI, как они определяют, полезен ли URI для клиента или нет?

Ну, как мы, люди, взаимодействуем с URI на веб-страницах?Обычно они снабжены удобочитаемым текстом, который суммирует содержание этой ссылки (как в спецификации, т.е. выше).Такие короткие, но значимые имена обычно называют именами связей и должны быть «прикреплены» к каждому URI.Клиент, считывающий такие имена отношений ссылок и просто вызывающий соответствующий URI, сможет продолжить свою задачу, если серверу когда-либо понадобится изменить свою структуру URI.Это один из важных шагов на пути отделения клиентов от серверов.Такие имена отношений ссылок должны быть стандартизированными , но могут также указываться в общеизвестных или указываться в самих медиа-типах.

Распространенная ошибка многих так называемых "API REST""do поддерживает только application/xml и / или application/json.Это очень плохие типы носителей в архитектуре REST, поскольку они определяют только используемый синтаксис, но не семантику соответствующих элементов.Таким образом, клиенту трудно определить цель такого документа и легко попасть в ловушку typed ресурса и предположить, что определенный ресурс имеет определенный тип.Если такое (нестандартизированное) представление изменяется, велика вероятность того, что клиент прервет дальнейшее взаимодействие с этим сервисом / API.

Типы носителей - это более или менее стандартизированные правила обработки для определенной полученной полезной нагрузки, которыедолжен помочь дать получателю какое-то значение контента и того, что он может с ним делать.Один, вероятно, хорошо известный тип мультимедиа - это HTML, который определяет, когда определенные элементы осуществимы и какое ограничение имеет каждый элемент.Он также определяет способ визуализации определенных элементов и обратную совместимость с предыдущими версиями.Это стандарт де-факто, когда речь заходит о поддержке ссылок и ссылочных отношений.Хотя HAL , Collection + JSON , ... являются шагами в правильном направлении с точки зрения поддержки ссылок и имен отношений, они далеки от предоставления той же семантики, что и HTML,хотя они должны быть предпочтительнее простого JSON, поскольку они не только определяют синтаксис, но и семантику определенных элементов, таких как _links, то есть которые помогают клиенту отличать ссылки от контента.

Типы медиа особенно важны с точки зрениясогласования типа контента, когда клиент запрашивает у сервера вернуть формат представления, который понимает клиент.Если сервер не может создать такое представление, он сообщит клиенту с достаточно выразительным кодом ошибки (406).Если сервер не может обработать тип мультимедиа, предоставленный клиентом (в операциях POST, PUT, PATCH, ...), он также сообщит клиенту, что он не понимает такой формат (415).

Общий совет по разработке REST API заключается в том, чтобы думать об API с точки зрения веб-сервера, а также описывать весь процесс взаимодействия с ним.Т.е. если клиент должен выполнить определенный ввод, ему не следует отправлять на сервер только файл JSON воспроизведения с некоторыми случайными полями (указанными в некоторой внешней документации), но сервер должен научить клиента отправлять такой запрос для начала.,Подобно веб-формам, где люди должны вводить текст и прочее, API-интерфейсы REST должны возвращать медиа-тип, представляющий формуляр, который сообщает клиенту, какие поля ожидает сервер, какую операцию использовать и цель для отправки полезной нагрузки.

Что касается самого вопроса, я не уверен, почему ваш сотрудник так заинтересован в удалении параметров из URI.Как упомянуто в моем первом параграфе об отправке полезной нагрузки, вам нужно переключиться на POST и, следовательно, автоматически потерять гарантированные safe и idempotent функции операции GET, кроме того, что они не будут кэшироваться по умолчанию.

То, что вы можете сделать, т.е. позволить пользователям или вашим коллегам предварительно сконфигурировать определенные запросы и создать короткие / крошечные URL-адреса для этих предварительно сконфигурированных URI.Здесь вы должны предоставить клиенту тип мультимедиа, похожий на форму, где он может выбрать опции для выбора и ввести дополнительные необходимые данные.Получив такой запрос, вы сохраняете такую ​​предварительную конфигурацию и возвращаете короткий / миниатюрный URL-адрес для этой предварительной конфигурации в заголовке Location ответа.Вам также следует добавить предварительно настроенные ссылки в обычный ответ, чтобы клиент мог вызвать его, если он не сохранил его сразу после сохранения.Благодаря этому вы по-прежнему получаете преимущества операции GET, при этом вы можете гибко добавлять новые или настраивать существующие запросы на лету.Как упоминалось ранее, клиент не сможет много использовать такие ссылки в простом application/json представлении.Если клиент поддерживает application/hal+json, он может, по крайней мере, знать, что такое link-отношение и ссылки, и, следовательно, иметь возможность искать и вызывать URI через сопровождающее имя отношения link.По сути, это дает вам свободу в дальнейшем изменять структуру URI, если это необходимо, не затрагивая клиента.

0 голосов
/ 07 февраля 2019

Возможно, вам нужно изменить тип метода на POST и передать данные в виде json в теле запроса.

Запрос GET

GET /v1/yourServerName:8080/instance/toto?date=21090207&instnum=0000

может стать следующим запросом POST

POST /v1/instance
{
  "serverName":"yourServerName",
  "portNumber":8080,
  "date":21090207,
  "instnum":"0000"
}

Обратите внимание, что instnum не является числовым полем, поскольку вы передали строку 0000, которая не может быть представлена ​​в виде числового значения.Вместо portNumber и date могут быть числовые значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...