I've started with ActiveResource, but quickly hit the wall. Could not get ActiveResource to work when overriding to_json and to_xml on the underlying model. Plus, could not make resource representation inject links into the generated xml document. Oh btw, I'm using Rails 3.2.1.
I did a bit of research and found out about its gem. Tried it, for some reason didn't work for me. So my question is:
If I have one resource (say books) hosted in one web site (something like http://books.org), and another resource (say students, http://students.org), hosted in another web site, how can I get books to represent themselves to a student in their full HATEOS glory?
I was able to get the book resource to represent itself to the asking student as an XML document. I did that by using vanilla Rails ActiveResource in the students site. I've created Books resource that inherits from ActiveResource::Base. Then I specified the self.site and self.element_name, after which I was able to perform some rudimentary ActiveRecord-like queries against the remote books site. The only thing that worked for me was Book.all and Book.find(1). Even that was not satisfactory because the representation contained all database columns, and I wanted to at least remove some of those, which turned out not to be possible.
Now that I've abandoned that approach, I am wondering if there is a working example in Rails where it is possible to build a more sophisticated representation of a resource (i.e. books) that will contain links that will drive the application state transfer? I find it simply unbelievable that such a simple requirement seems so devilishly difficult to implement in Rails. All I'm trying to do is create a representation of a resource that will include some links which will guide the consumer on its discovery of what that resource is capable of. I'm mostly interested in implementing the workflow, which is a layered, peeling-the-onion type of conversational process of discovery.
In Rails, you'd need to change the way the serialization of your object happens if you're looking to do this in JSON. (You need to override the way Rails gives back representations of resources.) The most common gem for doing that would be: https://github.com/rails-api/active_model_serializers
If you don't want to use AMS or want to return HTML, consider following this presenter pattern: http://blog.steveklabnik.com/posts/2012-01-06-implementing-hateoas-with-presenters
Related
I'm a junior Rails developer and I'm trying to understand the pros/cons between CRUD web apps and REST API's.
I know how to turn a Rails Blog into an API, but I don't understand what advantages there are to doing this.
The main difference I can see is that my url for reading a blog went from this
localhost:3000/blog/1
to this
localhost:3000/api/v1/blog/1
And if I want to create a blog the url went from this
localhost:3000/blog/new
to this
localhost:3000/api/v1/blog
I made the view for the API and the Blog controller look exactly the same.
So the end result is that reading a blog or creating a blog has the exact same UX.
I feel like there is something I am not truly understanding about REST API's.
Can anyone describe a hypothetical situation where a Blog API would be better than a CRUD Blog?
I feel like there is something I am not truly understanding about REST API's.
That's not your fault; there is a lot of misunderstanding about REST API's. The Rails community in particular got confused circa 2005, and I don't know that it was ever straightened out.
localhost:3000/blog/1
localhost:3000/api/v1/blog/1
That's just a change of spelling convention. REST doesn't care what spelling conventions you use for your URI, but if you are using a framework (like Rails) to route HTTP requests to the appropriate implementation, then you want to choose spellings that make the routing easy ("convention over configuration").
localhost:3000/blog/new
localhost:3000/api/v1/blog
This change better aligns a "create" request with the caching semantics of the web. It's often the case that adding a new entry to a blog also changes the blog resource itself (the new entry gets listed in the index, for example). So after a successful create, you would like the client to stop using the old copy of the index and fetch a new one.
HTTP's cache invalidation rules describing invalidation of the target resource after a successful unsafe request, so this:
POST /api/v1/blog
instructs the client to invalidate its previously cached copies of /api/v1/blog (if the response isn't an error). Which is great, because the /api/v1/blog representation has been changed by the addition of the new blog post.
POST /blog/new
has exactly the same semantics (because "uniform interface" -- all resources understand the same messages the same way). Which means that a non error response informs general purpose clients that the /blog/new representation should be invalidated.
And that's probably not useful, because it's /blog, not /blog/new, that was changed when we added a new entry to the blog.
In general: the target-uri doesn't identify the handler of the action, it identifies the document (resources being generalizations of documents) that we are trying to change. That allows us to leverage the caching magic that is built into the web.
I have tried out the RESTful API concept and found out that its a great mindset for building resources APIs. For example, adding comment to post would be
POST /posts/{id}/comments
However, there are some cases, correct me if I am wrong, that the expected APIs can not really be model as a simple CRUD
For example, adding product to the system requires adding picture, adding multiple tags specify its category?
How do I do this the restful way?
1.) Do I force the API user to follow after multiple API calls?
POST /pictures -- add picture
GET /categories -- get selected category
POST /tags -- add tags
POST /products -- input picture, category, tags ids as JSON fields
2.) Do I use nested object which automatically do find all subresources?
POST /products -- input nested JSON array with picture/category/tags object field
In this case, all subresources will be existing resources instead of some (picture, tags) that should be posted.
Also, what would happen if adding picture succeed internally but adding tags failed?
3.) Do I just do a casual API? How does this fit with REST? Doesn't this break the RESTful idea?
POST /add_products
Is there any guide to deal with complex API for RESTful APIs?
Thank you.
In my opinion, one of the biggest misconception people have about REST is that internal models (tables in db or document in mongo) and REST resources must be same. REST resources can be a real model or it can be an abstract entity as well which might not exist in db.
So in this case, your url with POST i.e. POST /products request is perfectly alright as far as REST is concerned. And advice from my personal experience - One doesn't needs to be too dogmatic about url as long as basic principles of REST are conserved such as
Use right HTTP verbs
Use right status codes
Cacheable architecture
Unique indentification of resource by url
Hypermedia (if you can go that far)
I have a Backbone.js application with RoR for the backend.
The typical backbone.js setup is it gets the data from the table, and updates/saves data to that same table. However, my backbone model is made of a universal list of vendors, and I want a user to be able to "select" a vendor, which would dump into a DIFFERENT table, called user_selected_vendors.
I don't even know how to set this up in backbone. Any ideas?
Its hard to give specific advice without seeing some code examples.
In general though, you should think of your Rails backend as providing JSON service endpoints for your Backbone code to talk with. When your Rails app receives requests from the Backbone front end, you can do whatever is necessary with the request data. You are not limited to providing JSON endpoints which directly map to your database tables.
Also, based on the name of your user_selected_vendors table, it seems like you are not taking advantage of the ActiveRecord associations. What you may really want is something along the lines of adding has_many :vendors association to your User model. See: http://guides.rubyonrails.org/association_basics.html#the-has_many-association
I'd like to keep a log of all searches that users do on my site which uses the sunspot-rails gem. I don't need the logs to be real-time accessible by my application as they're for analytics that will be processed later.
I'm thinking that I should do the logging in rails rather than in solr itself so that I have access to the entire session, but I'm not sure how to build that. Is there a standard method for this? I saw this question but I would think there would be something more generic than writing it all myself in ApplicationController.
The ultimate answer depends on howwhere you're implementing your search. If you have a single search controller, do the logging there. If you have a collection of search controllers, either do it in each one, or create a base class, do the filter/logging in the base class.
Can you provide any more details?
I'm a new REST convert and I'm trying to design my first RESTful (hopefully) api and here is my question about addressing resources
Some notes first:
The data described here are 3d render
jobs
A user (graphics company) has multiple projects.
A project has multiple render jobs.
A render job has multiple frames.
There is a hierarchy enforced in the data (1 render job
belongs to one project, to one user)
How's this for naming my resourses...?
https:/api.myrenderjobsite.com/
/users/graphicscompany/projects
/users/graphicscompany/projects/112233
/users/graphicscompany/projects/112233/renders/
/users/graphicscompany/projects/112233/renders/889900
/users/graphicscompany/projects/112233/renders/889900/frames/0004
OR a shortened address for renders?
/users/graphicscompany/renders/889900
/users/graphicscompany/renders/889900/frames/0004
OR should I shorten (even more) the address if possible, omitting the user when not needed...?
/projects/112233/
/renders/889900/
/renders/889900/frames/0004
THANK YOU!
Instead of thinking about your api in terms of URLs, try thinking of it more like pages and links
between those pages.
Consider the following:
Will it be reasonable to create a resource for users? Do you have 10, 20 or 50 users? Or do you have 10,000 users? If it is the latter then obviously creating a single resource that represents all users is probably not going too work to well when you do a GET on it.
Is the list of Users a reasonable root url? i.e. The entry point into your service. Should the list of projects that belong to a GraphicsCompany be a separate resource, or should it just be embedded into the Graphics Company resource? You can ask the same question of each of the 1-to-many relationships that exist. Even if you do decide to merge the list of projects into the GraphicsCompany resource, you may still want a distinct resource to exist simple for the purpose of being able to POST to it in order to create a new project for that company.
Using this approach you should be able get a good idea of most of the resources in your API and how they are connected without having to worry about what your URLs look like. In fact if you do the design right, then any client application you right will not need to know anything about the URLs that you create. The only part of the system that cares what the URL looks like is your server, so that it can dispatch the request to the right controller.
The other significant question you need to ask yourself is what media type are you going to use for these resources. How many different clients will need to access these resources? Are you writing the clients, or is someone else? Should you attempt to reuse an existing standard like XHTML and classes/microformats? Could you squeeze most of the information into Atom? Maybe Atom with some extra namespaces like GDATA does it? Or is this only going to be used internally so you can just create your own media types, like application/vnd.YourCompany.Project+xml, application/vnd.YourCompany.Render+xml, etc.
There are many things to think about when designing a REST api, don't get hung up on what your URLs look like and you should really try to avoid doing "design by URL".
Presuming that you authenticate to the service, I would use the 1st option, but remove the user, particularly if the user is the currently logged in user.
If user actually represents something else (like client), I would include it, but not if it simply designates the currently logged in user. Agree with StaxMan, though, don't worry too much about squeezing the paths, as readability is key in RESTful APIs.
Personally I would not try to squeeze path too much, that is, some amount of redundant information is helpful both to quickly see what resource is, and for future expansion.
Generally users won't be typing paths anyway, so verbosity is not all that bad.