API RESTful - правильное поведение, когда ложные/не запрашиваемые параметры передаются в запросе

Мы разрабатываем RESTful api, который принимает параметры запроса в запросе в виде закодированных JSON-данных.

Нам было интересно, что такое правильное поведение, когда не запрошенные/ожидаемые параметры передаются вместе с требуемыми.

Например, нам может потребоваться, чтобы запрос PUT на заданной конечной точке должен был предоставить ровно два значения соответственно для ключей имя и фамилия:

{
    "name": "Jeff",
    "surname": "Atwood"
}

Что делать, если в приведенном ниже примере передан ложный ключ, например цвет?

{
    "name": "Jeff",
    "surname": "Atwood",

    "color": "red"
}

Значение цвет не ожидается, не задокументировано.

Следует ли игнорировать его или отклонять запрос с ошибкой состояния BAD_REQUEST 400?

Мы можем утверждать, что запрос плохой, потому что он не соответствует документации. И, вероятно, пользователь API должен быть предупрежден об этом (она передала значение, она будет ожидать чего-то для этого.)

Но мы также можем утверждать, что запрос может быть принят, поскольку, поскольку все необходимые параметры предоставляются, он может быть выполнен.

Ответ 1

Используя RESTful API от многочисленных поставщиков на протяжении многих лет, позвольте мне дать вам точку зрения пользователей.

Много раз документация просто плохая или устаревшая. Возможно, имя параметра изменилось, возможно, вы применяете точный корпус в именах свойств, возможно, вы использовали неправильный шрифт в своей документации и имеете I, который выглядит как l - да, это разные буквы.

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

Эта небольшая вещь будет иметь большое значение для ограничения запросов поддержки в отношении потребления вашего API.

Если вы просто игнорируете параметры, тогда разработчик может подумать, что допустимые значения передаются во время разговора с вашим API, потому что, очевидно, API не работает правильно.

Если вы выбросите общее сообщение об ошибке, у вас появится Dev, который вытаскивает свои волосы, пытаясь понять, что происходит и наводняет ваш форум, этот сайт или ваш телефон будет спрашивать, почему ваши серверы не работают. (Недавно я столкнулся с этой проблемой с продавцом, который просто не понимал, что сообщение 404 не является допустимым ответом на неправильный параметр и что документация должна отражать используемые фактические имена параметров...)

Теперь, тем не менее, я ожидаю, что вы также получите хорошее сообщение об ошибке при отсутствии требуемого параметра. Например, "Обязательное свойство: Имя отсутствует".


По сути, вы хотите быть настолько полезными, насколько это возможно, чтобы потребители вашего API могли быть максимально самодостаточными. Как вы можете сказать, я совершенно не согласен с "милостивым" и "суровым" расстройством. Чем более "любезными" вы являетесь, тем больше вероятность того, что потребители вашего API столкнутся с проблемами, когда они думают, что они поступают правильно, но получают неожиданное поведение из вашего API. Вы не можете думать о всех возможных путях, которые люди собираются испортить, поэтому строгое соблюдение соответствующих сообщений об ошибках очень поможет.

Ответ 2

Если вы создаете API-интерфейс, вы можете следовать двум путям: "суровый" или "любезный".

  • Стерн означает: если вы делаете что-либо, чего я не ожидал, я буду злиться на вас.
  • Милостивый означает: если я знаю, чего вы хотите и можете выполнить, я сделаю это.

REST позволяет использовать прекрасный дизайн API, и я постараюсь как можно дольше следовать этому пути и ожидать того же самого из моих клиентов. Если мой API развивается, мне, возможно, придется добавить дополнительные параметры в мои ответы, которые применимы только для конкретных клиентов. Если мои клиенты будут любезны со мной, они смогут справиться с этим. Сказав, что хочу добавить, что есть место для строгой архитектуры API. Если вы проектируете в чувствительном домене (например, операции с наличными деньгами), и вы не хотите оставлять место для недоразумений между клиентом и сервером. Представьте следующий запрос POST (действительный для вашего /account/ {no}/transaction/API):

{ amount: "-100", currency : "USD" }

Что бы вы сделали со следующим (неверный запрос API)?

{ amount: "100", currency : "USD", type : "withdrawal" }

Если вы просто проигнорируете атрибут "type", вы будете депонировать 100 долларов США вместо их снятия. В такой области я бы следовал строгому подходу и не показывал никакой градации.

Будьте любезны, если можете, будьте строгими, если вы должны.

Update:

Я полностью согласен с @Chris Lively answer, что пользователь должен быть проинформирован. Я не согласен с тем, что это всегда должно быть ошибкой, даже сообщение не является двусмысленным для ссылочного ресурса. Выполнение этого в противном случае будет препятствовать повторному использованию представлений ресурсов и требует переупаковки семантически идентичной информации.

Ответ 3

Просто игнорируйте их.

Не предоставляйте пользователю возможность перепроектировать ваш RESTful API через сообщения об ошибках.

Дайте разработчикам самую четкую, четкую и полную документацию и проанализируйте только параметры, необходимые вашему API и поддержку.

Ответ 4

Это зависит от вашей документации.. насколько строго вы хотите быть.
Но, вообще говоря, Just ignore it. Большинство других серверов также игнорируют параметры запроса, которые он не понимал.

Пример, взятый из моего предыдущего сообщения

Дополнительные параметры запроса в URL-адресе REST API

"" Google игнорирует мои два дополнительных параметра здесь https://www.google.com/#q=search+for+something&invalid=param&more=stuff ""

Ответ 5

Представьте, что у меня есть следующая схема JSON:

{
   "frequency": "YEARLY",
   "date": 23,
   "month": "MAY",
}

Атрибут частоты принимает значения "ЕЖЕНЕДЕЛЬНО", "ЕЖЕМЕСЯЧНО" и "ГОД". Ожидаемая полезная нагрузка для значения частоты "ЕЖЕНЕДЕЛЬНО":

{
   "frequency": "WEEKLY",
   "day": "MONDAY",
}

И ожидаемая полезная нагрузка для значения частоты "ЕЖЕМЕСЯЧНО":

{
   "frequency": "MONTHLY",
   "date": 23,
}

Приведите приведенную выше схему JSON. Обычно для десериализации мне понадобится POJO, содержащий поля частоты, дня, даты и месяца.

Если полученная полезная нагрузка:

{
   "frequency": "MONTHLY",
   "day": "MONDAY",
   "date": 23,
   "year": 2018
}

Я отправлю сообщение об ошибке в атрибут "day", потому что никогда не узнаю намерения отправителя:

  1. частота: "ЕЖЕНЕДЕЛЬНО" и день: "ПОНЕДЕЛЬНИК" (введено неверное значение частоты) или
  2. частота: "ЕЖЕМЕСЯЧНО" и дата: 23

Для атрибута "год" у меня действительно нет выбора. Даже если я хочу выдать ошибку для этого атрибута, я не смогу. Он игнорируется библиотекой сериализации/десериализации JSON, поскольку мой POJO не имеет такого атрибута. И это поведение GSON, и это имеет смысл, учитывая проектное решение.

Навигация по дереву Json или целевому дереву типов при десериализации

Когда вы десериализуете строку Json в объект нужного типа, вы можете перемещаться либо по дереву ввода, либо по дереву типов нужного типа. Gson использует последний подход для навигации по типу целевого объекта. Это держит вас под строгим контролем создания экземпляров только того типа объектов, который вы ожидаете (по сути, проверка ввода по отношению к ожидаемой "схеме"). Делая это, вы также игнорируете любые дополнительные поля, которые ввод Json имеет, но не ожидал.

Как часть Gson, мы написали ObjectNavigator общего назначения, который может взять любой объект и перемещаться по его полям, вызывая посетителя по вашему выбору.

Извлечено из проектного документа GSON

Ответ 6

Я предлагаю вам игнорировать дополнительные параметры. Повторное использование API - это смена игры в мире интеграции. Что делать, если один и тот же API может использоваться другой интеграцией, но с небольшими дополнительными параметрами?

Приложение A ожидает:

{
    "name": "Jeff",
    "surname": "Atwood"
}

Приложение B ожидает:

{
    "name": "Jeff",
    "surname": "Atwood",
    "color": "red"
}

Простое приложение-приложение A, чтобы игнорировать "цвет", будет выполнять задание, а иметь два разных API для обработки.