Class: FaradayJSON::EncodeJson

Inherits:
Faraday::Middleware
  • Object
show all
Includes:
Encoding
Defined in:
lib/faraday_json/encode_json.rb

Overview

Request middleware that encodes the body as JSON.

Processes only requests with matching Content-type or those without a type. If a request doesn’t have a type but has a body, it sets the Content-type to JSON MIME-type.

Doesn’t try to encode bodies that already are in string form.

Constant Summary collapse

CONTENT_TYPE =
'Content-Type'.freeze
CONTENT_LENGTH =
'Content-Length'.freeze
MIME_TYPE =
'application/json'.freeze
MIME_TYPE_UTF8 =
'application/json; charset=utf-8'.freeze

Instance Method Summary collapse

Methods included from Encoding

#bin_to_hex, #get_bom, #get_canonical_encoding, #get_dominant_encoding, #strip_bom, #to_utf8, #transcode

Instance Method Details

#call(env) ⇒ Object



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
# File 'lib/faraday_json/encode_json.rb', line 32

def call(env)
  if process_request?(env)
    body = env[:body]

    # Detect and honour input charset. Basically, all requests without a
    # charset should be considered malformed, but we can make a best guess.
    # Whether the body is a string or another data structure does not
    # matter: all strings *contained* within it must be encoded properly.
    charset = request_charset(env)

    # Strip BOM, if any
    body = strip_bom(body, charset, { 'default_encoding' => 'us-ascii' })

    # Transcode to UTF-8
    body = to_utf8(body, charset, { 'force_input_charset' => true })

    # If the body is a stirng, we assume it's already JSON. No further
    # processing is necessary.
    # XXX Is :to_str really a good indicator for Strings? Taken from old
    #     code.
    if not body.respond_to?(:to_str)
      # If body isn't a string yet, we need to encode it. We also know it's
      # then going to be UTF-8, because JSON defaults to that.
      # Thanks to to_utf8 above, JSON.dump should not have any issues here.
      body = ::JSON.dump(body)
    end

    env[:body] = body

    # We'll add a content length, because otherwise we're relying on every
    # component down the line properly interpreting UTF-8 - that can fail.
    env[:request_headers][CONTENT_LENGTH] ||= env[:body].bytesize

    # Always base the encoding we're sending in the content type header on
    # the string encoding.
    env[:request_headers][CONTENT_TYPE] = MIME_TYPE_UTF8
  end
  @app.call env
end

#has_body?(env) ⇒ Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/faraday_json/encode_json.rb', line 84

def has_body?(env)
  body = env[:body] and !(body.respond_to?(:to_str) and body.empty?)
end

#process_request?(env) ⇒ Boolean

Returns:

  • (Boolean)


72
73
74
75
# File 'lib/faraday_json/encode_json.rb', line 72

def process_request?(env)
  type = request_type(env)
  has_body?(env) and (type.empty? or type == MIME_TYPE)
end

#request_charset(env) ⇒ Object



77
78
79
80
81
82
# File 'lib/faraday_json/encode_json.rb', line 77

def request_charset(env)
  enc = env[:request_headers][CONTENT_TYPE].to_s
  enc = enc.split(';', 2).last if enc.index(';')
  enc = enc.split('=', 2).last if enc.index('=')
  return enc
end

#request_type(env) ⇒ Object



88
89
90
91
92
# File 'lib/faraday_json/encode_json.rb', line 88

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