-
Notifications
You must be signed in to change notification settings - Fork 882
Introduce Local Identities extension #1436
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
Conversation
Curious about this requirement:
One of the prime use cases for local IDs is to sync records in JS memory with the server, which this prevents. IOW let's say I have 3 |
@richmolj We discussed different means to return a local/server mapping of IDs, but were unable to justify the additional complexity for the known use cases. The position of resources in a response document should be sufficient to make the association between local IDs and server-generated IDs in every scenario in both the base spec and the proposed atomic operations extension (#1437). Clients should be able to await the response document to perform mappings for server-generated IDs. |
Co-Authored-By: Gabe Sullice <[email protected]>
@richmolj Won't a |
@jugaadi My understanding is that while a local ID could indeed be defined in a resource's meta object via a profile, referencing a local ID in relationship data requires an addition to the base spec which can only be achieved by an extension. |
I have the same comment as @richmolj, that afaik most people that want local IDs need them to sync JS state with server-state.
Some examples:
|
The challenge here is that we are now essentially discussing making accommodations for extensions that have not been written and formalized. As I said above, the position of resources in a response document should be sufficient to make the association between local IDs and server-generated IDs in every scenario in both the base spec and the proposed atomic operations extension. Let's say that someone decides to formalize the conventions used by Ember's embedded record mixin as a community extension. There are a couple paths we could take:
There are pros / cons to each approach. With the first approach, the "pro" is that we keep "official" extensions as lean as possible, while encouraging other extensions to meet their own needs. The "con" is that the embedded extension may not share the same logic as another community extension that attempts to solve the same problem. With the second approach, the "pro" is that the solution is probably general enough to meet the future needs of any extension that needs a local identity map. The "con" is that it adds complexity to the local identities extension and every implementation that supports it so that some as-yet-unspecified extension can benefit. |
A related point I should make here is that extensions themselves can evolve, as long as they evolve in a compatible way. For example, we could start with the simple form of the local identities extension (as currently defined). If the need arises over time across multiple extensions to have an identities map, we could specify that if clients include an array of |
@dgeb I see your point! Position in the document is indeed enough (theoretically), however it feels somewhat brittle and I guess that's what some people (me included) have against it. Also, maybe there are scenarios where the server won't respond with all embedded records in the payload? You know the spec better than me, but it seems like it may allow returning only the primary document. I think your suggestion about making it optional depending on whether the client included an array of local:ids in the request or not could be a good middle ground. Also, although I understand your concern about making accommodations for something somewhat specific, I still think there is a difference between the main spec and the extensions. I think it's natural that extensions are slightly more opinionated/narrow than the base spec, because they are catering to specific use-cases. Handling of side-posting for embedded records has been an known issue for several years and this would be an awesome way to fix it. It could look something like this:
POST /people HTTP/1.1
Content-Type: application/vnd.api+json;ext="https://jsonapi.org/ext/local"
Accept: application/vnd.api+json;ext="https://jsonapi.org/ext/local"
{
"data": {
"type": "people",
"attributes": {
"firstName": "John",
"lastName": "Doe"
},
"relationships": {
"addresses": [{
"data": {
"local:id": "a",
"type": "addresses"
}
}, {
"data": {
"local:id": "b",
"type": "addresses"
}
}]
}
},
"included": [{
"data": {
"local:id": "a",
"type": "addresses",
"attributes": {
"label": "Work",
"street": "10 Downing Street",
"zip": "3819ZY",
"city": "London"
}
}
}, {
"data": {
"local:id": "b",
"type": "addresses",
"attributes": {
"label": "Home",
"street": "5 Kensington Gardens",
"zip": "4213ZV",
"city": "London"
}
}
}],
"local:ids": ["a", "b"]
} HTTP/1.1 201 Created
Location: http://example.com/people/550e8400-e29b-41d4-a716-446655440000
Content-Type: application/vnd.api+json;ext="https://jsonapi.org/ext/local"
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"type": "people",
"attributes": {
"firstName": "John",
"lastName": "Doe"
},
"relationships": {
"addresses": [{
"data": {
"local:id": "4ceb5ea7-8f2f-4836-9294-f235f3e506b4",
"type": "addresses"
}
}, {
"data": {
"local:id": "9dc4ec66-4c2b-483d-b15f-151a61d91bf9",
"type": "addresses"
}
}]
}
},
"included": [{
"data": {
"id": "4ceb5ea7-8f2f-4836-9294-f235f3e506b4",
"type": "addresses",
"attributes": {
"label": "Work",
"street": "10 Downing Street",
"zip": "3819ZY",
"city": "London"
}
}
}, {
"data": {
"id": "9dc4ec66-4c2b-483d-b15f-151a61d91bf9",
"type": "addresses",
"attributes": {
"label": "Home",
"street": "5 Kensington Gardens",
"zip": "4213ZV",
"city": "London"
}
}
}],
"local:map": {
"a": "4ceb5ea7-8f2f-4836-9294-f235f3e506b4",
"b": "9dc4ec66-4c2b-483d-b15f-151a61d91bf9"
}
} Regardless of where this discussion ends up, my main desire is for this to move forward! 😄 |
I'm not quite sure I understand it. I was only referring to the root meta object. I guess the best way forward would be to evolve this extension based on the community feedback as @dgeb suggested. |
Any updates? |
Great observation @freddrake, you helped @dgeb and me understand that the spec is missing some nuance in its content negotiation responsibilities (see #1461). I think you're right about the example too. We'll get that fixed. Thanks! |
@dgeb @gabesullice I've updated my comment with a more fleshed-out example. Let me know what you think! |
@freddrake @gabesullice I've removed the extension from both the |
@sandstrom Thank you for the continued discussion.
You'll have to provide an example of brittleness for me to agree here. I believe you're confusing brittleness with inability to fully support potential future extensions, not inability to support the base spec or the proposed operations extension.
We are not seriously considering side-posting support in the base spec, since there are many limitations and edge cases that it does not support. However, let's say that someone creates a "side-posting" extension in the future. To support server-generated IDs, that extension may rely upon this local identities extension to declare relationships among resources. The side-posting extension could then declare how to request and return a map of those local identities. That map would need to be under the |
At this point, the biggest debate I'm having re: this extension is whether Should that hole be filled directly in the base spec or via extension? |
@dgeb: Here's a question for you; perhaps you've thought of this use case already, but I think it's a fairly common situation. If an application provides an "issue tracker" functionality (similar to github, gitlab, etc.), where there's an I can imagine handling this as a I started asking about modeling this in the forum (https://discuss.jsonapi.org/t/post-one-resource-type-to-create-another/1830), but discussion didn't get anywhere (possibly because my explanation wasn't clear). I'm really not sure of the best way to model this in a proper REST API. Since local ids are really only present in requests, and responses won't have them, I don't see a problem with making it an extension. What a service implementation needs to do to handle them correctly can be fairly significant, to making it clear in the headers that the additional concerns are in play might be valuable. For applications that want to take advantage of other 1.1 enhancements, but that don't need this, knowing a request can be quickly rejected might be worthwhile. |
@dgeb I agree with your statement above, it's certainly true. Brittle is the wrong word. Perhaps implicit/obtuse is better. For example, if you rely on a serialization library it may be difficult to modify it to ensure a correct order of the returned resources, and possibly easier with something like
The self-reference use-case is a valid one. For us it's a much lesser concern than the problem with embedded records, specifically in Ember data. But what you propose (adding it to the 1.1. base spec) sounds reasonable! For us specifically, our main pain point is around side-posting and embedded records, and how to reference them such that the client can map the embedded records it sent in, with the response it got back. I guess there are several routes that can take us there:
You're in a better position to determine which course of actions is best to take, so I'd be in favour of both! 😄 If I'd have to guess, maybe smaller, narrow increments are easier to make progress on. |
The local identities extension proposal is being withdrawn in favor of the original |
This is a proposal for an official extension to the JSON:API spec, as described in #1435. This proposal is based upon #1244, and supersedes that PR.
This extension provides a means to uniquely identify resources "local" to a specific document. It uses the namespace
local
.Resources can be assigned a "local identity" (
local:id
) that can be used to reference each other before they have been assigned a permanentid
.