class Grape::Formatter::Hal::Json

Public Class Methods

call(body, env) click to toggle source

Formats a Grape end-point body using JSON-formatted hypertext application language. Assumes that the body is a hypertext-application-language representation, either a resource or collection of resources.

Derives the end-point's request URL using only the plain Rack environment if necessary; doing so assumes nothing about any higher-level framework, e.g. Grape or Sinatra. Uses the base URL to adjust all the relative hypertext references. They become absolute references; meaning not relative, i.e. the reference does not include a scheme. Applies this adjustment to the representation itself as well as all the embedded representations if any.

Automatically converts the body to a hypertext-application-language representation unless the body is already such a HAL representation. Passes the Rack environment to the HAL converter. Converters can use the environment to extract addressing information for the representation's links, including the self link.

Handles arrays of objects if, and only if, the elements themselves respond to to_hal. In such cases, it replaces the array body with a HAL representation conforming to a HAL collection where the collection representation includes links to the elements in the collection as well as embedding the nested resources. Uses the request path for the self link; and uses the last element of the path as the relation. Uses duck typing to determine if the body is an array or not. If the body responds to each then it assumes that the response is some kind of enumeration.

# File lib/grape/formatter/hal/json.rb, line 34
def self.call(body, env)
  unless body.is_a?(HypertextApplicationLanguage::Representation)
    if body.respond_to?(:each)
      representation = HypertextApplicationLanguage::Representation.new

      href = env['REQUEST_PATH']
      representation.with_link(HypertextApplicationLanguage::Link::SELF_REL, href)

      rel = env['PATH_INFO'].split('/').last
      body.each do |resource|
        next unless resource.respond_to?(:to_hal)
        resource_representation = resource.to_hal(env: env)
        representation.with_link(rel, resource_representation.link.href)
        representation.with_representation(rel, resource_representation)
      end

      properties = env['hypertext_application_language.collection.properties']
      representation.properties = properties if properties

      body = representation
    else
      return body unless body.respond_to?(:to_hal)
      body = body.to_hal(env: env)
    end
  end

  endpoint = env['api.endpoint']
  request = endpoint ? endpoint.request : Rack::Request.new(env)
  base_uri = Addressable::URI.parse(request.base_url + request.script_name + '/')

  representations = [body] + body.representations
  representations.map(&:links).flatten.each do |link|
    uri = Addressable::URI.parse(link.href)
    link.href = base_uri.join(uri).to_s unless uri.absolute?
  end

  renderer = HypertextApplicationLanguage::HashRepresentationRenderer.new
  JSON.pretty_generate(renderer.render(body))
end