Pattern: handling unstable IDs

I have a model whose ID is unstable. Examples of this might be using a username, email address, or blog post title as a primary ID. Most uses of JSON:API I’ve seen use stable, surrogate (or “synthetic”) keys and this is generally a good practice. Sometimes, however, you can’t change the model.

An unstable ID is a problem for JSON:API because if you make an update via PATCH, you might change the one or more fields that cause the ID to change. In that case, the response object will have an ID that doesn’t match what you sent or what’s in the URL.

My proposal for this pattern is that the response includes no data but does have an included:

PATCH /songs/never-gonna-give-you-up
Accept: application/vnd.api+json
Content-Type: application/vnd.api+json
{
  "data": {
    "id": "never-gonna-give-you-up",
    "type": "song",
    "attributes": {
      "title": "Please don't Rick-roll me",
    }
  }
}

200 OK
Content-Type: application/vnd.api+json
{
  included: [{
    "data": {
      "id": "please-dont-rick-roll-me",
      "type": "song",
      "attributes": {
        "title": "Please don't Rick-roll me",
      }
    }
  }]
}

What do people think?

Hi James, I’d like to suggest you create a UUID to refer to this resource outside of the title or some other example. An unstable identifier is likely a resource design flaw, and you should look to address it there.

I believe your proposal is invalid as far as the spec is concerned, and with the backwards compatibility philosophy of the spec it will not be acceptable.

I’d like to suggest you create a UUID to refer to this resource outside of the title

Where, exactly would you suggest I do that? The underlying system has this unstable identifier and nothing I do can change that. The only thing I could think of doing would be to create a proxy system with its own database with UUIDs mapping to the underlying (unstable) IDs, but that seems like an awful lot of work just to be compliant with JSON:API.

I have very little knowledge of your context. However, with my background I disagree with the assertion creating a stable identifier is only for {json:api} compliance.

I am a consultant and I specialize in APIs, modernizing legacy systems, and supplementing existing platform capabilities. One of the absolute first things I do is look at the domain models and architectural context and determine if there is any ‘quick sand’ like this and immediately move to remediate it.

If you can’t be sure of the resources you think you are referencing, are in fact the ones you are, then you have a much larger problem on your hands than {json:api} compliance.

@jamesarosen You are assuming that ID must not be changed to be JSON API complaint. I’m not quite sure if this assumption is true.

Specification requires that a pair of type and id must be unique and identify a single resource but if I didn’t missed anything it does not require that a single resource is only identified by one type and id pair.

Within a given API, each resource object’s type and id pair MUST identify a single, unique resource. (The set of URIs controlled by a server, or multiple servers acting as one, constitute an API.)

Specification explicitly allows a server to change “the resource(s) in ways other than those specified by the (update) request”. It only requires a server to return a 200 OK response and to “include a representation of the updated resource(s) as if a GET request was made to the request URL”.

Putting that two pieces together I don’t see how your case violates the spec. Of course you must make sure that id and type pair is always unique. And you should expect bugs in existing tools cause I don’t think anybody has considered this edge case for implementations.