jsonapi icon indicating copy to clipboard operation
jsonapi copied to clipboard

Dynamic fields in views

Open whatyouhide opened this issue 3 years ago • 3 comments

Currently, if I define some fields in my JSONAPI.View.fields/0 callback that are not part of the data passed when rendering, then I have to define one public function per such field.

This is alright, but it limits flexibility when we need something akin to dynamic fields. For example, imagine that for convenience I keep my data structure as

%{
  id: 1,
  attrs: %{foo: true, bar: false, baz: nil}
}

With the current capabilities, I can do this:

def fields do
  [:id, :foo, :bar, :baz]
end

def foo(%{attrs: %{foo: foo}}, _conn), do: foo
def bar(%{attrs: %{bar: bar}}, _conn), do: bar
def baz(%{attrs: %{baz: baz}}, _conn), do: baz

It works, but imagine what this can become if you want to do something similar with many more fields. Metaprogramming can come in handy if you generate the public functions programmatically, but it leads to code that's a bit harder to understand (especially for newcomers).

Possible Solution

A possible solution could be a c:JSONAPI.View.get_field/3 callback that takes the field name, the data, and the Plug connection. I would reimplement the example above as:

def fields do
  [:id, :foo, :bar, :baz]
end

def get_field(field, %{attrs: attrs}, _conn) do
  Map.fetch!(attrs, field)
end

Did I missing an already-existing way to do this? 🙃 What are you folks' thoughts on it in case I didn't?

whatyouhide avatar Aug 31 '22 15:08 whatyouhide

Seems reasonable. I imagine it would be beneficial to still allow individually defined functions named after fields to take precedence over get_field/3.

So for the following

def fields do
  [:id, :foo, :bar, :baz]
end

def foo(attrs, conn), do: ...

def get_field(field, attrs, conn), do: ...

The framework would be expected to call foo/2 for the foo attribute but call get_field/3 for all other attributes.

mattpolzin avatar Sep 14 '22 23:09 mattpolzin

Yes, exactly. I'll work on a PR for this 🙃

whatyouhide avatar Sep 20 '22 18:09 whatyouhide

@mattpolzin PR open https://github.com/beam-community/jsonapi/pull/273!

whatyouhide avatar Sep 20 '22 19:09 whatyouhide