Skip to content

Instantly share code, notes, and snippets.

@pimterry
Last active October 3, 2019 07:14
Show Gist options
  • Save pimterry/7e5fbc1a2a89b68a1bcf55bab40ec07c to your computer and use it in GitHub Desktop.
Save pimterry/7e5fbc1a2a89b68a1bcf55bab40ec07c to your computer and use it in GitHub Desktop.

A Proposal for Batched REST

An alternative to both REST & GraphQL, combining the benefits of each, based on https://tools.ietf.org/id/draft-snell-http-batch-00.html.

Batch multiple related requests into one HTTP request, which can be sent once & processed once on the server-side, but otherwise keep all the benefits of REST & HTTP. This is one single raw HTTP request:

POST /batch
Host: example.com
Content-Type: multipart/batch

--batch
Content-Type: application/http;version=1.1
Content-Id: author
Multipart-Failure: fail

GET /authors/5?fields=name
Accept: application/json

--batch
Content-Type: application/http;version=1.1
Content-Id: books
Parent-Content-Id: author
Multipart-Failure: ignore

GET /books?fields=title
Accept: application/json

Shown as HTTP/1.1 for readability, but there's no reason this couldn't work with HTTP 2 or 3. All the above is valid today, the only totally new headers are Multipart-Failure (to describe what to if a part is not available) and Parent-Content-Id (filters the books according to the related content). Otherwise it's all 100% standard REST & HTTP.

Equivalent to:

Vanilla REST

GET /authors/5?fields=name
Host: example.com
Accept: application/json

plus

GET /books?author=5&fields=title
Host: example.com
Accept: application/json

(or /author/5/books?fields=title, if you prefer)

GraphQL

POST /graphql
Host: example.com
Accept: application/json

{
    author(id: 5) {
        name
        books {
            title
        }
    }
}

Benefits

  • One single batched request; sent in one go, can be processed server-side in one go, and returns a single consistent view of the data.
  • CDNs & browser caches can cache each part of this, if they'd like.
    • For root resources (author) that's trivial: understand the structure, cache exactly as normal
    • For dependent resources (books) the cache can be aware of the relationship, and cache based on that. It needs to store the books request along with the base resource URL of the parent content. Could do this incrementally later, and cache just root data initially.
  • Cache behaviour can be controlled with cache-control headers just like normal, content type negotiation per part works just like normal, etc etc.
  • Unlike GraphQL, batches can be explicitly resilient to missing data (multipart-failure: ignore/fail in the headers)
  • The response can be streamed as each part is available, rather than blocking for the whole batch, as GraphQL has to. The response would also be a multipart response, with In-Reply-To refering to the Content-Id of each part of the request, and each part of that response can be sent as soon as it's available on the server.
  • Separate headers mean you can do things like authenticate different parts of the same request independently, and/or use different content types for each, or whatever else you like.
  • Data requests can be easily batched alongside resource requests (get a user and their profile photo), unlike GraphQL.

Caveats

  • No caches support this right now (but they totally could)
  • None of your backend frameworks support this right now (but they totally could)
  • None of your HTTP request libraries support this right now (but they totally could)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment