I always have the doubt that you can see below when i need to create theresource URLs for a REST API. I wonder if some one can help me.
Let's suppose that i have two models.
User
Post
User can submit his own posts and can comment his own and another posts.
Main resources URLs for User would be:
GET /users # Retrieve all users.
POST /users # Create a new user.
GET/DELETE/PUT /users/{user_id} # Get, remove and update an user.
Main resource URLs for Post would be:
GET /posts # Retrieve all posts.
POST /posts # Create a new post.
GET/DELETE/PUT /posts/{post_id} # Get, remove and update a post.
My problem come when for example i want:
Top 10 submitters (filter for a parameter(external link, discussion, all)). The URL should be:
GET /users/top?type=ext
GET /users/top?type=disc
GET /users/top # for all
Or maybe it should be:
GET /users?top=ext
GET /users?top=disc
GET /users?top=all
The same but with posts:
Top 10 commented post (filter for a parameter(external link, discussion, all)). The URL should be:
GET /posts/comments?type=ext
GET /posts/comments?type=disc
GET /posts/comments # for all
Or maybe it should be:
GET /posts?top=ext
GET /posts?top=disc
GET /posts?top=all
Any of above options are good for you or it should be another way?
Regards
I like to think of the REST URI as a model representation in itself.
So /users/top doesn't make a lot of sense but /posts/comments seems to be fine (as comments could also be a different model). But for your case, I recommend other set of query parameters as they're widely used for filtering & sorting requests. So in your case, I'd recommend something like:
GET /users?sort=ext&order=desc&limit=10
which would help me understand that I'm requesting 10 user resources which have been sorted for ext in the descending order. (you can even change it to type=ext if you want)
As usual; REST doesn't care what spellings you use.
One place you might look for inspiration is... stack overflow itself. Do these URI look familiar?
/questions?sort=newest
/questions?sort=featured
/questions?sort=votes
The API has pretty decent documentation, which will also offer hints at decent spellings to deal with paging and search ranges.
That said, IMDB takes a different approach - The Shawshank Redemption uses a straight forward "I am an element of a collection" spelling
http://www.imdb.com/title/tt0111161/
But the top rated titles of all time? they appear as a chart
http://www.imdb.com/chart/top
But i want to know if there is a standard according to #Hawkes answer or there is no standard at all.
No standard at all; just local spelling conventions. Which is, to some degree, part of the point of REST: the server can use whatever spellings for URI make sense, and the client just "follows its nose" based on its understanding of the processing rules for the media type and the data provided by the server.
Related
I'm designing a REST API where, amongst others, there are two objects.
Journey
Report
For each Journey there are many Reports enroute, and each Report has exactly one associated Journey.
A user might create a Journey using the API as follows...
POST /journey/
Then retrieve the details...
GET /journey/1226/
The first question is, if a user wanted to post an Report to their Journey, which is the 'correct' URL structure that the API should impose? This seems intuitive to me...
POST /journey/1226/report/
...or is this the case...
POST /report/
...whereby in the latter, the Journey ID is passed in the request body somewhere?
The second question is, how might one go about implementing the first case in a tool such as the Django REST framework?
Thanks!
The URL/URI structure is almost completely irrelevant. It is nice to be able to read it, or easily change or even guess it, but that is it. There is no "requirement" official or unwritten how they should look like.
The point is however, that you supply the URIs to your clients in your responses. Each GET will get you a representation that contains links to the next "states" that your client can reach. This means the server has full control over URI structure, the client usually has to only know the "start" or "homepage" URI, and that's it.
Here is an article which discusses this question, has some good points: http://www.ben-morris.com/hackable-uris-may-look-nice-but-they-dont-have-much-to-do-with-rest-and-hateoas/
Pass for the second question :) I didn't use that particular framework.
Im currently working on a more or less RESTful webservice, a type of content api for my companys articles. We currently have a resource for getting all the content of a specific article
http://api.com/content/articles/{id}
will return a full set of article data of the given article id.
Currently we control alot of the article's business logic becasue we only serve a native-app from the webservice. This means we convert tags, links, images and so on in the body text of the article, into a protocol the native-app can understand. Same with alot of different attributes and data on the article, we will transform and modify its original (web) state into a state that the native-app will understand.
fx. img tags will be converted from a normal <img src="http://source.com"/> into a <img src="inline-image//{imageId}"/> tag, samt goes for anchor tags etc.
Now i have to implement a resource that can return the articles data in a new representation
I'm puzzled over how best to do this.
I could just implement a completely new resource, on a different url like: content/articles/web/{id} and move the old one to content/article/app/{id}
I could also specify in my documentation of the resource, that a client should always specify a specific request header maybe the Accept header for the webservice to determine which representation of the article to return.
I could also just use the original url, and use a url parameter like .../{id}/?version=app or .../{id}/?version=web
What would you guys reckon would be the best option? My personal preference lean towards option 1, simply because i think its easier to understand for clients of the webservice.
Regards, Martin.
EDIT:
I have chosen to go with option 1. Thanks for helping out and giving pros and cons. :)
I would choose #1. If you need to preserve the existing URLS you could add a new one content/articles/{id}/native or content/native-articles/{id}/. Both are REST enough.
Working with paths make content more easily cacheable than both header or param options. Using Content-Type overcomplicates the service especially when both are returning JSON.
Use the HTTP concept of Content Negotiation. Use the Accept header with vendor types.
Get the articles in the native representation:
GET /api.com/content/articles/1234
Accept: application/vnd.com.exmaple.article.native+json
Get the articles in the original representation:
GET /api.com/content/articles/1234
Accept: application/vnd.com.exmaple.article.orig+json
Option 1 and Option 3
Both are perfectly good solutions. I like the way Option 1 looks better, but that is just aesthetics. It doesn't really matter. If you choose one of these options, you should have requests to the old URL redirect to the new location using a 301.
Option 2
This could work as well, but only if the two responses have a different Content-Type. From the description, I couldn't really tell if this was the case. I would not define a custom Content-Type in this case just so you could use Content Negotiation. If the media type is not different, I would not use this option.
Perhaps option 2 - with the header being a Content-Type?
That seems to be the way resources are served in differing formats; e.g. XML, JSON, some custom format
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
Hi all,
I'm new to REST and Web API. I'm a bit confused on how to design URIs for my resources.
Given that I have a domain with the following resources: Blogs, Posts and Users.
Blog (1) ------ (0..*) Post (0..*) ------ (1) User
A blog can have many posts and each post is associated with one blog. An user can have many posts and each post is associated with one user.
For Blog and User resources the URIs would be like the following:
GET /blogs - get list of all blogs
GET /blogs/{id} - get blog by id
POST /blogs - create new blog
PUT /blogs/{id} - update blog
DELETE /blogs/{id} - delete blog
GET /users- get list of all users
GET /users/{id} - get user by id
POST /users - create new user
PUT /users/{id} - update user
DELETE /users/{id} - delete user
But what about Posts resource? How to handle associations? I'm thinking of the following alternatives - which ones are correct and why?
-- Get all posts by blog
1. GET /blogs/{id}/posts
or
2. GET /posts?blogid={id}
-- Create new post in a blog
3. POST /blogs/{id}/posts
or
4. POST /posts (here I would then in the payload send the IDs of the resources this post is associated with. BlogId and UserId)
-- Get all posts by blog and by user
5. GET /blogs/{id}/posts?userid={id}
or
6. GET /posts?blogid={id}&userid={id}
If anyone could point me in the right direction here, I'd be grateful.
Since a post is always associated with a blog and a user ID, I would choose options 1, 3 and 5:
GET /blogs/{id}/posts
POST /blogs/{id}/posts
GET /blogs/{id}/posts?userid={id}
The first question you should ask yourself is how important it is to you that your API is truly RESTful? It's actually a lot more fiddly than it seems to achieve this.
Is your API going to be consumed only by your own software\organisation?
Will your API be accompanied by documentation?
If the answer to 1 or 2 above is true, then the value of being truly RESTful is questionable... it's all or nothing with REST so either you go the whole hog or you don't worry.
For an API to be a true REST API, it must be discoverable from a single entry point (see here: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven). Each call should return information on other related calls that can be made on that resource.. usually via links of some kind, this is one possible structure:
{
"Id" : 1,
"Identifier" : "123's First Blog",
"links" : [
{
"rel": "http://myapi/res/posts",
"href": "http://myapi/blog/1/posts"
},
{
"rel": "http://myapi/res/users",
"href": "http://myapi/user/123"
}
]
}
The rel is a link to a summary\definition of the resource, and the href should point to the api itself.
Anyways, the point of all this is that if you do want to be truly RESTful, then let the links between resources and uris dictate the design. Think about how you would discover the particulars for each call from a single starting point, and the structure should reveal itself much like software design through TDD.
If you don't need to be RESTful, then things become much simpler. Just design your API in the most natural way for you, your architecture, and your developers. If you document things properly, then this will lead to a much more efficient API and one that is quicker to develop against.
Mario's answer to this question is sound, and I would also favour those options over the others. I just thought you should know the whole story that accompanies such a desicion.
If this doesn't make sense or you would like more information then post a comment and I'll try to help :)
I'm doing research into a web API for my company, and it's starting to look like we might implement a RESTful one. I've read a couple of books about this now (O'Reilly's "RESTful web services" seeming the most useful) and have come up with the following set of URIs and operations for an object that can be commented on, tagged, and rated.
It doesn't really matter what the object is, as this scenario applies to many things on the net, but for the sake of argument lets say it's a movie.
Some of these seem to fit quite naturally, but others seem a bit forced (rating and tagging particularly) so does anybody have any suggestions about how these could be improved? I'll list them with the URI and then the supported verbs, and what I propose they would do.
/movies
GET = List movies
/movies/5
GET = Get movie 5
/movies/5/comments
GET = List comments on movie 5
POST = Create a new comment on movie 5
/movies/5/comments/8
GET = Get comment 8 on movie 5
POST = Reply to comment 8 on movie 5
PUT = Update comment 8 on movie 5
/movies/5/comments/8/flag
GET = Check whether the movies is flagged as inappropriate (404 if not)
PUT = Flag movie as inappropriate
/movies/5/rating
GET = Get the rating of the movie
POST = Add the user rating of the movie to the overall rating
Edit: My intention is that the movie object would contain its rating as a property, so I wouldn't really expect the GET method to be used here. The URI really exists so that the rating can be an individual resource that can be updated using the POST verb. I'm not sure if this is the best way of doing it, but I can't think of a better one
/movies/5/tags/tagname
GET = Check whether the movies is tagged with tagname (404 if not; but if it is tagged with the tag name should it return the actual tag resource by redirecting to something like /tags/tagname?)
PUT = Add tag tagname to the movie, creating the tag resource /tags/tagname if required
DELETE = Remove tag tagname from the movie, deleting the tag resource tags/tagname if nothing is tagged with it after this removal
Note that these wouldn't be the entire URIs, for example the URI to list the movies would support filtering, paging and sorting. For this I was planning on something like:
/movies/action;90s/rating,desc/20-40
Where:
action;90s is a semi-colon delimited set of filter criteria
rating,desc is the sort order and direction
20-40 is the range of item indices to get
Any comments about this API scheme too?
Edit #1
This post is getting quite long now! After reading some of the answers and comments, this is the changes from above I'm planning on making:
Tags will be handled as a group rather than individually, so they will be at:
/movies/5/tags
GET = List tags
POST = Union of specified tags and existing tags
PUT = Replace any current tags with specified tags
DELETE = Delete all tags
I'm still really not sure how to handle flagging a comment though. One option is that instead of POSTing to a comment replying to it, a comment object will include its parent so it can be POSTed to the general URI, i.e.
/movie/5/comment
POST = Create a new comment (which may be a reply to a comment)
I could then use the POST to a comment to flag it. But this still doesn't feel quite right.
/movie/5/comment/8
POST = Flag comment
Most of what you have looks good. There were just a couple of strange things I saw. When I put my URLs together, I try to follow these four principles.
Peel the onion
If you make the R in REST really be a resource then the resource URL should be able to be peeled back and still be meaningful. If it doesn't make sense you should rethink how to organize the resource. So in the case below, each makes sense. I am either looking at a specific item, or a collection of items.
/movies/horror/10/
/movies/horror/
/movies/
The following seems funny to me because flag isn't a resource, it's a property of the movie.
/movies/5/comments/8/flag -> Funny
/movies/5/comments/8/ -> Gives me all properties of comment including flag
Define the View
The last peice of the URL describes how to show the resource. The URL /movies/horror/ tells me I will have a collection of movies refined by horror. But there might be different ways I want to display that collection.
/movies/horror/simple
/movies/horror/expanded
The simple view might just be the title and an image. The expanded view would give a lot more information like description, synopsis, and ratings.
Helpers
After the resource has been limited and the proper view figured out, query string parameters are used to help the UI with the little stuff. The most common query string parameters I use are
p => Page
n => number of items to display
sortby => field to sort by
asc => sort ascending
So I could end up with a URL like
/movies/horror/default?p=12&n=50&sortby=name
This will give me the list of movies limited to horror movies with the default view; starting on page 12 with 50 movies per page where the movies are sorted by name.
Actions
The last thing needed are your action on the resource. The action are either collection based or item based.
/movies/horror/
GET -> Get resources as a list
POST -> Create, Update
/movies/horror/10/
GET -> Get resource as item
POST -> Update
I hope this helps.
I disagree with the edit. Queries should be defined by querystrings as per Martijn Laarman's post. i.e.:
/movies?genre=action&timeframe=90s&lbound=20&ubound=40&order=desc
Well, the way I see it some of the information you return now as objects could simply be added to the metadata of its parent object.
For instance, rating could be part of the response of /movies/5
<movie>
<title>..</title>
..
<rating url="movies/ratings/4">4</rating>
<tags>
<tag url="movies/tags/creative">creative</tag>
...
Removing a tag simply means posting the above response without that tag.
Also queries should go in URL variables, I believe:
/movies/?startsWith=Forrest%20G&orderBy=DateAdded
Based on my understanding of ROA (I'm only on chapter five of RESTful Web Services) it looks good to me.
This is an awesome initial draft for a spec of a REST API. The next step would to specify expected return codes (like you did with "404 No Tag Available"), acceptable Content-Types, and available content-types (e.g., HTML, JSON). Doing that should expose any additional chinks you'll need to hammer out.
#Nelson LaQuet:
Using the HTTP methods as they are actually defined gives you the safety of knowing that executing a GET on anything on a web site or service won't eat your data or otherwise mangle it. As an example (pointed out in RESTful Web Services) Google's Web Accelerator expects this behaviour -- as stated in the FAQ -- and presumably other services do too.
Also it gets you idempotency for free. That is doing a GET, DELETE, HEAD or PUT on a resource more than once is the same as doing it only once. Thus if your request fails then all you have to do is run it again.
This is not REST.
A REST API must not define fixed resource names or hierarchies (an obvious coupling of client and server). Servers must have the freedom to control their own namespace. Instead, allow servers to instruct clients on how to construct appropriate URIs, such as is done in HTML forms and URI templates, by defining those instructions within media types and link relations. [Failure here implies that clients are assuming a resource structure due to out-of band information, such as a domain-specific standard, which is the data-oriented equivalent to RPC's functional coupling].
http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven