-
Notifications
You must be signed in to change notification settings - Fork 887
Clarify usage of parallel relationships #1677
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: gh-pages
Are you sure you want to change the base?
Conversation
Hey. We're using the JSON:API spec for some REST APIs at TIDAL, and have discussed the topic of parallell relationships. We have weighed some pros and cons for a specific case, and we will probably go for a solution where we support parallell relationships. The SHOULD NOT wording seems to strike a good balance in the specification. In addition to adding the SHOULD NOT clarification on to-many relationships, would it make sense to also update the wording in the Updating to-many relationships section? Currently it reads, for POSTs:
Changing MUST NOT to SHOULD NOT also for CRUD operations wrt parallell relationships, would keep the recommendation not to support parallell relationships, but also clarify that it is a valid implementation. Thanks! |
I feel we should keep the MUST NOT in this case. One of the design goals of JSON:API is ensuring that a client can change the server's state without needing to know it. That eases consumers a lot. E.g. in case a request to add a relationship fails, the client can send the request again without needing to check before if the server has processed the request or not. Maybe we should add a similar clarification that a I get that this requires using full replacement to manage parallel relationships. But in my perspective that's only one of the many drawbacks you get when using that discouraged pattern. The benefits for the recommended usage of relationships strongly outweigh that trade-off in my perspective. Please note that the primarily reason for using SHOULD NOT instead of MUST NOT for parallel relationships is not introducing breaking changes. So far I have not seen any use case, which is better solved by parallel relationships than intermediate resources. |
Thank you for the swift and clear reply @jelhan, much appreciated. First of all, I do agree that from a modelling perspective, using intermediate resources most likely represents the best solution. The reason we are leaning towards supporting parallell relationships are strictly practical. We are in essence retrofitting JSON:API on top of a previously existing system/API. The way our data is currently structured, and the way we handle includes, would mean either quite a bit of work for us, or quite a compromise on performance and flexibility for clients, if we relied on intermediate resources. Also, each resource in the relationship will have a unique id in A few follow ups, just to make sure I understand correctly:
Got it, makes sense. What is your take on how compatible this goal is with the note in section 7.2.2.4, essentially saying that an implementation may choose to treat a to-many relationship as ordered (something we are also doing for several to-many relationships!). In essence, if an implementation chooses to treat a to-many relationship as ordered, doesn't the ordering of the to-many relationship represent a state that a client may need to relate to before mutating the relationship? Thank you. |
I struggle imagining such a scenario. Would be great if you could elaborate. Maybe I'm missing relevant use cases for parallel relationships. I assume it's just a matter of the serialization if representing it as an intermediate resource or not. If I get you right, you already have a unique identifier for each reference to a resource in that parallel relationship. In that case you already have an I expect you have a serialization such as the following today: {
"data": {
"type": "teams",
"id": "1",
"relationships": {
"members": {
"data": [
{
"type": "teams_members",
"id": "23",
"meta": {
"id": "101"
}
},
{
"type": "users",
"id": "23",
"meta": {
"id": "102"
}
}
]
}
}
}
} What additional challenges due you face serializing it as the following: {
"data": {
"type": "teams",
"id": "1",
"relationships": {
"members": {
"data": [
{
"type": "teamsMembers",
"id": "101"
},
{
"type": "teamsMembers",
"id": "102"
}
]
}
}
},
"included": [
{
"type": "teamsMembers",
"id": "101",
"relationships": {
"user": {
"type": "users",
"id": "23"
}
}
},
{
"type": "teamsMembers",
"id": "102",
"relationships": {
"user": {
"type": "users",
"id": "23"
}
}
}
]
} Unless I missed something, I have just moved existing information around and made up a
No. Mutation of parallel relationships are possible. But with the limitation that full replacement must be used in some cases:
The JSON:API specification does not define how a client can change the order of an ordered to-many relationship. If sending the same request multiple times could lead to unexpected results depends on the specific implementation. I expect that most implementations does not have such a problem. E.g. if the order is mutated by a full-replacement of the relationship, the client describes the desired state in the request independently of the server state. The result is the same regardless if the request is successfully processed once or multiple times. The same is true if the implementation provides some way for a client to specify adding a reference in a specific position of a relationship. It's only an issue if an implementation allows mutation depending on current state (e.g. "move one up/down"). |
You didn't miss anything, and your example illustrates exactly how we would model it using intermediate resources. As I mentioned, the reasons we're leaning towards not using intermediate resources are strictly practical and a result of some design decisions/trade offs, and our current implementation. One concrete example is our logic that generates compound documents (
Thanks
Thanks, and yes - it is the "It's only an issue if an implementation allows mutation depending on current state (e.g. "move one up/down")." case I had in mind. "Move up/down" could be one scenario. "Insert after" could be another. |
This PR tries to implement the agreement we came up in #1361.
I struggled with the wording to be honest. I found it difficult to distinguish between the different kinds of parallel relationships. For sake of clarity let me show them in code:
Different relationships
Intermediate resource
Multiple, direct reference on same relationship
We only aim to discourage using the third type of parallel relationships. We recommend to use the second type instead. I'm not sure how well this is expressed in the current wording.
Open questions:
author
,editors
) and references to resource in such relationships?Closes #1361