RESTful API и i18n: как оформить ответ?

15

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

API обрабатывает i18n через заголовок Accept-Language в запросах. Это работает для всех вещей, которые должен сделать клиент, за исключением одной функции, в которой клиент должен хранить ответы на запрос к одной конечной точке во всех доступных локалях.

Можем ли мы каким-то образом спроектировать API таким образом, чтобы клиент мог собрать всю эту информацию с помощью одного запроса и без нарушения согласованного, хорошо структурированного дизайна RESTful API?

Варианты, которые мы рассмотрели до сих пор:

  • Разрешение на включение нескольких языковых стандартов в заголовок Accept-Language и добавление локализованных версий для всех запрошенных языковых стандартов в ответе, каждый из которых идентифицируется своим языковым кодом ISO 639-1 в качестве ключа.
  • Создание чего-то вроде параметра «? All_languages ​​= true» для этой конечной точки и возвращение локализованных версий для всех доступных языковых стандартов в ответе, если этот параметр присутствует.
  • (Если ничего из вышеперечисленного не работает для нас) сделать несколько запросов, чтобы получить все локализованные версии от клиента.

Какой из них является лучшей альтернативой?

AMM
источник

Ответы:

22

Вы описали два эффективных способа запроса нескольких языков. Либо должно работать нормально. Я бы выбрал явный параметр запроса языка для моего собственного кода.

TL; DR предыстория

Есть заголовок Accept-Language . Обратите внимание, Acceptнет Accepted. Это стандартная часть согласования содержимого HTTP. Ответ обычно устанавливает обратно заголовок Content-Language .

Accept-Languageэто начальная ставка, предлагающая набор опций; Content-Languageэто резолюция с указанием того, какой язык был выбран. Большинство Content-Languageответов возвращают один язык, но есть возможность предоставить список языков ответов через запятую. Обычно это будет смешанный контент, но нет никаких причин, по которым он не может сигнализировать о множественных непересекающихся альтернативах. Если вы хотите, чтобы клиент запрашивал все доступные языки, уже есть опция запроса с подстановочными знаками *.

Так что уже есть механизм HTTP-заголовка, который вы можете использовать. Тем не менее, имейте в виду, что вы будете участвовать в процессе переговоров, который чаще представляет множество возможных вариантов и возвращает один вариант. Вы бы изменили смысл: «Вот список вариантов, дайте мне все из них!» Если вы согласны с этим, у вас есть решение.

Тем не менее, существуют серьезные споры относительно пригодности сигнализации параметров REST API в заголовках HTTP. Это немного похоже на вход в ресторан и написание подробного заказа хозяину или метрдотелю, а не ожидание появления официанта или официантки. Он может работать и может работать хорошо, например, если заказ, направленный на хост, относится к напиткам или закускам - вещам, которые хост может быстро увидеть или быстро сообщить вашему серверу. Но это также можно рассматривать как нарушение протокола, адресованное на неправильном уровне / уровне или не тому игроку.

Второй альтернативой будет явный параметр запроса. Вы предлагаете ?all_languages=true. Это кажется слишком конкретным. Что-то вроде lang=en,fr,es(разрешить несколько перечисленных языков) или lang=*или lang=all(указать каждый доступный язык) кажется более общим. Это может быть выражено либо в URL, либо в теле запроса.

В любом случае, ваш многоязычный ответ может быть легко закодирован в возвращаемую полезную нагрузку JSON:

[ { "lang": "en", "content": "As Gregor Samsa awoke one morning..." },
  { "lang": "de", "content": "Als Gregor Samsa eines Morgens..." },
  ...
]

В конце концов, любой из этих подходов должен работать хорошо для вас. Любой из них можно рассматривать как «согласованный, хорошо структурированный дизайн RESTful API». Определение того, что лучше, основывается главным образом на вашем отношении к целесообразности совмещения (и небольшого изменения типичного смысла) заголовков согласования содержимого HTTP.

Я предпочитаю не смешивать заголовки и другие параметры как равные части запроса API. Явное langили languageпараметр кажется мне чище. Но так как HTTP глагол (например GET, PUT, POST, PATCH, ...) является частью заголовка, а также имеет важное значение для / перемешано с интерпретацией запроса, я признаю , конверт против содержания различия немного искусственный и нечеткий. Как и в случае большинства дизайнерских решений, настоящие эксперты отвечают на это по-разному и YMMV.

Джонатан Юнис
источник
Их ответ был очень образовательным и информативным. Спасибо. Спасибо также за то, что обратили внимание на вещь Accept-not-Accepted. Это правильно в нашем коде, но тогда я не смог использовать правильный термин при написании поста. Я изменю это для дальнейших ссылок.
AMM