Skip to content

Next iteration of serializers

Description

I recently though that our serializers (app/serializers) might need a next iteration with some minor refactoring.

This is how pipelines and environments serializers look like at the moment:

We have more serializers, but these are most complicated ones at the moment.

It appears that using serializers to set some constraints / extensions to ActiveRecord::Relation objects which are passed to Serializer#represent(resource) is a convenient thing to do.

How we use PipelinesSerializer now:

pipelines: PipelineSerializer
  .new(project: @project, user: @current_user)
  .with_pagination(request, response)
  .represent(@pipelines),

This represents paginated resource, but in other places of GitLab we still do not paginate pipelines, so we don't call with_pagination on the serializer object.

The problem with this approach is that we pass @resource after we set pagination, which means that we have to somehow memoize the pagination request, and apply pagination after this is done.

In the new environments serializer we want to sometimes group some environments into folders, it looks quite similar. But code like this:

  def represent(resource, opts = {})
   resource = paginate(resource) if paginated?

    if itemized?
      itemize(resource).map do |item|
        # ...
      end
    else
      super(resource, opts)
    end
  end

does not scale very well, because we have to add itemized?, paginated? for each condition. Would it be better to add pagination to the ActiveRecord::Relation object once we call with_pagination? Changing the resource object when someone calls with_folders might be a good solution as well.

This would mean that we should refine serializers and pass the ActiveRecord::Relation object to the initializer and set RequestAwareEntity parameters with method like .with_request(user: @current_user, project: @project).

Proposal

Refine serializers to support code like:

PipelineSerializer.new(@pipelines)
  .with_request(user: @user, project: @project)
  .with_pagination
  .with_something_else
  .represent!

Fluent interface like this may simplify the underlying implementation.

I remember @DouweM didn't like this solution when we introduced serializers in the first place, but I wonder what do you and @rymai think about it since we know a little more about serializers now, once we have few implemented already.