You don't need to subclass from your main app, you can just mount separate Grape::API sub-classes inside the main one. And of course you can define those classes in separate files, and use require
to load in all the routes, entities and helpers that you app might need. I have found it useful to create one mini-app per "domain object", and load those in app.rb
, which looks like this:
# I put the big list of requires in another file . .
require 'base_requires'
class MyApp < Grape::API
prefix 'api'
version 'v2'
format :json
# Helpers are modules which can have their own files of course
helpers APIAuthorisation
# Each of these routes deals with a particular sort of API object
group( :foo ) { mount APIRoutes::Foo }
group( :bar ) { mount APIRoutes::Bar }
end
I arrange files in folders, fairly arbitrarily:
# Each file here defines a subclass of Grape::API
/routes/foo.rb
# Each file here defines a subclass of Grape::Entity
/entities/foo.rb
# Files here marshal together functions from gems, the model and elsewhere for easy use
/helpers/authorise.rb
I would probably emulate Rails and have a /models/
folder or similar to hold ActiveRecord or DataMapper definitions, but as it happens that is provided for me in a different pattern in my current project.
Most of my routes look very basic, they just call a relevant helper method, then present an entity based on it. E.g. /routes/foo.rb
might look like this:
module APIRoutes
class Foo < Grape::API
helpers APIFooHelpers
get :all do
present get_all_users_foos, :with => APIEntity::Foo
end
group "id/:id" do
before do
@foo = Model::Foo.first( :id => params[:id] )
error_if_cannot_access! @foo
end
get do
present @foo, :with => APIEntity::Foo, :type => :full
end
put do
update_foo( @foo, params )
present @foo, :with => APIEntity::Foo, :type => :full
end
delete do
delete_foo @foo
true
end
end # group "id/:id"
end # class Foo
end # module APIRoutes