class Graphiti::Deserializer

Responsible for parsing incoming write payloads

Given a PUT payload like:

{
  data: {
    id: '1',
    type: 'posts',
    attributes: { title: 'My Title' },
    relationships: {
      author: {
        data: {
          id: '1',
          type: 'authors'
        }
      }
    }
  },
  included: [
    {
      id: '1'
      type: 'authors',
      attributes: { name: 'Joe Author' }
    }
  ]
}

You can now easily deal with this payload:

deserializer.attributes
# => { id: '1', title: 'My Title' }
deserializer.meta
# => { type: 'posts', method: :update }
deserializer.relationships
# {
#   author: {
#     meta: { ... },
#     attributes: { ... },
#     relationships: { ... }
#   }
# }

When creating objects, we accept a temp-id so that the client can track the object it just created. Expect this in meta:

{ type: 'authors', method: :create, temp_id: 'abc123' }

Attributes

attributes[W]

Override the attributes # @see attributes

Public Class Methods

new(payload = {}) click to toggle source
# File lib/graphiti/deserializer.rb, line 48
def initialize(payload = {})
  @payload = payload
  @payload = @payload[:_jsonapi] if @payload.key?(:_jsonapi)
end

Public Instance Methods

attributes() click to toggle source

@return [Hash] the raw :attributes hash + id

# File lib/graphiti/deserializer.rb, line 68
def attributes
  @attributes ||= raw_attributes.tap do |hash|
    hash[:id] = id if id
  end
end
data() click to toggle source

@return [Hash] the raw :data value of the payload

# File lib/graphiti/deserializer.rb, line 58
def data
  @payload.fetch(:data, {})
end
id() click to toggle source

@return [String] the raw :id value of the payload

# File lib/graphiti/deserializer.rb, line 63
def id
  data[:id]
end
include_hash(memo = {}, relationship_node = nil) click to toggle source
# File lib/graphiti/deserializer.rb, line 99
def include_hash(memo = {}, relationship_node = nil)
  relationship_node ||= relationships

  relationship_node.each_pair do |name, relationship_payload|
    merge_include_hash(memo, name, relationship_payload)
  end

  memo
end
meta(action: :update) click to toggle source

‘meta’ information about this resource. Includes:

type: the jsonapi type method: create/update/destroy/disassociate. Based on the request env or the method within the relationships hash temp_id: the temp-id, if specified

@return [Hash]

# File lib/graphiti/deserializer.rb, line 85
def meta(action: :update)
  {
    type: data[:type],
    temp_id: data[:'temp-id'],
    method: action,
    payload_path: ["data"]
  }
end
params() click to toggle source
# File lib/graphiti/deserializer.rb, line 53
def params
  @payload
end
relationships() click to toggle source

@return [Hash] the relationships hash

# File lib/graphiti/deserializer.rb, line 95
def relationships
  @relationships ||= process_relationships(raw_relationships)
end

Private Instance Methods

deep_merge!(a, b) click to toggle source
# File lib/graphiti/deserializer.rb, line 138
def deep_merge!(a, b)
  Graphiti::Util::Hash.deep_merge!(a, b)
end
included() click to toggle source
# File lib/graphiti/deserializer.rb, line 120
def included
  @payload[:included] || []
end
merge_include_hash(memo, name, relationship_payload) click to toggle source
# File lib/graphiti/deserializer.rb, line 111
def merge_include_hash(memo, name, relationship_payload)
  arrayified = [relationship_payload].flatten
  return if arrayified.all? { |rp| removed?(rp) }

  memo[name] ||= {}
  deep_merge!(memo[name], nested_include_hashes(memo[name], arrayified))
  memo
end
nested_include_hashes(memo, relationship_payloads) click to toggle source
# File lib/graphiti/deserializer.rb, line 129
def nested_include_hashes(memo, relationship_payloads)
  {}.tap do |subs|
    relationship_payloads.each do |rp|
      nested = include_hash(memo, rp[:relationships])
      deep_merge!(subs, nested)
    end
  end
end
process_relationship(relationship_data) click to toggle source
# File lib/graphiti/deserializer.rb, line 154
def process_relationship(relationship_data)
  if relationship_data.is_a?(Array)
    relationship_data.map do |rd|
      process_relationship_datum(rd)
    end
  else
    process_relationship_datum(relationship_data)
  end
end
process_relationship_datum(datum) click to toggle source
# File lib/graphiti/deserializer.rb, line 164
def process_relationship_datum(datum)
  temp_id = datum[:'temp-id']
  included_object = included.find { |i|
    next unless i[:type] == datum[:type]

    (i[:id] && i[:id] == datum[:id]) ||
      (i[:'temp-id'] && i[:'temp-id'] == temp_id)
  }
  included_idx = included.index(included_object)

  included_object ||= {}
  included_object[:relationships] ||= {}

  attributes = included_object[:attributes] || {}
  attributes[:id] = datum[:id] if datum[:id]
  relationships = process_relationships(included_object[:relationships] || {})
  method = datum[:method]
  method = method.to_sym if method

  {
    meta: {
      jsonapi_type: datum[:type],
      temp_id: temp_id,
      method: method,
      payload_path: ["included", included_idx]
    },
    attributes: attributes,
    relationships: relationships
  }
end
process_relationships(relationship_hash) click to toggle source
# File lib/graphiti/deserializer.rb, line 142
def process_relationships(relationship_hash)
  {}.tap do |hash|
    relationship_hash.each_pair do |name, relationship_payload|
      name = name.to_sym

      if relationship_payload[:data]
        hash[name] = process_relationship(relationship_payload[:data])
      end
    end
  end
end
raw_attributes() click to toggle source
# File lib/graphiti/deserializer.rb, line 195
def raw_attributes
  data.fetch(:attributes, {})
end
raw_relationships() click to toggle source
# File lib/graphiti/deserializer.rb, line 199
def raw_relationships
  data.fetch(:relationships, {})
end
removed?(relationship_payload) click to toggle source
# File lib/graphiti/deserializer.rb, line 124
def removed?(relationship_payload)
  method = relationship_payload[:meta][:method]
  [:disassociate, :destroy].include?(method)
end