JSON API
jsonapi.org
jsonapi.org
What's the reason for the top level rel? It seems like it's just there to stop the urls from being repeated and to save space, but isn't that what gzip is for? Why complicate the data format and require all that extra logic and gzip would remove most of the redundancy before transmission anyway?
Also the name is a bit of an annoying land grab. It'll make it hard to talk about JSON APIs without getting them confused with JSON APIs that specifically use "JSON API".
Lastly, it really seems based on a rails active record style data store, it's assuming ids are the most important thing and that links are all relations that point to other objects within the system. Proper hyperlinks and point anywhere and can link together disperate systems which don't necessarily all use the exact same formats.
It also makes it possible to cache things locally indexed on their IDs, and to form URLs that make requests for just the precise documents that aren't available locally. In order to achieve this, it's necessary to have both (1) IDs, and (2) a way to convert a list of IDs into a single request for all of the documents at once.
> Also the name is a bit of an annoying land grab
HAL is "The Hypertext Application Language". In general, people tend to be using generic names for these things, so I chose an available, generic name.
> Lastly, it really seems based on a rails active record style data store, it's assuming ids are the most important thing and that links are all relations that point to other objects within the system
I reviewed a large number of server-side solutions (Firebase, Parse, CouchDB, Django, Rails) and they all had the concept of an ID for the document. As I said above, this ID is useful to keep track of which documents have already been cached locally, and how to formulate a URL that makes a request for just the missing URLs. I don't consider this solution to be particularly tied to ActiveRecord.
Less importantly, it is also more convenient to cache documents on the server using their IDs (or slugs, or whatever the storage wants to use), and allow a top-level configuration to define how to generate URLs. This allows server-side solutions to serialize and cache documents without having to be plugged into the router architecture, but enforces a URL-centric view once the HTTP response is built.
The proper layer for caching is HTTP, do we really want to end up with duplicated overlapping functionality between the layers? I see you have an application specific need for a certain thing but I don't think it generalises enough.
A few other things I noticed:
- There's no name spaceing of your special properties, they're just mixed up with the domain-specific properties. So I can't have a property of my object named "rel" and worse still you can't ever add features to the spec without breaking backwards compatibility.
- No type information in items, which kind of breaks automatic caching.
- Multiple entities returned for a URL with no indication as to which is the main one represented by that URL and which are just extra associated ones.
HTTP caching doesn't work well with compound documents that represent a graph of objects. The kind of caching described in JSON API allows an application to group together requests for documents while avoiding making requests for documents it already has. The only way HTTP caching works is if every request for a document is 1:1 with an HTTP request, which doesn't map onto my experience (and our experience with Ember Data) at all.
> I see you have an application specific need for a certain thing but I don't think it generalises enough.
This functionality was extracted out of a general purpose framework used by a number of applications that made heavy use of it. The ability to send a normalized graph of objects in a single payload, and then make a small number of additional requests, only for the documents that the client doesn't already have, is a huge win for clients working with a non-trivial number of related objects.
The rest of your concerns are very valid. FWIW, I envision future extensions being added to the `meta` section, which is already reserved. ID, URL, and rel are the building blocks of the graph, while other kinds of extensions (like pagination, etc.) are optional metadata. But you raise a good point and I will give it some thought :)
That's exactly it! This looks like a sensible design for an API served from rails and consumed by Ember.JS. It's just over selling it a bit to imply that this should be how all JSON APIs should be.
In short, it's an attempt to extract the learnings about efficiently transporting a non-trivial number of objects over a REST-like transport in a sometimes-incremental way. Many different server/client combinations have been attempting to do this in an ad-hoc way for years, and Ember Data was simply an attempt to try something general-purpose out in the real world.
Couldn't the id column contain a canonical url then? E.g.:
{
"posts": {
"id": "http://example.com/posts/1",
"title": "Rails is Omakase",
"rels": {
"author": "http://example.com/people/9"
}
},
"people": [{
"id": "http://example.com/people/9",
"name": "@d2h"
}]
}Keep in mind that this spec actually requires that every ID be able to be readily converted into a URL based on information found in the same payload, so URLs are still front-and-center in the design. It just separates out the notion of a unique identifier, so that it can be used in other kinds of requests.
In theory, things like pipelining allow you to never have to worry about compound documents. In practice, I don't know anyone who has gotten this to work well for browser clients and general-purpose frameworks when dealing with non-trivial numbers of documents.
The server side support seems like the wrong thing to base the protocol design on, but I admit that is probably just me showing my limited experience with very high traffic api's. I would think though that much of this could be alleviated by proper caching. As requests would naturally be finely granulated into individual resources, presumably that could be done efficiently.
The point of browser support is probably more pressing. I'm curious as to how big an issue that still is? Which browsers support it properly these days and which don't?
I wonder if it would be worth to build an api around the assumption of support for pipelining and then provide a fallback hack for those that lack support. E.g. something similar to the good old _method hidden-field hack for lack of http method support. I'm thinking something like an optional "batch request endpoint", that would tunnel through multiple requests, similar to what a pipeline would do. I believe Facebook is offering something similar in their api's.
SPDY begins to offer some very appealing alternatives where when sending a document the transport can push all of the individual dependent documents. It really does fix things, begins pushing all the data at once, in a glorious resource-oriented fashion. That said, I would also enjoy a spec that does resource-description of subresources so we can send linked data around without having to have every piece of data be an endpoint.
That said, the immediate follow on question arises- now that we're sending sub-resources, can we get the most important agent to understand and grok our sub-resources- can the browser follow our subresourcing and those subresources to their canonical URLs, and serve those subresources if it's seen them inside another document? There are two questions- first, is your spec good enough to enable that facility where addressing can be well known- here, in this Json Resource Description spec presented yes, via URI templates, very good- and second, does the browser bother to inspect the JSON it sees? No? Well, I'm not super bothered by this academic interest not being materialized, knowing at least in principle the specs make it possible.
How's that, Interlinked Json, IJ? Relational Json? Seriously, pick something that's not going to muddy the highest level of namespace we swim in wycats.
Someday also more people will realize how useful and effective the equivalence of control structures and data really is.
JSON: { "posts": { "id": "1", "title": "Rails is Omakase", "rels": { "author": 9, "comments": [ 5, 12, 17, 20 ] } } }
LISP: (posts (id 1) (title "Rails is Omakase") (rels (author 9) (comments (5 12 17 20))))
No matter what kind of code I'm looking at: "could I express this as s-expressions?" Sure. "Would I want to?" Hell no.
Of course it is possible to implement syntactic sugar in Lisp which supports JSON style expressions. DSLs are common in Lisp, and that actually became a weakness of Lisp (so-called "DSL hell").
The interesting thing about s-expr is that Lisp doesn't need special data conversion tools to handle them. Even control structures are expressed as s-expr, and they can be created and modified dynamically which means that even code can be exchanged at runtime on the fly.
There is a distinction between reader macros and compiler macros, for example, which is relevant for allowing using special syntax be optional for end users.
Certain things also need to be defined if you want them to be available in the compile-time environment. And, sometimes you have to do a bit of extra work if you want to have literal objects in your compilation environment and pass them to runtime.
Check out http://www.lispworks.com/documentation/HyperSpec/Body/03_bc.... though it will probably take you a few readings to make sense of it; I know it did for me.
But for the most part things happen automatically.
No. Just no. I could agree about reading, but writing is much easier with s-exps. There's just less symbols to type. And remember, you still can put newlines and indent however you want.
{ "posts" { "id" "1", "title" "Rails is Omakase", "rels" { "author" 9, "comments" [ 5, 12, 17, 20 ] } } }
Commas are unnecessary, I kept them for clarity.I read an interview with Rich Hickey where he said that adding these three syntax constructs reduced cognitive burden on programmers. He meant () for lists, [] for vectors and {} for hashes.
I should implement it in Racket and just see how it feels.
Personally I think that differentiating between lists and maps is important and the way Clojure does it (as well as JSON) is quite easy to write and read. FWIW example given by bitcracker is broken because there's no way to understand what does the following mean:
(rels (author 9) (comments (5 12 17 20)))
The outermost element is it a list or a map? { :posts { :id 1 :title "Rails is Omakase" :rels { :author 9 :comments [5 12 17 20] }}} [posts: [id: 1 title: "Rails is Omakase" rels: [author: 9 comments: [5 12 17 20]]]]
See relevant|related|interesting blog post On JSON and REBOL by Carl Sassenrath - http://www.rebol.com/cgi-bin/blog.r?view=0522Lisp is harder to read than JavaScript because it doesn't disambiguation between lists and dictionaries in a clear way like js and python do.
This is easy to identify: nearly all json is just atoms thought- very few json definitions encode any kind of machine-works or program-code.
So, to put it another way: it amazes you how all Lisp looks like data structures. And hopefully I've helped let you know why you are so amazed here, thanks for reading.
Media type designers should keep Postel in mind. Designers can make
supporting the Robustness Principle easier for implementor by keeping the
number of MUST elements in the compliance profile to a minimum. The fewer
MUST elements implementors need to support, the more likely it is that they
will be able to craft compliant representations using that media type.Be a nazi in what you accept, fail loudly and early enough and there will be no problem for the user to correct his error - it is only when you 50000 php pages full of echo statements that you can't change. If it had complained when he made the first, he wouldn't be in that situation now.
And don't tell me that nobody would use it then. C++, C# and Java are the top most used languages and they are all anal-retentive.
The request MUST contain a Content-Type header whose value is
application/json. It MUST also include application/json as the only or
highest quality factor.
It makes sense for fully compliant implementation to have those headers, but they way I understand MUST here is that a server would reject any request without them.Couple of things that might be nice to see here:
* Pagination concerns
You call out "meta: meta-information about a resource, such as pagination", but that doesn't say whether things are 0/1 based, what the names of the values for per-page are, how to indicate length of the underlying collection, etc.
* Search concerns
I don't know whether this is an area that has best practices yet, but having it said and decided on something called "jsonapi.org" could save many people many hours of pain in the future.
* Elective compound documents
Bit more of a reach, but there have been a bunch of times I wanted to say "this resource, and these relations of it, and those relations of those". And in some cases partial documents (id and name alone) of those tertiary relations.
#3 will be do-able I think. I'm interested in this too.
#1 is something that needs a good answer, yes. I THINK it's out of the scope of this, as there are already registered REL values that handle this, but we should clarify.
I will be happy to answer anyone else's questions after I land, it's time to turn off electronic devices.
What about hypermedia instead of rels?
I feel like `ids` param is a hack, clearly the system has a group of objects, should that not be it's own collection?
For instances:
`GET /friends?ids=1,34,54`
Could be:
`GET /friends/best.json` and `best` to the system in some form, represents 1,34,54.
I don't want a RESTful JSON API. I want a REST JSON API.
I've been using djangorestframework, and one of the things that I love about it (instead of tastypie) is the "Browsable API" renderer/parser mode. It's an excellent way to see if your API makes sense: if I'm not able to discover/manipulate resources just by clicking on the links or posting forms, it is a sign that the API design is ill-conceived.
How is a 'resource template' different than a <form> hypermedia control in HTML?
Why does the URI format matter? It's hypermedia, that's basically irrelevant.
It seems you want a "REST"ful API, and that's great. Build that. But then why the first sentence being seemingly upset with some sort of lack of imagined hypermedia support?
`PUT /friends/???.json`
Indeed. And importantly, this API makes it possible to restrict the query to a list of documents that the client doesn't already have from another source. In practice, once you start using compound documents with an identity map, there are many cases where existing documents exist on the client and shouldn't be re-fetched.
One really simple example is having a number documents that are related to "people" documents. For example, imagine a blog with blog posts and comments, each of which point at an author. When a list of comments for a post is downloaded, each comment will point to an author. Some of those authors will be the same, and some of them will already have been seen from previous posts. This structure allows the client to request only the authors that have not yet been seen (and if you're lucky, it may even be the empty set!).
Compounded documents or unions/nested data should only be avoid. I think strong normalization is a good idea.
In the second case. The flow could be:
GET /posts GET /posts/1/comments GET /posts/1/comments/authors
Comments only need to rel to authors, which can be loaded next. Data-binding for the win.
I'm not against embedded data as an optimization. It's difficult to fit.
Another method is having a collection sorted and slices.
DELETE /teams?id[gt]=10&id[lt]=13
As for non-sequel ids or random ids. It could be possible to support ?id[]=12&id[]=9&id[]=4. Sure it could be /teams/1,2,3 this is just a small detail of the parser. I'm more interesting in how a collection is queried and represented.
... can you elaborate a bit more on what this means? I don't understand what you're trying to say.
> I feel like `ids` param is a hack, clearly the system has a group of objects, should that not be it's own collection?
I'm not 100% sure what you mean here either, but I'm reading it as "Why not use a comma rather than passing a list of GET parameters?"
The answer is "I don't think that's particularly important either." Constructing your own URIs is against the very spirit of REST. Let the server do that for you.
Basically rest apis map exactly one resource to a url and should never use the hack that is ?.
Also, ? is not a 'hack', I don't know where you're getting that from either.
When you're competing against nothing, lack of elegance is a difficult problem. The need to be elegant is stronger and you can't simply be as or more elegant than your competition.
I'd love to see a spec for how to search a collection against an API that is jsonapi compliant. Different folks are all over the place here.
The base URL for search is different for different API producers. I like
GET /teams?homecity=los+angeles
but have also seen things like GET /search/teams?homecity=los+angeles
or GET /teams/search?homecity=los+angeles
How to specify mildly complex search parameters is also unclear in the world. For referenced objects "/teams?homecity.state=ca" seems to fit with the style used for URL templates.For bounded queries, should it be mongodb style?
GET /teams?homecity.population.$lt=100000&homecity.population.$gt=100
And since we're talking about searches and pagination, do we need to specify a parameter for ordering results? GET /teams?wins.$gt=3&$order=homecity.population.$descWouldn't this be:
GET /teams/los+angeles
We could have query-able attributes, this is where I think OPTION verb should come into play. So I would OPTION /teams. This returns some JSON with the meta information about the collection, for instance: `{key :'wins', type: 'string', description: 'some api description', sortable => true, filter: true, group_by: false }`, this should probably hint at the abilities of the attribute (sortable/filter/group_by). This really raises the question of what is a good querying api for collections? I think our answer may be in the form SQL-like interface.
GET /teams?wins[gt]=1&losses[gt]=1&wins[sort]=desc&limit=10&offset=0
SELECT * FROM teams WHERE wins > 1 AND losses gt > 1 ORDER BY wins LIMIT 10 OFFSET 0
So what about support ORs or Unions and Joins? Well, ORs are simple they could act like a named scope.
GET /teams?wins_or_losses[gt]=1&wins[sort]=desc&limit=10&offset=0
SELECT * FROM teams WHERE (wins > 1 OR losses gt > 1) ORDER BY wins LIMIT 10 OFFSET 0
What about a Union or Join? These should be handled by a new endpoint (joins) or avoided by querying individual collections (unions).
Quick intro video http://www.odata.org
Query formatting documentation http://www.odata.org/documentation/odata-v2-documentation/ur...
JSON representation documentation http://www.odata.org/documentation/odata-v2-documentation/js...
So, yes, I guess, in some ways, more OData like.
I would imagine they'd use OpenSearch in some form. Not 100% sure yet.
> The base URL for search is different for different API producers.
You've hit upon the reason why this needs to not be ad-hoc anymore; a few dozen ways of searching isn't good!
* HAL embeds child documents recursively, while JSON API flattens the entire graph of objects at the top level. This means that if the same "people" are referenced from different kinds of objects (say, the author of both posts and comments), this format ensures that there is only a single representation of each person document in the payload.
* Similarly, JSON API uses IDs for linkage, which makes it possible to cache documents from compound responses and then limit subsequent requests to only the documents that aren't already present locally. If you're lucky, this can even completely eliminate HTTP requests.
* HAL is a serialization format, but says nothing about how to update documents. JSON API thinks through how to update existing records (leaning on PATCH and JSON Patch), and how those updates interact with compound documents returned from GET requests. It also describes how to create and delete documents, and what 200 and 204 responses from those updates mean.
In short, JSON API is an attempt to formalize similar ad hoc client-server interfaces that use JSON as an interchange format. It is specifically focused around using those APIs with a smart client that knows how to cache documents it has already seen and avoid asking for them again.
It is extracted from a real-world library already used by a number of projects, which has informed both the request/response aspects (absent from HAL) and the interchange format itself.
I see your point with the first one, although I must say in our APIs we have rarely encountered duplication. And the recursive nature of HAL makes it really easy to generate on the server-side.
(By the way, we've introduced a sideloading convention that only when you pass along ?embedded=author,comments those sub-resources will be present under _embedded. This way the clients can easily request only what's needed.)
as noted in other comments, there is JSON HAL;
there is also OData (you might not appreciate that it is an ms initiative, but its pretty well established and has many providers) http://www.odata.org/libraries/
[1]: http://www.odata.org/documentation/odata-v2-documentation/js...
Was hopping to see something more substantive in a comparison other than: 'results are returned under "d" instead of directly "posts"'.
Most project need to answer the simple question of 'why?' - 'why do I as a project exist'; jsonapi.org's is full of 'Ember'; hence why my original comment hinted that it should possibly be called 'emberjsonapi'.
If this is intended to be generic; it should ditch references to Ember and instead refer to similar standards; explaining 'why?' it is better than them.
By all means if your intent is to make a more elegant standard (again comparing to odata) then that's a worthy goal. Stating _that_ will help your 'consumers' understand what they are getting
edit: clean up
JSON API's design is based around a smart client that wants the ability to avoid making unnecessary requests for documents it already has, and to provide a format that avoids unnecessary duplication in compound documents. It also aims to be relatively easy to implement, both on the client and server, using tools and frameworks that are already widely in use using familiar idioms.
Everything I've seen just says that this is simply a subset of OData's functionality. And the features that are being asked for by users commenting on the OP are ones already provided by the existing standard.
And what about querying the data? There have already been questions elsewhere in this thread about how this would work. OData already provides very rich query support, including document projection (returning a subset of a document) through to complex queries navigating multiple relationships (I easily could ask, through a GET query string, to return all the actors who have starred in films that belong to the comedy genre - navigating 3 collections, actors,films,genres). If queries are out of the scope, then fine, but its clear people want to query their data.
So please answer what this offers over existing standards if you want to compete.
Oh, and in response to your earlier post of what OData JSON looks like, you're much better served by linking to v4, not v2 as you did:
http://docs.oasis-open.org/odata/odata-json-format/v4.0/cspr...
That doesn't look so dissimilar.
I feel that if you have an author with many comments:
{ authors: { '1': { id: '1', comments: [1, 2] } }, comments: { '1': {}, '2': {} } }
it would be easier to say results['comments']['1'] instead of performing some type of search across them each time.
Edit: clarification
It's important to note that the goal of JSON API is to be consumed by a general-purpose client (like Ember Data), so the JSON will likely be processed once and indexed as needed. In the system we extracted this from, the Array is loaded into a Store, which indexes the documents by type and id, so future lookups are quite efficient.
In addition, you'll find that you're using an array at the toplevel only for the primary document when it is a collection, and for nested collections within documents (such as comment ids). Semantics that general-purpose clients can make use of.
The original reason for using Arrays (and something that still carries some weight with me), is that people expected that Arrays be presented in a particular order returned by the server. Indeed, the semantics of a to-many relationship need to be set-like (in order to avoid nasty concurrent modification issues), but people really wanted the ability to return an array and have it "work as expected". In general, the right way to handle position, imho, is to use a `position` attribute and sort on the client. After saying all of that, perhaps this is a good reason to use ID indices, so people don't get the wrong idea.
I'll sleep on it :)
For example, consider the posts.comments.users relationship. Here "posts" is the primary document (and let's say a collection), "comments" and "users" are related documents. The same user may have commented in multiple posts within a single response, so which `position` attribute would you use in the related "users" document? The answer is you don't, you can't, because the user appears in different positions in different posts. The order of comments is defined by the "post" document's "comments" array. Each comment document contains a user id. You look up the user from the unique "users" map by that id. There is no order that makes sense for related documents, since by nature of being related documents their entries may appear in different places/positions in the parent document, where they are already referred to from ordered collections (e.g. arrays of ids) or singular fields.
Hope that clears it all up :)
We generate a results array that is ordered based on the default order or supplied order. You can easily iterate over that then do direct lookups in the top level keys.
Some thoughts:
1. I'm not sure about the name. There will definitely many JSON APIs that don't use (your) JSON API for a long time, even if this becomes hugely popular. I don't see how this will not lead to avoidable confusion in the future. Given that it's very document-centric, why not use something like "JSON Doc API" or similar?
2. In the ID approach, why are the base URIs the client needs to know about not always discoverable, e.g. using standard link relations? Or phrased differently, why would I ever not want to use the "URL Template Shorthands" approach mentioned later?
3. Why use application/json and not something more specific? I can see some reasons, but would be interested in yours.
4. On creation, if I accept the pain of generating an ID on the client and can construct the URI using the template, why can't I use PUT instead of POST?
5. If I use a POST to create something, why don't I get a 201 Created with a Location header?
6. I'd suggest to upgrade the "MAY" for caching to a "SHOULD".
/edited to match @steveklabnik's numbers
2. If you're transitioning _to_ this kind from some sort of older kind. Remember, this is extracted from real, working software; it's not some sort of thing we imagined up. Not everyone is super on the hypermedia bandwagon yet, and some will need to transition kind of slowly.
3. I filed for 'appplication/vnd.api+json' yesterday, and so we'll be changing the document as soon as the IANA gets back to me.
4. You could, in theory. Allowing PUT seems fine, it just doesn't often seem to be the case, so we didn't include it. I wouldn't mind having that in there.
5. You should be, this is an oversight.
6. That's very possible.
What I meant is that this is a particular kind of backend API, a very "model-centric" one. Nothing wrong with that, I just don't think this is the one and only kind and thus should take on the generic name.
> 2. If you're transitioning _to_ this kind from some sort of older kind.
Understood. Maybe an approach is to allow for this to specified optionally, with the fallback of being hard-coded if it's not present?
> with the fallback of being hard-coded if it's not present?
See above for some other good stuff about the IDs that wycats knew that I wasn't as current on.
Good feedback. Many people have said this, and I'm thinking about an alternative.
> Or phrased differently, why would I ever not want to use the "URL Template Shorthands" approach mentioned later?
You can think of the ID-based approach as just coming with a set of default URL templates in a top-level rel. The primary reason I included it (and I considered not including it), is that it may be easier for servers, when getting started, to adhere to both strict URL naming and skip generating URLs in the JSON serialization layer of their application. I'm working on some tooling for Rails that will pretty much eliminate these considerations, but I weighed ease of server-implementation when I built this. Again, don't think of the ID form as being URL-less, think of it as coming with a default, easy to implement URL template.
> Why use application/json and not something more specific? I can see some reasons, but would be interested in yours.
Two reasons: (1) Many existing clients and servers already support easy generation of JSON requests and JSON responses. (2) I haven't yet registered an alternative MIME type.
> On creation, if I accept the pain of generating an ID on the client and can construct the URI using the template, why can't I use PUT instead of POST?
Good point. That seems fine.
> If I use a POST to create something, why don't I get a 201 Created with a Location header?
Also good point, and an embarrassing oversight on my part. That should be how it works.
> I'd suggest to upgrade the "MAY" for caching to a "SHOULD".
Hmm. You think a server SHOULD use HTTP caching? RFC terminology is pretty dodgy, but caching really seems more like an optional feature ("One vendor may choose to include the item because a particular marketplace requires it or because the vendor feels that it enhances the product while another vendor may omit the same item") than a strong recommendation ("This word, or the adjective "RECOMMENDED", mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course").
Thanks for all the feedback. It was really valuable.
Then I'd be perfectly happy. But why is the paragraph that mentions exactly this ("... The top-level of a JSON API document MAY have the following keys") in the "URL-Based JSON API" section?
> You think a server SHOULD use HTTP caching?
No, you're probably right - a SHOULD is too strong. I guess my reaction was more negative to the "MAY" in your text about caching than anything else. The caching section (which is currently in the writing document?) doesn't seem to actually add much value beyond what HTTP says anyway. Maybe dropping it is the easiest path?
* http://schema.org/docs/full.html
* http://schema.rdfs.org/all.json
* http://schema.rdfs.org/all.ttl (Turtle RDF Triples)
* http://json-ld.org/spec/latest/json-ld/
* http://json-ld.org/spec/latest/json-ld-api/
* http://www.w3.org/TR/ldp/ Linked Data Platform TR defines a RESTful API standard
* http://wiki.apache.org/incubator/MarmottaProposal implements LDP 1.0 Draft and SPARQL 1.1
I think that you should specify the format for cursor based paging of resource collections. One way to do it would be to require a url to get more results:
{
"posts": [...]
"meta": {
"next":"/posts/search?q=baseball&after=1234"
}
}
Another option would be for it to be a key/value pair that must be added to the url: {
"posts": [...]
"meta": {
"next":"after=1234"
}
}
Either way, rest clients should treat it as a meaningless string.(So you'd define your own rels and use them, doesn't affect this level of abstraction.)
* Standardized paging
* Optional side-loading - GET /albums.json?include=artists,songs
* Multiple meta elements - so we'd have "albums_meta", "artists_meta" and "songs_meta" in the example above. This allows us to include 'has_n' relationship paging data.
Standardized paging seems to come up a lot, so it seems like a good thing to add once the core spec stabilizes. Optional sideloading also has come up a few times, and seems easy to add as a MAY in the spec. I need to flesh out the meta stuff in general, and the ability to have "meta anywhere" as well as top-level metas is coming.
https://github.com/RestPack/restpack-serializer
In the light of your proposals, I'll either implement JSON API or switch back to AM:Serializers. Side-loading, paging and Ember Data compatibility are my main goals.
One question though: I notice that the language they use if very similar to a typical RFC. Is this an RFC? and if not, why? I'm a little naive about the process for submitting them and getting them accepted, but it would be great if this ended up as an official RFC that could be referred to just like SOAP/WSDL.
If you're not, then this is significantly different than SOAP, so no, this isn't what you're looking for.
This is not an RFC. It may eventually become an internet-draft and then (hopefully) an RFC.
To address your issues around defining a standard JSON API - OData is itself the standard API for any OData service. All that would differ between your OData service and mine is the schema and the data inside. How you explore that schema and access that data is what OData defines.
I would love to get some feedback on the initial version. I will definitely be implementing more of the OP's spec this weekend.
Why can't you just PATCH a resource?
PATCH /resource
{
"src": "newvalue.png"
}I'm still of the opinion that it might be overkill to use only replace from that RFC when you can just PATCH the actual field to change.
Is there some bit of wisdom or experience that I'm missing?
It also makes it really easy to add a compound PATCH (updates to posts/1/title, posts/1/rels/author, posts/2/body, etc. all at the same time) in a single format. Once I bought into JSON Patch for the rest of this stuff, I figured I may as well use it for attributes :)
There's also some value in the patch format looking somewhat different to the main format, to avoid confusion.
Why would you say something like that? There's no basis for that at all. From a REST POV, URIs are just opaque identifiers, the characters they're made up from don't matter a bit.
For a single resource you can still use /collection/1
2. This spec is for protocol-level semantics, you define your application semantics with a profile link in the meta section.