Single Endpoint Proposal


#1

Has anyone explored using a single endpoint for their API?

On my team, we recently began using the included array for updating multiple resources in a single PATCH request:

http://example.com/people/1

{
  "data": {
    "type": "people",
    "id": "1"
    "attributes": {
      "first-name": "Mike"
    }
  },
  "included": [{
      "type": "comments",
      "id": "2",
      "attributes": {
        "body": "My updated comment!"
      }
    }
  ]
}

This made me realize that if we can update multiple resources using the included array as an entry point, our API can act similarly, sending and receiving a data array of mixed types – so long as each object has a type property and optionally an id when using PATCH or DELETE.

For example, if we want to create multiple resources we can POST to our single endpoint API:

http://example.com/api

{
  "data": [{
      "type": "people",
      "attributes": {
        "first-name": "Dan",
        "last-name": "Gebhardt",
        "twitter": "dgeb"
      }
    }, {
      "type": "comments",
      "attributes": {
        "body": "First!"
      }
    }, {
      "type": "comments",
      "attributes": {
        "body": "I like XML better"
      }
    }
  ]
}

A GET of various resource, even those which do not have a relationship, can look like this:

{
  "data": [{
      "type": "people",
      "id": "9"
    }, {
      "type": "comments",
      "id": "5"
    }, {
      "type": "comments",
      "id": "12"
    }
  ]
}

I realize this may require some reworking of the request/response object structure, however I believe this approach allows for an API that closely resembles GraphQL and no longer requires the overhead of creating endpoints for every resource type.


#2

There is a lot of prior work and discussion on the best way to support multiple write operations in a single request. See for example https://github.com/json-api/json-api/issues/795

I think the desire to avoid the “overhead of creating endpoints” misses the point that any server smart enough to serve arbitrary requests on a single endpoint in a performant way can just as easily auto-generate multiple endpoints instead. There is no real savings in trying to fit everything into a single endpoint – the difference is cosmetic.

One of the strengths of JSONAPI is that the server gets to be more picky about what access patterns it supports. Some access patterns are fiendishly more expensive to serve quickly than others. But nothing stops a JSONAPI server from offering fully-generic access just like a GraphQL server.


#3

Thanks for linking to that thread. I’ve quickly read through it, however I was unable to determine the leading proposal. Is it this proposal: https://github.com/json-api/json-api/issues/1097?

I found this on the thread as well:

PATCH /articles HTTP/1.1
Host: example.org
Content-Type: application/tbd

[
  {
    op: 'add',
    data: {
      type: 'articles',
      attributes: {
        title: 'JSON API paints my bikeshed!'
      }
    }
  },
  {
    op: 'add',
    ref: {
      type: 'authors'
    },
    data: {
      type: 'authors',
      attributes: {
        name: 'dgeb'
      }
    }
  },
  {
    op: 'replace',
    ref: {
      type: 'articles',
      id: { path: '/0/data/id' },
      relationship: 'author'
    },
    data: {
      type: 'authors',
      id: { path: '/1/data/id' }
    }
  }
]

#4

Yes, many specifications do this. It’s against RESTful principles, though, as you lose a lot of things when you do it that way.