state-machine-systems / JsonCodec

JSON combinator library for BuckleScript/Reason
Apache License 2.0
38 stars 7 forks source link

HOWTO decode into records? #20

Open justgage opened 6 years ago

justgage commented 6 years ago

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
johnwright commented 6 years ago

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.

strega-nil commented 6 years ago

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