File: response_middleware.rb

package info (click to toggle)
ruby-faraday-middleware 1.2.0-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 376 kB
  • sloc: ruby: 2,388; sh: 15; makefile: 6
file content (119 lines) | stat: -rw-r--r-- 3,011 bytes parent folder | download
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# frozen_string_literal: true

require 'faraday'

# Main FaradayMiddleware module.
module FaradayMiddleware
  # Internal: The base class for middleware that parses responses.
  class ResponseMiddleware < Faraday::Middleware
    CONTENT_TYPE = 'Content-Type'

    class << self
      attr_accessor :parser
    end

    # Store a Proc that receives the body and returns the parsed result.
    def self.define_parser(parser = nil, &block)
      @parser = parser ||
                block  ||
                raise(ArgumentError, 'Define parser with a block')
    end

    def self.inherited(subclass)
      super
      subclass.load_error = load_error if subclass.respond_to? :load_error=
      subclass.parser = parser
    end

    def initialize(app = nil, options = {})
      super(app)
      @options = options
      @parser_options = options[:parser_options]
      @content_types = Array(options[:content_type])
    end

    def call(environment)
      @app.call(environment).on_complete do |env|
        process_response(env) if process_response_type?(response_type(env)) && parse_response?(env)
      end
    end

    def process_response(env)
      env[:raw_body] = env[:body] if preserve_raw?(env)
      env[:body] = parse(env[:body])
    rescue Faraday::ParsingError => e
      raise Faraday::ParsingError.new(e.wrapped_exception, env[:response])
    end

    # Parse the response body.
    #
    # Instead of overriding this method, consider using `define_parser`.
    def parse(body)
      if self.class.parser
        begin
          self.class.parser.call(body, @parser_options)
        rescue StandardError, SyntaxError => e
          raise e if e.is_a?(SyntaxError) &&
                     e.class.name != 'Psych::SyntaxError'

          raise Faraday::ParsingError, e
        end
      else
        body
      end
    end

    def response_type(env)
      type = env[:response_headers][CONTENT_TYPE].to_s
      type = type.split(';', 2).first if type.index(';')
      type
    end

    def process_response_type?(type)
      @content_types.empty? || @content_types.any? do |pattern|
        pattern.is_a?(Regexp) ? type =~ pattern : type == pattern
      end
    end

    def parse_response?(env)
      env[:body].respond_to? :to_str
    end

    def preserve_raw?(env)
      env[:request].fetch(:preserve_raw, @options[:preserve_raw])
    end
  end

  # DRAGONS
  module OptionsExtension
    attr_accessor :preserve_raw

    def to_hash
      super.update(preserve_raw: preserve_raw)
    end

    def each
      return to_enum(:each) unless block_given?

      super
      yield :preserve_raw, preserve_raw
    end

    def fetch(key, *args)
      if key == :preserve_raw
        value = __send__(key)
        value.nil? ? args.fetch(0) : value
      else
        super
      end
    end
  end

  if defined?(Faraday::RequestOptions)
    begin
      Faraday::RequestOptions.from(preserve_raw: true)
    rescue NoMethodError
      Faraday::RequestOptions.include OptionsExtension
    end
  end
end