If you are serving a Rails application, you are probably already using some sort of compression for the responses. If not, enabling simple gzip compression is pretty straightforward (using a simple middleware) and can give boosts of as much as 80% in some cases. You can put this in an initializer somewhere and your responses will be gzipped if the receiver supports it.
config.middleware.insert_after ActionDispatch::Static, Rack::Deflater
The middleware automatically detects when compression is supported and allowed. For example, no transformation is made when a cache directive of ‘no-transform’ is present, or when the response status code is one that doesn’t allow an entity body.
But, if you have a really specific use case, you can go one step further. For example, if you deal mostly in JSON responses, messagepack could help your API get even leaner. A word of caution before you venture further, don’t expect huge savings if you are already using gzip compression as messagepack savings can vary hugely based on the kind of data you are transmitting over the socket.
Let’s create a custom middleware that can compress responses with messagepack before sending them out. A few things that we need to keep in mind for this extension are:
X-MessagePack-Compression
) in the request signaling that it wants a compressed response.With these conditions, here’s a sample middleware that you can put in.
module MessagePack
class RackMiddleware
def initialize(app)
@app = app
end
def call(env)
status, headers, body = @app.call(env)
return [status, headers, body] unless compress?(env, headers)
suppress(Exception) do
body = MessagePack.pack(Oj.load(body.body))
headers["X-MessagePack-Compression"] = true
end
[status, headers, [body]]
end
private
def compress?(env, headers)
env["HTTP_X_MESSAGEPACK_COMPRESSION"] &&
headers["Content-Type"].include?("application/json;")
end
end
end
Using the middleware is easy, you just need one extra line during initialization:
Rails.application.config.middleware.use MessagePack::RackMiddleware