Same resources with different attributes in different objects

I dont understand how to apply the JSONAPI framework on my particular problem. Hopefully someone can help. Let’s say I have a shop and clients order products. Asynchronously I ship parts from different orders to the client in one shipping. I have many orders to many shippings relationships and also one order to many shippings rlship.

Thus I have /orders/:id/shippings and I get:

"jsonapi": {
    "version": "1.0"
},
"data": [
    {
        "type": "shippings",
        "id": "5DDECEN",
        "relationships": {
            "products": {
                "data": [
                    {
                        "type": "parts",
                        "id": "10PIQPD3"
                    },
                    {
                        "type": "parts",
                        "id": "10RAGPD3"
                    }
                ]
            }
        }
    },
    {
        "type": "shippings",
        "id": "5FK6CEN",
        "relationships": {
            "products": {
                "data": [
                    {
                        "type": "parts",
                        "id": "10PIXPD3"
                    }
                ]
            }...

This way I can follow up each ordered product in each shipping from each order etc. Now when it comes to the resource object of the relationship which is defined by the related route order/:id/shippings I would get all the products including their quantity and price etc. An here is also what I do not understand… if each product is from the type ‘part’ and I include all the parts in the order-shippings relationship I have different attributes compared to the type ‘part’ self link

Let’s say I include products into the shippings thus I will be able to see which products have been shipped in which quantity. The type part on the other hand is the underlying type of product and thus the self link of the product/part points to /parts/:id

"data": [
    {
        "type": "shippings",
        "id": "5DDECEN",
        "relationships": {
            "products": {
                "data": [
                    {
                        "type": "parts",
                        "id": "10PIQPD3"
                    },.......

"included": [
    {
        "type": "parts",
        "id": "10PIQPD3",
        "attributes": {
            "partCondition": "F01",
            "qtyShipped": 1
        }, links: { self: '/parts/10PIQPD3' }

However if you follow the self link you will never see the shipped quantity within the parts resource object… is this an allowed behavior / design ?

What are better approaches ? If I just attach the shipped products as an array to attributes I will display type ‘parts’ with ids within the data.attributes which is not allowed as far as I understood. How to deal with such a behavior ?

I went through it again … might this be the solution? (putting non-valid resource attributes into the meta object)

"included": [
{
    "type": "parts",
    "id": "10PIQPD3",
    "attributes": { ..... some standard resource attributes
    },
    "meta": {
        "partCondition": "F01",
        "qtyShipped": 1
    }, links: { self: '/parts/10PIQPD3' }

It seems I should go with this:

https://discuss.jsonapi.org/t/how-to-deal-best-with-relationship-in-contained-list-item/1259/3

Hey,
that product relation seems like a m:n relation with pivot data, right?

Shippings-Table {shipping_id, …}
Products-Table {shipping_id, part_id, qtyShipped, other-pivot-data}
Parts-Table {part_id}

I didn’t like it to put on the meta-tag, because actually its not meta-information.
I’ve added the field “pivot” (outside of the specification)

"included": [
    {
      "type": "parts",
      "id": "10PIQPD3",
      "attributes": {
           "name": "Part PIQ PD3", ...
      },
      "pivot": {
          "partCondition": "F01",
          "qtyShipped": 1
      }, 
      links: { self: '/parts/10PIQPD3?shipping_id=1' }
    }
]

As well I populate the links with params, like here linking to an ID: shipping_id

But actually while writing I’ve checked the specification, and I don’t know whether its good to do that?

Sorry, I think that was not to much help, but maybe it helps you for your project.

@SpirIT This is just wrong. I would strongly suggest not to add an non-standard member in included. I’m not even sure the specification allows it.

I think the error here is that you are confusing items in an order with items in a catalogue for example.

You should have something like parts with prices and whatever you need. Then, when an order is created, the products relationship should point to items or something like that. Those resources would have attributes like quantity, price (this time it’s the price that was charged to the client, it shouldn’t change), and of course, a relationship that points to a resource of type parts.

@maark thanks for your answer, somehow its confusing.
@dimisus how did you end up making it?

Relationships what we are using in you example are “Shippings” and “Parts”.
Shippings has many Parts (named products)
Parts belong to many Shippings

So we have a relation-table with pivot data in between.
eg. shipping-id: 1, part-id: 4, quantity: 3, price: 100,-

@maark what I understood is, you would make three ObjectResources: shippings, products and parts

so that you have then the include with type “products”

 "included": [
    {
      "type": "products",
      "id": "10PIQPD3",
      "attributes": {
           "partCondition": "F01",
           "qtyShipped": 1,
      },
      "relationships": {
          "part": { type: "parts", id: "10PIQPD3" },
          "shipping": { type: "shippings", id: "1" },
      }
      links: { self: '/shippings/1/products' }
    }
]

Thanks for clarifying.
Stefan

How can parts be part of many shippings?

I think this is were the error is. The original poster made a many-to-many relationship that does not work. The solution is not go around the specification to make it work, but to change the strategy completely.

And yes, your example seems good. I think the name items instead of products is more clear. When shopping, a customer can choose among some parts. When a part is selected, an items resource is created and added to a cart. This resource has a quantity, a price, and a relationship to the parts resource it represents. Once ordered, a shippings resource has many items to be shipped.

Hey guys,

I ended up with (a probably not conform) solution by handling the products as attributes of each document resource. Means I have my document eg. shipping header with all the details of this document and a special attribute called products which is the table of the document (array of products).

    "data": {
        "type": "shippings",
        "id": "4FYRCEN",
        "attributes": {
            "title": "",
            …other attributes
            "updated": "",
            "created": "",
            "products": [
                {
                    "partNumber": “123456”,
                    "partCondition": "",
                    "qtyShipped": 2,
                }
	]
}

I haven’t tried to add products as relationship resources because of the many to many relationship.
When I request all possible shippings of a client -> I will receive 1…N headers of the shipping documents where each resource can have 1…N products. Each product can be part of 1…N shippings.
Thus when I include products as resource objects and I have many ID_SHIPPING to many ID_PRODUCT relationship… how can I know which shipping or order or another document has what quantity of each product?

If we think about the article / comment relationship… provided the comment has article related content => a comment cannot be part of multiple articles… otherwise you would end up with the exact same problem I had/have …

Basically what I can do now is to add the ID shipping to ID single item relationship, where “self” points to the basic details of each product … but the document related products will still be an attribute of the document… this is only possible because my products can be identified by part numbers/article numbers and I do not include their primary ID (I think @maark described the same behaviour in this first comment)… including IDs in attributes is not legal according to the spec… but this inclusion might be pointless since the relationship would not affect my order attributes…

PS: I am using the 3 tables as described here by @SpirIT

When you say probably not conform, you just ruined your solution. It is not JSON:API compliant.

I really believe this can have a much simpler (and compliant) solution.

I think you should give use more information about how the system works. How can a parts resource be part of many shippings? What is the workflow from browsing your inventory to have parts shipped to a location?

See https://en.wikipedia.org/wiki/XY_problem

How can a parts resource be part of many shippings ? What is the workflow from browsing your inventory to have parts shipped to a location?

My workflow is that a client orders products. Each order can be partially shipped, means I can ship 50% now and 50% in one week. It mostly depends on the arrivals from the suppliers. If the customer made more than one order you have also the relationship of many orders to many shippings.

Given that I want to show all shippings which belong to one order, one product ID can be part of many shippings (eg. part X is shipped with qty 3 in shipping #1 … same part X is shipped with qty 5 in shipping #2).

Back to JSONAPI if I include parts I will have to differ which qty of part X is shipped in which shipping #ID.

eg. part X is shipped with qty 3 in shipping #1 … same part X is shipped with qty 5 in shipping #2

Well there it is. Go back to my first post:

I think the error here is that you are confusing items in an order with items in a catalogue for example.

You need shippings, parts (what users browse in your store), and something else, like items (the parts that are in an order). An items resource has a quantity, maybe also the price charged to the customer, and a relationship to the parts resource it represents.

Definitely no need to make this complicated with pivot tables, invalid JSON:API implementations, etc.

This makes sense to me. Is the trick here to try and be brutal on the identification of what the true resources are? Meaning, resources really aren’t objects?

So parts would identify parts in a catalog but when added to a shipping or order or similar they become something else, like ordered_parts (or items in your example)?

The question then is how does one build a “type” and “id” for those items as they only exist within the context of (relative to) the shipping?

Is the trick here to try and be brutal on the identification of what the true resources are?

I don’t consider this brutal at all.

Meaning, resources really aren’t objects?

Object is the sense of programming objects? All resources are objects.

So parts would identify parts in a catalog but when added to a shipping or order or similar they become something else, like ordered_parts (or items in your example)?

That’s roughly the idea.

The question then is how does one build a “type” and “id” for those items as they only exist within the context of (relative to) the shipping?

Well, the type is whatever name you want (ordered_parts, items…) and the ID is also whatever you want. They do only exist as part of a shipment. How is that an issue?

Not an issue at all it turns out. Thanks for your comments.
Subsequent to my post I’ve read all the related posts on the subject and it seems to boil down to implementation. To have IDs that are unique within a “context” just means one has to decide whether one builds a composite key or use some broader mapping table etc.

Once I started building a service in this vein it turns out to be relatively simple once I’ve decided on what are attributes and what are related resources.

There are more tricks to learn like aggregated pricing or ordered resources in a relationship but it seems even that can be nicely handled with meta objects etc.