class JSONAPI::Parser::Document

Constants

JSONAPI_OBJECT_KEYS
RELATIONSHIP_KEYS
RESOURCE_IDENTIFIER_KEYS
TOP_LEVEL_KEYS

Public Class Methods

ensure!(condition, message) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 183
def self.ensure!(condition, message)
  raise InvalidDocument, message unless condition
end
parse!(document) click to toggle source

Validate the structure of a JSONAPI response document.

@param [Hash] document The input JSONAPI document. @raise [JSONAPI::Parser::InvalidDocument] if document is invalid.

# File lib/jsonapi/parser/document.rb, line 16
def self.parse!(document)
  ensure!(document.is_a?(Hash),
          'A JSON object MUST be at the root of every JSON API request ' \
          'and response containing data.')
  ensure!(!(document.keys & TOP_LEVEL_KEYS).empty?,
          "A document MUST contain at least one of #{TOP_LEVEL_KEYS}.")
  ensure!(!(document.key?('data') && document.key?('errors')),
          'The members data and errors MUST NOT coexist in the same ' \
          'document.')
  ensure!(document.key?('data') || !document.key?('included'),
          'If a document does not contain a top-level data key, the ' \
          'included member MUST NOT be present either.')
  parse_data!(document['data']) if document.key?('data')
  parse_errors!(document['errors']) if document.key?('errors')
  parse_meta!(document['meta']) if document.key?('meta')
  parse_jsonapi!(document['jsonapi']) if document.key?('jsonapi')
  parse_included!(document['included']) if document.key?('included')
  parse_links!(document['links']) if document.key?('links')
end
parse_attributes!(attrs) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 67
def self.parse_attributes!(attrs)
  ensure!(attrs.is_a?(Hash),
          'The value of the attributes key MUST be an object.')
end
parse_data!(data) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 37
def self.parse_data!(data)
  if data.is_a?(Hash)
    parse_resource!(data)
  elsif data.is_a?(Array)
    data.each { |res| parse_resource!(res) }
  elsif data.nil?
    # Do nothing
  else
    ensure!(false,
            'Primary data must be either nil, an object or an array.')
  end
end
parse_error!(_error) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 177
def self.parse_error!(_error)
  # NOTE(beauby): Do nothing for now, as errors are under-specified as of
  #   JSONAPI 1.0
end
parse_errors!(errors) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 170
def self.parse_errors!(errors)
  ensure!(errors.is_a?(Array),
          'Top level errors member must be an array.')
  errors.each { |error| parse_error!(error) }
end
parse_included!(included) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 163
def self.parse_included!(included)
  ensure!(included.is_a?(Array),
          'Top level included member must be an array.')
  included.each { |res| parse_resource!(res) }
end
parse_jsonapi!(jsonapi) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 149
def self.parse_jsonapi!(jsonapi)
  ensure!(jsonapi.is_a?(Hash), 'A JSONAPI object must be an object.')
  unexpected_keys = jsonapi.keys - JSONAPI_OBJECT_KEYS
  ensure!(unexpected_keys.empty?,
          'Unexpected members for JSONAPI object: ' \
          "#{JSONAPI_OBJECT_KEYS}.")
  if jsonapi.key?('version')
    ensure!(jsonapi['version'].is_a?(String),
            "Value of JSONAPI's version member must be a string.")
  end
  parse_meta!(jsonapi['meta']) if jsonapi.key?('meta')
end
parse_meta!(meta) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 144
def self.parse_meta!(meta)
  ensure!(meta.is_a?(Hash), 'A meta object must be an object.')
end
parse_primary_resource!(res) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 51
def self.parse_primary_resource!(res)
  ensure!(res.is_a?(Hash), 'A resource object must be an object.')
  ensure!(res.key?('type'), 'A resource object must have a type.')
  parse_attributes!(res['attributes']) if res.key?('attributes')
  parse_relationships!(res['relationships']) if res.key?('relationships')
  parse_links!(res['links']) if res.key?('links')
  parse_meta!(res['meta']) if res.key?('meta')
end
parse_relationship!(rel) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 80
def self.parse_relationship!(rel)
  ensure!(rel.is_a?(Hash), 'A relationship object must be an object.')
  ensure!(!rel.keys.empty?,
          'A relationship object MUST contain at least one of ' \
          "#{RELATIONSHIP_KEYS}")
  parse_relationship_data!(rel['data']) if rel.key?('data')
  parse_relationship_links!(rel['links']) if rel.key?('links')
  parse_meta!(rel['meta']) if rel.key?('meta')
end
parse_relationship_data!(data) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 91
def self.parse_relationship_data!(data)
  if data.is_a?(Hash)
    parse_resource_identifier!(data)
  elsif data.is_a?(Array)
    data.each { |ri| parse_resource_identifier!(ri) }
  elsif data.nil?
    # Do nothing
  else
    ensure!(false, 'Relationship data must be either nil, an object or ' \
                   'an array.')
  end
end
parse_relationships!(rels) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 73
def self.parse_relationships!(rels)
  ensure!(rels.is_a?(Hash),
          'The value of the relationships key MUST be an object')
  rels.values.each { |rel| parse_relationship!(rel) }
end
parse_resource!(res) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 61
def self.parse_resource!(res)
  parse_primary_resource!(res)
  ensure!(res.key?('id'), 'A resource object must have an id.')
end
parse_resource_identifier!(ri) click to toggle source

@api private

# File lib/jsonapi/parser/document.rb, line 105
def self.parse_resource_identifier!(ri)
  ensure!(ri.is_a?(Hash),
          'A resource identifier object must be an object')
  ensure!(RESOURCE_IDENTIFIER_KEYS & ri.keys == RESOURCE_IDENTIFIER_KEYS,
          'A resource identifier object MUST contain ' \
          "#{RESOURCE_IDENTIFIER_KEYS} members.")
  ensure!(ri['id'].is_a?(String), 'Member id must be a string.')
  ensure!(ri['type'].is_a?(String), 'Member type must be a string.')
  parse_meta!(ri['meta']) if ri.key?('meta')
end