In a Rack-based application, including frameworks built on top of Rack like Ruby on Rails and Sinatra, middleware plays a crucial role in processing HTTP requests and responses. When you're working within a Rack middleware, accessing request headers is straightforward because the request is represented as an environment hash (env) passed to the call method of your middleware.
Here's how to access request headers in different ways within a Rack middleware:
app/middleware/user_token_authenticator_middleware.rb
class UserTokenAuthenticatorMiddleware
def initialize(app)
@app = app
end
def call(env)
if (user = find_user_by_token)
env[:current_user] = user
@app.call(env)
else
[
401,
{ 'Content-Type' => 'application/json' },
[{error: 'invalid or missing authentication token '}]
]
end
end
def find_user_by_token
request = Rack::Request.new(env)
from_authorization = requests.headers["Authorization"]&.split&.last
user_token = request.params["authToken"] || from_authorization
# Implemented via decoding token and searching by that
User.find_by_authentication_token?(user_token)
end
end
The most direct way to access request headers in a Rack middleware is by directly referencing the env hash. Rack converts HTTP headers to uppercase, replaces hyphens with underscores, and prefixes them with HTTP_, making them easy to identify and access. For example, to access the Content-Type header, you would do the following:
content_type = env['HTTP_CONTENT_TYPE']
Converting the previous examples to use the env hash it would look like this
class UserTokenAuthenticatorMiddleware
def initialize(app)
@app = app
end
def call(env)
if (user = find_user_by_token)
env[:current_user = user
@app.call(env)
else
[
401,
{ 'Content-Type' => 'application/json' },
[{error: 'invalid or missing authentication token '}]
]
end
end
def find_user_by_token
from_authorization = env["HTTP_AUTHORIZATION"]&.split&.last
User.find_by_authentication_token?(from_authorization)
end
end
Accessing request headers in a Rack middleware is primarily done through the env
hash, either directly or by wrapping it in a Rack::Request
object for convenience and more Ruby-like access patterns.