JsonCodec icon indicating copy to clipboard operation
JsonCodec copied to clipboard

HOWTO decode into records?

Open justgage opened this issue 7 years ago • 2 comments

Just some nice examples in the README.md would go a long way.

Love the idea of this library by the way ❤️.

One thing I was hoping to find: How do you convert a some JSON into a record? In Elm you would use something like: http://package.elm-lang.org/packages/elm-lang/core/5.1.1/Json-Decode#map or perhaps http://package.elm-lang.org/packages/NoRedInk/elm-decode-pipeline/latest

Example in Elm using elm-decode-pipeline

import Json.Decode exposing (int, string, float, Decoder)
import Json.Decode.Pipeline exposing (decode, required, optional, hardcoded)

-- basically a record in Elm
type alias User =
  { id : Int
  , email : Maybe String
  , name : String
  , percentExcited : Float
  }


userDecoder : Decoder User
userDecoder =
  decode User
    |> required "id" int
    |> required "email" (nullable string) -- `null` decodes to `Nothing`
    |> optional "name" string "(fallback if name is `null` or not present)"
    |> hardcoded 1.0

justgage avatar Apr 03 '18 20:04 justgage

At the moment, you have to convert between tuples and records, so there's a bit of boilerplate involved. The above example would look something like this:

type user = {
  id: int,
  email: option(string),
  name: string,
  percentExcited: float
};

let userCodec = JsonCodec.(
  object4(
    field("id", int),
    field("email", nullable(string)),
    optionalNullable("name", string) |> wrap(
      fun | "" => None | name => Some(name),
      fun | Some(name) => name | None => ""
    ),
    field("percentExcited", constant(number, 1.0))
  ) |> wrap(
   fun | {id, email, name, percentExcited} => (id, email, name, percentExcited),
   fun | (id, email, name, percentExcited) => {id, email, name, percentExcited}
  )
);

I'd definitely like to look at improving this, and translating the example has already highlighted another opportunity to improve handling of default values :) Elm has kind of a head start since User is a constructor function for the record type, but maybe there's a way around that.

johnwright avatar Apr 04 '18 20:04 johnwright

It seems like someone could, fairly easily, write a ppx to automate this?

strega-nil avatar Apr 04 '18 22:04 strega-nil