Sending over a channel when I have already-encoded JSON

What would you think of allowing handle_in callbacks to return {:reply, {:ok, json}, sock} where json is already a JSON string? The current interface of returning a map works fine for data that is built up in Elixir, but sometimes I am sending requests to other backends that return JSON, and it’s rather wasteful to decode that to a map and return it just to have the serializer turn around and encode it back.

For what it’s worth, I actually implemented it this afternoon. So this is not at all a question about how, it’s a question of whether it’s viewed as a good idea. If it’s seen as desirable, then I can take some time to turn it into a decent pull request. (Update docs & error messages, apply similar changes to other callbacks as appropriate…)

That brings up another point about the design: is there a philosophical reason why only maps are supported? For instance, in the case where my return value is a list of maps, it seems kind of clunky to have to embed the list into a single-attribute object with some arbitrary key. Would it cause any problem to allow any value that can be JSON-encoded? (And note that requiring it to be a map does not guarantee that it can be JSON encoded.)

2 Likes

You’d probably add a custom serializer https://hexdocs.pm/phoenix/Phoenix.Transports.Serializer.html, and specify it when defining transports. It could be as simple as " if the data is a binary or an iolist → return untouched", “if the data is a map → encode to iolist”.

For what it’s worth, I actually implemented it this afternoon. So this is not at all a question about how, it’s a question of whether it’s viewed as a good idea.

Oh, sorry. Should’ve read to the end.

That brings up another point about the design: is there a philosophical reason why only maps are supported?

Simplicity, probably.

1 Like

You can leverage the fact that a JSON encoder is backed by a protocol to do this. I wrote on how this could be achieved with Poison some time ago: https://michal.muskala.eu/2017/01/25/serving-encoded-json-with-poison.html

If you’re using Jason, this is built-in with the Jason.Fragment module (the docs could use improvement around how to use it, though).

4 Likes