Babel - Data transformations made easy

Just to give an example: here’s an excerpt from how we use Babel at work. I’ve changed model names and omitted some functions but the basic idea should be clear. The strength I’d argue is that it’s composable and readable in how it specifies the desired outcome, and if it fails at any given step it will tell you exactly what went wrong:

@spec list_of_pieces(opts) :: Babel.t([Piece.t()])
def list_of_pieces(opts) do
  :pieces
  |> Babel.begin()
  |> Babel.fetch(["contentCollection", "items"])
  |> Babel.map(piece(opts))
end

@spec piece(opts) :: Babel.t(Piece.t())
def piece(opts) do
  Babel.into(%Piece{
    id: cms_id(),
    locale: locale(),
    name: Babel.fetch("name"),
    is_locked:
      Babel.then(fn
        %{"isPremium" => true} -> opts[:lock_premium?]
        %{"isPremium" => _} -> false
      end),
    category: category(),
    audio:
      :audio
      |> Babel.begin()
      |> Babel.fetch(["audioCollection", "items"])
      |> Babel.match(fn
        [_ | _] -> Babel.at(0) |> Babel.chain(audio())
        [] -> Babel.const(nil)
      end)
  })
end

This can then be used to parse like this:

Babel.apply(list_of_pieces(opts), data)

Or if you only want to parse a single Piece:

Babel.apply(piece(opts), data)
1 Like