Logo

Use JSON::Serializable to generate dynamic JSON/fields

Build Status License API Documentation GitHub release

Website Shard Docs


A Crystal Library which extends JSON::Serializable to allow JSON to be generated via method calls, instead of requiring the use of variables.

NOTE: This library only supports Serialization. Deserialization to Fake FIelds is not possible.

Installation

  1. Add the dependency to your shard.yml:

    dependencies:
      serializable-fake:
        github: ryan-kraay/json-serializable-fake
  2. Run shards install

Usage

require "json"
require "json-serializable-fake"

class Sum
  include JSON::Serializable
  include JSON::Serializable::Fake

  property a : UInt32
  property b : UInt32

  def initialize(@a, @b)
  end

  @[JSON::FakeField]
  def sum(json : ::JSON::Builder) : Nil
    json.number(a + b)
  end
end

s = Sum.new(10, 5)
puts s.to_json    # => { "a": 10, "b": 5, "sum": 15 }

Additional documentation can be found here.

Features

This library was born out of desire to use classes and members to construct JSON object, but also to use methods to construct JSON fields that do not necessarily need to be stored as members in a class definition.

Some additional features:

NOTE: The use of JSON::Serializable relies on an "opt-out" feature (ie: JSON::Field(ignore_serialization: true)]). Meaning all instance variables will be added to the json document, unless you explicitly "opt-out".. JSON::Serializable::Fake relies on an "opt-in" for instance methods. Meaning that only those instance methods which contain the JSON::FakeField annotation will be added to the json document.

Advanced Example

require "json"
require "json-serializable-fake"

class User
  include JSON::Serializable
  include JSON::Serializable::Fake

  property first : String
  property last : String
  property password : String

  @[JSON::FakeField]
  def user(json : ::JSON::Builder) : Nil
    json.string( (@first + @last).downcase )
  end

  def initialize(@first, @last, @password)
  end
end

class SecuredUser < User
  property age : UInt32

  # replace our user() implementation via simple inheritance
  def user(json : ::JSON::Builder) : Nil
    json.string("retracted")
  end

  @[JSON::FakeField(key: password)]
  def hide_password(json : ::JSON::Builder) : Nil
    json.string("******")
  end

  @[JSON::FakeField(suppress_key: true)]
  def age(json : ::JSON::Builder) : Nil
    # Only show the age, if the user is over 18
    if age > 18
      json.field "age", @age
    end
  end

  def initialize(@first, @last, @age, @password)
  end
end

user = User.new("John", "Doe", "hunter2")
puts user.to_json     # => {"first":"John","last":"Doe","password":"hunter2","user":"johndoe"}

child = SecuredUser.new("Jimmy", "Doe", 5_u32, "hunter2")
puts child.to_json    # => {"first":"Jimmy","last":"Doe","password":"******","user":"retracted"}
puts child.password   # => hunter2

adult = SecuredUser.new("Jane", "Doe", 24_u32, "hunter2")
puts adult.to_json    # => {"first":"Jane","last":"Doe","password":"******","age":24,"user":"retracted"}
puts adult.password   # => hunter2

Limitations

  1. This library only supports JSON Serialization (not YAML). There is no technical reason for this limitation, just a lack of time.
  2. This library only support Serialization. Deserializing into a method call is not support. Again, there is no technical limitation, only time. However, JSON::FakeFields will appear as objecct.json_unmapped[<fakefield>], when JSON::Serializable::Unmapped is used.

Contributing

  1. Fork it (https://github.com/ryan-kraay/json-serializable-fake/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request