JSON API для ответов, не связанных с ресурсами

В настоящее время я работаю над новым продуктом и делаю REST API как для общественных, так и для внутренних нужд. Я начал со спецификации {json:api} и был ею вполне доволен, пока не столкнулся с некоторыми вопросами, на которые не могу найти ответы.

Согласно спецификации JSON API, каждый ресурс ДОЛЖЕН содержать id.

http://jsonapi.org/format/

Каждый ресурсный объект ДОЛЖЕН содержать элемент id и элемент типа. Значения элементов id и type ДОЛЖНЫ быть строками.

И это хорошо во многих случаях, но не во всех.

Большинство наших конечных точек связаны с «ресурсами».

Если я попрошу коллекцию "вещей" (http://example.com/things)

{
  "data": [{
    "type": "things",
    "id": "1",
    "attributes": {
      "title": "first"
    },
    "links": {
      "self": "http://example.com/things/1"
    }
  }, {
    "type": "things",
    "id": "1",
    "attributes": {
      "title": "second"
    },
    "links": {
      "self": "http://example.com/things/2"
    }
  }]
}

Если я попрошу один ресурс "вещи" (http://example.com/things/1)

{
  "data": {
    "type": "things",
    "id": "1",
    "attributes": {
      "title": "first"
    },
    "links": {
      "self": "http://example.com/things/1"
    }
  }
}

Но что делать с конечными точками, которые не относятся к ресурсам и не имеют идентификатора?

Например, в нашем приложении есть конечная точка http://example.com/stats, которая должна возвращать статистику текущего пользователя, вошедшего в систему. Нравиться

{
  "active_things": 23,
  "last_login": "2017"
}

Для этого «ресурса» нет идентификатора (на самом деле это не ресурс, не так ли?). Бэкэнд просто собирает некоторую «статистику» для вошедшего в систему пользователя и возвращает объект статистики. В этом приложении много подобных конечных точек, например, у нас есть страница Центр уведомлений, где пользователь может менять адреса электронной почты для разных уведомлений.

Таким образом, внешнее приложение (одностраничное приложение) сначала должно получить текущие значения и отправить запрос на GET http://example.com/notification-settings.

{
  "notifications_about_new_thing": "[email protected]",
  "notification_about_other_thing": "[email protected]"
}

И таких конечных точек гораздо больше. Проблема в том, как вернуть эти ответы в формате JSONAPI? В этих конечных точках нет идентификатора.

И самый большой вопрос - почему никто больше не сталкивается с этой проблемой (по крайней мере, я не могу найти обсуждения по этому поводу)? :D Все API, которые я когда-либо создавал, имеют некоторые конечные точки, у которых нет «id».

У меня есть две идеи, первая — подделать id, как "id": "doesnt_matter", вторая — не использовать json-api для этих конечных точек. Но мне они оба не нравятся.


person Arūnas Smaliukas    schedule 10.04.2018    source источник
comment
для вашего примера с вошедшим в систему пользователем, не может ли идентификатор быть идентификатором пользователя?   -  person Nathan Hughes    schedule 10.04.2018
comment
Не используйте json-api.   -  person Quazer    schedule 10.04.2018
comment
@NathanHughes да, может.. но мне это не нравится :)) Тогда я должен также отправить запрос http://example.com/stats/<user-id>?..   -  person Arūnas Smaliukas    schedule 10.04.2018
comment
@Quazer не использует его для этих конечных точек или вообще не использует?   -  person Arūnas Smaliukas    schedule 10.04.2018
comment
@ArūnasSmaliukas Если внешняя система с JSONAPI априори не подключается к вашему проекту - не используйте JSONAPI. Используйте собственный JSON. Конечные точки для C# — RestRequest, Python — Requests.   -  person Quazer    schedule 10.04.2018


Ответы (2)


Думайте полноценно, и все может (должно) быть ресурсом. Нет «вошедшего в систему» ​​пользователя, поскольку в RESTful API нет сеансов, поскольку они не имеют состояния. Между вызовами REST API состояние сеанса не сохраняется, поэтому вы должны четко указать, кто является пользователем.

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

GET /users/1234 { "data": { "type": "users", "id": "1234", "attributes": { "name": "etc.", "active_things": 23, "last_login": "2017" } } }

person n2ygk    schedule 10.04.2018

Я не эксперт по JSON API, но стоит отметить, что, хотя JSON API является конкретной спецификацией, это не то же самое, что JSON или REST API. Если вам не нравится его семантика, я согласен с комментаторами, которые утверждают: «Не используйте его». Если вы собираетесь использовать JSON API, делайте это в соответствии с требованиями, когда каждый ответ является ресурсом; каждый ресурс имеет идентификатор и тип; и дополнительная информация предоставляется как атрибуты ресурса.

Что касается вашего вопроса, я думаю о чем-то подобном, когда мое приложение возвращает результаты вычислений. Теперь, с одной стороны, это не совсем «ресурсы», и поэтому я играл с идеей возврата необработанного результата в виде массива (который, как я полагаю, будет действительный JSON с оговоркой), например:

[ 47 ] 

С другой стороны, есть идея, что результаты являются результатами вычислений, которые клиент указал RESTful, и в этом случае, вероятно, один из следующих двух случаев:

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

В обоих случаях ответ действительно является объектом «результат», и хотя у него нет идентификатора как такового, у него есть идентификатор. Если больше ничего не подходит, ID может быть запросом, который сгенерировал ответ.

Мне это кажется RESTful. Пользователь @n2ygk предполагает, что это неверно в отношении спецификации JSON API, что идентификатор должен быть просто уникальным идентификатором и не иметь другой семантической интерпретации.

Я хотел бы услышать другие точки зрения.

person Brandon Kuczenski    schedule 18.04.2018
comment
Я думаю, что существует много досадной путаницы между спецификацией jsonapi.org и терминами JSON и API, первый из которых является конкретным стандартным шаблоном для API JSON. Внимательное прочтение спецификации jsonapi.org по-прежнему потребует от вас представления этого результата в виде ресурса с type, id, attributes и т. д. Рекомендуемый id — это UUID (глобально уникальный), поэтому вы можете каждый раз возвращать новый. или кешировать результат и возвращать тот же самый... Однако я бы не стал использовать идентификатор с другой семантикой. - person n2ygk; 26.04.2018
comment
Спасибо за эти наблюдения. Я обновил свой ответ (надеюсь), чтобы отразить его. - person Brandon Kuczenski; 09.05.2018