Existing Options respond_to / respond_with inline in controller ActiveModel::Serializers with rails_api Separate Rails controller(s), Jbuilder or RABL Grape - github.com/intridea/grape Lots of other options...
Versioning / Namespacing module Api class Endpoints < Base get "/" do json({ message: "Welcome to the API" }) end get "/v1" do json({ message: "This is version 1 of the API" }) end namespace "/v1" do get "/me" do authenticate! json current_user.api_authenticated_hash end end end end gist.github.com/4226520
Test it! describe Api::Endpoints do let(:browser) { Rack::Test::Session.new(...) } describe "base" do it "responds with JSON at the root" do browser.get("/") should_200({message: "Welcome to the API"}) should_be_json end end end gist.github.com/4226520
404 gist.github.com/4226520 # Any unmatched request within the /api/ namespace should render 404 as JSON # Stop the request here so that JSON gets returned instead of having it # run through the whole Rails stack and spit HTML. get "/*" do halt_with_404_not_found end post "/*" do halt_with_404_not_found end put "/*" do halt_with_404_not_found end patch "/*" do halt_with_404_not_found end delete "/*" do halt_with_404_not_found end
Test it! it "responds with 404 JSON at misc not found paths" do browser.get("/a") should_404 should_be_json browser.get("/a-b") should_404 should_be_json browser.get("/a/b/c") should_404 should_be_json end gist.github.com/4226520
error error ActiveRecord::RecordNotFound do halt_with_404_not_found end error ActiveRecord::RecordInvalid do halt_with_422_unprocessible_entity end error ActiveRecord::UnknownAttributeError do halt_with_422_unprocessible_entity end error ActiveRecord::DeleteRestrictionError do halt_with_400_bad_request end error MultiJson::DecodeError do halt_with_400_bad_request("Problems parsing JSON") end error do if ::Exceptional::Config.should_send_to_api? ::Exceptional::Remote.error(::Exceptional::ExceptionData.new(env['sinatra.error'])) end halt_with_500_internal_server_error end gist.github.com/4226520
App Endpoints get "/users/:user_id/events" do user = User.find(params[:user_id]) json paginate(user.events).map(&:api_base_hash) end gist.github.com/4226520
Test it! describe "events" do before do @user = User.create! User.prototype @event = @user.events.create! Event.prototype end it "should fetch a collection of events" do browser.get("/v1/users/#{@user.login}/events") should_200([@event.api_base_hash]) end end gist.github.com/4226520
App Endpoints post "/events" do event = current_user.events.create!(parsed_request_body) status 201 json event.api_authenticated_hash end put "/events/:event_id" do event = current_user.events.find(params[:event_id]) event.update_attributes!(parsed_request_body) json event.api_authenticated_hash end delete "/events/:event_id" do current_user.events.find(params[:event_id]).destroy status 204 end gist.github.com/4226520
Test it! describe "events" do before do @user = User.create! User.prototype authorize(@user) end it "should create a new event" do browser.post("/v1/me/events", json({name: "Foo", date: "2012-06-09"})) should_201 @user.events.count.should == 1 lrb = decode_json(browser.last_response.body) lrb.should == @user.events.first.api_authenticated_hash end it "should fail to create a event if missing required fields" do browser.post("/v1/me/events", json({})) should_422 end end gist.github.com/4226520