Cantido/liberator

The text/plain codec should stringify maps

Cantido opened this issue · 0 comments

Is your feature request related to a problem? Please describe.
This kind of a cross between a feature and a bug. The functions later in the evaluation pipeline assume that the handlers return some sort of data structure that is then serialized. For example, handle_ok/1 should return a map, that will then be converted into a JSON string if the accepts header is application/json. If you do the same thing while the accept header is text/plain, the request crashes. Specifically, the compression step crashes, because the argument is not a binary.

Describe the solution you'd like
Stringify maps in a pretty-printed format. If you returned a map

%{a: "value a", b: %{nested: "nested value b"}`

Then the text/plain codec should return

a: value a
b:
  nested: nested value b

This almost seems like a YAML format, which TBH would be pretty nice. I might consider that.

Describe alternatives you've considered
Just calling Kernel.inspect/1 on the result. That would be ugly but it would get the job done.

Additional context
While we're in there, we should also make sure that the value returned from the media codec is a binary, so that we don't pass invalid data to the compression codecs.

For anyone who would want to help me with this change request, Liberator.MediaType.TextPlainCodec is where you'll want to be working. Make encode!/1 always return a string, or raise if there's an error.

To implement the check for a binary, add something at line 190 in Liberator.Evaluator that just checks if the return value from the codec is a binary, then throw an exception with a nice error message, and point to the module that failed.

Liberator.Codec also needs to be split into a MediaTypeCodec which is typespecced for any -> binary, then an EncodingCodec which is typespecced for binary -> binary.