How to map complex URLs - web-services

It's easy to map stuff like this to a method. Below shows examples of URI Templates and related mapped methods in the back-end service or mvc controller:
/Cars/
Get()
/Cars/{id}
Get(int id)
But what if you have more than just that. Lets say you have this:
/Cars/{id}/seat/{id}
So I am saying I want to target one of the seats in this care (I know bad example but this is all I could think of for the moment).
So I want a seat, and seat is at the end which tells use the resource I'm asking for.
I want to know how someone would map this back to a controller (or service) and related method.
I'm thinking since you want seat, the Seat Service or controller would have I guess something like this:
Seat (service)
Get() - gets all seats, maps to /seats/
GetSeatByCarId(int id) - this would I think match my url above, maybe we strip out whatever is before /seat/ like the car id? I don't know, that's what I'm asking, ways I can do this.
What do people do when the url has more than just a [resource]/[id]? How do you manage that and what does it look like in the backend, what kind of method and how are you mapping these more complicated URI templates?

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

RESTful API and Foreign key handling for POSTs and PUTs

I'm helping develop a new API for an existing database.
I'm using Python 2.7.3, Django 1.5 and the django-rest-framework 2.2.4 with PostgreSQL 9.1
I need/want good documentation for the API, but I'm shorthanded and I hate writing/maintaining documentation (one of my many flaws).
I need to allow consumers of the API to add new "POS" (points of sale) locations. In the Postgres database, there is a foreign key from pos to pos_location_type. So, here is a simplified table structure.
pos_location_type(
id serial,
description text not null
);
pos(
id serial,
pos_name text not null,
pos_location_type_id int not null references pos_location_type(id)
);
So, to allow them to POST a new pos, they will need to give me a "pos_name" an a valid pos_location_type. So, I've been reading about this stuff all weekend. Lots of debates out there.
How is my API consumers going to know what a pos_location_type is? Or what value to pass here?
It seems like I need to tell them where to get a valid list of pos_locations. Something like:
GET /pos_location/
As a quick note, examples of pos_location_type descriptions might be: ('school', 'park', 'office').
I really like the "Browseability" of of the Django REST Framework, but, it doesn't seem to address this type of thing, and I actually had a very nice chat on IRC with Tom Christie earlier today, and he didn't really have an answer on what to do here (or maybe I never made my question clear).
I've looked at Swagger, and that's a very cool/interesting project, but take a look at their "pet" resource on their demo here. Notice it is pretty similar to what I need to do. To add a new pet, you need to pass a category, which they define as class Category(id: long, name: string). How is the consumer suppose to know what to pass here? What's a valid id? or name?
In Django rest framework, I can define/override what is returned in the OPTION call. I guess I could come up with my own little "system" here and return some information like:
pos-location-url: '/pos_location/'
in the generic form, it would be: {resource}-url: '/path/to/resource_list'
and that would sort of work for the documentation side, but I'm not sure if that's really a nice solution programmatically. What if I change the resources location. That would mean that my consumers would need to programmatically make and OPTIONS call for the resource to figure out all of the relations. Maybe not a bad thing, but feels like a little weird.
So, how do people handle this kind of thing?
Final notes: I get the fact that I don't really want a "leaking" abstaction here and have my database peaking thru the API layer, but the fact remains that there is a foreign_key constraint on this existing database and any insert that doesn't have a valid pos_location_type_id is raising an error.
Also, I'm not trying to open up the URI vs. ID debate. Whether the user has to use the pos_location_type_id int value or a URI doesn't matter for this discussion. In either case, they have no idea what to send me.
I've worked with this kind of stuff in the past. I think there is two ways of approaching this problem, the first you already said it, allow an endpoint for users of the API to know what is the id-like value of the pos_location_type. Many API's do this because a person developing from your API is gonna have to read your documentation and will know where to get the pos_location_type values from. End-users should not worry about this, because they will have an interface showing probably a dropdown list of text values.
On the other hand, the way I've also worked this, not very RESTful-like. Let's suppose you have a location in New York, and the POST could be something like:
POST /pos/new_york/
You can handle /pos/(location_name)/ by normalizing the text, then just search on the database for the value or some similarity, if place does not exist then you just create a new one. That in case users can add new places, if not, then the user would have to know what fixed places exist, which again is the first situation we are in.
that way you can avoid pos_location_type in the request data, you could programatically map it to a valid ID.

REST-ish URI design for multiple dependent resources

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.

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.

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