nesaulov/surrealist

Introduce an abstract serializer class

nesaulov opened this issue · 7 comments

I think that in most of the cases the logic of serialization should be separated from the model itself. So I suggest having a class that will represent abstract serializer which will be inherited by particular ones. API that I propose:

class HumanSerializer < Surrealist::Serializer
  json_schema do
    { name: String, name_length: Integer }
  end

  def name_length
    name.length
  end
end

class Human
  include Surrealist

  attr_reader :name

  surrealize_with HumanSerializer

  def initialize(name)
    @name = name
  end
end

And two ways of serializing:

  • Implicit (through DSL):
Human.new('John').surrealize(camelize: true)
# => '{"name": "John", "nameLength": 4}'
  • Explicit:
HumanSerializer.new(Human.new('Alfred')).surrealize(camelize: true)
# => '{"name": "Alfred", "nameLength": 6}'

@AlessandroMinali what do you think?

Yea the idea behind this separation of concerns makes sense to me. I'd like less repetition and further complete separation. I'm not sure how much complexity it would add to have it just so the model would just be:

class Human
  include HumanSerializer

  attr_reader :name

  def initialize(name)
    @name = name
  end
end

and still have the same api you mentioned.

EDIT: I can see the benefit of having an explicit call of what is being used to serialize though, less magic I suppose.

I think that

class Human
  include HumanSerializer

is kind of counterintuitive and contradicts the separation of concerns principle. As for me, when I see include I think of multiple inheritance in sense of adding methods to the object. Here, on the other hand we just need to delegate serialization logic to a separate object.
As for APIs, I suggest having both ways (explicit & implicit) available. I personally prefer explicit way over implicit, but I think for many people ease of use is preferable over explicitness ¯_(ツ)_/¯

Makes sense to me what you're saying. We should definitely have an explicit way to allow one off calls to other serializers and to potentially override what is defined in the object for that single explicit call.

Hi guys!
I think we can use multiple serializers for one model. I suggest that:

class HumanSerializer < Surrealist::Serializer
  json_schema do
    { name: String, name_length: Integer }
  end

  def name_length
    name.length
  end
end

class SmallHumanSerializer < Surrealist::Serializer
  json_schema do
    { name: String }
  end
end

class Human
  include Surrealist

  attr_reader :name

  surrealize_with HumanSerializer # default
  surrealize_with SmallHumanSerializer, tag: :small

  def initialize(name)
    @name = name
  end
end
# default behaviour
Human.new('John').surrealize(camelize: true)
# => '{"name": "John", "nameLength": 4}'

# using tags
Human.new('John').surrealize(camelize: true, tag: :small)
# => '{"name": "John"}'

@nulldef It looks interesting, I think we should negotiate on tag parameter and API in general. Could you please create a new issue for this feature request, as this one should be closed due to #61 ?

Alright, closing this.