lib/ridley/middleware/parse_json.rb
module Ridley
module Middleware
class ParseJson < Faraday::Response::Middleware
include Ridley::Logging
JSON_TYPE = 'application/json'.freeze
BRACKETS = [
"[",
"{"
].freeze
WHITESPACE = [
" ",
"\n",
"\r",
"\t"
].freeze
class << self
include Ridley::Logging
# Takes a string containing JSON and converts it to a Ruby hash
# symbols for keys
#
# @param [String] body
#
# @return [Hash]
def parse(body)
result = JSON.parse(body)
result.is_a?(Hash) ? Hashie::Mash.new(result) : result
end
# Extracts the type of the response from the response headers
# of a Faraday request env. 'text/html' will be returned if no
# content-type is specified in the response
#
# @example
# env = {
# :response_headers => {
# 'content-type' => 'text/html; charset=utf-8'
# }
# ...
# }
#
# ParseJson.response_type(env) => 'application/json'
#
# @param [Hash] env
# a Faraday request env
#
# @return [String]
def response_type(env)
if env[:response_headers][CONTENT_TYPE].nil?
log.debug { "response did not specify a content type" }
return "text/html"
end
env[:response_headers][CONTENT_TYPE].split(';', 2).first
end
# Determines if the response of the given Faraday request env
# contains JSON
#
# @param [Hash] env
# a Faraday request env
#
# @return [Boolean]
def json_response?(env)
response_type(env) == JSON_TYPE && looks_like_json?(env)
end
# Examines the body of a request env and returns true if it appears
# to contain JSON or false if it does not
#
# @param [Hash] env
# a Faraday request env
# @return [Boolean]
def looks_like_json?(env)
return false unless env[:body].present?
BRACKETS.include?(first_char(env[:body]))
end
private
def first_char(body)
idx = -1
begin
char = body[idx += 1]
char = char.chr if char
end while char && WHITESPACE.include?(char)
char
end
end
def on_complete(env)
if self.class.json_response?(env)
log.debug { "==> parsing Chef response body as JSON" }
env[:body] = self.class.parse(env[:body])
else
log.debug { "==> Chef response did not contain a JSON body" }
end
end
end
end
end
Faraday::Response.register_middleware parse_json: Ridley::Middleware::ParseJson