/re-code

Basic and advanced JSON decoding and validations in ReScript

Primary LanguageReScript

ReCode

Simple yet powerful JSON parser and validator that relies solely on the built-in Js.Json module. The API is heavily inspired by the Elm Json package, and the Yup library.

The library is well documented and well tested. Using VS Code with the official plugin should show up documentation and examples on function hover.

Screenshot 1

A simple example (Decoder)

Let's pretend we need to parse an incoming JSON that should contain a user object with the following requirements:

  • Should have a positive age
  • Should have a non empty name
  • May have a valid email address
  • Should have a logged in status (boolean)
  • May have a non empty phone number
  • Should have a non empty list of hobbies
  • Should have a date of birth that's a valid date
// Let's define our User module
module User = {
  // It contains the user type
  type t = {
    age: int,
    name: string,
    email: option<string>,
    loggedIn: bool,
    phoneNumber: option<string>,
    hobbies: array<string>,
    dateOfBirth: Js.Date.t,
  }

  // And a convenient `make` function
  let make = (
    age,
    name,
    email,
    loggedIn,
    phoneNumber,
    hobbies,
    dateOfBirth,
  ) => {
    age: age,
    name: name,
    email: email,
    loggedIn: loggedIn,
    phoneNumber: phoneNumber,
    hobbies: hobbies,
    dateOfBirth: dateOfBirth,
  }

  // We can now define our decoder
  let decoder = {
    open Decode
    open DecodeExtra

    pure(make)
    ->Object.required("age", int->Int.min(0))
    ->Object.required("name", string->String.required)
    ->Object.optional("email", string->String.email)
    ->Object.required("loggedIn", bool)
    ->Object.optional("phoneNumber", string->String.required)
    ->Object.required("hobbies", array(string)->Array.notEmpty)
    ->Object.required("dateOfBirth", Date.iso)
  }
}

// We can now validate our incoming payload!
// This example assumes `payload` exists and is a string
switch payload->Decode.decodeString(User.decoder) {
| Ok(user) => Js.log(`User with name ${user.name} is valid!`)
| Error(ParseError) => Js.log("Humm, the JSON was invalid")
| Error(TypeError(error)) => Js.log(`The JSON was valid, but not the value it contained: ${error}`)
}

A simple example (Encoder)

We can also turn complex values into Json:

// Reusing the previous User module and type only
module User = {
  type t = {
    age: int,
    name: string,
    email: option<string>,
    loggedIn: bool,
    phoneNumber: option<string>,
    hobbies: array<string>,
    dateOfBirth: Js.Date.t,
  }
}

let userEncoder = (user: User.t) => {
  open Encode

  object([
    ("age", int(user.age)),
    ("name", string(user.name)),
    ("email", maybe(string, user.email)),
    ("loggedIn", bool(user.loggedIn)),
    ("phoneNumber", maybe(string, user.phoneNumber)),
    ("hobbies", array(string, user.hobbies)),
    ("dateOfBirth", date(user.dateOfBirth)),
  ])
}

// We assume a `myUser` variable exists and has type `User.t`
let json = userEncoder(myUser)

// Let's display our newly created json
Js.log(Js.Json.stringify(json))

See more

You can check the tests for more.