Rails 5 has an excellent API-only mode which is meant to give you a ‘lighter’ version of Rails. Even in the API mode though, there are parts of the middleware stack that you might not need.

I recently took over such a Rails 5 API which was essentially being passed some parameters, calculating some values based on data memoized off the database, then returning the computed result as JSON. This was meant to happen for every request, without any cached responses.

With the above functions, I was able to easily remove the following middleware classes:

  1. Rack::Sendfile: From the docs here: “The Sendfile middleware intercepts responses whose body is being served from a file and replaces it with a server specific X-Sendfile header.”

  2. ActionDispatch::Static: This serves data through static files like those in your application’s public/ directory.

  3. Rack::Runtime: This sets a header which contains the time taken to execute the request. The header is X-Runtime and the time is in seconds. I removed it but re-added it after spotting it in NewRelic’s source code (Ruby agent) in a few places. I will perhaps remove this again after a proper investigation, aiming to confirm that removing this class will not affect my NewRelic reporting.

  4. Rack::Head: This converts HEAD requests to GET requests. My API had no use for this.

  5. Rack::ConditionalGet: This helps make a Conditional GET request. Again, this was something the API had no use for; in the scenario I outlined above, fresh computations should be made for each request.

  6. Rack::ETag: This adds the ETag header which helps cache data client-side. I didn’t want any such caching to be done.

With those six middleware classes out of the equation, I reduced each request’s time by a few miliseconds.

If you are interested in seeing what middleware you can get rid of in your Rails 4 or 5 project, you can first get a list of your middleware stack using this command:

bundle exec rails middleware

Then you can time each middleware class by using a dirty gem I created last night: MiddlewareTimer. I would normally recommend RackTimer but it doesn’t work with Rails versions beyond 3.

From there you can understand (and remove) individual middleware classes using the docs here.