Use Some Middleware Only for Specific Rack Website

How do I use a Rack middleware only for certain paths?

You could have MyMiddleware check the path and not pass control to the next piece of middle ware if it matches.

class MyMiddleware
def initialize app
@app = app
end
def call env
middlewary_stuff if env['PATH_INFO'] == '/foo'
@app.call env
end

def middlewary_stuff
#...
end
end

Or, you could use URLMap w/o the dslness. It would look something like this:

main_app = MainApp.new
Rack::URLMap.new '/'=>main_app, /^(foo|bar)/ => MyMiddleWare.new(main_app)

URLMap is actually pretty simple to grok.

How to run a simple Ruby Rack app that consists of only middleware?

A Rack app (including middleware) is basically just an object that responds to call, accepting a hash describing the request and returning an array describing the response.

When using a rackup file, Rack uses the DSL described in Rack::Builder. The run method just sets the “base” app:

def run(app)
@run = app
end

The use method stores the middleware classes you want to include in your app, and then when constructing the final app does something like this for each one (in reverse order of how they appear in the config.ru file):

@run = MiddleWare.new(@run, other_args)

It’s a little more complex than this, but this is the general idea. A new instance of the middleware class is created, with the existing app passed as the first argument of the constructor, and the resulting object becomes the new app. This is the (not well documented) “interface” to Rack middleware: the first argument to its initializer is the app it is wrapping, the rest are any other arguments passed to use.

The DSL expects there will always be either a run or map statement, you will get an error if you omit both.

If your middleware is written in such a way that it can handle having no arguments passed to its initializer and it will behave like a full app, then you may be able to use it directly as the app in config.ru:

run SomeMiddleware.new

This is what Sinatra does to allow it to be used as middleware. It stores the app in the initializer if it is given, and then when a request arrives that doesn’t match any route it uses the presence of @app to decide whether to behave as middleware and pass the request on, or to behave as the final app and treat it as a not found error.

If your middleware doesn’t have this flexibility then you will need to provide an app for it to wrap, as you have in your example. In this case it may also be useful to have the app for error handling, in the event that the middleware doesn’t correctly handle a request and tries to pass it on to the wrapped app.

If you want to avoid using separate use and run statements in your config.ru, you could just use run, and pass a simple app directly to your middleware:

run SomeMiddleware.new(->(e){
[500, {'Content-type' => 'text/plain'}, ["Error: SomeMiddleware didn't handle request"]]
}

Note how this follows the interface described above for middleware: the first argument to the initializer is the app to wrap.

How to test if some specific rack middleware is being used?

With help from ruby-raven guys, we've got this:

ENV['RACK_ENV'] = 'test'

# the app: start

require 'sinatra'
require 'sentry-raven'

Raven.configure(true) do |config|
config.dsn = '...'
end

use Raven::Rack

get '/' do
'Hello, world!'
end

# the app: end

require 'rspec'
require 'rack/test'

Raven.configure do |config|
logger = ::Logger.new(STDOUT)
logger.level = ::Logger::WARN
config.logger = logger
end

describe 'app' do
include Rack::Test::Methods

def app
@app || Sinatra::Application
end

class TestRavenError < StandardError; end

it 'sends errors to sentry' do
@app = Class.new Sinatra::Application do
get '/' do
raise TestRavenError
end
end
allow(Raven.client).to receive(:send).and_return(true)
begin
get '/'
rescue TestRavenError
end
expect(Raven.client).to have_received(:send)
end
end

Or if raven sending requests is in the way (when tests fail because of raven sending requests, and not because of the underlying error), one can disable them:

Raven.configure(true) do |config|
config.should_send = Proc.new { false }
end

And mock Raven.send_or_skip instead:

...
allow(Raven).to receive(:send_or_skip).and_return(true)
begin
get '/'
rescue TestRavenError
end
expect(Raven).to have_received(:send_or_skip)
...

Toggle Mixpanel Middleware Call in Ruby

it seems that mixpanel have updated their gem

Prevent middleware from inserting code
Note: Only applies when Rack Middleware is setup.

Occasionally you may need to send a request for HTML that you don't want the middleware to alter. In your AJAX request include the header "SKIP_MIXPANEL_MIDDLEWARE" to prevent the mixpanel code from being inserted.

   $.ajax("/path/to/api/endpoint", {
headers: {"Skip-Mixpanel-Middleware": true}, // valid http headers don't allow underscores and get filtered by some webservers
success: function(data) {
// Process data here
} });

//Alternatively, you can add this line of code to your controller to temporarily disable the middleware:

Mixpanel::Middleware.skip_this_request

Taken from:
https://github.com/zevarito/mixpanel#prevent-middleware-from-inserting-code

Ruby on rails: how to exclude certain path from rack middleware authentication?

If you want to exclude only "home/users/" path then you middleware should have following structure,

def call(env)
request = Rack::Request.new(env)
return @app.call(env) if request.path == "home/users/"
# your middleware logic of authentication here.
end

For more information of rack, you can refer this.

Ruby on Rails Rack middleware exclude

Damien Matheiu's answer to the question you link will absolutely work for you. You'll just need to write an appropriate filter expression.

For the example above, that would be something like:

unless env['REQUEST_PATH'].match /^\/api\/v2\/gadgets\/(\d+)\/specs$/
middleware = BasicAuth.new #... args ...
env = middleware.call(env)
end

So you will call the BasicAuth middleware only when the path doesn't match any of your excluded paths.



Related Topics



Leave a reply



Submit