How do you represent "thin" and "fat" versions of a RESTful resource? - rest

How would you model a resource that can have two different representations. For example, one representation may be "thin" withe most of its related resources accessible by links. Another representation may be "fat" where most of its related resources are embedded. The idea being, some clients don't mind having to make many calls to browse around the linked resources, but others want to get the data all at once.
Consider a movie resource that is associated with a director, actors, etc. Perhaps the thin version of it has the movie title only, and to get the data for the director, list of actors, etc., one must make additional requests via the embedded links to them. Perhaps the fat version of it contains all the movie nested inside, including the director's data, the data for the various actor's, etc.
How should one model this?
I see a few options:
these two representations are really two different resources and require different URIs
these two representations are in fact the same resource, and you can select between the two representations via custom media types, for example application/vnd.movie.thin+json and application/vnd.movie.fat+json.
these two representations are in fact the same resource, and selecting the different representations should be done with query parameters (e.g. /movies/1?view=thin).
Something else...
What do you consider the proper approach to this kind of API?

You could use the prefer header with the return-minimal parameter.

I prefer using Content-Type for this. You can use parameters, too:
application/vnd.myapp; profile=light

The Fielding dissertation about REST tells you about the resource interface, that you have to bind your IRIs to resources, which are entity sets. (This is different from SOAP, because by there you usually bind your IRIs to operations.)
According to Darrel Miller, the path is for describing hierarchical data and the query string is for describing non-hierarchical data in IRIs, but we use the path and the query together to identify a resource inside an API.
So based on these you have two approaches:
You can say, that the same entity with fewer properties can be mapped to a new resource with an own IRI. In this case the /movies/1?view=thin or the /movies/1/view:thin is okay.
Pros:
According to the
RDF a
property has rdf:type of rdf:Property and rdfs:Resource either, and REST has connections to the semantic web and linked data.
It is a common practice to create an IRI for a single property, for example /movies/1/title, so if we can do this by a single property, then we can do this by a collection of properties as well.
It is similar to a map reduce we already use for collection of entites: /movies/recent, etc... The only difference, that by the collection of entities we reduce a list or ordered set, and by the collection of properties we reduce a map. It is much more interesting to use the both in a combination, like: /movies/recent/title, which can return the titles of the recent movies.
Cons:
By RDF everything has an rdf:type of rdfs:Resource and maybe REST does not follow the same principles by web documents.
I haven't found anything about single properties or property collections can be or cannot be considered as resources in the dissertation, however I may accidentally skipped that section of the text (pretty dry stuff)...
You can say that the same entity with fewer properties is just a different representation of the same resource, so it should not have a different IRI. In this case you have to put your data about the preferred view to somewhere else into the request. Since by GET requests there is no body, and the HTTP method is not for storing this kind of things, the only place you can put it are the HTTP headers. By long term user specific settings you can store it on the server, or in cookies maintained by the client. By short term settings you can send it in many headers. By the content-type header you can define your own MIME type which is not recommended, because we don't like having hundreds of custom MIME types probably used by a single application only. By the content-type header you can add a profile to your MIME type as Doug Moscrop suggested. By a prefer header you can use the return-minimal settings as Darrel Miller suggested. By range headers you can do the same in theory, but I met with range headers only by pagination.
Pros:
It is certainly a RESTful approach.
Cons:
Existing HTTP frameworks not always support extracting these kind of header params, so you have to write your own short code to do that.
I cannot find anything about how these headers are affecting the client and server side caching mechanisms, so some of them may not be supported in some browsers, and by servers you have to write your own caching implementation, or find a framework which supports the header you want to use.
note: I personally prefer using the first approach, but that's just an opinion.
According to Darrel Miller the naming of the IRI does not really count by REST.
You just have to make sure, that a single IRI always points to the same resource, and that's all. The structure of the IRI does not count by client side, because your client has to meet the HATEOAS constraint if you don't want it to break by any changes of the IRI naming. This means, that always the server builds the IRIs, and the client follows these IRIs it get in a hypermedia response. This is just like using web browsers to follow link, and so browse the web... By REST you can add some semantics to your hypermedia which explains to your client what it just get. This can be some RDF vocabulary, for example schema.org, microdata, iana link relations, and so on (even your own application specific vocab)...
So using nice IRIs is not a concern by REST, it is a concern only by configuring the routing on the server side. What you have to make sure by REST IRIs, that you have a resource - IRI mapping and not an operation - IRI mapping, and you don't use IRIs for maintaining client state, for example storing user id, credentials, etc...

Related

Sub-resource creation url

Lets assume we have some main-resource and a related sub-resource with 1-n relation;
User of the API can:
list main-resources so GET /main-resources endpoint.
list sub-resources so GET /sub-resources endpoint.
list sub-resources of a main-resource so one or both of;
GET /main-resources/{main-id}/sub-resources
GET /sub-resouces?main={main-id}
create a sub-resource under a main-resource
POST /main-resource/{main-id}/sub-resouces: Which has the benefit of hierarchy, but in order to support this one needs to provide another set of endpoints(list, create, update, delete).
POST /sub-resouces?main={main-id}: Which has the benefit of having embedded id inside URL. A middleware can handle and inject provided values into request itself.
create a sub-resource with all parameters in body POST /sub-resources
Is providing a URI with main={main-id} query parameter embedded a good way to solve this or should I go with the route of hierarchical URI?
In a true REST environment the spelling of URIs is not of importance as long as the characters used in the URI adhere to the URI specification. While RFC 3986 states that
The path component contains data, usually organized in hierarchical form, that, along with data in the non-hierarchical query component (Section 3.4), serves to identify a resource within the scope of the URI's scheme and naming authority (if any). The path is terminated by the first question mark ("?") and number sign ("#") character, or by the end of the URI. (Source)
it does not state that a URI has to have a hierarchical structure assigned to it. A URI as a whole is a pointer to a resource and as such a combination of various URIs may give the impression of some hierarchy involved. The actual information of whether URIs have some hierarchical structure to it should though stem from link relations that are attached to URIs. These can be registered names like up, fist, last, next, prev and the like or Web linking extensions such as https://acme.org/rel/parent which acts more like a predicate in a Semantic Web relation basically stating that the URI at hand is a parent to the current resource. Don't confuse rel-URIs for real URIs though. Such rel-URIs do not necessarily need to point to an actual resource or even to a documentation. Such link relation extensions though my be defined by media-types or certain profiles.
In a perfect world the URI though is only used to send the request to the actual server. A client won't parse or try to extract some knowledge off an URI as it will use accompanying link relation names to determine whether the URI is of relevance to the task at hand or not. REST is full of such "indirection" mechanism in order to help decoupling clients from servers.
I.e. what is the difference between a URI like https://acme.org/api/users/1 and https://acme.org/api/3f067d90-8b55-4b60-befc-1ce124b4e080? Developers in the first case might be tempted to create a user object representing the data returned by the URI invoked. Over time the response format might break as stuff is renamed, removed and replaced by other stuff. This is what Fielding called typed resources which REST shouldn't have.
The second URI doesn't give you a clue on what content it returns, and you might start questioning on what benefit it brings then. While you might not be aware of what actual content the service returns for such URIs, you know at least that your client is able to process the data somehow as otherwise the service would have responded with a 406 Not Acceptable response. So, content-type negotiation ensures that your client will with high certainty receive data it is able to process. Maintaining interoperability in a domain that is likely to change over time is one of RESTs strong benefits and selling points. Depending on the capabilities of your client and the service, you might receive a tailored response-format, which is only applicable to that particular service, or receive a more general-purpose one, like HTML i.e.. Your client basically needs a mapping to translate the received representation format into something your application then can use. As mentioned, REST is probably all about introducing indirections for the purpose of decoupling clients from servers. The benefit for going this indirection however is that once you have it working it will work with responses issued not only from that server but for any other service that also supports returning that media type format. And just think a minute what options your client has when it supports a couple of general-purpose formats. It then can basically communicate and interoperate with various other services in that ecosystem without a need for you touching it. This is how browsers operate on the Web for decades now.
This is exactly why I think that this phrase of Fielding is probably one of the most important ones but also the one that is ignored and or misinterpreted by most in the domain of REST:
A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types. (Source)
So, in a true REST environment the form of the URI is unimportant as clients rely on other mechanisms to determine whether to use that URI or not. Even for so called "REST APIs" that do not really care about the true meaning of REST and treat it more like old-school RPC the question at hands is probably very opinionated and there probably isn't that one fits all solution. If your framework supports injecting stuff based on the presence of certain query parameters, use that. If you prefer the more hierarchical structure of URIs, go for those. There isn't a right or wrong in such cases.
According to the URI standard when you have a hierarchical relationship between resources, then better to add it to the path instead of the query. https://datatracker.ietf.org/doc/html/rfc3986#page-22 Sometimes it is better to describe the relation itself, not just the sub-resource, but that happens only if the sub-resource can belong to multiple main resources, which is n:m relationship.

What is the RESTful way to design URL that returns parent of a child resource?

I am modeling blogging REST API which has resources Blog, Post and Comment with following URLs:
/api/blogs
/api/blogs/{blogId}
/api/blogs/{blogId}/posts
and I create separate endpoint for all Posts in and their Comment`s:
/api/posts
/api/posts/{postId}
/api/posts/{postId}/comments
Given that I have postId, what is the RESTful way to get Blog for a specific Post? I have three ideas:
1. /api/posts/{postId}/blog
2. /api/blogs/parent-of-post/{postId}
3. /api/blogs?postId={postId}
To me the 1. URL looks more "prettier" but the 2. option looks more "logical" since that endpoint (eg. /api/blogs/*) is generally for blogs resources.
The third option uses query string as parameter but the issue I have with it is that this endpoint would return different type of body depending on the parameter. Eg. without parameter /api/blogs returns a collection of Blog resources, while with parameter postId it would return just single instance of Blog. I am not sure if this is good thing to do (especially because I am using ASP.NET Core and C# which has strongly typed return objects, so implementation might be awkward).
what is the RESTful way to get Blog for a specific Post?
Real answer: anything you want.
REST doesn't care what spelling conventions you use for your resource identifiers. As long as your identifiers conform to the production rules described by RFC 3986, you are good to go.
/api/blogs?postId={postId}
This is a perfectly normal choice, and turns out to be a really convenient one when you want to use general purpose web browsers, because HTML forms already have standards that make it easy to create URI with this shape.
Your other two choices are fine; they lose a point for not being HTML form friendly, but it's still easy enough to describe these identifiers using a URI template.
The third option uses query string as parameter but the issue I have with it is that this endpoint would return different type of body depending on the parameter
General purpose API consumers do NOT assume that two resources are alike just because the spellings of their identifiers overlap each other.
Which is to say, from the outside, there is no implied relationship between
/api/blogs
/api/blogs/1
/api/blogs?postId=2
so the fact that they return different bodies really isn't going to be a surprise to a general purpose consumer.
Now, your routing framework may not support returning different types from the handlers for these resources (or, more likely, may not have any "nice" way to do the routing automatically), but that's an implementation detail deliberately hidden behind the REST API facade.
Similarly, the human beings that read your access log might prefer one spelling to another, to reduce their own cognitive load.

REST API design: what is a unique operation or resource

Years ago I created a tiny web service that serves the same resource in two representations.
# returns a collection of Foos
GET /foo
# returns the same collection of Foos in a different JSON representation
GET /foo?projection=X with 'Accept: my-specific-media-type'
This works quite well in (Java) code as I can have two methods mapped to the same #Path both with different return types. One accepts a #QueryParam and #Consumes a specific media type while the other doesn't.
However, according to the (current) #ApiOperation Swagger annotation I opted for the wrong API design.
A combination of a HTTP method and a path creates a unique operation
Hence, after I upgraded my old project to current library versions the Swagger model only contains a single GET /foo operation - which one is random as it depends on runtime code introspection through Java reflections.
So, the question is this: is the Foo resource in a different representation effectively the "same" resource or is it a different resource? The Swagger annotation seems to hint at the latter (different resource -> different path).
Part of the problem that you are running into is a mix of REST concepts and Swagger/OpenAPI concepts.
Resource is a REST concept: "any concept that might be the target of an author's hypertext reference must fit within the definition of a resource"
Representation is a REST concept: "A representation is a sequence of bytes, plus representation metadata to describe those bytes."
Operations are an OpenAPI concept: "OpenAPI defines a unique operation as a combination of a path and an HTTP method."
There's a certain amount of tension here because the viewpoints aren't actually in alignment with each other.
For example, from the perspective of REST, there's no reason to document a "GET operation", because GET is part of the uniform interface - it has the same semantics no matter what value is used as the target-uri. That's a part of a key architectural constraint that makes the world wide web possible - consistent semantics means that we can use general purpose components (like web browsers) to interact with all of the different resources on the web.
is the Foo resource in a different representation effectively the "same" resource or is it a different resource?
"It depends".
A classic example of "one resource, different representations" would be a picture, where we might have a GIF, JPEG, PNG, BMP. Same picture (ish), but different sequences of bytes that need to be processed in different ways.
Similarly, you might have a web page (HTML), and also a text/plain representation, or a JSON representation, etc.
One of the important questions to ask: is a general purpose cache going to have the information necessary to return the "correct" representation for a request?
That said: given that your original design was using a query parameter to distinguish one projection from another, you should likely respect that instinct and continue to treat the different representations as belonging to different resources (meaning that general purpose caches will keep them completely separate).
Whether that means that you want to share the same path /foo (treating projection as an optional #ApiParam), or give each projection a different path (defining separate operations for each unique path) is less clear. In a brownfield project, my bias would be toward documenting what you already have, rather than making a bunch of breaking changes.
But it is certainly reasonable to treat "easy to document" as a design constraint.
So, the question is this: is the Foo resource in a different representation effectively the "same" resource or is it a different resource?
Fielding defined a resource as such:
The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource. A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time.
More precisely, a resource R is a temporally varying membership function MR(t), which for time t maps to a set of entities, or values, which are equivalent. The values in the set may be resource representations and/or resource identifiers. A resource can map to the empty set, which allows references to be made to a concept before any realization of that concept exists -- a notion that was foreign to most hypertext systems prior to the Web [61]. Some resources are static in the sense that, when examined at any time after their creation, they always correspond to the same value set. Others have a high degree of variance in their value over time. The only thing that is required to be static for a resource is the semantics of the mapping, since the semantics is what distinguishes one resource from another.
...
REST uses a resource identifier to identify the particular resource involved in an interaction between components. REST connectors provide a generic interface for accessing and manipulating the value set of a resource, regardless of how the membership function is defined or the type of software that is handling the request. The naming authority that assigned the resource identifier, making it possible to reference the resource, is responsible for maintaining the semantic validity of the mapping over time (i.e., ensuring that the membership function does not change). (Source)
In short, a resource is something that you give a name in order to reference it later on. This resource is a container for data. That data can be represented in plenty of ways. A representation is a concrete instance of the resource' data with respect to the media-type the representation was created for. The media-type itself defines the syntax and semantic of a concrete instance. I.e. HTML defines which attributes and elements are admissible within the payload and what these things express.
As REST shouldn't have typed "resources" meaningful to clients content type negotiation should be used. Here a client express its capabilities via the Accept header to the server and the server will chose a representation format that will suite the data the best. A well-behaved server will only chose among the suggested media types as it knows the client can handle the data. A non-well-behaved client will just ignore the header and send whatever it wants which eventually may prevent clients from being able to process the payload at all.
REST is all about decoupling of clients from servers and allowing the server side from evolving in future without breaking clients. This however is only possible if both use some kind of indirection. I.e. not the URI itself is the relevant thing in a payload but the link-relations that are attached to that URI. A link relation might be something like next, prev, first or last for a traversable collection or something like prefetch witch just states that the content of the annotated URI may be loaded once the client has loaded all other things and is currently IDLE as this content may be requested next with some likelihood. Such link relations are either standardized or should follow the extension mechanism defined in Web Linking.
In regards to your actual question. Think of an arbitrary product ABC1234. This product contains some properties such as its price, the current number of items in stock, some metadata describing the product and what not. These properties might be expressed in JSON, in XML or in HTML. Clients which are able to process these media-types will be able to create an "object" with the same properties with hardly any issues. The actual representation format used shouldn't have an influence on the actual data of the resource itself. After all, the representation format is just a mutually agreed way of exchanging the data between client and server in order to allow the recipient of the payload to process it in the same way the sender intended it initially.
As Fielding mentioned before, such a resource may be static or change over time. With the product example from above, the price may change over time, though this doesn't change the semantics of the actual product. Over time sometimes the same data that is present for a resource need to be made available as part of an other resource. This is totally fine and here things start to get a bit more interesting. As part of a company merger one of our clients needed to expose all of their items with different names. In their case they opted for providing both product names for a year simultaneously. By definition these would be two different resources to an arbitrary HTTP client, i.e ABC1234 and XYZ12345 even though they "represent" the data of the same real-live product. They could also have opted for using (permanent) redirection of clients to the "new" URI and therefore hint clients that the product is actually the same.
The resource per name (or URI) concept is also noticable if you take a look at how caching works in the HTTP ecosystem. Here the effective request URI is used as cache-key in order to look up whether for the requested URI already a stored response is present. Any unsafe operation performed on that URI will lead to an eviction of that stored response. This is i.e. one of the reasons why HTTP isn't meant for batch-operations as these may bypass the cache at all and lead to wrong and/or misleading results.
Years ago I created a tiny web service that serves the same resource in two representations.
GET /foo # returns a collection of Foos
GET /foo?projection=X # returns a collection of Foos in a different coordinate system i.e. different representation
According to how HTTP defines effective request URIs these two URIs would target two different resources actually, event though they express the same data just with different representations. A probably better approach would have been to expose just /foo and use either specialized media-types for the different coordinate systems or even better a media-type that supports profiles and hint the recipients processor via the profile attribute which "kind of" data it receives. Link relations, as mentioned above, also define a profile relation name that can be used to allow a client to chose between the URI returning "metric" or "imperial", "Kelvin", "Fahrenheit" or "Celsius" or similar measurement figures or the like.
So, long story short, loosely speeking the absolut URI, including matrix, query and path parameters, is what "names" a resource at an arbitrary client. The whole URI is the identifier of that resource after all. Slightly different names might result in local or intermediary cache misses and therefore indicate a different resource, even though the data expressed is the same as before. Instead of using two slighly different URIs redirection directives, content type negotiation or profiles on the same resource can be used to "get rid" of the sibling "resource" that only differ in different representation formats returned.

REST strategy for overloading GET verb

Consider a need to create a GET endpoint for fetching Member details using either of 4 options (It's common in legacy application with RPC calls)
Get member by ID
Get member by SSN
Get member by a combination of Phone and LastName (both must be passed)
What's a recommended strategy to live the REST spirit and yet provide this flexibility?
Some options I could think of are:
Parameters Based
/user/{ID}
/user?ssn=?
/user?phone=?&lname=?
Separate Endpoints
/user/{ID}
/user/SSN/{SSNID}
/user/{lname}/{phone}
RPC for custom
/user/{ID}
/user/findBySSN/
/user/findbycontact/
REST doesn't care what spelling you use for your identifiers.
For example, think about how you would do this on the web. You would provide forms, one for each set of search criteria. The consumer would choose which form to use, and submit the form, without ever knowing what the URI is.
In the case of HTML forms, there are specific processing rules for describing how the form information will be copied into the URI. The form takes on the aspect of a URI Template.
A URI Template provides both a structural description of a URI space and, when variable values are provided, machine-readable instructions on how to construct a URI corresponding to those values.
But there aren't any rules saying that restrict the server from providing a URI template that directs the client to copy the variable values into path segments rather than into the query string.
In other words, in REST, the server retains control of its own URI space.
You might sometimes prefer to use path segments because of their hierarchical nature, which may be convenient if you want the client to use relative resolution of relative references in your representations.
REST ≠ pretty URLs. The two are orthogonal.
Your question is about the latter, I feel.
Whilst the other answers have been good, if you want your API to work with HTML forms, go with query parameters on the collection /user resource for all fields, even for ID (assuming a human is typing these in based on information they are getting from sheets of paper on their desk, etc.)
If your server is able to produce links to each record, always produce canonical links such as /users/{id}, don't duplicate data under different URLs.

REST resource with multiple views

We are trying to follow a quite strict idiom for our REST service however we have come across a situation where we have two clients who require different representations of the same resource. One is front-end and they would prefer a very minimal resource with only the fields they require and in a more flattened structure (for performance), the other requires all fields that we have in our data store in a heavily nested structure. What is the idiomatic way for REST services to deal with this given the canonical URL should be the same as they are accessing the same resource. We thought of adding projections to the request but with this the structure would still be quite nested which causes performance issues in the JS client as it will have to walk through the structure and flatten it, something that can be quite costly when the number of resources returned is high.
I would suggest there are two alternatives:
1) If the query field can vary, you could specify the fields (structure) you want as query parameters. This is common in REST APIs. With no specification, you would return a default list of fields. What should be default or not depends on the service, but in general the minimal set makes a better default for performance. In order to avoid listing all fields, something like fields=all could be used. In your case structure might make more sense.
2) You can encode the field request in a custom request headers. Some would argue that this is the more REST-ful approach as you're only modifying the format of the response and not the underlying action invoked, and therefore the URL should be the same.
In practice, most services prefer the first approach as it's considered more approachable.
Personally, I think it's a marginal choice. I prefer to encode the return media (JSON, HTML, XML, etc.) in the Accept header. Any decent developer has tools that make it easy enough to set the headers, but the fields query parameter idiom is, in my experience, far more prevalent and there's a great deal to be said for convention.
Note, if you use the headers approach, you should probably not use the Accept header for the structure/field specification. Add your own header if you go that route.