As you may have read on this blog, we are working on a RESTful API for Floorplanner. This post contains some random observations I have made and questions I had (and still have) during the development.
to_xml incompatible with to_json
ActiveRecord#to_json does not seem to be fully compatible with ActiveRecord#to_xml. With to_xml, it is possible to overwrite the to_xml method of your models. The overwritten method will be called, even if an instance of such a model is :included within the XML of another model. For to_json however, only the overwritten method of the instance you call to_json on will be executed; for every included model, the default implementation is used.
A workaround in most cases is to pass every option to the initial call of to_json:
@object.to_json(:except => [:id],
:include => {:related_objects => {:except => [:id, :object_id]}})
Weird behavior in to_xml called on an array of objects
One model in our project seems to have some caching issues in production mode. If to_xml is called on a collection of instances of this model, the results seems to get stored in cache. On every call, the result is appended to this cached value. The result is a lot of repetition of the same XML, which is invalid XML. The weird part is that it works OK if it is only a single instance of this model or if config_cache_classes == false (a development environment). to_json does not seem to have this problem either. All other models are unaffected as well. A more complete write-up of the problem can be found here.
I am still not able to figure out what causes this behavior and I am currently working around this issue by using some String#split-magic on the result of the to_xml-call. I know this is extremely ugly, so if anybody has experienced a similar problem, please let me know! It’s driving me nuts!
Testing an XML API
What is the best way to test a REST API, besides the Unit-tests that are already in place? Currently, I have an integration test suite, with a lot of testing code that looks like this:
def test_create_project
post projects_path(:format => :xml),
{:project => {:description => 'Original description'}}
assert_response :created
@new_project_location = headers['location'].first # array?
get @new_project_location
assert_response :success
project_doc = REXML::Document.new(response.body)
assert_equal 'Original description',
project_doc.elements['//description'].text
end
It works, but is isn’t very elegant in my eyes. Moreover, all that XML parsing is making the test suite slower and slower. Does anybody have suggestions to build a cleaner and faster test suite for a RESTful XML API? By the way, is there an easy way to POST an XML document rather than “normal” POST-parameters in these calls?