So I have a dilema here. Trying to build out a RESTful API. Which means I'd like to have resources defined and also require that consumers reference those resources by id.
For example, the typical {resourceName}/{id}?{querystring}
But the way of course a web UI works, for a ecommerce site is that naturally you have SEO-friendly urls.
So there is a mismatch in terms of application specific URLs where we have application context based urls, context here being an ecommerce site using SEO-friendly URLs. They wouldn't have stuff like /id in it 100% of the time. And actually our site doesn't have any ids whatsoever in the web UI's urls.
So when users go from page to page, we might have urls like www.ourdomain.com/cars/local/usa/ca/sunnyvale-cars. And sometimes we're talking about stripping the '-' or other characters out of the more seo friendly urls, after the UI devs send a request to lets say like above a state resource. I'd strip the city name out of 'sunnyvale-cars' if lets say I wanted info on that city so the UI team might send me '/cities?name=sunnyvale-cars' where our API would need to strip out the city name in order to do the query in the backend which to me just doesn't sound like something our API should be doing. It's also coupling our REST API to the web and web conventions...our REST API should be ignorant of any type of delivery mechanism so that our API can be reused for other apps or other APIs in our Business domain.
There might be times where the UI Engineering team, in fact a lot of times they'll only have URLs like this. There is no user action or lets say dropdown list where they can just grab an id. So they can't always request stuff for the next page by sending me a RESTful URI request every time as they may not have ids all the time. In other words, sometimes they'll have to instead request stuff like this: /states?name="ca" to get something related to that state just as a hypothetical example.
So how in the world do you even build a REST API if your UI team is telling you they won't have ids for everything?
From a REST purist's point of view no URI is inherently more RESTful than another as long as both use identify the resources. At least, I could not find anything about that in the original thesis.
However, if you find some structure fitting the purposes of your API better, you can create a second endpoint exclusively for the needs of your UI team. That endpoint would serve as a proxy and simply map the SEO-friendly structure to your API in possibly generic way.
Or, applications from the outside are just expected to do the rewriting or any app specific mapping-to-REST API "stuff" since it's really app specific in what that mapping looks like anyway, thus keeping the API ignorant of application specific details, domain logic, or even web conventions which the API should not care about or even know about.
Related
When using routing in a SPA web app (angular, react, etc), the user doesn't have to start at the entry point of the application. They can use a URL in the browser to drill down into any part of the application.
When implementing HATEOAS in a RESTful backend API, we assume that the front-end only knows the URL to the entry point of the API, and then the API provides links to other parts of the application from there.
So this begs the question, if a user enters a URL in the browser that loads a specific part of the SPA (not the entry point), how does the SPA get the appropriate API link needed for just that part of the SPA?
Does the SPA just make a bunch of API calls all at once, starting at the entry point of the API and following links until it gets the link it needs for the state it needs to load? And what happens when the API does not include the link needed because it's not a valid link based on the current state of the application?
HATEOAS doesn't seem to be very compatible with a modern SPA where you can load the application at very specific sections/states.
This has been asked on SO before, but I'm having trouble finding these past questions and answers. I've answered at least two, but I'll summarize how this usually gets answered.
Camp 1: Don't do SPA's, it doesn't make sense. Your HATEOAS service should serve the entire state in a way that the client can interpret and SPA's are basically a hack.
Camp 2 (the camp I'm in): You'll need some way to map SPA links to links on your backend.
You're kind of describing this by talking about 'all the steps needed' to get to the right resource, but if your goal it ultimately map this to an API uri, why not embed just that
https://spa.example/http://api.example/some/resource
Having bookmarkable urls that contain the full path to your backend, means you don't need to jump through complex hoops, and your SPA is a true client for the API you are building.
Another nice benefit is that you can also easily point your client to multiple live/dev environments.
Lastly, you could allow for relative urls and automatically resolve them to the API url, shortening:
https://spa.example/http://api.example/some/resource
to
https://spa.example/some/resource
I'm trying to figure out best or common practices for API design.
My concern is basically this:
PUT /users/:id
In my view this endpoint could by used for a wide array of functions.
I would use it to change the user name or profile, but what about ex, resetting a password?
From a "model" point of view, that could be flag, a property of the user, so it would "work" to send a modification.
But I would expect more something like
POST /users/:id/reset_password
But that means that almost for each modification I could create a different endpoint according to the meaning of the modification, i.e
POST /users/:id/enable
POST /users/:id/birthday
...
or even
GET /user/:id/birthday
compared to simply
GET /users/:id
So basically I don't understand when to stop using a single POST/GET and creating instead different endpoints.
It looks to me as a simple matter of choice, I just want to know if there is some standard way of doing this or some guideline. After reading and looking at example I'm still not really sure.
Disclaimer: In a lot of cases, people ask about REST when what they really want is an HTTP compliant RPC design with pretty URLs. In what follows, I'm answering about REST.
In my view this endpoint could by used for a wide array of functions. I would use it to change the user name or profile, but what about ex, resetting a password?
Sure, why not?
I don't understand when to stop using a single POST/GET and creating instead different endpoints.
A really good starting point is Jim Webber's talk Domain Driven Design for RESTful systems.
First key idea - your resources are not your domain model entities. Your REST API is really a facade in front of your domain model, which supports the illusion that you are just a website.
So your resources are analogous to documents that represent information. The URI identifies the document.
Second key idea - that URI is used by clients to cache representations of the resource, so that we don't need to send requests back to the server all the time. Instead, we have built into HTTP a bunch of standard ways for communicating caching meta data from the server to the client.
Critical to that is the rule for cache invalidation: a successful unsafe request invalidates previously cached representations of the same resource (ie, the same URI).
So the general rule is, if the client is going to do something that will modify a resource they have already cached, then we want the modification request to go to that same URI.
Your REST API is a facade to make your domain model look like a web site. So if we think about how we might build a web site to do the same thing, it can give us insights to how we arrange our resources.
So to borrow your example, we might have a web page representation of the user. If we were going to allow the client to modify that page, then we might think through a bunch of use cases (enable, change birthday, change name, reset password). For each of these supported cases, we would have a link to a task-specific form. Each of those forms would have fields allowing the client to describe the change, and a url in the form action to decide where the form gets submitted.
Since what the client is trying to achieve is to modify the profile page itself, we would have each of those forms submit back to the profile page URI, so that the client would know to invalidate the previously cached representations if the request were successful.
So your resource identifiers might look like:
/users/:id
/users/:id/forms/enable
/users/:id/forms/changeName
/users/:id/forms/changeBirthday
/users/:id/forms/resetPassword
Where each of the forms submits its information to /users/:id.
That does mean, in your implementation, you are probably going to end up with a lot of different requests routed to the same handler, and so you may need to disambiguate them there.
Background:
I have a single page application that pulls data from a REST API. The API is designed such that the only URL necessary is the API root, ie https://example.com/api which provides URLs for other resources so that the client doesn't need to have any knowledge of how they are constructed.
API Design
The API has three main classes of data:
Module: Top level container
Category: A sub-container in a specific module
Resource: An item in a category
SPA Design
The app consuming the API has views for listing modules, viewing a particular module's details, and viewing a particular resource. The way the app works is it keeps all loaded data in a store. This store is persistent until the page is closed/refreshed.
The Problem:
My question is, if the user has navigated to a resource's detail view (example.com/resources/1/) and then they refresh the page, how do I load that particular resource without knowing its URL for the API?
Potential Solutions:
Hardcode URLs
Hardcoding the URLs would be fairly straightforward since I control both the API and the client, but I would really prefer to stick to a self describing API where the client doesn't need to know about the URLs.
Recursive Fetch
I could fetch the data recursively. For example, if the user requests a Resource with a particular ID, I could perform the following steps.
Fetch all the modules.
For each module, fetch its categories
Find the category that contains the requested resource and fetch the requested resource's details.
My concern with this is that I would be making a lot of unnecessary requests. If we have 100 modules but the user is only ever going to view 1 of them, we still make 100 requests to get the categories in each module.
Descriptive URLs
If I nested URLs like example.com/modules/123/categories/456/resources/789/, then I could do 3 simple lookups since I could avoid searching through the received data. The issue with this approach is that the URLs quickly become unwieldy, especially if I also wanted to include a slug for each resource. However, since this approach allows me to avoid hardcoding URLs and avoid making unnecessary network requests, it is currently my preferred option.
Notes:
I control both the client application and the API, so I can make changes in either place.
I am open to redesigning the API if necessary
Any ideas for how to address this issue would by greatly appreciated.
Expanding on my comment in an answer.
I think this is a very common problem and one I've struggled with myself. I don't think Nicholas Shanks's answer truly solves this.
This section in particular I take some issues with:
The user reloading example.com/resources/1/ is simply re-affirming the current application state, and the client does not need to do any API traversal to get back here.
Your client application should know the current URL, but that URL is saved on the client machine (in RAM, or disk cache, or a history file, etc.)
The implication I take from this, is that urls on your application are only valid for the life-time of the history file or disk cache, and cannot be shared with other users.
If that is good enough for your use-case, then this is probably the simplest, but I feel that there's a lot of cases where this is not true. The most obvious one indeed being the ability to share urls from the frontend-application.
To solve this, I would sum the issue up as:
You need to be able to statelessly map a url from a frontend to an API
The simplest, but incorrect way might simply be to map a API url such as:
http://api.example.org/resources/1
Directly to url such as:
http://frontend.example.org/resources/1
The issue I have with this, is that there's an implication that /resource/1 is taken from the frontend url and just added on to the api url. This is not something we're supposed to do, because it means we can't really evolve this api. If the server decides to link to a different server for example, the urls break.
Another option is that you generate uris such as:
http://frontend.example.org/http://api.example.org/resources/1
http://frontend.example.org/?uri=http://api.example.org/resources/1
I personally don't think this is too crazy. It does mean that the frontend needs to be able to load that uri and figure out what 'view' to load for the backend uri.
A third possibility is that you add another api that can:
Generate short strings that the frontend can use as unique ids (http://frontend.example.org/[short-string])
This api would return some document to the frontend that informs what view to load and what the (last known) API uri was.
None of these ideas sound super great to me. I want a better solution to this problem, but these are things I came up with as I was contemplating this.
Super curious if there's better ideas out there!
The current URL that the user is viewing, and the steps it took to get to the current place, are both application state (in the HATEOAS sense).
The user reloading example.com/resources/1/ is simply re-affirming the current application state, and the client does not need to do any API traversal to get back here.
Your client application should know the current URL, but that URL is saved on the client machine (in RAM, or disk cache, or a history file, etc.)
The starting point of the API is (well, can be) compiled-in to your client. Commpiled-in URLs are what couple the client to the server, not URLs that the user has visited during use of the client, including the current URL.
Your question, "For example, if the user requests a Resource with a particular ID", indicates that you have not grasped the decoupling that HATEOAS provides.
The user NEVER asks for a resource with such-and-such an ID. The user can click a link to get a query form, and then the server provides a form that generates requests to /collection/{id}. (In HTML, this is only possible for query strings, not path components, but other hypermedia formats don't have this limitation).
When the user submits the form with the ID number in the field, the client can build the request URL from the data supplied by the server+user.
I'm building an API for collecting events from an ecommerce site. The data flow, besides authentication and HTTP response codes, will be entirely from client to server.
Does it make sense to design such an API in a RESTful way?
For example, I'm not sure if I get much from URL endpoints representing resources. For instance, when a user on the ecommerce site goes to a new page, I'd like the API to be notified, and sent all the user data that has changed. RESTfully, I'd have to do it at an endpoint like /pageloads, /webpages or maybe /users since I'm interested not only in the page data but the user's too. Not quite RESTfully, the following seems more natural: /pageloadEvents along with other events represented like this. I'm saying "not quite RESTfully" because such endpoints don't seem to represent real resources, such as the web pages, users, etc, underneath.
Additionally, because of the communication going only from client to server, I won't have any need for the REST verb GET. In other words, the server is just a listener here. Perhaps this one sided communication is REST-wise OK, but looking around, I get a sense that that's a bit unusual.
Many thanks!
I'm developing a project to be used by both a smartphone app and a single page app website. I'm using Backbone.js for my data binding.
I've got a bit of an architectural question: How do I make my API restful, yet enrich the data coming back in my models.
An example:
I would like to change the roles of a user in a group.
In the restful case, I'd load a collection of the roles for a particular user in the group. I'd check and uncheck the roles I'd like to apply to the user in the context of that group, then save. I'm therefore doing a GET for the array of roles and a PUT to save the altered list. The issue I am facing is that I need to enrich my model with more meta data such as the Group's name, the User's name etc so the user has some context when editing the data.
I can quite easily do this but then I'm not really restful anymore with my model.
Does anyone have any resources they can point me to that can help me to architect my solution to achieve the best of both RESTfulness and usability using Backbone.js?
Backbone model does not make your application more or less restful.
For the most part, rest is about the interactions between the HTTP client and server.
Like in REST API URI Design Approach question, mostly the focus is on the URI design.
The more practical way of thinking or applying REST as the starting point (at least it works for me) is to think in the following ways:
1) Use only HTTP ‘GET/POST/PUT/DELETE’ as the way to model your domain ‘actions’ . Just like when you dealing with database, all your actions are mapped to CURD.
2) URI/URL is to identify resources only. Should never have any ‘actions’ in your URI.
3) The data exchanged should be in the body of the HTTP messages.
Just to simplify the discussions, not getting into how to model the data itself
Two great books on rest.
REST in Practice
Restful Web Services
You can create a Restful web service which can be consumed in both smartphone app and a single page app website.
Please have a look at
http://blogs.msdn.com/b/hongyes/archive/2012/08/30/single-page-application-with-backbone-js-and-asp-net-web-api.aspx
Here they are creating SPA with backbone.js and ASP.NET Web API ( to create Restful web service).
Other great resource can be found here:
http://www.asp.net/single-page-application/overview/templates/backbonejs-template
Thanks.