How to deal best with relationship in contained list item


#1

Hi,

I have a design question related to a contained list within a resource.

The root resource is a recipe resource containing a list of ingredients.

In a traditional json representation this could look like:

{ 
  "title": "Baked potatoes",
  "ingredients: ["potatoes", "salt"]
}

But extending on this we are creating s specific ingredient resource to re-use.
And we want to add quantity of the ingredient to the recipe, something like:

{ 
  "title": "Baked potatoes",
  "ingredients: [
    { "name": "potatoe", "quantity": "1 kg" },
    { "name": "salt", "quantity": "10 gr" }
  ]
}

The ingredients collection within the recipe is not a resource as on it’s own it does not exist.
Technically in the datastore there will be something like recipe_ingredient but not in the resource model.

How would this look like with jsonapi?
Basically I want to have a relationship for each recipe ingredient to an actual ingredient resource.


#2

Take a look here where there is a great answer. Do note my follow up post just after.


#3

Hi Michael,

It’s quite interesting discussion you linked with various opinions.
With my case I just wanted represent a simple example as actually my model is a little bit more complicated :wink:

That’s why using "meta" is not an option.
So it probably best to introduce a fabricated resource.
In the example below a use id’s 1, 2 but it probably would be better to use some opaque id here.

Note that I’m also not adding self links to the ingredients resources as I have no resource endpoint for them.
Looking at the spec this is not required. So basically this ingredients resources can only be retrieved as part of the recipes resource, but not on itself, although that feels a little bit weird to be honest.

      {
        "data": {
          "type": "recipes",
          "id": "1",
          "attributes": {
            "title": "Baked potatoes",
            "ingredients: [
              { "name": "potatoe", "quantity": "1 kg" },
              { "name": "salt", "quantity": "10 gr" }
            ]
          },
          "ingredients": {
            "links": {
              "self": "http://example.com/recipes/1/relationships/ingredients",
              "related": "http://example.com/recipes/1/ingredients"
            },
            "data": [
              { "type": "ingredients", "id": "1" },
              { "type": "ingredients", "id": "2" }
            ]
          },
          "links": {
            "self": "http://example.com/recipes/1"
          }
        },
        "included": [{
          "type": "ingredients",
          "id": "1",
          "attributes": {
            "name": "potatoe",
            "quantity": "1 kg"
          }
        }, {
          "type": "ingredients",
          "id": "2",
          "attributes": {
            "name": "salt",
            "quantity": "10 gr"
          }
        }]
      }

#5

I’m not gonna lie, this is pretty novel and interesting. Based on my knowledge of the spec, I have to agree this is valid.

I can see some interesting and unintended side effects of this, but I can’t even suggest this is against the intent of the spec.

My feedback, would be to remove the attributes, as they are extraneous, add a sortOrder field if ordering is significant. What is clear is using attribute and include is against the spec.

I’d suggest as a convention for resources using this method to not support the include and possibly even field parameters, as it should render the ingredients unreachable.

Good find, cool idea!