File: middleware.rb

package info (click to toggle)
ruby-versionist 2.0.1-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 244 kB
  • sloc: ruby: 798; makefile: 3
file content (42 lines) | stat: -rw-r--r-- 1,621 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
module Versionist
  # When your routes don't include an explicit format in the URL (i.e. `match 'foos.(:format)' => foos#index`),
  # Rails inspects the `Accept` header to determine the requested format. Since an `Accept` header can have multiple values,
  # Rails uses the first one present to determine the format. If your custom version header happens to be the first value
  # in the `Accept` header, it would incorrectly be interpretted as the format. This middleware moves your custom version header
  # (if found) to the end of the `Accept` header so as to not interfere with this format logic in Rails.
  class Middleware

    ACCEPT = "Accept"
    HTTP_ACCEPT = "HTTP_ACCEPT"
    
    def initialize(app)
      @app = app
    end

    def call(env)
      dup._call(env)
    end

    def _call(env)
      request = ::Rack::Request.new(env)
      potential_matches = Versionist.configuration.header_versions.select {|hv| hv.config[:header][:name] == ACCEPT && env[HTTP_ACCEPT].try(:include?, hv.config[:header][:value])}
      if !potential_matches.empty?
        strategy = potential_matches.max {|a,b| a.config[:header][:value].length <=> b.config[:header][:value].length}
      end
      if !strategy.nil?
        entries = env[HTTP_ACCEPT].split(',')
        index = -1
        entries.each_with_index do |e, i|
          e.strip!
          index = i if e == strategy.config[:header][:value]
        end
        if (index != -1)
          version = entries.delete_at(index)
          entries << version
        end
        env[HTTP_ACCEPT] = entries.join(", ")
      end
      @app.call(env)
    end
  end
end