Outline
Since I like to get more hands on experience with Ajax websites which communicate with the server using JSON, the outline of my solution is the following:- The rectangles are drawn using SVG.
- The rectangles are moved around using drag-and-drop.
- There is a Rails application which provides a RESTful web service to retrieve the positions of the rectangles and of course, to persist changes of the positions. (This is inspired by an example in "RESTful web services" by Richardson and Ruby.)
- To simplify the usage the example page is provided as the index page of the Rails web application.
Creating the RESTful service
Creating a RESTful web service with rails is very simple. You will see, it takes just a few minutes.
$ rails spike-dnd-with-svg-and-rails create create app/controllers create app/helpers create app/models create app/views/layouts create config/environments create config/initializers create config/locales create db create doc create lib create lib/tasks create log create public/images create public/javascripts create public/stylesheets create script/performance create test/fixtures create test/functional create test/integration create test/performance create test/unit create vendor create vendor/plugins create tmp/sessions create tmp/sockets create tmp/cache create tmp/pids create Rakefile create README create app/controllers/application_controller.rb create app/helpers/application_helper.rb create config/database.yml create config/routes.rb create config/locales/en.yml create db/seeds.rb create config/initializers/backtrace_silencers.rb create config/initializers/inflections.rb create config/initializers/mime_types.rb create config/initializers/new_rails_defaults.rb create config/initializers/session_store.rb create config/environment.rb create config/boot.rb create config/environments/production.rb create config/environments/development.rb create config/environments/test.rb create script/about create script/console create script/dbconsole create script/destroy create script/generate create script/runner create script/server create script/plugin create script/performance/benchmarker create script/performance/profiler create test/test_helper.rb create test/performance/browsing_test.rb create public/404.html create public/422.html create public/500.html create public/index.html create public/favicon.ico create public/robots.txt create public/images/rails.png create public/javascripts/prototype.js create public/javascripts/effects.js create public/javascripts/dragdrop.js create public/javascripts/controls.js create public/javascripts/application.js create doc/README_FOR_APP create log/server.log create log/production.log create log/development.log create log/test.log $ cd spike-dnd-with-svg-and-rails
Now we use the scaffolding to create our domain object "item", which represents a rectangle to be drawn. An item has x and y coordinates, a name and an id.
$ ruby script/generate scaffold item id:integer name:text x:integer y:integer exists app/models/ exists app/controllers/ exists app/helpers/ create app/views/items exists app/views/layouts/ exists test/functional/ exists test/unit/ create test/unit/helpers/ exists public/stylesheets/ create app/views/items/index.html.erb create app/views/items/show.html.erb create app/views/items/new.html.erb create app/views/items/edit.html.erb create app/views/layouts/items.html.erb create public/stylesheets/scaffold.css create app/controllers/items_controller.rb create test/functional/items_controller_test.rb create app/helpers/items_helper.rb create test/unit/helpers/items_helper_test.rb route map.resources :items dependency model exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/item.rb create test/unit/item_test.rb create test/fixtures/items.yml create db/migrate create db/migrate/20110514212212_create_items.rb
$ rake db:migrate (in /Users/alex/SWDEV/spike-dnd-with-svg-and-rails) == CreateItems: migrating ==================================================== -- create_table(:items) -> 0.0014s == CreateItems: migrated (0.0015s) ===========================================
The service is started with a script contained in the folder script.
$ script/server --daemon
=> Booting Mongrel => Rails 2.3.5 application starting on http://0.0.0.0:3000
What we have so far?
We have a very simple web application running on http://localhost:3000 which allows for managing our domain objects. Its index page shows some welcome message with some hints. The interesting page is http://localhost:3000/items. It returns a list of our domain objects, which we called "item". Of course the list is empty.To create our first entry we klick on "New item" and fill the form with id=1 and some fantasy. Now http://localhost:3000/items returns a list containing one item. Beside the HTML pages we can also request XML data:
$ curl -i http://localhost:3000/items.xml TTP/1.1 200 OK Connection: close Date: Sun, 15 May 2011 14:00:00 GMT ETag: "8fc46ac5da86d8127536a43e164a4878" Content-Type: application/xml; charset=utf-8 X-Runtime: 7 Content-Length: 339 Cache-Control: private, max-age=0, must-revalidate <?xml version="1.0" encoding="UTF-8"?> <items type="array"> <item> <created-at type="datetime">2011-05-14T21:40:20Z</created-at> <id type="integer">1</id> <name>my first rect</name> <updated-at type="datetime">2011-05-15T10:39:21Z</updated-at> <x type="integer">3</x> <y type="integer">4</y> </item> </items>
Using the verbose option -i of curl tells us a lot more details about the request, especially its return code.
As the Rails application provides a RESTful service we can access the "item" with id 1 using
As the Rails application provides a RESTful service we can access the "item" with id 1 using
$ curl -i http://localhost:3000/items/1.xml HTTP/1.1 200 OK Connection: close Date: Sun, 15 May 2011 14:01:24 GMT ETag: "a388de3aec9d892bc1b1af2f81194701" Content-Type: application/xml; charset=utf-8 X-Runtime: 7 Content-Length: 293 Cache-Control: private, max-age=0, must-revalidate <?xml version="1.0" encoding="UTF-8"?> <item> <created-at type="datetime">2011-05-14T21:40:20Z</created-at> <id type="integer">1</id> <name>my first rect</name> <updated-at type="datetime">2011-05-15T10:39:21Z</updated-at> <x type="integer">3</x> <y type="integer">4</y> </item>
What about JSON?
Cool, out of the box we got HTML and XML. Let's try to use json. We either can tell cURL that we would like to get JSON results or we append the postfix ".json" to the URL,pre>
$ curl -i http://localhost:3000/items.jsonl HTTP/1.1 406 Not Acceptable Connection: close Date: Sun, 15 May 2011 14:10:41 GMT Content-Type: text/html; charset=utf-8 X-Runtime: 5 Content-Length: 1 Cache-Control: no-cache $ curl -i -H "Accept: application/json" http://localhost:3000/items HTTP/1.1 406 Not Acceptable Connection: close Date: Sun, 15 May 2011 14:13:27 GMT Content-Type: text/html; charset=utf-8 X-Runtime: 5 Content-Length: 1 Cache-Control: no-cache
Both calls are returning 406 and no content. So, there is something to do to enable JSON support.
How to ad JSON support?
To provide JSO we have to extend our controller
To add json support we simply copy each "format.xml" line and exchange "xml" with "json". That's it. (Of course, it would be very nice if an option for scaffolding could enable the json support.)
Let's verify whether the JSON support works.
./app/controllers/items_controller.rb
. The controller has code like this:def index @items = Item.all respond_to do |format| format.html # index.html.erb format.xml { render :xml => @items } end end
To add json support we simply copy each "format.xml" line and exchange "xml" with "json". That's it. (Of course, it would be very nice if an option for scaffolding could enable the json support.)
Let's verify whether the JSON support works.
$ curl http://localhost:3000/items/1.json {"item":{"name":"my first rect","created_at":"2011-05-14T21:40:20Z","x":3,"y":4,"updated_at":"2011-05-14T21:40:20Z","id":1}}
Conclusion
Cool. we have out first RESTful web service with JSON, XML (and also HTML) support... written in less than 10 minutes. Not so bad.
With the next post I try to cover the manipulation of data using PUT and DELETE requests rather than GET requests.
No comments:
Post a Comment