# Managing relationships with data

**URL:** <https://discuss.jsonapi.org/t/managing-relationships-with-data/2852>\
**Category:** Uncategorized\
**Created:** [June 4, 2024, 10:04pm UTC](https://discuss.jsonapi.org/t/managing-relationships-with-data/2852 "2024-06-04T22:04:35Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![lukas79](https://avatars.discourse-cdn.com/v4/letter/l/9dc877/32.png) [@lukas79](https://discuss.jsonapi.org/u/lukas79)\
**Post date:** [June 4, 2024, 10:04pm UTC](https://discuss.jsonapi.org/t/managing-relationships-with-data/2852/1 "2024-06-04T22:04:35Z")

</div>

Hi all!  
Our team is going to implement some APIs. We committed to use json:api specification, but we struggle to handle correctly the `relationship` concept.  
We have Project and Components. Each Project contains an ordered set of Components. Each Component could be contained in several Projects. A relationship between the two entities is used to store the position of each Component within a Project. We have identified the following resources:

- Project (a resource)
- Component (a resource)
- ProjectComponent (a relationship resource): this resource is the only way we have found (in our intepretation of json:api) to handle the position of a Component within a Project

I would like to know if the following content is correct in terms of json:api specification.

**Project**

```auto
{
    links: {
        self: "/project/1"
    },
    data: [{
        id: "1",
        type: "project",
        attributes: {
            title: "Project A"
        },
        relationships: {
            project_components: {
                links: {
                    self: "/project/1/relationships/project_components",
                    related: "/project/1/project_components"
                },
                data: [{
                    id: "A",
                    type: "ProjectComponent"
                },
                {
                    id: "B",
                    type: "ProjectComponent"
                }]
            }
        }
    }]
}

```

**Relationship ProjectComponents**

```auto
{
    links: {
        self: "/project/1/relationships/project_components",
        related: "/project/1/project_components"
    },
    data: [{
        id: "A",
        type: "ProjectComponent"
    },
    {
        id: "B",
        type: "ProjectComponent"
    }]
}

```

**ProjectComponents**

```auto
{
    links: {
        self: "/project/1/project_components"
    },
    data: [{
        id: "A",
        type: "ProjectComponent",
        attributes: {
            position: "1"
        },
        relationships: {
            project: {
                links: {
                    related: "/project/1"
                },
                data: [{
                    id: "1",
                    type: "project"
                }]
            },
            component: {
                links: {
                    related: "/component/A"
                },
                data: [{
                    id: "A",
                    type: "component"
                }]
            }
        }
    {
        id: "B",
        type: "ProjectComponent",
        attributes: {
            position: "2"
        },
        relationships: {
            project: {
                links: {
                    related: "/project/1"
                },
                data: [{
                    id: "1",
                    type: "project"
                }]
            },
            component: {
                links: {
                    related: "/component/B"
                },
                data: [{
                    id: "B",
                    type: "component"
                }]
            }
        }
    }]
}

```

**Component**

```auto
{
    links: {
        self: "/components"
    },
    data: [{
        id: "A",
        type: "Component",
        attributes: {
            title: "Component A"
        },
        relationships: {
            project_components: {
                links: {
                    related: "/project/1/project_components/A"
                },
                data: [{
                    id: "A",
                    type: "ProjectComponent"
                }]
            },
            component_questions: {
                links: {
                    self: "/component_questions/A"
                },
                data: [{
                    id: "100",
                    type: "ComponentQuestion"
                },{
                    id: "101",
                    type: "ComponentQuestion"
                }]
            }
        }
    {
        id: "B",
        type: "Component",
        attributes: {
            title: "Component B"
        },
        relationships: {
            project_components: {
                links: {
                    related: "/project/1/project_components/B"
                },
                data: [{
                    id: "B",
                    type: "ProjectComponent"
                }]
            },
            component_questions: {
                links: {
                    self: "/component_questions/B"
                },
                data: [{
                    id: "200",
                    type: "ComponentQuestion"
                },{
                    id: "201",
                    type: "ComponentQuestion"
                }]
            }
        }
    }]
}

```

---

<div class="post-metadata">

**Author:** ![jelhan](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.jsonapi.org/jelhan/32/822_2.png) [@jelhan](https://discuss.jsonapi.org/u/jelhan)\
**Post date:** [June 9, 2024, 11:27am UTC](https://discuss.jsonapi.org/t/managing-relationships-with-data/2852/2 "2024-06-09T11:27:31Z")

</div>

> [@lukas79](#):
>
> I would like to know if the following content is correct in terms of json:api specification.

Yes. Everything looks fine.

> [@lukas79](#):
>
> ProjectComponent (a relationship resource): this resource is the only way we have found (in our intepretation of json:api) to handle the position of a Component within a Project

This is one way to model an ordered relationship.

As relationship data may be interpreted as an ordered list you could omit the interim resource. But this has the trade-off that changing the order requires a full replacement of the relationship. This may cause collisions.

Your approach using an index also comes with trade-offs. Moving a resource in the list may require updating several Indexes at once. You have two options doing so:

1. Updating only the index of the moved resource. The server takes care of updating all other indexes to ensures that there aren’t any collisions. And - depending on your implementation - no gaps. The server needs to inform the client about those side-effects by including the changes resources in the response.

2. Updating the index of all affected resources. This has the major trade-off that an extension such as [Atomic Operations](https://jsonapi.org/ext/atomic/) is required. JSON:API base specification does not support updating multiple resources in an atomic operation.

---

<div class="post-metadata">

**Author:** ![lukas79](https://avatars.discourse-cdn.com/v4/letter/l/9dc877/32.png) [@lukas79](https://discuss.jsonapi.org/u/lukas79)\
**Post date:** [June 10, 2024, 6:31am UTC](https://discuss.jsonapi.org/t/managing-relationships-with-data/2852/3 "2024-06-10T06:31:17Z")

</div>

@jelhan  
Thank you for your answer.

Ok. I should say, we were a bit worried, because to model a simple relationship that carries one value (the position) we had to define several endpoints. But this is how the json:api specification works, hence it’s ok. It also means that we’ve correctly interpreted the specifications.

Yes, I’ve also thought about integrating the position within the order of the relationship itself, but I wanted to model a relationship in a way that could be extended with other attributes (even if now it was just to understand if the model was correctly defined).

About the consequent tradeoffs, we are going to update the position within the server. That means, a patch would trigger on the server a set of updates on different components. I’ve a question about the suggested response: if I patch a single resource, how could I send back in the response the resources that have been touched too? I send back all the list of resources when I patch one? Or at least the ones that have changed? This should be documented in the API.

I’ve read about that extension, at the moment we are not going to use it.

Thank you again.

---

<div class="post-metadata">

**Author:** ![jelhan](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.jsonapi.org/jelhan/32/822_2.png) [@jelhan](https://discuss.jsonapi.org/u/jelhan)\
**Post date:** [June 10, 2024, 7:48am UTC](https://discuss.jsonapi.org/t/managing-relationships-with-data/2852/4 "2024-06-10T07:48:35Z")

</div>

> [@lukas79](#):
>
> I should say, we were a bit worried, because to model a simple relationship that carries one value (the position) we had to define several endpoints.

You don’t need to expose such endpoints. The JSON:API specification does not enforce having the endpoints. It only defines processing rules for them if they exist. You can also have resources which are only available through including in a compound document.

> [@lukas79](#):
>
> if I patch a single resource, how could I send back in the response the resources that have been touched too?

A server can and should respond with a compound document in that case. If you include all related resources or only those which have been modified is an optimization question for your implementation.

---

<div class="post-metadata">

**Author:** ![lukas79](https://avatars.discourse-cdn.com/v4/letter/l/9dc877/32.png) [@lukas79](https://discuss.jsonapi.org/u/lukas79)\
**Post date:** [June 10, 2024, 8:44am UTC](https://discuss.jsonapi.org/t/managing-relationships-with-data/2852/5 "2024-06-10T08:44:27Z")

</div>

> [@jelhan](#):
>
> You don’t need to expose such endpoints. The JSON:API specification does not enforce having the endpoints. It only defines processing rules for them if they exist. You can also have resources which are only available through including in a compound document.

Yes, this I know. But as soon as I need to modify them, I need at least some of them. In my case, I need at least the **ProjectComponents** because it’s the only way I have to edit the whole content of the relationship (if it carries more information than just the position). Because, if I’m not wrong, I can’t edit a related resource within a **patch** request. Or I use the **AtomicOperation** extension, but I would try to use it only when I can’t do otherwise.

---

<div class="post-metadata">

**Author:** ![jelhan](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.jsonapi.org/jelhan/32/822_2.png) [@jelhan](https://discuss.jsonapi.org/u/jelhan)\
**Post date:** [June 10, 2024, 9:28am UTC](https://discuss.jsonapi.org/t/managing-relationships-with-data/2852/6 "2024-06-10T09:28:47Z")

</div>

> [@lukas79](#):
>
> I need at least the **ProjectComponents** because it’s the only way I have to edit the whole content of the relationship (if it carries more information than just the position).

Yes. Even to modify the position you need to provide a `self` link for that resource. If you have a `self` link it must support fetching the resource via GET request as well.

---

<div class="post-metadata">

**Author:** ![lukas79](https://avatars.discourse-cdn.com/v4/letter/l/9dc877/32.png) [@lukas79](https://discuss.jsonapi.org/u/lukas79)\
**Post date:** [June 10, 2024, 9:57am UTC](https://discuss.jsonapi.org/t/managing-relationships-with-data/2852/7 "2024-06-10T09:57:37Z")

</div>

Wait, I’m a big confused now.  
In **Project** we have the relationship **project\_components** :

```auto
...
relationships: {
            project_components: {
                links: {
                    self: "/project/1/relationships/project_components",
                    related: "/project/1/project_components"
                },
                data: [{
                    id: "A",
                    type: "ProjectComponent"
                },
                {
                    id: "B",
                    type: "ProjectComponent"
                }]
            }
        }
... 

```

that provides two links.

- self, to obtain the same list of object (relationship), and
- related, that provides a way to obtain the related resource, **ProjectComponents**.

I thought I could avoid `self`, because what it returns is just this:

```auto
links: {
    self: "/project/1/relationships/project_components",
    related: "/project/1/project_components"
},
data: [{
    id: "A",
    type: "ProjectComponent"
},
{
    id: "B",
    type: "ProjectComponent"
}]

```

While I must have the `related` because in my situation it’s the only way to manipulate the content of the relationship.

```auto
{
    links: {
        self: "/project/1/project_components"
    },
    data: [{
        id: "A",
        type: "ProjectComponent",
        attributes: {
            position: "1"
        },
...

```

With `self` here

> [@jelhan](#):
>
> Yes. Even to modify the position you need to provide a `self` link for that resource. If you have a `self` link it must support fetching the resource via GET request as well.

Do you mean this? Right? Self refers to the resource object itself, not the relationship defined in **project**.

If yes, then I could say that I’ve understood correctly the specification.

---

<div class="post-metadata">

**Author:** ![jelhan](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.jsonapi.org/jelhan/32/822_2.png) [@jelhan](https://discuss.jsonapi.org/u/jelhan)\
**Post date:** [June 10, 2024, 6:31pm UTC](https://discuss.jsonapi.org/t/managing-relationships-with-data/2852/8 "2024-06-10T18:31:44Z")

</div>

I was talking about the `self` link of a _resource_. That’s different from the `self` link of a _relationship_.

The `self` link of a _resource_ is used to interact with that resource. E.g. to fetch it (`GET`), to update it (`PATCH`), or to delete it (`DELETE`).

The `self` link of a _relationship_ is used to interact with the relationship. E.g. to add a resource to a has-many relationship (`POST`) and to remove a resource from a has-many relationship (`DELETE`).

Depending on your API design you may not need neither `self` nor `related` links for the `project_components` relationship. You could provide relationship data only via compound document from either the project (`GET /project/1?include=project_components.component`) or the component (`GET /component/A?include=project_components.project`). The relationship between a project and component could be managed by creating (`POST /project/1/project_components`) or deleting (`DELETE /project/1/project_components/A`) the interim model.

---

<div class="post-metadata">

**Author:** ![lukas79](https://avatars.discourse-cdn.com/v4/letter/l/9dc877/32.png) [@lukas79](https://discuss.jsonapi.org/u/lukas79)\
**Post date:** [June 10, 2024, 7:54pm UTC](https://discuss.jsonapi.org/t/managing-relationships-with-data/2852/9 "2024-06-10T19:54:45Z")

</div>

That’s a much better and clear explanation of what I was meaning with my post.

Thank you very much for your help! I would say that for me the whole question got an answer that is satisfying.
