Martin Catty
04 01 2011

Place aux middlewares avec rack

posté par dans les catégories ruby

Créer son middleware

Dans mon introduction à rack je vous ai laissé sur votre faim concernant la création de middleware.

Nous allons donc voir comment faire un mini-logger.

Tout d’abord ne pas oublier de rajouter le dossier lib dans l’autoload:

  module App
    class Application < Rails::Application
      config.autoload_paths += %W(#{config.root}/lib)
    end
  end

Ensuite on crée une class Tracking dans notre dossier lib:

  class Tracking
    def initialize(app)
      @app = app
    end

    def call(env)
      request = Rack::Request.new(env)
      File.open(File.join(Rails.root, "log", "custom.log"), "a") do |f|
       f << "IP: #{request.ip}, PATH: #{request.path}, PARAMS: #{request.params}\n"
      end
      @app.call(env)
    end
  end

Et voilà notre middleware d’une 10aine de ligne.

Quelques explications:

  • Le constructeur se contente de placer l’objet app dans une variable d’instance pour pouvoir y accéder depuis call.
  • call prend l’environnement en entrée. Les middlewares sont chaînés, ce qui permet de modifier l’environnement d’un middleware à l’autre.

Par exemple je pourrai définir env[‘foo’] = ‘bar’ et y avoir accès dans le middleware suivant.

L’invocation de app.call(env) va renvoyer le status de la requête (code http, ex: 200), les entêtes et la réponse. Le middleware peut donc modifier ces 3 éléments.

Ici nous nous contentons de parser la requête à partir de l’environnement entrant à l’aide de rack. Ensuite nous avons accès à toutes les méthodes classiques de request.

Inclure son middleware

Dans notre fichier d’environnement, par exemple developement.rb il suffit de définir les middlewares de la sorte:

  App::Application.configure do
    config.middleware.delete("Rails::Rack::Logger")
    config.middleware.insert_after("ActionDispatch::ParamsParser", "Tracking")
    # config.middleware.use("Tracking")
  end

Il est important de bien utiliser les versions quotées des classes. L’utilisation de la constante entrainerait une exception, car la classe ne serait pas encore chargée.

On a ici commencé par retirer le logger de rack pour ajouter notre middleware après le parser. La dernière ligne montre l’utilisation de use, qui permet d’ajouter le middleware en fin de liste.

On remarque que Rails 3 est vraiment modulable, l’ajout ou la suppression d’un middleware est très simple, rendant le framework très souple.

Analyse d’un middleware existant: Etag

Bon, notre middleware est vraiment basique, mais vous allez voir qu’un middleware plus pratique tel qu’Etag ne fait pas grand chose de plus compliqué.

  require 'digest/md5'

  module Rack
    # Automatically sets the ETag header on all String bodies
    class ETag
      def initialize(app)
        @app = app
      end

      def call(env)
        status, headers, body = @app.call(env)

        if !headers.has_key?('ETag')
          digest, body = digest_body(body)
          headers['ETag'] = %("#{digest}")
        end

        [status, headers, body]
      end

      private
        def digest_body(body)
          digest = Digest::MD5.new
          parts = []
          body.each do |part|
            digest << part
            parts << part
          end
          [digest.hexdigest, parts]
        end
    end
  end

L’initialisation est identique. Le call va récupérer le status, les entêtes et la requête.

Ensuite le contenu de la requête est hashé et un entête Etag avec le checksum MD5 ajouté, ce qui permettra au serveur de servir directement le contenu s’il a déjà été calculé.

Et c’est tout !

L’équipe Synbioz.

Libres d’être ensemble.

Articles connexes

04 12 2012

Dragonfly et Fineuploader

Aujourd’hui, je voudrais partager une astuce pour faire fonctionner Dragonfly et Fineuploader ensemble. Fineuploader permet de fournir une expérience d’envoi de fichier intuitive et visuelle pour l’…

Lire la suite

Ajouter un commentaire

Notre expérience vous intéresse ? Inscrivez-vous à nos articles !

×

Newsletter

Rejoignez-nous !

Poursuivons la conversation

N° Vert
0 805 69 35 35

Nos dernières nouvelles

Nos derniers tweets

RT @tayebM: @_fuse pour "https://t.co/aOw3wiSJTz" il faudra peut être ajouter un espace traduction? pleins de gens seraient intéressés, sin…

Présentation d’#angular avec exemples à l’appui https://t.co/kyM0HPtqNQ

#hackademy Et vous, quels sujets aimeriez vous voir traités en vidéo ?