Middleware is very useful for writing logic that is not specific to your web application, such as authenticating the request, logging, or error handling. It focuses on doing one thing and doing it well.

Middleware sits between the user and the application code. When an HTTP request comes in, the middleware can intercept, examine, and modify it. Similarly, it can examine and modify the HTTP response before forwarding it to the user.

Middleware provides a convenient mechanism for inspecting and filtering HTTP requests entering your application. For example, Rails includes the Rack::MethodOverride middleware that inspects and overrides the HTTP verb of the incoming request.

Using middleware simplifies your application code, and it can only focus on the logic related to the application.

Authentication is another good use case for middleware. If the user is not authenticated, the middleware will redirect the user to your application's login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application.

You can write middleware to perform a variety of tasks besides authentication. For example, as we'll see later, a logging middleware logs all incoming requests to your application.

There are several middleware (is 'middlewares' a word?) included in the Rails framework. You can see a list of all middleware by running the bin/rails middleware command. The Rails guides also provide a brief description of what each middleware does.

Middleware can perform tasks before or after passing the request deeper into the application. For example, the following middleware performs some task both before and after the request is handled by the application:

module Middleware
  class DoSomething
    def initialize(app)
      @app = app
    end

    def call(env)
      # perform something before passing the request to the application
      process_request(env)

      response = @app.call(env)

      # perform something after receiving the response from the application. 
      # It should also return the response.
      process_response(response)
    end
  end
end

No matter where a middleware performs its action, it still has to return a valid Rack-compatible response to the next middleware in the pipeline, or the web server.

In the next section, we'll learn how you can create your own middleware.