Question

I am writing an API in Grape, but it stands alone, with no Rails or Sinatra or anything. I'd like to split the app.rb file into separate files. I have looked at How to split things up in a grape api app?, but that is with Rails.

I'm not sure how to make this work with modules or classes — I did try subclassing the different files into my big GrapeApp, but that was ugly and I'm not even sure it worked properly. What's the best way to do this?

I currently have versions split by folders (v1, v2, etc) but that is all.

Was it helpful?

Solution

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top