1

Given the following types:

type alias Wrapper =
 { data : Data }
type alias Data =
 { name : String }

And the following JSON:

{"data": {"name": "Keith"}}

How can I write a decoder which will allow me to turn an HTTP response into an instance of the Wrapper type alias?

I've tried a number of approaches using the core libraries, Json.Decode.Pipeline and Json.Decode.Extra, without finding a workable solution.

Here's my latest attempt:

dataDecoder =
 succeed Data
 |> andMap (field "name" Decode.string)
wrapperDecoder =
 succeed Wrapper
 |> andMap (field "data" dataDecoder)

Which results in:

BadPayload "Expecting an object with a field named name but instead got: {\"data\":{\"name\":\"foo\"}}" { status = { code = 200, message = "OK" }, headers = Dict.fromList [("cache-control","max-age=0, private, must-revalidate"),("content-type","application/json; charset=utf-8")], url = "http://localhost:5000//users/foo", body = "{\"data\":{\"name\":\"foo\"}}" }

EDIT:

This wound up being an end-user problem. I was passing the correct decoder to Http.post, but Http.send wasn't actually calling the function wrapping Http.post. Doh.

asked Sep 26, 2017 at 0:56
1
  • 1
    Glad to see you figured it out! Commented Sep 26, 2017 at 16:47

2 Answers 2

1

Your decoders work fine against your example input, but the error message you are getting leads me to believe you are trying to use dataDecoder in your Http call rather than wrapperDecoder, since the error message is looking for a field named name.

While succeed and andMap can be used to construct your decoder, you can get by with map:

dataDecoder : Decoder Data
dataDecoder =
 Decode.map Data (field "name" string)
wrapperDecoder : Decoder Wrapper
wrapperDecoder =
 Decode.map Wrapper (field "data" dataDecoder)
answered Sep 26, 2017 at 1:26
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer and the vanilla solution. Unfortunately, I am passing wrapperDecoder to Http.post. e.g. Http.post apiUrl body wrapperDecoder.
Is there a way to do this without the wrapper/wrapper-decoder, or do I need the extra wrapper type-alias?
1

As Chad Gilbert wrote, your decoders are fine: https://ellie-app.com/kDX99XRbta1/0

To doublecheck, add type annotations to your decoders:

dataDecoder : Decoder Data
dataDecoder = ...
wrapperDecoder : Decoder Wrapper
wrapperDecoder = ...

If you're really using wrapperDecoder (Http.post apiUrl body wrapperDecoder), there's one more possibility for an error: that your API endpoint returns data with a different shape, something like:

{"data": {"data": {"name": "foo"}}}

Can you doublecheck this? (in Chrome's Web Inspector etc.)

answered Sep 26, 2017 at 10:18

1 Comment

Thanks for the answer and the working sample! I can confirm that I'm passing wrapperDecoder to Http.post and that my API is returning data in the expected shape. curl -X POST http://localhost:5000/users/foo => {"data":{"name":"foo"}}. I will attempt to clean up my code and add it to my question to rule out any doubts.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.