REST-ish URI design for multiple dependent resources - web-services

I'm trying to design a REST-ish based Web Service to interface with a farm animal management system I am working on.
To explain the problem in detail, I have a collection of animals belonging to a farm. Each animal has its own information - such as name, ID number, breed age, etc. Therefore, I would assume a URI such as the following would suit:
/animals <- retrieve list of animals
/animals/{animal-id} <- Retrieve only one animal
/animals?breed=sheep <- Search/query
The problem arises when I try to link in other dependent resources to each animal. An animal can have a collection of weight information, as well as what I call comments (observations made for a particular animal). Each of these are dependent and only exist to that one particular animal, but are themselves a resource I want to access.
The easiest approach IMO would be to nest the resources within the animal URI:
/animals/{animal-id}/weights
/animals/{animal-id}/comments
However, I see a need to access and query the weights and comments directly, without referencing the animal. Examples in usage would be to retrieve the most recent (or all) weight(s) from all animals of a particular breed ...?breed=sheep or even return weights/comments for a selection of individual animal ID's ...?animals={ID1},{ID2},{...}.
Further complications arise when I want to add one comment to multiple animals at once. (please excuse my representation of a POST and JSON)
POST ....
{
"comment":"Animal moved to paddock B",
"animals":[{id1}, {id2}, ...]
}
I understand that the obvious solution to this problem would be to GET and POST (for example) to each animal that I wanted to retrieve/edit. I would prefer not to do this though, as eventually I want this service accessed from mobile devices, and therefore decreasing the number of calls seems wise.
I believe that the web standards allow CSV in the URI, so something like this could work,
/animals/{id1},{id2},{..}/weights
But, I am expecting cases where ten(s) of animals may need to be referenced at once (or queried), and that would lead to a messy and unfriendly URI.
My current perceived solution is to expose weights and comments as their own resource, which allows me to access and query them directly
/weights
/weights/{weight-id}
/weights?breed=sheep
and even post directly to the collection
POST /comments
{
"comment":"Animal moved to paddock B",
"animals":[{id1}, {id2}, ...]
}
But what would /animals/{animal-id}/weights return? Is it even needed, or would I just reference a link to the /weights?animal={animal-id} resource itself? But is it okay to link to a queried resource?
Am I making one redundant, or just providing "another" way to access the information?
Is there something that I am doing wrong, am I letting my database influence my service model, or am I just missing the point completely?
I am quite new to this, and have read quite a few contradicting arguments regarding these issues, and so am quite confused as to what is best for my requirements.
Thanks!

It would be better to define top level resources for your other entities if you want to address them as such (/weights, /comments etc). You can then POST to those endpoints in a batch fashion.
POST /comments
{
"animals" : [
{"id" : 1},
{"id" : 2},
{"id" : 3},
{"id" : 4},
],
"commentText" : "Sent to Hamburger Hamlet"
}
Note that including long lists of id's in your URL is not good design for several reasons, including that most browsers and HTML proxies have restrictions on URL length (the good rule of thumb is to try and keep URL lengths at 2083 characters in length or less).

I have had similar issues to you, but in the end we were able to remove the complexities you are getting by having specific url namespaces (so to speak) for different user types using the API.
For example it might be a farm worker client app that would perform your /weights, /comments actions (POST, PUT, DELETE etc) that you are describing, so you could keep their functionality clean via something like:
/farmworkers/comments
/farmworkers/weights
And then still keep the /animals/{animal-id}/weights URL within some other "namespace".
Another thing to consider is embedding resources using something like the HAL format (http://stateless.co/hal_specification.html), which could allow you to embed multiple animal resources within the request etc. Hope this helps.

Related

What's the correct way to create a REST service that allows for different types of identifiers?

I need to create a RESTful webservice that allows for addressing entities by using different types of IDs. I will give you an example based on books (which is not what I need to process but I want to build a common understanding this way).
Books can be identifier by:
ISBN 13
ID
title
I can create a book by POSTing to /api/v1/books/The%20Bible. This book can then later be addressed by its ISBN /api/v1/books/12312312301 or ID /api/v1/books/A9471IZ1. If I implemented it this way I would need to analyze whatever identifier gets sent and convert it internally.
Is it 'legal' to add the type of identifier to the URL ? Like /api/v1/books/title/The%20Bible?
It seems that what you need is not simply retrieving resources, but searching for them by certain criteria (in your case, by ISBN, title or ID). In that case, rather than complicate your /books endpoint (which, ideally, should only returns books by ID), I'd create a separate /search function. You can then use it search for books by any field.
For example, you would have:
GET /search?title=bible
GET /search?isbn=12312312301
It can even be easily expanded to add more fields later on.
First: A RESTful URl should only contain nouns and not verbs. You can find a lot of best-practices online, as example: RESTful API Design: nouns are good, verbs are bad
One approach would be to detect the id/identifier in code.
The pattern would be, as you already mentioned:
GET /api/v1/books/{id}, like /api/v1/books/12312312301 or /api/v1/books/The%20Bible
Another approach, similar to this.lau_, would be with a query parameter. But I suggest to add the query parameter to the books URL (because only nouns, no verbs):
GET /api/v1/books?isbn=12312312301
The better solution? Not sure…
Because you are selecting “one book by id” (except title), rather than performing a query/search, I prefer the first approach (…/books should return “a collection of books” and .../books/{id} should return only one book).
But maybe someone has a better approach/idea?
Edit:
I suggest to avoid adding the identifier to the URL, it has “bad smell”. But is also a possible approach and I saw that a lot in other APIs. Let’s see if I can find some information on that, if its “ok” or should be avoided.
Edit 2:
See REST API DESIGN - Getting a resource through REST with different parameters but same url pattern and REST - supporting multiple possible identifiers

what's the difference between a collection and a store in REST?

I'm trying to wrap my head around the difference between a "collection" and a "store" in REST. From what I've read so far,
a collection is:
"a server-managed directory of resources"
and a store is a:
"client-managed resource repository"
I found this post: How "store" REST archetype isn't creating a new resource and a new URI?
but it didn't really help me clarify the difference. I mean, I understand one is controlled by the server and the other by the client... but can someone give me a concrete example of what a store might be in a real world application?
I *think it's something like this:
GET http://myrestapplication.com/widgets/{widget_id} -- retrieves a widget from db
POST http://myrestapplication.com/widgets/{widget_id} -- creates a new widget from db
PUT http://myrestapplication.com/widgets/{widget_id},[list of updated parms & their vals] -- update widget
PUT http://myrestapplication.com/users/johndoe/mywishlist/{widget_id} -- updates john doe's profile to add a widget that already exists in the database... but links to it as his favorite one or one that he wants to buy
Is this correct?
if so, could the last PUT also be expressed as a POST somehow?
EDIT 1
I found an online link to the book i'm reading... where it makes the distinction between the two:
https://books.google.ca/books?id=4lZcsRwXo6MC&pg=PA16&lpg=PA16&dq=A+store+is+a+client-managed+resource+repository.+A+store+resource+lets+an+API+client:+put+resources+in,+get+them+back+out,+and+decide+when+to+delete+them&source=bl&ots=F4CkbFkweL&sig=H6eKZMPR_jQdeBZkBL1h6hVkK_E&hl=en&sa=X&ei=BB-vVJX6HYWvyQTByYHIAg&ved=0CB0Q6AEwAA#v=onepage&q=A%20store%20is%20a%20client-managed%20resource%20repository.%20A%20store%20resource%20lets%20an%20API%20client%3A%20put%20resources%20in%2C%20get%20them%20back%20out%2C%20and%20decide%20when%20to%20delete%20them&f=false
REST uses http verbs to manipulate resources. Full-Stop. That's it. To build some classes of browser-based application developers sometimes use local storage (a store), but that has absolutely nothing to do with REST (in fact, it's the opposite). Collections are a special consideration in REST-based API design because the REST principles place considerable constraints on how they are represented in the results of your queries -- special consideration also because there are no standards on how these things should be represented and access if you're using anything other than html as a resource type.
Edit:
REST suggests that when we ask for a resource we receive that resource and only that resource and that things referenced by that resource are returned as links, not as data. This mimics the http standard by which we return the requested page and links to other pages rather than embedding linked pages. So, our resources should return links to related resources, not the resources themselves.
So, what about collections?
Let's use as an example a college management system that has Course objects each of which contains a huge lists of Students.
When I GET the course I don't want to have the collection of students returned as an embedded list, because that could be huge and because my user might not be interested. Instead, I want to know that the course has a students collection and I want to be able to query that collection separately (when I need to) and I want to be able to page it on demand. For this to work, the course needs to link to the students collection URL (maybe with an appropriate type so that my code knows how to handle the link). Then, I want to use the given collection's url to request a paged list of resources. In this example, the collection's url could be something like: course/1/students, with the convention that I can add paging info to the search string to constrain the results with something like course/1/students?page=1&count=10. Embedding the students collection into the course resource would be a violation of REST. I would not be returning a course, I'd be returning course-and-students.

ideal API routes

I'm writing an api. To this point I've been using a route:
http://api.com/resource
and I pass in an action that I want to do to the resource within a json field and go from there. Is this an ideal or preferable situation from both a programmer and user perspective?
Or,
Would something like:
http://api.com/resource/action
be more useful, restful, right (take you pick). Or does it not matter at all? It works as it is, but I'm aiming for public consumption and I'd like to get any problems I'm unaware of with this out of the way before it gets more difficult to change.
Edit:
To add more detail the action I'm not concerned about is of GET, POST, etc. I have a route:
http://api.com/thing
This is a POST route, it creates a thing. Things aren't being stored in a database or anywhere at this point, so the thing created is immediately returned with the response. Users can specify that thing be returned painted a color: red, yellow, or green. From a user perspective, is it more useful to specify the color requirement as part of the post data above or to have routes like:
http://api.com/thing/red
where posting to returns a red thing.
Basically, the action doesn't need to be specified (in the URL or in the data sent) as HTTP verbs, in a REST approach, are used to describe actions to perform on resources. So, your two solutions are not really "REST compliant". What you should do first is combining your route http://api.com/resources with some HTTP verbs in order to:
Create a resource is: POST http://api.com/resources
Read a resource is: GET http://api.com/resources/
Update (replacing actually) a resource is: PUT http://api.com/resources/
Delete a resource is: DELETE http://api.com/resources/
As usual, following conventions is better. Your two solutions are not ideal for a programmer with a taste for conventions and best practices. However, your second solution is readable and explicit. That means if you really want to choose between your two solutions, the second one seems better. But, if you want to update your API to follow more REST conventions, you should consider your resource as a real resource and use HTTP verbs.
I recommend you these two presentations about REST APIs:
http://fr.slideshare.net/Wombert/designing-http-interfaces-and-restful-web-services-dpc2012-20120608
https://speakerdeck.com/u/nicola/p/developing-restful-web-apis-with-python-flask-and-mongodb
You may be interested by this other question and the answer I gave: Resource and Action URI convention for REST.
Edit: according to your new question, send all data as post data, even your color. It will be more consistent. Why should it be different anyway? You should change the URI only if you describe different resources. If the color is just a property of a thing then you don't describe two resources and you should send the color with all other post data.

How to solve two REST problems: the interface document; loss of privacy in descriptive URLs

Coming from a lot of frustrating times with WSDL/Soap, I very much like the REST paradigm, but am trying to solve two basic problems in our application, before moving over to REST. The first problem relates to the lack of an interface document. I think I finally see how to handle this situation: One can query his way down from a top-level "/resources" resource using various requests of GET, HEAD, and OPTIONS to find the one needed resource in the correct hypermedia format. Is this the idea? If so, the client need only be provided with a top-level resource URI: http://www.mywebservicesite.com/mywebservice/resources. He will then have to do some searching and possible keep track of what he is discovering, so that he can use the URIs again efficiently in future to do GETs, POSTs, PUTs, and DELETEs. Are there any thoughts on what should happen here?
The other problem is that we cannot use descriptive URLs like /resources/../customer/Madonna/phonenumber. We do have an implementation of opaque URLs we use in the context of a session, and I'm wondering how opaque URLs might be applied to REST. The general problem is how to keep domain-specific details out of URLs, and still benefit from what REST has to offer.
The other problem is that we cannot use descriptive URLs like /resources/../customer/Madonna/phonenumber.
I think you've misunderstood the point of opaque URIs. The notion of opaque URIs is with respect to clients: A client shall not decipher a URI to guess anything of semantic meaning from it. So a service may well have URIs like /resources/.../customer/Madonna/phonenumber, and that's quite a good idea. The URIs should be treated as opaque by clients: not infer from the URI that it represents Madonna's phone number, and that Madonna is a customer of some sort. That knowledge can only be obtained by looking inside the URI itself, or perhaps by remembering where the URI was discovered.
Edit:
A consequence of this is that navigation should happen by links, not by deconstructing the URI. So if you see /resouces/customer/Madonna/phonenumber (and it actually represents Customer Madonna's phone number) you should have links in that resource to point to the Madonna resource: e.g.
{
"phone_number" : "01-234-56",
"customer_URI": "/resources/customer/Madonna"
}
That's the only way to navigate from a phone number resource to a customer resource. An important aspect is that the server implementation might or might not have domain specific information in the URI, The Madonna record might just as well live somewhere else: /resources/customers/byid/81496237. This is why clients should treat URIs as opaque.
Edit 2:
Another question you have (in the comments) is then how a client, with the required no knowledge of the server's URIs is supposed to be able to find anything. Clients have the following possibilities to find resources:
Provide a search interface. This could be done by providing an OpenSearch description document, which tells clients how to search for items. An OpenSearch template can include several variables, and several endpoints, depending on what you're looking for. So if you have a "customer ID" that's unique, you could have the following template: /customers/byid/{proprietary:customerid}", the customerid element needs to be documented somewhere, inside the proprietary namespace. A client can then know how to use such a template.
Provide a custom form. This implies making a custom media type in which you explicitly define how (based on an instance of the document) a URI to a customer can be forged. <customers template="/customers/byid/{id}"/>. The documentation (for the media type) would have to state that the template attribute must be interpreted as a relative URI after the string substitution "{id}" to an actual customer ID.
Provide links to all resources. Some resources aren't innumerable, so you can simply make a link to each and every one of them, optionally including identifying information along with the links. This could also be done in a custom media type: <customer id="12345" href="/customer/byid/12345"/>.
It should be noted that #1 and #2 are two ways of saying the same thing: Clients are allowed to create URIs if they
haven't got the URI structure a priori
a media type exists for which the documentation states that URIs should be created
This is much the same way as a web browser has no idea of any URI structure on the web, except for the rules laid out in the definition of HTML forms, to add a ? and then all the query parameters separated by &.
In theory, if you have a customer with id 12345, then you could actually dispense with the href, since you could plug the customer id 12345 into #1 or #2. It's more common to actually provide real links between resources, rather than always relying on lookup or search techniques.
I haven't really used web RPC systems (WSDL/Soap), but i think the 'interface document' is there mostly to allow client libraries to create the service API, right? if so, REST shouldn't need it, because the verbs are already defined and don't really need to be documented again.
AFAIUI, the REST way is to document the structure of each resource (usually encoded in XML or JSON). In that document, you'll also have to document the relationship between those resources. In my case, a resource is often a container of other resources (sometimes more than one type), therefore the structure doc specifies what field holds a list of URLs pointing to the contained resources. Ideally, only one unique resource will need a single, fixed (documented) URL. everithing else follows from there.
The URL 'style' is meaningless to the client, since it shouldn't 'construct' an URL. Every URL it needs should be already constructed on a resource field. That let's you change the URL structure without changing the client (that has saved tons of time to me). Your URLs can be as opaque or as descriptive as you like. (personally, i don't like text keys or slugs; my keys are all BIGINTs or UUIDs)
I am currently building a REST "agent" that addresses the first part of your question. The agent offers a temporary bookmarking service. The client code that is interacting with the agent can request that an URL be bookmarked using some identifier. If the client code needs to retrieve that representation again, it simply asks the agent for the url that corresponds to the saved bookmark and then navigates to that bookmark. Currently those bookmarks are not persisted so they only last for the lifetime of the client application, but I have found it a useful mechanism for accessing commonly used resources. E.g. The root representation provides a login link. I bookmark that link and if the client ever receives a 401 then I can redirect to the "login" bookmark.
To address an issue you mentioned in a comment, the agent also has the ability to store retrieved representations in a dictionary. If it becomes necessary to aggregate and manipulate multiple representations at the same time then I can simply request that the agent store the current representation in a dictionary associated to a key and then continue navigating to the next resource. Once the client has accumulated all the necessary representation it can do what it needs to do.

REST services - exposing non-data "actions"

I understand how to use REST for doing general entity interactions - using urls names to map to entities and the HTTP verbs to map to actions on those entities. But what is the generally accepted way of looking at "actions" more like RPC?
For example, let's say I want to send a command for the device to reset? There's no real "entity" here or do I do something like POST to http://mydevice/device/reset?
/device/reset or /system/reset are ok.
The REST "design pattern" does encourage you to NOT use any verbs.. You could do:
POST http://mydevice/system/state
<stateType>RESET</stateType>
Related information:
How to create REST URL’s without verbs?
Threads tagged with restful-url
I don't think that's the case to use POST. The "RESET action" is a idempotent action (if you call it n times you will always get the same result), so IMHO you should use a PUT call instead POST (as POST is not idempotent).
Also, as you are Putting a resource, you can use
PUT http://system
<device>
<status>RESET</status>
</device>
or
PUT http://system/status/reset
But I think the first one is "more restful", since you are putting a resource, while the second one you just use the URL.
I usually name the entity "system" or something like that. So you do "/system/reset". You've chosen device so that works too.
But yea, I usually consider these types of actions to be updates, which would use the POST method. So I think you are right to POST to /device/reset