REST and RDF, what's the representation strategy? - rest

Your triplestore contains a lot of nodes, and you have to make accessible this database via a REST interface.
Now, my solution would be that every named (not-anonymous) node is exported as a resource, whose representation is:
all the triples having the node as a subject
all the triples having the node as an object
all the connected anonymous nodes.
I am a little reluctant on point number 2: this would basically give both incoming and outgoing triples.
What is your take on a REST sytle representation of a purely RDF-oriented data store ?
Do you share my point of view or not, and if not, what is your take on it ?

Depends on what the the data is and what the interface users want to do with it. This question is similar to what the SPARQL DESCRIBE query form should return. (It's determined by the implementation.)
For the use cases I've had with RDF data, I'd go with 1 and 3, producing a blank node closure of the resource. Additionally, you could have a separate interface for case 2, returning the incoming arcs of the resource.

One easy way to make an RDF dataset REST traversible is to use URLs for all traversible elements.
When the URL is accessed, for example via HTTP GET, then result shows the connected nodes (connected as properties and/or inverse properties).
More formally the returned representation could be a Concise Bounded Description of the resource.

(disclaimer: this may not correspond exactly to the content of your question, but it corresponds to the title)
I think that about the topic of Rest representation of RDF data is a general problem of inverting the order of concepts. For me the normal would be to have a collection of Rest documents with RDF data and use a RDF database for indexing and making global querys.
In this situation you can organize your resources in the way you prefer.
Also (if you pretend to use the URI of the node as the exported resource) your approach will have subtle problems about what is the meaning of your resources: the Rest resources you propose here are "information resources" and then they cannot be abstract resources. There will be a conflict between information and meta-information.
I published an article here explaining this view in more detail.

Related

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 Best practise for filtering and knowing the result is singular: List or single?

Variety of REST practises suggest (i.e. 1, 2, 3) to use plurals in your endpoints and the result is always a list of objects, unless it's filtered by a specific value, such as /users/123 Query parameters are used to filter the list, but still result in a list, nevertheless. I want to know if my case should 'abandon' those best practices.
Let's use cars for my example below.
I've got a database full of cars and each one has a BuildNumber ("Id"), but also a model and build year which combination is unique. If I then query for /cars/ and search for a specific model and year, for example /cars?model=golf&year=2018 I know, according to my previous sentence, my retrieve will always contain a single object, never multiple. My result, however, will still be a list, containing just one object, nevertheless.
In such case, what will be the best practise as the above would mean the object have to be extracted from the list, even though a single object could've been returned instead.
Stick to best practises and export a list
Make a second endpoind /car/ and use the query parameters ?model=golf&year=2018, which are primarily used for filtering in a list, and have the result be a single object, as the singular endpoint states
The reason that I'm asking this is simply for the cleanness of the action: I'm 100% sure my GET request will result in single object, but still have to perform actions to extract it from the list. These steps should've been unnecessary. Aside of that, In my case I don't know the unique identifier, so cars/123 for retrieving a specific car isn't an option. I know, however, filters that will result in one object and one specific object altogether. The additional steps simply feel redundant.
1: https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design
2: https://blog.mwaysolutions.com/2014/06/05/10-best-practices-for-better-restful-api/
3: https://medium.com/hashmapinc/rest-good-practices-for-api-design-881439796dc9
As you've specifically asked for best practices in regards to REST:
REST doesn't care how you specify your URIs or that semantically meaningful tokens are used inside the URI at all. Further, a client should never expect a certain URI to return a certain type but instead rely on content-type negotiation to tell the server all of the capabilities the client supports.
You should furthermore not think of REST in terms of object orientation but more in terms of affordance and statemachines where a client get served every information needed in order to make an educated decision on what to do next.
The best sample to give here is probably to take a close look at the Web and how it's done for HTML pages. How can you filter for a specific car and how it will be presented to you? The same concepts that are used in the Web also apply to REST as both use the same interaction model. In regards to your car sample, the API should initially return some control-structures that teach a client how a request needs to be formed and what options could be filtered for. In HTML this is done via forms. For non-HTML based REST APIs dedicated media-types should be defined that translate the same approach to non-HTML structures. On sending the request to the server, your client would include all of the supported media-types it supports in an Accept HTTP header, which informs the server about the capabilities of the client. Media-types are just human-readable specification on how to process payloads of such types. Such specifications may include hints on type information a link relation might return. In order to gain wide-usage of media-types they should be defined as generic as possible. Instead of defining a media-type specific for a car, which is possible, it probably would be more convenient to use an existing or define a new general data-container format (similar to HTML).
All of the steps mentioned here should help you to design and implement an API that is free to evolve without having to risk to break clients, that furthermore is also scalable and minimizes interoperability concerns.
Unfortunately your question targets something totally different IMO, something more related to RPC. You basically invoke a generic method via HTTP on an endpoint, similar like SOAP, RMI or CORBA work. Whether you respect the semantics of HTTP operations or not is only of sub-interest here. Even if you'd reached level 3 of the Richardson Maturity Model (RMM) it does not mean that you are compliant to REST. Your client might still break if the server changes anything within the response. The RMM further doesn't even consider media-types at all, hence I consider it as rather useless.
However, regardless if you use a (true) REST or RPC/CRUD client, if retrieving single items is your preference instead of feeding them into a collection you should consider to include the URI of the items of interest instead of its data directly into the collection, as Evert also has suggested. While most people seem to be concerned on server performance and round-trip-times, it actually is very elegant in terms of caching. Further certain link-relation names such as prefetch may inform the client that it may fetch the targets payload early as it is highly possible that it's content will be requested next. Through caching a request might not even have to be triggered or sent to the server for processing, which is probably the best performance gain you can achieve.
1) If you use query like cars/where... - use CARS
2) If you whant CAR - make method GetCarById
You might not get a perfect answer to this, because all are going to be a bit subjective and often in a different way.
My general thought about this is that every item in my system will have its own unique url, for example /cars/1234. That case is always singular.
But this specific item might appear as a member in collections and search results. When /cars/1234 apears in these, they will always appear as a list with 1 item (or 0 or more depending on the query).
I feel that this is ultimately the most predictable.
In my case though, if a car appears as a member of a search or colletion, it's 'true url' will still be displayed.

Should rest resource have same structure in collection

I found question about subset of REST when display resource by GET /task/ID and as row in collection GET /task.
REST - Resource and Collection Representations
I'm using Apigility.
I know REST is not official, but want to hold as strict as could with overall best practice/standard.
Can i have others fields in collection and resource. Of cource part will be the same, but for collection i need some extra information for filtering and in resource there is now need for them.
Is this will breaking in any way some rules?
It is not uncommon to return partial representations of resources in a REST collection response, while the full representation is returned when the singleton endpoint is requested.
Read for example here (one of the first links I found with this search on Google, there are many more).
Getting a collection
Getting a collection, like "members" may return
1) the entire list of resources as a list of links,
2) partial representations of each resource, or
3) full representations of all the resources in the collection.
So it is not uncommon that a resource representation in a collection differs from the singleton representation, but I would say you would rather have less then more data.
What particular fields were you thinking about adding to the response in your collection? Can you give an example?
That would certainly be unusual, it's better to be consistent, why have 2 models for the same thing? Looking at the Richardson Maturity Model level 1, one would expect a service endpoint mapped to a (single) resource. And what do you mean by extra information for filtering?
If that's a frequent scenario, you might want to handle it on the server through templated URIs (query string) like so:
GET /task?type={type}&property2={value2}
Otherwise, you could just fetch them all and do the filtering on the client (in which case you'll surely need those properties).

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

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...

How should I deal with object hierarchies in a RESTful API?

I am currently designing the API for an existing PHP application, and to this end am investigating REST as a sensible architectural approach.
I believe I have a reasonable grasp of the key concepts, but I'm struggling to find anybody that has tackled object hierarchies and REST.
Here's the problem...
In the [application] business object hierarchy we have:
Users
L which have one-to-many Channel objects
L which have one-to-many Member objects
In the application itself we use a lazy load approach to populate the User object with arrays of these objects as required. I believe in OO terms this is object aggregation, but I have seen various naming inconsistencies and do not care to start a war about the precise naming convention </flame war>.
For now, consider I have some loosely coupled objects that I may / may not populate depending on application need.
From a REST perspective, I am trying to ascertain what the approach should be. Here is my current thinking (considering GET only for the time being):
Option 1 - fully populate the objects:
GET api.example.com/user/{user_id}
Read the User object (resource) and return the User object with all possible Channel and Member objects pre-loaded and encoded (JSON or XML).
PROS: reduces the number of objects, no traversal of object hierarchies required
CONS: objects must be fully populated (expensive)
Option 2 - populate the primary object and include links to the other object resources:
GET api.example.com/user/{user_id}
Read the User object (resource) and return the User object User data populated and two lists.
Each list references the appropriate (sub) resource i.e.
api.example.com/channel/{channel_id}
api.example.com/member/{member_id}
I think this is close to (or exactly) the implications of hypermedia - the client can get the other resources if it wants (as long as I tag them sensibly).
PROS: client can choose to load the subordinates or otherwise, better separation of the objects as REST resources
CONS: further trip required to get the secondary resources
Option 3 - enable recursive retrieves
GET api.example.com/user/{user_id}
Read the User object and include links to lists of the sub-objects i.e.
api.example.com/user/{user_id}/channels
api.example.com/user/{user_id}/members
the /channels call would return a list of channel resources in the form (as above):
api.example.com/channel/{channel_id}
PROS: primary resources expose where to go to get the subordinates but not what they are (more RESTful?), no requirement to get the subordinates up front, the subordinate list generators (/channels and /members) provide interfaces (method like) making the response more service like.
CONS: three calls now required to fully populate the object
Option 4 - (re)consider the object design for REST
I am re-using the [existing] application object hierarchy and trying to apply it to REST - or perhaps more directly, provide an API interface to it.
Perhaps the REST object hierarchy should be different, or perhaps the new RESTful thinking is exposing limitations of the existing object design.
Any thoughts on the above welcomed.
There's no reason not to combine these.
api.example.com/user/{user_id} – return a user representation
api.example.com/channel/{channel_id} – return a channel representation
api.example.com/user/{user_id}/channels – return a list of channel representations
api.example.com/user/{user_id}/channel_list – return a list of channel ids (or links to their full representations, using the above links)
When in doubt, think about how you would display the data to a human user without "API" concerns: a user wants both index pages ({user_id}/channel_list) and full views ({user_id}/channels).
Once you have that, just support JSON instead of (or in addition to) HTML as the representation format, and you have REST.
The best advice I can give is to try and avoid thinking about your REST api as exposing your objects. The resources you create should support the use cases you need. If necessary you might create resources for all three options:
api.example.com/completeuser/{id}
api.example.com/linkeduser/{id}
api.example.com/lightweightuser/{id}
Obviously my names are a bit goofy, but it really doesn't matter what you call them. The idea is that you use the REST api to present data in the most logical way for the particular usage scenario. If there are multiple scenarios, create multiple resources, if necessary. I like to think of my resources more like UI models rather than business entities.
I would recommend Restful Obects which is standards for exposing domain model's restful
The idea of Restful Objects is to provide a standard, generic RESTful interface for domain object models, exposing representations of their structure using JSON and enabling interactions with domain object instances using HTTP GET, POST, PUT and DELETE.
According to the standard, the URIs will be like:
api.example.com/object/user/31
api.example.com/object/user/31/properties/username
api.example.com/object/user/31/collections/channels
api.example.com/object/user/31/collections/members
api.example.com/object/user/31/actions/someFunction
api.example.com/object/user/31/actions/someFunction/invoke
There are also other resources
api.example.com/services
api.example.com/domain-types
The specification defines a few primary representations:
object (which represents any domain object or service)
list (of links to other objects)
property
collection
action
action result (typically containing either an object or a list, or just feedback messages)
and also a small number of secondary representations such as home, and user
This is interesting as you’ll see that representations are fully self-describing, opening up the possibility of generic viewers to be implemented if required.
Alternatively, the representations can be consumed directly by a bespoke application.
Here's my conclusions from many hours searching and with input from the responders here:
Where I have an object that is effectively a multi-part object, I need to treat that as a single resource. Thus if I GET the object, all the sub-ordinates should be present. This is required in order that the resource is cacheable. If I part load the object (and provide an ETag stamp) then other requestors may receive a partial object when they expected a full one. Conclude - objects should be fully populated if they are being made available as resources.
Associated object relationships should be made available as links to other (primary) resources. In this way the objects are discoverable by traversing the API.
Also, the object hierarchy that made sense for main application site may appear not be what you need to act in RESTful manner, but is more likely revealing problems with the existing hierarchy. Having said this the API may require more specialised use cases than had been previously envisaged, and specialised resources may be required.
Hope that helps someone