Integrating Grape with Ruby on Rails

Grape is designed to work seamlessly with Ruby on Rails, allowing you to build and serve high-performance APIs directly from your Rails application.

Mounting Your API

The primary step to integrate Grape is to mount your API class in your Rails routes.

  1. File Organization: It's conventional to place your API files in the app/api/ directory. For a modular API, you might have a structure like:

    app/
      api/
        twitter/
          api.rb
          v1.rb
          v2.rb

  2. Autoloading: Ensure that Rails can find and load your API files by adding the directory to the autoload paths in config/application.rb:

    # config/application.rb
    config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
    config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]

  3. Zeitwerk Inflection (Rails 6+): Rails uses the Zeitwerk autoloader, which inflects api as Api. To ensure your Grape::API subclasses are loaded correctly, you need to add an acronym inflection. In config/initializers/inflections.rb, uncomment the inflector block and add:

    # config/initializers/inflections.rb
    ActiveSupport::Inflector.inflections(:en) do |inflect|
      inflect.acronym 'API'
    end

  4. Mounting in config/routes.rb: Finally, mount your main API class in your config/routes.rb file. You can mount it at the root or under a specific path like /api.

    # config/routes.rb
    Rails.application.routes.draw do
      # Mount the API at the root
      mount Twitter::API => '/'
    
      # Or, mount it under a specific path
      # mount Twitter::API => '/api'
    end

Reloading API Changes in Development

To ensure that changes to your API files are automatically reloaded in your Rails development environment, you need to configure a file watcher.

  1. Create an initializer file, for example, config/initializers/reload_api.rb.

  2. Add the following code, which tells Rails to monitor your API files and reload the routes when a change is detected.

    # config/initializers/reload_api.rb
    if Rails.env.development?
      # Make sure the main API class is unloadable
      ActiveSupport::Dependencies.explicitly_unloadable_constants << 'Twitter::API'
    
      api_files = Dir[Rails.root.join('app', 'api', '**', '*.rb')]
      api_reloader = ActiveSupport::FileUpdateChecker.new(api_files) do
        Rails.application.reload_routes!
      end
    
      # Use the appropriate hook depending on your Rails version
      if ActiveSupport.version >= Gem::Version.new('6.0')
        ActiveSupport::Reloader.to_prepare do
          api_reloader.execute_if_updated
        end
      else
        ActionDispatch::Callbacks.to_prepare do
          api_reloader.execute_if_updated
        end
      end
    end

With this setup, any changes you make to your API files will be automatically reloaded on the next request, just like your Rails controllers and models.