Surrealist 1.0.0 release: full support for all ORMs, custom serializers and more

Nikita
4 min readFeb 13, 2018

--

After four months of work we are happy to announce the first major release of Surrealist. In this post we will walk through new features since 0.1.0. Surrealist is a ruby serialization library. If you are unfamiliar with this gem you are welcome to read through the first post.

The icon was created by Simon Child from Noun Project and is published under Creative Commons License

Why Surrealist?

1) One dependency.

Which is Oj. Oj.dump is about 3x faster than standard ruby’s JSON.dump

2) Full test coverage

Coverage for Sureralist is and since 0.1.0 always was at 100%.

3) Rails-free

Neither Rails, nor ActiveSupport are used inside or needed for Surrealist to do its job. You are free to use it with Hanami, Sinatra or anything you have the mood to.

4) ORM-independent

Surrealist is proven to play well with ActiveRecord, Sequel and ROM.

5) Speed

Even though it’s Ruby we are talking about, it is still nice to know that you can win in speed sometimes. Surrealist is faster than AMS, please refer to benchmarks for comparison.

6) Type checks

Even though it’s Ruby we are talking about, it’s still nice to have some kind of type safety. Extra type awareness is guaranteed with dry-types!

Let’s walk through the new features introduced since the last post.

Custom serializers

If you want to keep the serialization logic in a separate class (because keeping it in the model is a bad idea in general), you can now use Surrealist::Serializer class. To specify the serializer in your model one should use the .surrealize_with class method. Example:

The constructor of Surrealist::Serializer takes two arguments: serializable model (or collection) and a context hash. So if there is an object that is not coupled to serializable model but it is still necessary for constructing JSON, you can pass it to constructor as a hash. It will be available in the serializer in the context hash. Example:

Multiple serializers

If you have a necessity to have multiple serializers for one model (for example having a preview page and a full display page) you can specify them via .surrealize_with method. Just mark the serializer with a tag!

To specify the serializer’s tag, pass the for argument to #surrealize or #build_schema . Without this argument Surrealist will use the default serializer (PostSerializer in this case)

Another way is to explicitly specify serializer’s class using serializer argument:

Full support for all ORMs

Since 0.4.0 Surrealist has support for ActiveRecord, ROM and Sequel. There are two kinds of return values of ORM methods: some return collections of objects, while others return instances. For the first ones one should use instance#surrealize, whereas for the second ones Surrealist.surrealize_collection(collection) Please keep in mind that if your serialization logic is kept in a separate class, then usage boils down to YourSerializer.new(instance || collection).surrealize.

1. ActiveRecord

The only thing with ActiveRecord is knowing which methods return instance and which collection. We have listed them in the README. The rest is pretty intuitive. All associations work as one would expect them to: .has_many, .has_and_belongs_to_many return collections, .has_one, .belongs_to return instances.

2. Sequel

Basically, Sequel returns instances only on .first, .last, .[] and .with_pk!. Collections are returned for all other methods. So, for instances serialization looks like this:

and for collections like this:

Most of the methods are covered in spec/orms/sequel specs, so please refer to them for more code examples. Associations serialization works the same way as it does with ActiveRecord.

3. ROM

Under the hood ROM uses Sequel, and as it was already mentioned Sequel returns instances only on .first, .last, .[] and .with_pk!. Collections are returned for all other methods. Basically, there are several ways to fetch data with ROM (and they vary a bit through ROM 3.x and 4.x). Assuming that we have a users container:

First way is to define json_schema in ROM::Struct::User :

Second option is to use ROM::Struct::Model#as(Representative) with json_schema defined in representative. Please note the difference between ROM 3 & ROM 4.

And the last way is to use Mappers. API also changes here from ROM 3 to ROM 4.

Benchmarks

Due to major release we have decided to make a benchmark suite to compare Surrealist with the main competitor — ActiveModelSerializers. Results are following:

So, as it can be seen, with the default configuration AMS is 17x slower than Surrealist for instance serialization and 2.4x slower for collection serialization. With a little tweak (turning off logger) AMS performs 7.7x slower for instances and 2.5x slower for collections. The benchmark itself can be found in benchmarks/surrealist_vs_ams.rb . As a side note, we understand that AMS is a much more complicated gem that has a lot of legacy code they have to support. Also we have to mention the new FastJsonapi gem that was recently released. In terms of speed it should be faster than Surrealist, but in terms of complexity, dependencies from Rails, ActiveRecord and ActiveSupport Surrealist keeps both feet on the ground.

Miscellaneous

Credits

I would like to express my big thanks @AlessandroMinali, @chrisatanasian and @nulldef for their contributions to this project.

ROADMAP

Right now in the roadmap we have DSL for serializer contexts, having a single configuration that will hold serialization arguments, memoization / caching and more. Contributions are as always welcome. Come and tune in, and feel free to create issues and pull requests with ideas or suggestions. Source code with more examples (in specs in particular) is available on GitHub, thanks for reading and have a nice day!

--

--