In your humble opinion: what would be a best practice aproach to map REST URLs to services/files within one's architecture (let's assume MVC pattern here)?
In addition to Darrel's answer:
Make use of the hierarchical nature of HTTP URIs; think of every path segment as drilling down into the overall space of managed items (e.g. orders, customers). If at some point you need to 'index' into a collection along multiple dimensions (e.g. query) then use query string parameters:
/service/products/cars/japanese-cars/toyota/corola/&priceMin=2000&priceMax=5000
Note that (as darrel said) the structure should be opaque to the client. That means that the client needs to discover the parameters at run time (that is what forms or URI templates are for). Of course client and server need shared knowledge about the meaning of e.g. priceMin. That knowledge should be in some design time specification, for example the specification of a link relation. Maybe look at http://www.opensearch.org for detailed use case.
Also interesting is the host part of the URIs. If you might at some stage need to move parts of your services to another machine, design your URIs so that the relevant information is in the domain part. Then you can use simple DNS to route requests to different machines.
HTH,
Jan
The best way to map URLs to resources is dependent on what web framework you use to provide the REST service. Pick whatever url structure is easiest to manage with the tools you have.
The url structure should be completely opaque to the clients of your service so they should not care what they look like.
The most important thing in my opinion is that when you are looking at an URL it should be relatively easy to guess which controller on the server is going to respond to that URL. That will make development and debugging much easier.
Related
Suppose I have two models, Order and Customer. I've implemented an API that lets you filter on both:
/orders?status=fulfilled
/customers?city=Atlanta
But what if I want to search for orders in a fulfilled status, whose associated customer also lives in Atlanta? Is it RESTful to do something like /orders?status=fulfilled&customer.city=Atlanta? Or is there a canonical format for doing this sort of thing?
Is it RESTful to do something like /orders?status=fulfilled&customer.city=Atlanta?
Yes.
is there a canonical format for doing this sort of thing?
No.
You will normally want to choose a resource identifier that is compatible with a standardized URI Template because that lets you leverage pre-existing libraries.
But there are a lot of different ways you can expand variables into a template.
A query part composed of application/x-www-form-urlencoded key value pairs is a common choice; it gives you compatibility with HTML forms "for free". But if you aren't expecting clients to interact with your API via web pages, maybe that's not too important.
URI spellings are a lot like spellings of variable names; the machines don't care. You, therefore, have extra degrees of freedom that you can use to make life easier for some people: your clients looking at identifiers in their browsing history, your operations people looking in logs, your technical writers trying to document the API....
You'll probably want to choose something that is convenient for yourself -- so make sure that your design fits well with your routing framework.
Choosing identifier spellings that direct these requests to the same controllers that you are already using vs. a new controller -- that's entirely up to you. Part of the point of the API is that the implementation details are hidden from the client and can be changed without breaking the interface.
I created a few Rest apis right now and I always preferred a solution, where I created an endpoint for each resource.
For example:
GET .../employees/{id}/account
GET .../supervisors/{id}/account
and the same with the other http methods like put, post and delete. This blows up my api pretty much. My rest apis in general preferred redundancy to reduce complexity but in this cases it always feels a bit cumbersome. So I create another approach where I work with inheritance to keep the "dry" principle.
In this case there is a base class User and via inheritance my employee and supervisor model extends from it. Now I only need one endpoint like
GET .../accounts/{id}
and the server decides which object is returned. Also while this thins out my api, it increases complexity and in my api documentation ( where I use spring rest docs ) I have to document two different Objects for the same endpoint.
Now I am not sure about what is the right way to do it ( or at least the better way ). When I think about Rest, I think in resources. So my employees are a seperate resource as well as my supervisors.
Because I always followed this approach, I tink I might be mentally run in it and maybe lost the objectivity.
It would be great if you can give my any objective advice on how this should be handled.
I built an online service that deals with this too. It's called Wirespec:
https://wirespec.dev
The backend automatically creates the url for users and their endpoints dynamically with very little code. The code for handling the frontend is written in Kotlin while the backend for generating APIs for users is written in Node.js. In both cases, the amount of code is very negligible and self-maintaining, meaning that if the user changes the name of their API, the endpoint automatically updates with the name. Here are some examples:
API: https://wirespec.dev/Wirespec/projects/apis/Stackoverflow/apis/getUserDetails
Endpoint: https://api.wirespec.dev/wirespec/stackoverflow/getuserdetails?id=100
So to answer your question, it really doesn't matter where you place the username in the url.
Try signing in to Wirespec with your Github account and you'll see where your Github username appears in the url.
There is, unfortunately, no wright or wrong answer to this one and it soley depends on how you want to design things.
With that being said, you need to distinguish between client and server. A client shouldn't know the nifty details of your API. It is just an arbitrary consumer of your API that is fed all the information it needs in order to make informed choices. I.e. if you want the client to send some data to the server that follows a certain structure, the best advice is to use from-like representations, such as HAL forms, Ion or even HTML. Forms not only teach a client about the respective properties a resource supports but also about the HTTP operation to use, the target URI to send the request to as well as the representation format to send the data in, which in case of HTML is application/x-www-form-urlencoded most of the time.
In regards to receiving data from the server, a client shouldn't attempt to extract knowledge from URIs directly, as they may change over time and thus break clients that rely on such a methodology, but rely on link relation names. Per URI there might be multiple link relation names attached to that URI. A client not knowing the meaning of one should simply ignore it. Here, either one of the standardized link relation names should be used or an extension mechanism as defined by Web linking. While an arbitrary client might not make sense from this "arbitrary string" out of the box, the link relation name may be considered the predicate in a tripple often used in ontologies where the link relation name "connects" the current resource with the one the link relation was annotated for. For a set of URIs and link relation names you might therefore "learn" a semantic graph over all the resources and how they are connected to each other. I.e. you might annotate an URI pointing to a form resource with prefetch to hint a client that it may load the content of the referenced URI if it is IDLE as the likelihood is high that the client will be interested to load that resource next anyway. The same URI might also be annotated with edit-form to hint a client that the resource will provide an edit form to send some data to the server. It might also contain a Web linking extension such as https://acme.org/ref/orderForm that allows clients, that support such a custom extension, to react to such a resource accordingly.
In your accounts example, it is totally fine to return different data for different resources of the same URI-path. I.e. resource A pointing to an employee account might only contain properties name, age, position, salery while resource B pointing to a supervisor could also contain a list of subordinates or the like. To a generic HTTP client these are two totally different resources even though they used a URI structure like /accounts/{id}. Resources in a REST architecture are untyped, meaning they don't have a type ouf of the box per se. Think of some arbitrary Web page you access through your browser. Your browser is not aware of whether the Web page it renders contains details about a specific car or about the most recent local news. HTML is designed to express a multitude of different data in the same way. Different media types though may provide more concrete hints about the data exchanged. I.e. text/vcard, applciation/vcard+xml or application/vcard+json all may respresent data describing an entity (i.e. human person, jusistic entity, animal, ...) while application/mathml+xml might be used to express certain mathematical formulas and so on. The more general a media type is, the more wiedspread usage it may find. With more narrow media types however you can provide more specific support. With content type negotiation you also have a tool at your hand where a client can express its capabilities to servers and if the server/API is smart enough it can respond with a representation the client is able to handle.
This in essence is all what REST is and if followed correctly allow the decoupling of clients from specific servers. While this might sound confusing and burdensome to implement at first, these techniques are intended if you strive for a long-lasting environment that still is able to operate in decateds to come. Evolution is inherently integrated into this phiolosophy and supported by the decoupled design. If you don't need all of that, REST might not be the thing you want to do actually. Buf if you still want something like REST, you for sure should design the interactions between client and server as if you'd intereact with a typical Web server. After all, REST is just a generalization of the concepts used on the Web quite successfully for the past two decades.
I'm building a RESTful wrapper around quite complex underlaying domain. I built a domain model using UML packages and classes and derived REST-resources from the meaningful classes.
When it came to the endpint-URL design, I decided to map the package/class structure directly to URLs in order to streamline the process and have a neat traceability between my logical model (domain) and physicall implementation (REST API).
Let's say I have a following domain extract:
Admin and Work are packages, while User, Permission and Task are classes (REST Resources).
I derived the following endpoint URLs from this domain:
mydomain/admin/user -> Users collection
mydomain/admin/user/id -> User instance with id
mydomain/admin/user/id/permissions -> All permissions of the User with id
mydomain/work/task, and so on...
A collegue of mine noticed that the URLs are not optimal, mainly because these "package" parts do not map to the concrete resources. For example "admin" is not a Resource and is part of the URL. As the domain structure grows, there will be even more these intermediary non-resource-segments in the URL and he finds it wrong.
I find it nice, as URL structure itself tells something about the resource and is backed up with a complete, well documented domain model.
Is this a violation of RESTful standard?
Is this a violation of RESTful standard?
No. REST has no opinon on how an URL should look. You could use an URL like
/foo/bar/baz?qux=12
without violating any REST principle. Such an URL has no meaning for a human reader but that doesn't matter.
It is not necessary that every parts of an URL like
/foo
/foo/bar
maps to a resource. In fact is is a common misconception that RESTful URLS must follow some pattern or build rule. That is not the case.
Of courese there are best practices commonly used. One such practice would be to have collection resources like
/mydomain/admin/user
and single resources like
/mydomain/admin/user/42
But, again, that is not required by REST.
The REST architecture doesn't dictate what your URL's should look like. So, from that perspective, you're not violating any rules.
Instead, an important aspect of REST is that one should be able to use hyperlinks in order to navigate from one URL to another (something we are all used to when browsing HTML websites, but is not as common in REST APIs). Using links, consumers of your web application (wether they are humans using a web browser, or other applications that are using your API) can discover the available URLs, and the actual structure of your URLs doesn't really matter. Your URLs can even change without breaking other applications, because they will simply follow the link to the new URL.
So from a REST perspective, you could use whatever URL structure you like. As long as you provide a fixed entry point that provides a link to your users collection, the actual URL could be anything.
However, it is obviously still helpful when URLs are easy to understand and somewhat predictable. For instance, right now you have collections with a singular URL (yourdomain/admin/user) and collections with a plural URL (yourdomain/admin/user/3/permissions), which isn't very consistent. I'd suggest using only plural names, so yourdomain/admin/user becomes yourdomain/admin/users.
As for your actual question, as I mentioned this doesn't matter from a REST perspective. More important is that the URL makes clear what it represents. Something I'd take into consideration is the amount of different endpoints you're gonna have. If you are building a small application, with a small amount of endpoints, I'd keep it simple. But if you are creating a very large application with a lot of domain models, prepending them with some kind of categories sounds like a good idea.
Conclusion
URLs in a REST API should be discoverable by hyperlinks, and therefore no hard rules exist. Just make sure your URLs make sense to anybody who has to dig into them.
Some tips for usefull URLs can be found in REST-ful URI design.
You aren't following the strict definition of being RESTful; but it's not due to your colleague's concerns.
Your main challenge is that your proposal has the endpoints baked in to the client applications. A client looking for a user goes straight to /mydomain/admin/user.
But if (and when) you re-locate that endpoint, say /mydomain/admin/department/user, your clients are now broken.
The solution:
REST defines that you have one (or very few) endpoints, termed "Cool URIs", which are fixed enough that they never change.
Instead of your client going to the endpoint of /mydomain/admin/user they will take this approach:
Retrieve a root object from /mydomain (the Cool URI). => "mydomain" service object.
"mydomain" object contains a URI which has the identifier of "admin". Follow that URI.
"admin" object contains a URI which has the identifier of "user". Follow that URI.
"user" object returned (more likely a list of users).
In this respect, there is no reliance upon the client application having to know the URI format; therefore when you change the endpoints, you just change the URIs that your service embeds in the returned REST objects.
This approach to REST, where each returned object contains the URI to the next, is part of the HATEOAS principle.
If you're worried about how a client will pull back a given ID number (e.g. user 42), then that's catered for too: you can implement something like OData. So again, the URI is provided by the parent object. Instead of the client using a pre-baked endpoint like this:
/mydomain/admin/users/42
...it instead does this:
/mydomain (Cool URI)
Follow the link for "admin".
Follow the link for "users", appending ?$filter=UserId eq 42
There are also some really good concepts around solving object versioning issues, which again are difficult if you take the approach of hard-coding the endpoints upfront.
If it's any consolation, I started off defining my REST architecture around fixed endpoints (as you are), and then discovered that using a true RESTful approach is actually simpler in the long run.
Best of luck!
I just began looking at REST and was wondering what the basic difference between the two representations was. The first one looks pretty nice to me and the second one has to pass some attribute values but the underlying logic seems to be boiling to almost the same thing (I could be mistaken though)
http://url/category/category_id/item_id
AND
http://url/category?category_id={12}&item_id={12334}
I think you are labouring under some fundamental misconceptions about what REST is about.
The URL used to access a resource really is a detail and actually should not matter to the client. URL's should really be "discovered" by clients anyway if they follow the HATEAOS principe that is one of the tenets of REST.
Essentially you are right though: either URL could represent the resource you are exposing in the end, but as I say, this really is a detail and it comes down to preference in many cases at what URL you expose something. The point of HATEOAS is to allow you to change the URL's that are used to access resources at-will without affecting clients that work against your existing services.
The following URL's might help you understand some of the properties that make services truly RESTful:
How to GET a cup of coffee
Describing RESTful Applications
[disclaimer: just because HATEAOS is a principle of REST does not make it easy to do. You will find most of the services on the web do not follow this principle strictly at all, as evidenced by their documentation which is full of URL templates; not the way services should be documented in the ideal world. I'm struggling myself to find good examples of truly RESTful services and clients...]
It should be possible for agents to reason about the resource structure:
based on the URL, and
based on links returned by requests for resources.
The problem with the second representation is that it can be considered as a set unordered keys and values, with no real structure/heirarchy.
If you click the button from your tag restful-url you get a good link from this site explaining the difference between those two styles:
How to obtain REST resource with different finder "methods"?
What is the benefit of referencing resources using globally-unique URIs (as REST does) versus using a proprietary id format?
For example:
http://host.com/student/5
http://host.com/student?id=5
In the first approach the entire URL is the ID. In the second approach only the 5 is the ID. What is the practical benefit of the first approach over the second?
Why does REST (seem to) go out of its way to advocate the first approach?
-- EDIT:
My question was confusing because it really asked two separate questions:
What is the benefit of addressibility?
What is the difference between the two URI forms seen above.
I've answered both questions below using my own post.
The main thing when i see uri's like that is a normal user would be able to remember that uri.
Us geeks are fine with question marks and get variables, but if someone remembers http://www.host.com/users/john instead of http://www.host.com/?view=users&name=john, then that is a huge benefit.
I will answer my own question:
1) Why are URIs important?
I'll quote from RESTful Web Services by Leonard Richardson and Sam Ruby (ISBN: 978-0-596-52926-0):
Consider a real URI that names a resource in the genre “directory of resources about
jellyfish”: http://www.google.com/search?q=jellyfish. That jellyfish search is just as
much a real URI as http://www.google.com. If HTTP wasn’t addressable, or if the Google
search engine wasn’t an addressable web application, I wouldn’t be able to publish that
URI in a book. I’d have to tell you: “Open a web connection to google.com, type ‘jellyfish’
in the search box, and click the ‘Google Search’ button.
This isn’t an academic worry. Until the mid-1990s, when ftp:// URIs
became popular for describing files on FTP sites, people had to write
things like: “Start an anonymous FTP session on ftp.example.com. Then
change to directory pub/files/ and download file file.txt.” URIs made
FTP as addressable as HTTP. Now people just write: “Download ftp://
ftp.example.com/pub/files/file.txt.” The steps are the same, but now they
can be carried out by machine.
[...]
Addressability is one of the best things about web applications. It makes it easy for
clients to use web sites in ways the original designers never imagined.
2) What is the benefit of addressibility?
It is far easier to follow server-provided URIs than construct them yourself. This is especially true as resource relationships become too complex to be expressed in simple rules. It's easier to code the logic once in the server than re-implement it in numerous clients.
The relationship between resources may change even though the individual resource URIs remain unchanged. For example, if Google Maps were to change the scale of their map tiles, clients that calculate relative tile positions would break.
3) What is the benefit of URIs over custom IDs?
Custom IDs identify a resource uniquely. URIs go a step further by telling you where to find it. This simplifies the client logic.
Search engine optimization mostly.
It also makes them easier to remember, and cleaner, more professional looking in my opinion.
The first is more aesthetically pleasing.
Technically there is no difference, but use the former when you can.
As Ólafur mentioned, The clarity of the former url is one benefit.
Another is implementation flexibility.
Let's say that student 5 changes infrequently. If you use the REST-style url you have the option of serving a static file instead of running code. In Rails it is common that the first request to students/5 would create a cached html file under your web root. That file is used to serve subsequent requests w/o touching the backend. Naturally, there's nothing rails specific about that approach.
The later url wouldn't allow for this. You can't have url variables (?, =) in the names of static pages.
Both URIs are valid from a REST perspective, however just realize that web caches treat the querystring parameters very differently.
If you want to use caching to your advantage then I suggest that you do not use a query string parameter to identify your resource.
I think it comes down to how closely you want to adhere to the principles of feng shui.