abstract class FastJSONAPISerializer::Base(T)
- FastJSONAPISerializer::Base(T)
- Reference
- Object
Overview
Base serialization superclass.
Considering you have various models - which can be from an ORM or just simple classes
class Address
getter id
property street
def initialize(@id = 101, @street = "some street")
end
end
class PostCode
getter id
property code
def initialize(@id = 101, @code = "code 24")
end
end
class Restaurant
property name,
address : Nil | Address = nil,
post_code : Nil | PostCode = nil,
rooms : Array(Room) = [] of Room
def initialize(@name = "big burgers")
end
def rating
"Great!"
end
# optional static id
def id
1
end
def tables
[Table.new(1), Table.new(2), Table.new(3)]
end
end
class Room
property id : Int32 = 1,
tables : Array(Table) = [] of Table
def initialize(@id)
end
def name
"#{id}-name"
end
end
class Table
property number
def initialize(@number = 1)
end
def room
Room.new(number)
end
def id
number
end
end
You can define various serializers
class AddressSerializer < FastJSONAPISerializer::Base(Address)
attributes :street
type "address" # be specific about the JSON-API type - default to Model camelcase
end
class PostCodeSerializer < FastJSONAPISerializer::Base(PostCode)
attributes :code
end
class RestaurantSerializer < FastJSONAPISerializer::Base(Restaurant)
attribute :name
attribute :rating, :Rating, if: :test_rating
attribute :own_field
belongs_to :address, serializer: AddressSerializer # option key-word args
has_one :post_code, PostCodeSerializer
has_many :rooms, RoomSerializer
has_many :tables, TableSerializer, :Tables
def test_rating(object, options)
options.nil? || !options[:test]?
end
def own_field(_object, _options)
12
end
# default meta
def self.meta(*options)
{:page => 0}
end
end
class RoomSerializer < FastJSONAPISerializer::Base(Room)
attribute :name
has_many :tables, TableSerializer
end
class TableSerializer < FastJSONAPISerializer::Base(Table)
attribute :number
belongs_to :room, RoomSerializer
end
Build your serialized json
resource = Restaurant.new
resource.address = Address.new
resource.post_code = PostCode.new
room = Room.new(1)
room.tables = [Table.new(1), Table.new(2)]
resource.rooms = [room]
RestaurantSerializer.new(resource).serialize(
except: %i(name),
includes: {
:address => [:address],
:post_code => [:post_code],
:tables => {:room => [:room]},
},
meta: {:page => 0, :limit => 50},
options: {:test => true}
)
Example above produces next output (this one is made to be readable - real one has no newlines and indentations):
{
"data": {
"id": "1",
"type": "restaurant",
"attributes": {
"own_field": 12
},
"relationships": {
"address": {
"data": {
"id": "101",
"type": "address"
}
},
"post_code": {
"data": {
"id": "101",
"type": "post_code"
}
},
"Tables": {
"data": [
{
"id": "1",
"type": "table"
},
{
"id": "2",
"type": "table"
},
{
"id": "3",
"type": "table"
}
]
}
}
},
"included": [
{
"id": "101",
"type": "address",
"attributes": {
"street": "some street"
}
},
{
"id": "101",
"type": "post_code",
"attributes": {
"code": "code 24"
}
},
{
"id": "1",
"type": "room",
"attributes": {
"name": "1-name"
},
"relationships": {}
},
{
"id": "1",
"type": "table",
"attributes": {
"number": 1
},
"relationships": {
"room": {
"data": {
"id": "1",
"type": "room"
}
}
}
},
{
"id": "2",
"type": "room",
"attributes": {
"name": "2-name"
},
"relationships": {}
},
{
"id": "2",
"type": "table",
"attributes": {
"number": 2
},
"relationships": {
"room": {
"data": {
"id": "2",
"type": "room"
}
}
}
},
{
"id": "3",
"type": "room",
"attributes": {
"name": "3-name"
},
"relationships": {}
},
{
"id": "3",
"type": "table",
"attributes": {
"number": 3
},
"relationships": {
"room": {
"data": {
"id": "3",
"type": "room"
}
}
}
}
],
"meta": {
"page": 0,
"limit": 50
}
}
For a details about DSL specification see DSL
.
Inheritance
You can DRY your serializers by inheritance - just add required attributes and/or associations in the subclasses.
class UserSerializer < Serializer::Base(User)
attributes :name, :age
end
class FullUserSerializer < UserSerializer
attributes :email, :created_at
has_many :identities, IdentitySerializer
end
Included Modules
Defined in:
fast-jsonapi-serializer/base.crConstructors
-
.new(resource : T | Array(T)?, _included = Set(String).new, _included_keys = Set(Tuple(String, IDAny)).new)
Only use @resource
Class Method Summary
-
.meta(_options)
Returns default meta options.
Instance Method Summary
-
#get_type : String
Default serializer
type
If class macrotype(str : String)
is not used the type will based on the object passed to the serializer -
#serialize(except : Array(Symbol) = [] of ::Symbol, includes : Array(Symbol) | Hash = [] of ::Symbol, options : Hash? = nil, meta : Hash(Symbol, MetaAny)? = nil)
Generates a JSON formatted string.
-
#unique_key(object)
builds de-duplication key to be used by @_included_keys(Set)
Constructor Detail
Only use @resource
serializer = RestaurantSerializer.new(resource)
@_included and @_included_keys are used internally to build child serializers via associations
Class Method Detail
Returns default meta options.
If this is empty and no additional meta-options are given - .meta
key is avoided. To define own default meta options
just override this in your serializer:
class UserSerializer < FastJSONAPISerializer::Base(User)
def self.meta(options)
{
:status => "ok",
} of Symbol => FastJSONAPISerializer::MetaAny
end
end
Instance Method Detail
Default serializer type
If class macro type(str : String)
is not used the type will based on the object passed to the serializer
Format: will be underscore and downcase
class AdminUserSerializer < FastJSONAPISerializer::Base(AdminUser)
attributes :name, :age
end
serializer = AdminUserSerializer.new(AdminUser.first)
serializer.get_type # => `admin_user`
Generates a JSON formatted string.
Arguments:
except
- array of fields which should be excludedincludes
- definition of relation that should be includedoptions
- options that will be passed to methods defined forif
attribute options and.meta(options)
.meta
- meta attributes to be added under"meta"
key at root level, merged into default.meta
RestaurantSerializer.new(resource).serialize(
except: %i(name),
includes: {
:address => [:address],
:post_code => [:post_code],
:tables => {:room => [:room]},
},
meta: {:page => 0, :limit => 50},
options: {:test => true}
)
Includes
includes option accepts Array
or Hash
values. To define just a list of association of resource object - just pass an array:
RestaurantSerializer.new(object).serialize(includes: [:tables])
You can also specify deeper and more sophisticated schema by passing Hash
. In this case hash values should be of
Array(Symbol) | Hash | Nil
type. nil
is used to mark association which name is used for key as a leaf in schema
tree.