I am trying to figure out the best way to call REST actions that perform multiple actions and multiple database updates from a single call.
In my data model, I have Diners and LunchBoxes, and Foods. LunchBoxes are just many-to-many relationships between Diners and Foods, but with a count attribute that says how many of that type of food the given Diner has.
I want to set up a call that indicates that the Diner has eaten one of their Foods, which increases the health of the Diner accordingly. Certain foods are more nutritious than others, and consequently increase the Diner's health by different amounts. The actions that constitute this would be:
Reduce the count attribute on the Diner's LunchBox for the given food by the correct amount
Increase the Diner's health accordingly
So two tables need to be updated here: Diner and Lunchbox, both within a single transaction.
Trying to use nouns, the best I could come up with was:
POST /diner/frank/meal
Where the XML describing a meal would be something like
<meal>
<food>
<id>apple</id>
</food>
<count>2</count>
</meal>
However, this strikes me as pretty contrived. POSTing a meal in REST should create a Meal resource. In this case not only are we not creating a Meal resource, but we are updating two other resources: Diner and LunchBox.
I suppose one approach is to have the client handle this in two separate calls - one to update the Diner, and one to update the LunchBox. However, this seems wrong because we have multiple clients (HTML, Flash, etc.) that all need to perform this action. If we ever update the business logic in the future that is used to consume foods then we would need to make that change on many clients instead of on a single server.
How have others approached this admittedly pretty basic problem?
First off, the updating of the diner and the lunchbox should absolutely be done in one request. Don't fall into the trap of trying to do transactions over a REST api.
Before we get to your specific question, lets lay the groundwork for how the client could interact with your service leading up to your question.
The client should always start at the root service url.
GET /DiningService
Content-Type: application/vnd.sample.diningservice+xml
200 OK
<DiningService>
<Link rel="diners" href="./diners"/>
<Link rel="lunchboxes" href="./lunchboxes"/>
<Link rel="foods" href="./foods"/>
</DiningService>
I don't know the way your users will interact with the client software, but lets assume that we first need to identify who is going to do the eating. We can retreive a list of diners from looking in the response for a link with the rel="diners" and follow that link.
GET /DiningService/diners
Content-Type: application/vnd.sample.diners+xml
200 OK
<Diners>
<Diner Name="Frank">
<Link rel="lunchbox" href="./Frank/lunchbox"/>
</Diner>
<Diner Name="Bob">
<Link rel="lunchbox" href="./Bob/lunchbox"/>
</Diner>
</Diners>
What comes back is a list of diners. I have chosen to create custom media types for simplicity, but you may be better off using something like Atom feeds for these lists.
The client needs to identify Frank as the diner and so now we want to access his lunchbox. The rules of our custom media type say that the url to Frank's lunch box
can be found in a link element with a rel="lunchbox".
We get that URL from the response document and follow it.
GET /DiningService/Frank/lunchbox
Content-Type: application/vnd.sample.lunchbox+xml
200 OK
<Lunchbox>
<Link rel="diner" href="/DiningService/Frank"/>
<Food Name="CheeseSandwich" NutritionPoints="10">
<Link rel="eat" Method="POST" href="/DiningService/Frank?food=/DiningService/Food/CheeseSandwich"/>
</Food>
<Food Name="CucumberSandwich" NutritionPoints="15">
<Link rel="eat" Method="POST" href="/DiningService/Frank?food=/DiningService/Food/CucumberSandwich"/>
</Food>
</Lunchbox>
What we get back is another custom media type defining the contents of a lunchbox and links describing what we can do with that lunch box. Once the client chooses the food to eat, we can identify the URL to follow by looking for a link with rel="eat" and following that URL. In this case it is a post.
POST /DiningService/Frank?food=/DiningService/Food/CucumberSandwich
Content-Type: None
200 OK
I didn't think too hard about what the best way of structuring that url is because if I change my mind next week and make it
<Link rel="eat" Method="POST" href="/DiningService/Frank/Mouth?food=/DiningService/Food?id=759"/>
or even
<Link rel="eat" Method="POST" href="/DiningService/Food/CheeseSandwich?eatenBy=Frank"/>
it really does not matter to the client because it will continue to look for a link with rel="eat" and will follow the URL. You choose whatever URL structure works easiest for the web framework you have chosen. The URL structure belongs to the server and you should be able to change it whenever and have little or no impact on the client.
If you take this approach you can stop stressing over coming up with the perfect URL. This artificial notion of a "RESTful URL" has done more to prevent people from learning REST than SOAP ever did!
If you look at meal as an action on Diner, rather than an resource itself, this makes a bit more sense. However, I would be tempted to change the name to a verb, such as eat. When modelling a REST system, some of the decisions you make will be arbitrary. From a theoretical point of view, this action can be on both the Diner and the LunchBox. I tend to model according to how my app is used, so what fits with the UI and what is easier to explain to a third party in documentation etc.
There is nothing in the REST model that dictates the underlying structure or precludes you from handling quite complex transactions inside an action. In this case I would simply have an action that handles all of the logic using a transaction as necessary.
The action would operate on a diner, taking a list of foods and quantities.
In rails you would now have something like
# routes.rb
map.resources :diner, :member => {:eat => :post}
#controller
def eat
#diner = Diner.find(params[:id])
#diner.eat(params[:foods])
respond_to ...
end
end
You will notice that I have actually pushed the logic into the model. I am assuming that the Diner model has an association with a LunchBox model. The eat method will increment the health and change the food amounts in the related LunchBox. This way you can encapsulate all of the logic quite neatly.
UPDATE
I think it is quite a common pattern to have Resources with some specific named operations. I often just add actions to my controller, but keep within the general framework of REST by exposing these actions using HTTP and the Rails conventions.
You can certainly model your system with Meal as a Resource, but I think this results in extra complexity for your requirements.
It is also possible to model you entire system with only operations that map to the standard HTTP methods, but for real-world systems it's cumbersome and clumsy. In this world view, you start walking down the path of coordinating multiple http actions to compose a higher-order API. Such a system is pretty much impossible to build with a half-decent UI, and if you are exposing an API to third-parties they're going to hate you.
Related
Does an equivalent of Wordpress “post types” and the Advanced Custom Fields plugin exist for Ghost?
As one example, I built a travel site that has multiple Trips (a custom post type), and each trip has various serialized itinerary destinations, tour guides, etc. Another example would be designer portfolios, where they might have a Projects post type, which contains serialized images, each with its own description and perhaps a date stamp or client or whatever.
Not supported and probably never will be. Seems like this doesn't have high priority in their team.
See: https://forum.ghost.org/t/custom-fields-for-posts/1124/46 and https://github.com/TryGhost/Ghost/issues/9020
I'm building a site that has items, with each item having a page, for example:
website.com/book/123
website.com/film/456
website.com/game/789
Each item can have multiple sub (and sub-sub, sub-sub-sub) pages, for example a book could have a blurb, a film could have a gallery and a game could also have a gallery.
My question is, does any sort of standard or best practice exist around structuring the URLs for pages associated with an item? For example:
website.com/film/456/gallery
Where the sub page comes after the item, or:
website.com/film/gallery/456/
where the item is the very last part of the URL.
Does anyone have any information on why which approach is best or if any web standard exists? It seems an obvious thing but I'm struggling to decide, I can think of pros and cons for each approach -- although I'm leaning towards the former option because it means the following user path would match the URL:
load website.com -> click "films" (website.com/films)-> click "a film" (website.com/film/123) -> click gallery (website.com/film/123/gallery)
but something about it seems... off, inconsistent maybe.
You are correct that the former URL is "better" and is more widely deployed. I don't think you would find this documented in any standard; it is rather more of a convention. Most articles and books covering REST do it that way.
The reason for this is, as you say, that the path components in the URL match the structure of resources and sub-resources. In particular, all of the following should be valid URLs:
website.com/
website.com/books
website.com/books/123
In particular, note that it is books/123, not book/123 like you have. I have seen the singular but IMHO the plural is better.
For the URL /books
a GET gets all books, but you can restrict the books with query parameters, e.g. /books?author=alice
a POST adds a new book (with a server-generated id).
For the URL /books/123
a GET gets that particular book
a PUT replaces the book with that id (or adds a book with that client-generated id)
Now if a book has blurbs and the blurbs are unique only to a particular book then you will add the following URLs:
website.com/books/123/blurbs
website.com/books/123/blurbs/72
You can do the same for films and galleries, provided each gallery belonged to a single film. But if galleries existed for multiple films, then you would make /galleries a top-level URL. Navigating from a film to a gallery would still be fine. You wouldn't have a structured URL. You would instead get all galleries containing pictures from film 456 via a GET to
website.com/galleries?film=456
The general rule is that if you have an ownership relation for the subresources you can use structured urls, but if there is a looser relationship among top-level items, query parameters are fine. Don't fall into the common misconception that RESTful URLs don't have query parameters; they do. :)
Now finally, to directly answer your question: website.com/films/galleries/456 is not a good URL IMHO because `website.com/films/galleries/ is not very useful. In fact I think it is rather ugly. What would it mean? All galleries? If so, it should be website.com/galleries.
Again I don't think this is standardized anywhere, but it feels very common and conventional.
I'm fairly familiar with REST principles, and have read the relevant dissertation, Wikipedia entry, a bunch of blog posts and StackOverflow questions on the subject, but still haven't found a straightforward answer to a common case:
I need to request a resource to display. Depending on the resource's state, I need to render either a read-only or an editable representation. In both cases, I need to GET the resource. How do I construct a URL to get the read-only or editable version?
If my user follows a link to GET /resource/<id>, that should suffice to indicate to me that s/he needs the read-only representation. But if I need to server up an editable form, what does that URL look like? GET /resource/<id>/edit is obvious, but it contains a verb in the URL. Changing that to GET /resource/<id>/editable solves that problem, but at a seemingly superficial level. Is that all there is to it -- change verbs to adjectives?
If instead I use POST to retrieve the editable version, then how do I distinguish between the POST that initially retrieves it, vs the POST that saves it? My (weak) excuse for using POST would be that retrieving an editable version would cause a change of state on the server: locking the resource. But that only holds if my requirements are to implement such a lock, which is not always the case. PUT fails for the same reason, plus PUT is not enabled by default on the Web servers I'm running, so there are practical reasons not to use it (and DELETE).
Note that even in the editable state, I haven't made any changes yet; presumably when I submit the resource to the Web server again, I'd POST it. But to get something that I can later POST, the server has to first serve up a particular representation.
I guess another approach would be to have separate resources at the collection level:
GET /read-only/resource/<id> and GET /editable/resource/<id> or GET /resource/read-only/<id> and GET /resource/editable/<id> ... but that looks pretty ugly to me.
Thoughts?
1) It is perfectly valid to have two distinct resources, one for viewing and one for editing some domain concept. Just be aware that because they are two different URIs from REST's perspective they are two different resources. Too often people conflate resource with domain object. That's why they end up being stuck only doing CRUD.
2) Don't get too hung up on the name of the resource. The important thing is that you realize that what the URI points to is a "thing", "a resource". If that's more obvious to you with editable instead of edit then use that. Having a verb in your URL doesn't make your application wrong, it just makes it a bit less readable to the human developer. Using a verb in the URL to try and redefine the semantics of the HTTP method, now that's a violation of the uniform interface constraint.
In REST, editing an existing resource is accomplished by a client GET-ing a representation of that resource, making changes to the representation, and then doing a PUT of the new representation back to the server.
So to just read a resource your REST client program would do a:
GET http://www.example.com/SomeResource
And to edit that resource:
GET http://www.example.com/SomeResource
... edit it ...
PUT http://www.example.com/SomeResource
Normally simultaneous updates are handled by letting the last PUT arriving at the server overwrite the earlier ones, on the assumption that it represents a newer state. But in your case you want to guard against this.
Carefully consider #Jason's suggestion to maintain an optional parallel lock resource for each main resource. Your client would first create the lock, do the edit, then delete the lock. Your system would need to release a lock automatically if the user making the lock subsequently never saves any changes. This would look like:
GET http://www.example.com/SomeResource
... user presses an edit button ...
PUT http://www.example.com/SomeResource/lock
... user edits the resource's representation ...
PUT http://www.example.com/SomeResource
DELETE http://www.example.com/SomeResource/lock
You'd need to do some appropriate error handling if the user is trying to edit a resource that's locked by someone else.
It sounds like you feel you're constrained by the current limitations of HTML. If you use a server-side REST framework like Restlet (for Java), it supports the notion of "overloaded POST", where you can use POST but tack on a query string argument like method=PUT or method=DELETE. If you're writing your own server-side components they can use this trick too.
There are tricks you can play at the HTML level too. For instance your page can have a read-only part that's initially displayed, and an input form that's initially not shown. When the user presses the edit button, your JavaScript hides the read-only part and shows the input form.
Be sure to read Richardson and Ruby's Restful Web Services (O'Reilly) too. It's extremely helpful.
I don't think returning a form or just values is up to a REST server, but the responsibility of the client. Whether a resource is editable is a property of the resource, and not something defined by the URL.
In other words: The URL for getting the resource is GET /resource/<id>. This has a property editable. If a user wants a form it can retrieve the resource from the same URL and populate the form. The client can than PUT/POST changes.
How do I construct a URL to get the read-only or editable version?
There's an underlying problem here, which is that you are constructing URLs in the first place - appending IDs to hard-coded URLs is not REST. Roy Fielding has written about this very mistake. Whichever document prompts you to edit the resource should contain the URI to the editable variant of that resource. You follow that URI, whether that's /resource/editable or /editable/resource is outside the scope of REST.
If instead I use POST to retrieve the editable version, then how do I distinguish between the POST that initially retrieves it, vs the POST that saves it?
You perform a GET (not a POST) to read the resource, and POST (or PUT) to write the resource.
If you want to create a lock on the resource in question, use POST to write to the resource (or the resource's container, with the resource ID encoded in the body of the POST), and have the server create a lock as a new resource, and return an ID of that resource as the response to the POST. (with authentication issues beyond the scope of your question or this answer)
Then to unlock the lock, either use a DELETE on the lock resource, or POST to the lock's container.
I guess your question could be "how to identify the readonly representation that return with GET action in PUT action?". You could do this:
<Root>
<readonly>
<p1><p1>
...
<readonly>
<others>
...
<others>
<Root>
After parsing the request XML from PUT you can ignore the readonly part and process others. In Response, return 200 status and leave a message saying the part in readonly is ignored.
Is it your expected?
This is a new application, and I have an index method on a Search controller. This also serves as the home page for the application, and I'm trying to decide if I am headed down the wrong path from a design pattern perspective.
The method is already 35 lines long. Here is what the method does:
3 lines of setting variables to determine what "level" of hierarchical data is being searched.
Another 10 lines to populate some view variables based on whether a subdomain was in the request or not.
A 10 line section to redirect to one of two pages based on:
1) If the user does not have access, and is signed in, and has not yet requested access, tell them "click here to request access to this brand".
2) If the user does not have access, is signed in, and has already requested access, tell them "so and so is reviewing your request".
Another 10 lines to build the dynamic arel.
I can't get it straight in my head how to separate these concerns, or even if they should be separated. I appreciate any help you can offer!
Summarizing what you've said in something codelike (sorry, don't know ruby; consider it pseudocode):
void index() {
establishHierarchyLevel();
if (requestIncludedSubdomain())
fillSubdomainFields();
else
fillNonsubdomainFields();
if (user.isSignedIn() && !user.hasAccess()) {
if (user.hasRequestedAccess())
letUserIn();
else
adviseUserOfRequestUnderReview();
}
buildDynamicArelWhateverThatIs();
}
14 lines instead of 35 (of course, the bodies of the extracted methods will lengthen the overall code, but you can look at this and know what it's doing). Is it worth doing? That really depends on whether it's clearer to you or subsequent programmers. My guess is it's worth doing, that splitting out little code blocks into their own method will make the code easier to maintain.
That's a lot of variables being set. Maybe this is a good opportunity for a module of some kind? Perhaps your module can make a lot of these decisions for you, as well as acting as a wrapper for a lot of these variables. Sorry I don't have a more specific answer.
Without your code it's somewhat difficult to suggest actual fixes, but it definitely sounds like a really wrong approach and that you're making things much harder than they need to be:
3 lines of setting variables to
determine what "level" of hierarchical
data is being searched
if there is a search form, I would think you would want to pass those straight from the params hash into scopes or Model.where() calls. Setup scopes on your model as appropriate.
Another 10 lines to populate some view variables based on whether a subdomain was in the request or not.
This seems to me like it should be at most 1 line. or that in your view, you should use if statements to change what you'd like your output to be depending on your subdomain.
A 10 line section to redirect to one of two pages based on:
the only thing different in your explanation of the 2 views is "whether the user has requested access" surely this is just a boolean variable? You only need 1 view. Wrap the differences into 2 partials and then in your view and write one if statement to choose between them.
Another 10 lines to build the dynamic arel.
It might be necessary to go into Arel, but I highly highly doubt it. Your actual search call can in most cases (and should aim to be) 1 line, done through the standard ActiveRecord query interface. You want to setup strong scopes in your models that take care of joining to other models/narrowing conditions, etc. through the ActiveRecord Query interface.
I am implementing a dashboard as a relative Rails newbie (more of an infrastructure guy). The dashboard will consist of multiple pages, each page of which will contain multiple charts/tables/etc. For modularity, I want it to be as easy as possible to add new charts or change views of the data.
Say one page has 5 different charts. I could have the controller do 5 separate data lookups, hold all the relevant data in instance variables, and render 5 partials, each of which touch subsets of the data. But it seems more modular to have one "index" controller action whose render has a bunch of divs, and for each div there is another controller action which does the data lookup and has an associated view partial in charge of managing the view of that data within the div.
So if I'm showing the website dashboard page which has two graphs, website/index would use website/graph1 and website/graph2 to look up the data for each and then _graph1.html.erb and _graph2.html.erb would use the controller data to fill out divs "graph1" and "graph2", etc.
Is this the right design, and if so, what's the easiest way to accomplish this? I have an approximation using remote_function with :action => "graph1" to fill out divs, but I'm not 100% happy with it. I suspect I'm missing something easier that Rails will do for me.
Version 1:
Simple method that I've actually used in production: iframes.
Most of the time you don't actually care if the page renders all at once and direct from the server, and indeed it's better for it to load staggered.
If you just drop an iframe src'd to the controller's show action, you have a very simple solution that doesn't require direct cross-controller interactions.
Pro:
dead easy
works with existing show actions etc
might even be faster, depending on savings w/ parallel vs sequential requests and memory load etc
Cons:
you can't always easily save the page together with whatever-it-is
iframes will break out of the host page's javascript namespace, so if they require that, you may need to give them their own minimalist layout; they also won't be able to affect the surrounding page outside their iframe
might be slower, depending on ping time etc
potential n+1 efficiency bug if you have many such modules on a page
Version 2:
Do the same thing using JS calls to replace a div with a partial, à la:
<div id="placeholder">
<%= update_page {|page| page['placeholder'].replace with some partial call here } %>
Same as above, except:
Pro:
doesn't lock it into an iframe, thus shares JS context etc
allows better handling of failure cases
Con:
requires JS and placeholder divs; a bit more complex
Version 3:
Call a whole bunch of partials. It gets complicated to do that once you're talking about things like dashboards where the individual modules have significant amounts of setup logic, however.
There are various ways to get around this by making those things into 'mixins' or the like, but IMO they're kinda kludgy.
ETA: The way to do it via mixins is to create what is essentially a library file that implements your module controllers' setup functions, include that wherever something that calls 'em is used, and call 'em.
However, this has drawbacks:
you have to know what top level controller actions will result in pages that include those modules (which you might not easily, if these are really widgety things that might appear all over, e.g. user preference dependent)
it doesn't really act as a full fledged controller
it still intermixes a lot of logic where your holding thing needs to know about the things it's holding
you can't easily have it be segregated into its own controller, 'cause it needs to be in a library-type file/mixin
It IS possible to call methods in one controller from another controller. However, it's a major pain in the ass, and a major kludge. The only time you should consider doing so is if a) they're both independently necessary controllers in their own rights, and b) it has to function entirely on the back end.
I've had to do this once - primarily because refactoring the reason for it was even MORE of a pain - and I promise you don't want to go there unless you have to.
Summary
The best method IMHO is the first if you have complex enough things that they require significant setup - a simple iframe which displays the module, passing a parameter to tell it to use an ultraminimalist layout (just CSS+JS headers) because it's not being displayed as its own page.
This allows you to keep the things totally independent, function more or less as if they were perfectly normal controllers of their own (other than the layout setting), preserve normal routes, etc.
If you DON'T need significant setup, then just use partials, and pass in whatever they need as a local variable. This will start to get fragile if you run into things like n+1 efficiency bugs, though...
why don't you give Apotomo a try, that's stateful widgets for Rails:
A tutorial how to build a simple dashboard
You could achieve this by using
render_output = render :action => "graph2"
But Me personally would probably wrap the code in either a shared helper or write you own "lib" under the lib directory to reuse the code with a shared template. Remember that unless you change your route.rb file any public method defined is accessible by
/controller/action/:id
Also remember to turn off the layout for the function :layout => nil (or specify at the top of the controller layout "graph", :except => ["graph2"]
Cheers
Christian
I'm not aware of any special Rails tricks for achieving this without using AJAX in the way you've outlined.
The simplest way to get the modularity you seek is to put those portions of controller code into separate methods (e.g. set_up_graph1_data, set_up_graph2_data, etc.), which you simply call from your index action to set up the variables for the view.
You can put these methods into ApplicationController if you want them available to multiple controllers.
As a side note, early on, Rails did used to have a feature called 'components' which would allow you to do exactly what you're asking for here, without having to use AJAX. From your view, you could just render another controller action, inline. However, this feature was removed for performance and design philosophy reasons.