0

Is there a way to put HTTP status in a particular struct before it's encoded by Poison?

I guess the more general question would be can I access the conn at the level of my encoder's encode function? I am trying to build an API akin to what's specified here: http://jsonapi.org/examples/#error-objects

In my controller function, I have this, which transparently puts the HTTP status before the request is sent out the door. However, if some plug modifies the HTTP status down the pipeline whatever status I put during the create of ApiMessage also needs to be updated.

conn |> put_status(:forbidden) |> json(%ApiMessage{ status: 403, message: "Nope" })

This is the struct I want to encode:

defmodule MyApp.ApiMessage do
  @enforce_keys [:message]

  defstruct message: nil, success: false, status: 422
end

I want to use a custom encoder to put the HTTP status before the struct is encoded, something like this:

defimpl Poison.Encoder, for: [MyApp.ApiMessage] do
  def encode(t, _options) do
    # get conn here somehow and set the status to current
    # conn status
  end
end

Is this possible to do in Phoenix? I think I only need to figure out how to get the final conn in the encoder to get the status.

hyde
  • 2,525
  • 4
  • 27
  • 49
  • You probably shouldn't be modifying the status after your controller code has run. – Justin Wood Jun 24 '17 at 14:55
  • 1
    Why do you want the status in your payload? It's already in the response; duplicating it seems pointless and brittle. – Dave Newton Jun 24 '17 at 15:26
  • I agree with @DaveNewton, but if you still need to do this, I'd suggest creating your own `json` function instead (e.g. `json_with_status`), which takes the status from `conn` and puts it in the struct before encoding it. I can write an answer with the implementation if it sounds good to you. – Dogbert Jun 24 '17 at 15:47
  • 1
    @Dogbert Wouldn't that have the same issue? To me it seems more like this would need to be a plug using `register_before_send` that modifies the response using the value of the HTTP status. – Dave Newton Jun 24 '17 at 16:21
  • @DaveNewton you're right, I misread the question. I thought OP wanted to reduce the duplication of specifying the status code twice. – Dogbert Jun 24 '17 at 16:27
  • @DaveNewton and Justin Wood, great points but I have a very contrived example here. I think the better question would be how to I get the conn context in my encoder's function. – hyde Jun 26 '17 at 04:49
  • @DaveNewton I am trying to build my API akin the JSON API spec., and they recommend putting the status in the body itself. The rationale is quite clearly written here: http://jsonapi.org/examples/#error-objects – hyde Jun 26 '17 at 14:34
  • @hyde I understand the rational, I just don't care for it. For JSON over non-HTTP IMO HTTP error codes shouldn't be used since it's not HTTP. I tend to favor application-specific error codes to aggregate system errors, while transport errors are a separate thing. In any case, my comment regarding a plug still stands, with the caveat that plug order matters, and putting the logic into a serializer (a) conflates separate concerns, and (b) would suffer from the same issue. – Dave Newton Jun 26 '17 at 14:38

0 Answers0