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
@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
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.
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
$ 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.