Skip to content

Instantly share code, notes, and snippets.

@ethanresnick
Last active April 13, 2018 22:00
Show Gist options
  • Save ethanresnick/7ffe6278ecea150a08f901c8e9cad4ca to your computer and use it in GitHub Desktop.
Save ethanresnick/7ffe6278ecea150a08f901c8e9cad4ca to your computer and use it in GitHub Desktop.
Profile extension ideas

Revision Member

A profile specifying a member clients/servers can include in each resource object (maybe as an attribute; maybe in meta) to indicate the "version" of the resource object, so that the server can reject requests to update the resource if it has changed since the client downloaded it. (Basically, #600.)

Key for profile error handling semantics: Servers that understand the extension MUST reject a PATCH to an old version of the resource. (Servers that don't understand the extension would allow the PATCH because they'd ignore the revision member.)

Deprecations

A way for the server to indicate that something used in the request (e.g., the request url, a query param, or a field included in a resource object) is deprecated, or that some data shown in the response is deprecated. The server can also provide dates when this information/features will be removed. All this information would live in document- and resource-level meta. As I imagine it, clients that support this extension would see the deprecation notices and log them, so that the API's administrator would be notified.

Resource Interfaces

A profile allowing the server to indicate, for each resource object, a list of "interfaces" or subtypes, to describe other contracts (in terms of fields and possibly operations) that the resource satisfies, in addition to the contract implied by its type. This feature is similar to interfaces in GraphQL and would address the problems/use cases raised in #862. Each interface is just a string name with an application-specific meaning. The list would be specified in the resource's meta object.

Relationships in complex attributes

This profile would allow relationships to be specified in complex attributes. This would be a (very-much-needed) hack until the base spec enables such relationships as first class citizens. Since the spec has reserved the relationships and links members, these relationships would have to live somewhere else. Exactly how they would live in the document depends a lot on the final profiles design (the aliasing system, etc.).

Filtering profile

A profile that defines standard query parameter values that can be used to filter a collection.

Actions

A profile allowing the server to indicate subsequent requests that the client can make relating to resources in the response document. Basically, a way for the server to provide (named) links for further navigation and (named) forms for further interaction.

The key here is that these actions are dynamic -- e.g., an article's "publish" action would appear in the response if and only if the article isn't published and the user is authorized to publish it. This makes it possible to create a permissions model on the server and not duplicate all that logic on every client, which is very useful.

Ideally, this data would live in links [though none of the proposals so far have thought about how to make that extensible], but it could also live in resource and document meta if need be.

JSON:API Home Doc

A profile that would define a set of attribute names, resource types, etc. that could be used to create a "home document". This home document would list the types the API supports, their fields and validation constraints, etc. I used such a home document on a past project to auto-generate an admin UI for an API, and it worked well.

The document might look something like:

{
  // The home document provides one resource object to describe each type
  // the api supports. The result is a valid json:api document, but where all
  // keys have a meaning/value defined by the profile. Here, the type for each
  // description must be "jsonapi-descriptions"; the `id` must be the name of 
  // the `type` being described; the attributes have special meanings; etc.
  "data": [{
    "id": "affiliations",
    "type": "jsonapi-descriptions",
    "attributes": {
      "name": {
        "model": "Affiliation",
        "plural": "Affiliations"
      },
      "childTypes": [],
      "fields": [{
        "name": "user",
        "friendlyName": "User",
        "kind": {
          "baseType": "Relationship",
          "isArray": false,
          "targetType": "users"
        },
        "validation": {
          "required": true
        }
      },
      /* more fields... */
      ]
    }
  },
  /* more types... */  
  ]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment