Разработка RESTful API с использованием HAL - сериализация отношений модели

Я относительно новичок в REST, но я делаю домашнюю работу о том, каким должен быть RESTful. Сейчас я пытаюсь создать RESTful API, реализующий сериализатор JSON+HAL для моих моделей, которые связаны с другими моделями.
Пример модели в питоне:

class Category(Model):
    name = CharField()
    parent = ManyToOneField(Category)
    categories = OneToManyField(Category)
    products = ManyToManyField(Product)

class Product(Model):
    name = CharField()
    price = DecimalField()
    related = ManyToManyField(Product)
    categories = ManyToManyField(Category)

Предположим, у нас есть категория "каталог" с подкатегорией "еда" с продуктами "гамбургер" и "хот-дог", которые связаны между собой.
Первый вопрос. Категории и продукты должны быть ресурсами, поэтому им нужен URI, должен ли я реализовать поле uri в моей модели и сохранить его в БД или каким-то образом рассчитать его во время выполнения, как насчет нескольких идентификаторов (URI)?
Второй вопрос Обнаруживаемость, в формате Hal то, что должны возвращать "GET /" и различные узлы, чтобы сделать API легко обнаруживаемым.

{
  "_links":{
    "self":{
      "href":"/"
    },
    "categories":[
      {
        "href":"/catalog"
      }
    ]
  }
}

Третий вопрос Добавить как свойства, встроить или ссылку. Пример "GET / каталог / еда":

{
  "_links":{
    "self":{
      "href":"/catalog/food"
    }
  },
  "name":"food",
  "parent":"/catalog",
  "categories":[],
  "products":[
    "/products/burger",
    "/products/hot-dog"
  ]
}

{
  "_links":{
    "self":{
      "href":"/catalog/food"
    },
    "parent":{
      "href":"/catalog"
    },
    "categories":[

    ],
    "products":[
      {
        "href":"/products/burger"
      },
      {
        "href":"/products/hot-dog"
      }
    ]
  },
  "name":"food"
}

{
  "_links":{
    "self":{
      "href":"/catalog/food"
    }
  },
  "name":"food",
  "_embedded":{
    "parent":{
      "_links":{
        "self":{
          "href":"/catalog"
        }
      },
      "name":"catalog",
      ...
    },
    "categories":[

    ],
    "products":[
      {
        "_links":{
          "self":{
            "href":"/products/burger"
          }
        },
        "name":"burger",
        ...
      },
      {
        "_links":{
          "self":{
            "href":"/products/hot-dog"
          }
        },
        "name":"hot-dog",
        ...
      }
    ]
  }
}

Четвертый вопрос. Как глубоко я должен идти при возвращении структур. Пример "GET / каталог

{
  "_links":{
    "self":{
      "href":"/catalog"
    }
  },
  "name":"catalog",
  "parent":null,
  "categories":[
    {
      "name":"food",
      "parent":{...},
      "categories":[],
      "products":[
        {
          "name":"burger",
          "price":"",
          "categories":[...],
          "related":[...]
        },
        {
          "name":"hot-dog",
          "price":"",
          "categories":[...],
          "related":[...]
        }
      ]
    }
  ],
  "products": []
}

2 ответа

О 1-м вопросе: я не буду хранить URI в БД. Вы можете легко вычислить их внутри вашего контроллера во время выполнения, и ответственность за URIs лежит на контроллере. Таким образом вы не будете связывать свою модель и API, и если вы решите изменить структуру API в будущем, вам не нужно будет обновлять всю базу данных новыми URI.

Насчет нескольких идентификаторов, я не уверен, что вопрос, но опять же, на мой взгляд, это не имеет ничего общего с БД, это маршрутизация и контроллеры, которые должны заботиться о том, как обращаться с любыми URI.

О 2-м вопросе: Прежде всего, как примечание: я бы оставил слова категории как часть URI. Например, у меня есть http://domain.com/api/categories/catalog/food, Таким образом, вы делаете свой API более информативным и более "взломанным", что означает, что пользователь должен иметь возможность удалить /catalog/food расстаться и ожидать получить коллекцию со всеми доступными категориями.

Теперь о том, что GET должен вернуться, чтобы разрешить обнаружение: я думаю, это уже проясняется из вашей структуры URI. Когда пользователь нажимает GET /categories он ожидает получить список с категориями (имя и URI для каждой, чтобы сохранить его легким), и когда он следует за одним из URI как GET /categories/catalog он должен получить ресурс catalog которая является категорией. Точно так же, когда он хочет GET /products/burgerОн должен получить ресурс продукта со всеми атрибутами, которые есть в вашей модели. Вы можете проверить этот пример на предмет структуры ваших ответов.

О третьем вопросе: опять тот же пример может помочь вам сформировать структуру. Я думаю, что ваш второй способ ответа ближе к этому, но я бы также добавил name поле, а не только href,

О четвертом вопросе: когда GET запрос ожидает коллекцию ресурсов (например, GET /categories) Я бы предложил предоставить только необходимый для каждого ресурса, то есть имя и URI для каждого, и только когда пользователь следует желаемому URI, он может получить остальную информацию.

В вашем примере catalog это ресурс, так далее GET /categories/catalog Я бы, конечно, включил name ресурса (каталога) и его собственной ссылки, а также для parent, sub-categories а также products которые связаны с этим, я бы просто предоставил имя и URI для каждого, чтобы было легче. Но: это была общая мысль о разработке API. В вашей реальной проблеме вы должны решить в зависимости от вашей конкретной бизнес-проблемы. Я имею в виду, если ваш API касается меню ресторана с категориями и блюдами, вы можете указать цену или небольшое описание, даже если отвечаете не за фактический продукт, а за набор продуктов, потому что, вероятно, для ваших пользователей это важная информация. Поэтому, как правило, предоставьте всю необходимую информацию (вы только знаете, что это за проблема), когда отвечаете о списке ресурсов, и предоставьте все детали ресурса, когда отвечаете о конкретном ресурсе.

  1. Я хотел бы что-то хранить в БД и вычислять URI во время выполнения. Таким образом, если вы перемещаете коробки, это не статично.
  2. Создайте страницу "закладки". Страница, которую мы создали, была просто списком ссылок с их ссылками. Я считаю, что HAL определяет это конкретно. Страница закладок была единственной страницей, о которой нужно было знать другим страницам.
  3. Не уверен насчет этого
  4. Как глубоко вы идете, зависит от вас. Сейчас у меня много споров о том, что зерно лучше, чем зерно. Я собираюсь сделать мелкое зерно с небольшим ресурсом, чтобы упростить API, но затем использую концепцию расширения возможностей. Это сочетание идеи составных ресурсов, определенной на стр. 35 книги REST Subbu, и концепции расширения, используемой Netflix. http://developer.netflix.com/docs/REST_API_Conventions
Другие вопросы по тегам