Skip to content

Instantly share code, notes, and snippets.

@johanste
Created July 1, 2020 20:55
Show Gist options
  • Save johanste/05a5cfb4b015795d2402ea1d6b8c3c7d to your computer and use it in GitHub Desktop.
Save johanste/05a5cfb4b015795d2402ea1d6b8c3c7d to your computer and use it in GitHub Desktop.
Design proposal for device update/updates

As a user, I want to create an update. The update take a manifest as input. I do not get a chance to give my update a name - the name is generated by the service. Creating the update can take a long time, and the process can fail in ways that cannot be validated on the initial request since the validation is too costly. If the create fails at any point in time, no update resource will be created.

It is tempting to, as an implementor of a service, use globally unique identifiers as keys. However, if there is any possibilty to use a natural key, that is preferred. Humans are bad a remembering GUIDs. A hybrid apprach is to allow the user to optionally specify a key, and generate a key if one is not provided. The hybrid apprach makes it possible to make the operation idempotent.

There is no need for me (as a user) to list all updates that are being created at any given time. Only the user who is creating a user (or someone they hand off the process to) need to monitor the progress.

This requirement - or lack thereof - generally maps to if there is a resource that the user creates the lifetime of when the create runs. In this case, the job resource is automatically expired/deleted after 72hrs. There are also no easily identifiable properties on the job resource that a user might want to see.

Since the service supports generation of resource ids for updates, the corresponding HTTP method is POST.

The canonical target URL is the collection resource for updates.

If the service allowed the client to set the name, the http method would be PUT, and the target URL would be the update item - e.g. /updates/mypreferredname.

Request:

HTTP/1.1 POST /updates
Content-Type: application/json

{
    ...
}

Response:

HTTP/1.1 202 OK
Operation-Location: /operations/1234

Request:

HTTP/1.1 GET /operations/1234

Response:

HTTP/1.1 200 OK

Retry-After: 37
{
    "status": "creating"
}

...

Request:

HTTP/1.1 GET /operations/1234

Response:

HTTP/1.1 200 OK

{
    "status": "succeeded",
    "resourceLocation": "/updates/7891"
}

...or (in case of failure)...

HTTP/1.1 200 OK

{
    "status": "failed",
    "error": {

    }
}

Alternate design

Create the update resource immediately and track the creation progress on the update resource itself. If possible, this (resource based long running operation/RELO) is the preferred API pattern since it is simpler for the client to understand (no custom redirects needed). The main differences between this and the current approach are:

  • The resource will be created and remain even in the case of failure. It is possible, but uncommon, to automatically clean up failed resources.
  • Clients can see all update resources that are being created. This is generally a good thing, but it does mean that the client has to check the status before they try to apply the update.
  • Signalling custom progress/status of the operation becomes slightly less elegant since you end up with fields on the update resource that only applies while the resource is being created.
  • It is not possible to track multiple parallel operations. For create operations, this is a non issue (you can only create a given resource once).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment