Creating a Ruby Rack Middleware for Application Version Id

If you are developing an application that uses the Ruby rack framework, and most Ruby application frameworks and servers do, it is pretty simple to create your own rack middleware.

In this post I outline how simple it is go create a new middleware for your rack application. In fact, I did something very similar in one of the web services I worked on so that we could get the exact version of the code that our app was running against for troubleshooting purposes. I suggested we add a version identifier to all responses so we could log the requests, the responses and their response codes, and have the version of the running code in every response as well. This would help us troubleshoot failures that are not failing anymore, or failed “intermittently” because they might be hitting one of two load balanced servers in case someone updated one server, but not the other, such as for A-B testing.

This was actually a very easy thing to do by taking advantage of rack’s middleware capability. The code below was all that it took to create a new piece of middleware to give us version identifiers on each response.

module Middleware
  class VersionIdentifier
    def initialize(app, version_id)
      @app = app
      @version_id = version_id
    end

    def call(env)
      @app.call(env).tap do |_status, headers, _body|
        headers["version-id"] = @version_id
      end
    end

    private
      attr_reader :version_id
  end
end

In the above source, we create a initialize method which takes app, which is the rack application that this middleware component is wrapping, and version_id, which is how we will identify the version of the application is running.

The next step to define the standard rack protocol of call(env). In this, since we are only concerned about the response, we call the next rack component by invoking call on @app which we got when the middleware was constructed. This could be another piece of middleware, or it could be the actual application, but we don’t care about specifics, which is part of the beauty of the way middleware for rack works. What we do care about is the return of the call to @app.call(env), since we are interested in modifying the response headers. We do this with using the tap method on all Ruby objects, and adding a new entry to the header hash with the key version-id and the value that we got on creation for @version_id.

That is all there is to creating a rack middleware component to add a version identifier to the headers for every response that is served by the rack web server.

To use this middleware, we first need to determine what the will represent the version of our app. For this example, we will use the git SHA that represents the code we are running against, since we are assuming we are behaving and there is no code running in production that is not checked into source control. We add this to our startup script/configuration file, e.g. config.ru.

git_sha = `git rev-parse HEAD`

Once we have that settled, we just declare we are going to use our middleware, and we pass in the git_sha that we found above.

use Middleware::VersionIdentifier, git_sha

We start up our application and voilà, we have a version identifier getting returned on every response with the header of version-id.

$ curl -i "localhost:9292"
HTTP/1.1 200 OK
version-id: 7df6e26a3dd1d3d05130e054fbcb1b878d965767
Content-Length: 7

Howdy!
$

The full source code can be found at https://github.com/stevenproctor/versionid-middleware-example.