RESTful 1-N необязательные отношения - PullRequest
3 голосов
/ 21 августа 2010

Я пытаюсь научиться писать приложения RESTful на Java с использованием Jersey и Hibernate, и я пытаюсь понять, как обрабатывать отношения типа родитель / потомок при размещении данных в ресурсе.Я использую JSON для обмена данными, но я не думаю, что это особенно актуально для моей проблемы.

Пример, с которым я работаю, моделирует отношения между сотрудниками и командами.Сотрудник может или не может быть членом одной команды:

GET /team/ - returns a list of teams
POST /team/ - creates a new team
GET /team/1 - returns a list of employees in the team with the ID 1

GET /employee/ - returns a list of employees
POST /employee/ - creates a new employee
GET /employee/1 - returns details about the employee with the ID 1

За этим у меня есть несколько аннотаций в Hibernate: один для команды и один для сотрудника с отношением 1-N междудва (помните, что Сотрудник не может быть членом команды!).Те же POJO также аннотированы как @XmlRootElements, так что JAXB позволит мне передавать их клиенту как JSON.

Свойства для двух сущностей выглядят следующим образом:

Team
    Long id;
    String name;
    String desc;
    List<Employee> employees;

Employee
    Long id;
    Team team;
    String name;
    String phone;
    String email;

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

Например,Я хотел бы иметь возможность вызывать POST / employee / с JSON, который выглядит следующим образом:

{
    "team_id":"1",
    "name":"Fred Bloggs",
    "phone":"1234567890",
    "email":"test@example.com"
}

Но вместо этого я должен передать что-то вроде этого:

{
    "team":{
        "id":"1",
        }
    "name":"Fred Bloggs",
    "phone":"1234567890",
    "email":"test@example.com"
}

Итак, мой вопрос: как другие обрабатывают создание отношений в JSON / REST без обхода целых графов объектов?

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

Ответы [ 4 ]

1 голос
/ 21 августа 2010

Если ваш фреймворк заставляет ваше представление включать странные конструкции, такие как { "id":"1" }, тогда я бы сказал, что пришло время сменить фреймворк!

Что более важно, вместо того, чтобы беспокоиться о добавлении в ваш код суб-JSONObject,Я бы беспокоился, что термин «1» действительно не является гиперссылкой.Читайте об ограничении гипермедиа, или HATEOAS, если хотите.

То, что вы хотите передать в своем POST, это:

{
    "team_href" : "/teams/1",
    "name":"can'tbebothered"
}

, поэтому, когда сервер видит это, он связывает недавносозданный сотрудник с командой # 1 только потому, что он распознает (относительный) URI.

1 голос
/ 21 августа 2010

Я бы использовал выделенный тип ссылки, я смоделировал его в теге xml-link, но он соответствовал бы следующему json:


{
  ...
  links: 
  [
      {
          "href" : "/teams/1",
          "rel" : "team"
      },
      {
          "href" : "/teams/2",
          "rel" : "team"
      }
  ]
}

Я предпочитаю вышеуказанный стиль ссылок, потому что он более общий (вы определяете отношения через атрибут rel). Для меня концепция ссылок настолько важна в HTTP REST, что я выделил для нее собственный тип.

В некоторых случаях помните, что по соображениям производительности (избегая сетевых вызовов для обхода связанного ресурса) вам необходимо встроить такие отношения. Для этого вы можете предложить переключатель для возврата встроенного представления /employee/123?inline=true. Но только предлагайте такие уловки, если это действительно необходимо. Мне когда-то приходилось это делать, но реализация не была тривиальной (хотя мой формат был XML, который более ограничен определениями схемы).

0 голосов
/ 06 сентября 2010

Есть несколько способов подойти к решению этой проблемы.Это проблема гиперссылок класса в области RESTful Web Services.Так как это связано с Джерси, первое, что я бы порекомендовал, это избегать JAXB все вместе, так как JAXB (в контексте XML или JSON) не HATEOAS.

После большого сокращения с Джерси и HATEOAS у меня естьпришли к выводу, что лучшим представлением для RESTful WS является формат синдикации Atom в сочетании с JSON.Для вашего примера команды и сотрудника я бы использовал следующий подход:

GET /team/ - returns a paginated Atom Syndication Feed list of teams
POST /team/ - creates a new team receiving a JSON representation
GET /team/1 - returns a paginated Atom Syndication Feed list of employees in the 
              team with the ID 1 with an Link to team's JSON representation too.

GET /employee/ - returns a paginated Atom Syndication Feed list of employees
POST /employee/ - creates a new employee using JSON
GET /employee/1 - returns details about the employee with the ID 1 in JSON

До сих пор я не сильно изменился, просто указав некоторые детали представления.Интересной частью является добавление / удаление сотрудника из команды.Для этого я бы добавил ресурсы с шаблоном

@Path("/team/{id}/employees)
class TeamEmployees {

  @Path("/{posId}")
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public Employee get(@PathParam("posId") int positonId) {}

  @Path("/{posId}")
  @DELETE
  public Employee remove(@PathParam("posId") int positonId) {}

  @POST
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  //empUri sample is /employee/{id} server knows how to parse it
  public Employee add(@FormParam("employeeUri") String empUri) {}

}

Теперь, что такое идентификатор позиции, один подход - это уникальное число для всех команд, то есть первичный ключ в таблице, который будет иметь position_id, team_id, emp_id каккортеж.Обеспечение того, чтобы никогда не было 2 одинаковых position_id для 2 команд.Таким образом, весь сценарий может быть превращен в HATEOAS.

В дополнение к возможности экспортировать URI в представлении JSON в DTO, я использую подход, представляющий DTO модель данных для ее постоянного хранилища, и у меня есть модель представления , представляющая сериализуемую (де) гиперссылочную версию DTO , где я сохраняю строковое значение как гиперссылку.Я рассматриваю модель представления как API и DTO как SPI для модели данных RESTful WS.

0 голосов
/ 21 августа 2010

REST предлагает также возможность использовать URL-адреса в качестве ссылок, что я считаю по-настоящему классным.Так это будет выглядеть так:

{
    "team":"http://myapp.com/team/1",
    "name":"Fred Bloggs",
    "phone":"1234567890",
    "email":"test@example.com"
}

Вы также можете избежать передачи вложенных объектов, просто указав

{
    "team":"1",
    "name":"Fred Bloggs",
    "phone":"1234567890",
    "email":"test@example.com"
}

. В этом случае ваш конвертер должен быть достаточно умным, чтобы понять, что еслизначение ключа команды является строкой (или целым числом, что бы ни работало), а не другим объектом JSON, его следует интерпретировать как идентификатор.

...