class ActiveModelSerializers::Adapter::JsonApi
Attributes
Public Class Methods
# File lib/active_model_serializers/adapter/json_api.rb, line 38 def self.default_key_transform :dash end
# File lib/active_model_serializers/adapter/json_api.rb, line 42 def self.fragment_cache(cached_hash, non_cached_hash, root = true) core_cached = cached_hash.first core_non_cached = non_cached_hash.first no_root_cache = cached_hash.delete_if { |key, _value| key == core_cached[0] } no_root_non_cache = non_cached_hash.delete_if { |key, _value| key == core_non_cached[0] } cached_resource = (core_cached[1]) ? core_cached[1].deep_merge(core_non_cached[1]) : core_non_cached[1] hash = root ? { root => cached_resource } : cached_resource hash.deep_merge no_root_non_cache.deep_merge no_root_cache end
ActiveModelSerializers::Adapter::Base::new
# File lib/active_model_serializers/adapter/json_api.rb, line 53 def initialize(serializer, options = {}) super @include_directive = JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true) @fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields)) end
Public Instance Methods
{jsonapi.org/format/#errors JSON API Errors} TODO: look into caching definition:
☑ toplevel_errors array (required) ☐ toplevel_meta ☐ toplevel_jsonapi
structure:
{ errors: toplevel_errors, meta: toplevel_meta, jsonapi: toplevel_jsonapi }.reject! {|_,v| v.nil? }
prs:
https://github.com/rails-api/active_model_serializers/pull/1004
# File lib/active_model_serializers/adapter/json_api.rb, line 174 def failure_document hash = {} # PR Please :) # Jsonapi.add!(hash) # toplevel_errors # definition: # array of unique items of type 'error' # structure: # [ # error, # error # ] if serializer.respond_to?(:each) hash[:errors] = serializer.flat_map do |error_serializer| Error.resource_errors(error_serializer, instance_options) end else hash[:errors] = Error.resource_errors(serializer, instance_options) end hash end
# File lib/active_model_serializers/adapter/json_api.rb, line 70 def fragment_cache(cached_hash, non_cached_hash) root = !instance_options.include?(:include) self.class.fragment_cache(cached_hash, non_cached_hash, root) end
{jsonapi.org/format/#crud Requests are transactional, i.e. success or failure} {jsonapi.org/format/#document-top-level data and errors MUST NOT coexist in the same document.}
# File lib/active_model_serializers/adapter/json_api.rb, line 61 def serializable_hash(*) document = if serializer.success? success_document else failure_document end self.class.transform_key_casing!(document, instance_options) end
{jsonapi.org/format/#document-top-level Primary data} definition:
☐ toplevel_data (required) ☐ toplevel_included ☑ toplevel_meta ☑ toplevel_links ☑ toplevel_jsonapi
structure:
{ data: toplevel_data, included: toplevel_included, meta: toplevel_meta, links: toplevel_links, jsonapi: toplevel_jsonapi }.reject! {|_,v| v.nil? }
rubocop:disable Metrics/CyclomaticComplexity
# File lib/active_model_serializers/adapter/json_api.rb, line 91 def success_document is_collection = serializer.respond_to?(:each) serializers = is_collection ? serializer : [serializer] primary_data, included = resource_objects_for(serializers) hash = {} # toplevel_data # definition: # oneOf # resource # array of unique items of type 'resource' # null # # description: # The document's "primary data" is a representation of the resource or collection of resources # targeted by a request. # # Singular: the resource object. # # Collection: one of an array of resource objects, an array of resource identifier objects, or # an empty array ([]), for requests that target resource collections. # # None: null if the request is one that might correspond to a single resource, but doesn't currently. # structure: # if serializable_resource.resource? # resource # elsif serializable_resource.collection? # [ # resource, # resource # ] # else # nil # end hash[:data] = is_collection ? primary_data : primary_data[0] # toplevel_included # alias included # definition: # array of unique items of type 'resource' # # description: # To reduce the number of HTTP requests, servers **MAY** allow # responses that include related resources along with the requested primary # resources. Such responses are called "compound documents". # structure: # [ # resource, # resource # ] hash[:included] = included if included.any? Jsonapi.add!(hash) if instance_options[:links] hash[:links] ||= {} hash[:links].update(instance_options[:links]) end if is_collection && serializer.paginated? hash[:links] ||= {} hash[:links].update(pagination_links_for(serializer)) end hash[:meta] = instance_options[:meta] unless instance_options[:meta].blank? hash end
Private Instance Methods
{jsonapi.org/format/#document-resource-object-attributes Document Resource Object
Attributes} attributes definition:
JSON Object
patternProperties:
^(?!relationships$|links$)\\w[-\\w_]*$
description:
Members of the attributes object ("attributes") represent information about the resource object in which it's defined. Attributes may contain any valid JSON value
structure:
{ foo: 'bar' }
# File lib/active_model_serializers/adapter/json_api.rb, line 296 def attributes_for(serializer, fields) serializer.attributes(fields).except(:id) end
# File lib/active_model_serializers/adapter/json_api.rb, line 338 def data_for(serializer, include_slice) data = serializer.fetch(self) do resource_object = ResourceIdentifier.new(serializer, instance_options).as_json break nil if resource_object.nil? requested_fields = fieldset && fieldset.fields_for(resource_object[:type]) attributes = attributes_for(serializer, requested_fields) resource_object[:attributes] = attributes if attributes.any? resource_object end data.tap do |resource_object| next if resource_object.nil? # NOTE(BF): the attributes are cached above, separately from the relationships, below. requested_associations = fieldset.fields_for(resource_object[:type]) || '*' relationships = relationships_for(serializer, requested_associations, include_slice) resource_object[:relationships] = relationships if relationships.any? end end
{jsonapi.org/format/#document-links Document Links} links definition:
JSON Object
properties:
self : URI related : link
description:
A resource object **MAY** contain references to other resource objects ("relationships"). Relationships may be to-one or to-many. Relationships can be specified by including a member in a resource's links object. A `self` member’s value is a URL for the relationship itself (a "relationship URL"). This URL allows the client to directly manipulate the relationship. For example, it would allow a client to remove an `author` from an `article` without deleting the people resource itself.
structure:
{ self: 'http://example.com/etc', related: link }.reject! {|_,v| v.nil? }
# File lib/active_model_serializers/adapter/json_api.rb, line 485 def links_for(serializer) serializer._links.each_with_object({}) do |(name, value), hash| next if value.excluded?(serializer) result = Link.new(serializer, value.block).as_json hash[name] = result if result end end
{jsonapi.org/format/#document-meta Docment Meta}
# File lib/active_model_serializers/adapter/json_api.rb, line 529 def meta_for(serializer) Meta.new(serializer).as_json end
{jsonapi.org/format/#fetching-pagination Pagination Links} pagination definition:
first : pageObject last : pageObject prev : pageObject next : pageObject
structure:
{ first: pageObject, last: pageObject, prev: pageObject, next: pageObject }
pageObject definition:
oneOf URI null
description:
The <x> page of data
structure:
if has_page? 'http://example.com/some-page?page[number][x]' else nil end
prs:
https://github.com/rails-api/active_model_serializers/pull/1041
# File lib/active_model_serializers/adapter/json_api.rb, line 524 def pagination_links_for(serializer) PaginationLinks.new(serializer.object, instance_options).as_json end
# File lib/active_model_serializers/adapter/json_api.rb, line 269 def process_relationship(serializer, include_slice) if serializer.respond_to?(:each) serializer.each { |s| process_relationship(s, include_slice) } return end return unless serializer && serializer.object return unless process_resource(serializer, false, include_slice) process_relationships(serializer, include_slice) end
# File lib/active_model_serializers/adapter/json_api.rb, line 262 def process_relationships(serializer, include_slice) serializer.associations(include_slice).each do |association| # TODO(BF): Process relationship without evaluating lazy_association process_relationship(association.lazy_association.serializer, include_slice[association.key]) end end
# File lib/active_model_serializers/adapter/json_api.rb, line 248 def process_resource(serializer, primary, include_slice = {}) resource_identifier = ResourceIdentifier.new(serializer, instance_options).as_json return false unless @resource_identifiers.add?(resource_identifier) resource_object = resource_object_for(serializer, include_slice) if primary @primary << resource_object else @included << resource_object end true end
{jsonapi.org/format/#document-resource-object-relationships Document Resource Object
Relationship} relationships definition:
JSON Object
patternProperties:
^\\w[-\\w_]*$"
properties:
data : relationshipsData links meta
description:
Members of the relationships object ("relationships") represent references from the resource object in which it's defined to other resource objects."
structure:
{ links: links, meta: meta, data: relationshipsData }.reject! {|_,v| v.nil? }
prs:
links [x] https://github.com/rails-api/active_model_serializers/pull/1454 meta [x] https://github.com/rails-api/active_model_serializers/pull/1454 polymorphic [ ] https://github.com/rails-api/active_model_serializers/pull/1420
relationshipsData definition:
oneOf relationshipToOne relationshipToMany
description:
Member, whose value represents "resource linkage"
structure:
if has_one? relationshipToOne else relationshipToMany end
definition:
anyOf null linkage
relationshipToOne description:
References to other resource objects in a to-one ("relationship"). Relationships can be specified by including a member in a resource's links object. None: Describes an empty to-one relationship.
structure:
if has_related? linkage else nil end
relationshipToMany definition:
array of unique items of type 'linkage'
description:
An array of objects each containing "type" and "id" members for to-many relationships
structure:
[ linkage, linkage ]
prs:
polymorphic [ ] https://github.com/rails-api/active_model_serializers/pull/1282
linkage definition:
type (required) : String id (required) : String meta
description:
The "type" and "id" to non-empty members.
structure:
{ type: 'required-type', id: 'required-id', meta: meta }.reject! {|_,v| v.nil? }
# File lib/active_model_serializers/adapter/json_api.rb, line 452 def relationships_for(serializer, requested_associations, include_slice) include_directive = JSONAPI::IncludeDirective.new( requested_associations, allow_wildcard: true ) serializer.associations(include_directive, include_slice).each_with_object({}) do |association, hash| hash[association.key] = Relationship.new(serializer, instance_options, association).as_json end end
{jsonapi.org/format/#document-resource-objects Document Resource Objects}
# File lib/active_model_serializers/adapter/json_api.rb, line 301 def resource_object_for(serializer, include_slice = {}) resource_object = data_for(serializer, include_slice) # toplevel_links # definition: # allOf # ☐ links # ☐ pagination # # description: # Link members related to the primary data. # structure: # links.merge!(pagination) # prs: # https://github.com/rails-api/active_model_serializers/pull/1247 # https://github.com/rails-api/active_model_serializers/pull/1018 if (links = links_for(serializer)).any? resource_object ||= {} resource_object[:links] = links end # toplevel_meta # alias meta # definition: # meta # structure # { # :'git-ref' => 'abc123' # } if (meta = meta_for(serializer)).present? resource_object ||= {} resource_object[:meta] = meta end resource_object end
{jsonapi.org/format/#document-resource-objects Primary data} resource definition:
JSON Object
properties:
type (required) : String id (required) : String attributes relationships links meta
description:
"Resource objects" appear in a JSON API document to represent resources
structure:
{ type: 'admin--some-user', id: '1336', attributes: attributes, relationships: relationships, links: links, meta: meta, }.reject! {|_,v| v.nil? }
prs:
type https://github.com/rails-api/active_model_serializers/pull/1122 [x] https://github.com/rails-api/active_model_serializers/pull/1213 https://github.com/rails-api/active_model_serializers/pull/1216 https://github.com/rails-api/active_model_serializers/pull/1029 links [x] https://github.com/rails-api/active_model_serializers/pull/1246 [x] url helpers https://github.com/rails-api/active_model_serializers/issues/1269 meta [x] https://github.com/rails-api/active_model_serializers/pull/1340
# File lib/active_model_serializers/adapter/json_api.rb, line 238 def resource_objects_for(serializers) @primary = [] @included = [] @resource_identifiers = Set.new serializers.each { |serializer| process_resource(serializer, true, @include_directive) } serializers.each { |serializer| process_relationships(serializer, @include_directive) } [@primary, @included] end