How do I receive JSON from a subscription?

273 views
Skip to first unread message

Brian Bugh

unread,
Jun 5, 2016, 8:36:17 PM6/5/16
to Elm Discuss
I have a port that will respond with some JSON from a web service (Blockspring). I'm using their custom library, so a REST call won't work.

I've set up the port call, which works fine. But I'm not sure how to set up the port to receive JSON and then turn that into Elm. I've read through the HTTP, JSON, and interop portions of the elm guide, but I can't figure out how to put it all together for this use case.

The JSON looks arbitrarily like this;

var projects = [
 
{ "project_name": "Gulf Coast", "email": "bl...@blah1.com" },
 
{ "project_name": "Sunny Lake", "email": "bl...@blah2.com" }
]

It's just a list of objects that have key/value pairs (which are all Strings except for one timestamp)

I also can't figure out the type definition, I've tried a bunch of things. 

port response : ??? -> Sub msg

1) What's the correct function signature here?
2) How do I decode that JSON to an Elm type of List Project? Without the decoder function call of Http.get, I am pretty stumped.

Thanks!

Max Goldstein

unread,
Jun 5, 2016, 10:20:24 PM6/5/16
to Elm Discuss
port projects : (Json.Value -> Msg) -> Sub Msg

type Msg = NewProjects Json.Value | OtherThings

subscriptions model =
  projects NewProjects

Then in the update function, run the decoder on the JSON value in the NewProjects tag, and handle the succeeding and failing cases.

Brian Bugh

unread,
Jun 5, 2016, 10:46:49 PM6/5/16
to Elm Discuss
Thanks again Max. 

Why in this case is it using uppercase Msg? I figured this out partially by studying this link https://robots.thoughtbot.com/decoding-json-structures-with-elm
and in that they use 

port response : (Json.Value -> msg) -> Sub msg

which works (obviously, because msg is any type). If I change that to uppercase Msg, it breaks. Can you help me understand why you used Msg instead of msg?

Brian Bugh

unread,
Jun 5, 2016, 10:49:01 PM6/5/16
to Elm Discuss
This is what I landed on for the Json decoding:

decodeProjects : Json.Value -> List Project
decodeProjects jsonResponse
=
 
case decodeValue (list decodeProject) jsonResponse of
   
Ok val -> val
   
Err msg -> Debug.crash msg


-- taken from http://package.elm-lang.org/packages/circuithub/elm-json-extra/2.2.1/Json-Decode-Extra
(|:) : Decoder (a -> b) -> Decoder a -> Decoder b
(|:) f aDecoder =
  f
`andThen` (\f' -> f' `map` aDecoder)


decodeProject
: Decoder Project
decodeProject
=
  succeed
Project
   
|: ( "projectName" := string )
   
|: ( "repoUrl" := string )
   
|: ( "description" := string )
   
-- etc.


I couldn't figure out any other way to map out the project than with using the |: operator from the library. 

Is there a better way to do this in elm-core?


On Sunday, June 5, 2016 at 9:20:24 PM UTC-5, Max Goldstein wrote:

Max Goldstein

unread,
Jun 5, 2016, 11:03:50 PM6/5/16
to Elm Discuss
Right, it needs to be lowercase msg, because the function will determine the message type.

You can use core's objectN if N ≤ 8. See here for an example. Otherwise you need to do what you're doing already. If you don't like the symbol, you can use "andMap", as in "map, andMap, andMap...", and you can also define it as object2 (<|) for reasons that are fascinating but tangential to building webapps.

Brian Bugh

unread,
Jun 6, 2016, 6:40:50 AM6/6/16
to Elm Discuss
Thanks so much for the help!

Could you give me an example of andMap? I thought about it for a bit and I'm not sure how I'd write that with object2. 
Reply all
Reply to author
Forward
0 new messages