package conformist

  1. Overview
  2. Docs
Conformist allows you to define schemas to decode, validate and sanitize input data declaratively

Install

Dune Dependency

Authors

Maintainers

Sources

conformist-0.0.1.tbz
sha256=2340e7ce1c8e14a259f388a27a83675158904320f2f2546bef80d220754b75ad
sha512=59c1533658e6179a709a1bf53bd36e67229aabd530af9a3dc35aa57cfd0d9679a87c5f9f45b87491f004c6ba23f1322fe5eedbd407835bc148bd338b9cb6438b

Description

Conformist allows you to define schemas to decode, validate and sanitize input data declaratively. It comes with runtime types for primitive OCaml types such as int, string, bool and float but also Ptime.date, optional and custom types. Re-use business rules in validators and run it on the client side with js_of_ocaml. Arbitrary meta data can be stored in schemas which is useful to build functionality on top of conformist.

Published: 21 Sep 2020

README

README.md


Conformist

Runtime types, schema validation and decoding
Explore the docs »

Table of Contents

About

Conformist allows you to define schemas to decode, validate and sanitize input data declaratively. It comes with runtime types for primitive OCaml types such as int, string, bool and float but also Ptime.date, optional and custom types. Re-use business rules in validators and run it on the client side with js_of_ocaml. Arbitrary meta data can be stored in schemas which is useful to build functionality on top of conformist.

Typical use cases are enforcing invariants of models or user input sanitization.

In essence, conformist helps you to keep your runtime types/contracts in sync with your static types.

Installation

opam install conformist

In your dune file:

(executable
  (name app)
  (libraries
   ...
   conformist))

Usage

Let's look at an example.

module C = Conformist

type gender = Male | Female | Other

type user = {
  gender : gender;
  email : string;
  birthday : int * int * int;
  nr_of_siblings : int;
  comment : string option;
  wants_premium : bool;
}

let user gender email birthday nr_of_siblings comment wants_premium
    =
  {
    gender;
    email;
    birthday;
    nr_of_siblings;
    comment;
    wants_premium;
  }

let gender_decoder = function
  | "male" -> Ok Male
  | "female" -> Ok Female
  | "other" -> Ok Other
  | _ -> Error "Unknown gender provided"

let user_schema =
  C.make
    C.Field.
      [
        C.custom "gender" gender_decoder ~meta:() ();
        C.string "email" ();
        C.date "birthday" ();
        C.int "nr_of_siblings" ();
        C.optional (C.string "comment" ());
        C.bool "wants_premium" ();
      ]
    user

let user =
  [
    ("gender", [ "male" ]);
    ("email", [ "test@example.com" ]);
    ("birthday", [ "2020-12-01" ]);
    ("nr_of_siblings", [ "3" ]);
    ("comment", [ "hello" ]);
    ("wants_premium", [ "true" ]);
  ]
in
  C.decode Schema.user_schema input

let validation_erorrs =
  [
    ("gender", [ "male" ]);
    ("email", [ "test@example.com" ]);
    ("birthday", [ "2020-12-01" ]);
    ("nr_of_siblings", [ "3" ]);
    ("comment", [ "hello" ]);
    ("wants_premium", [ "true" ]);
  ]
in
  C.validate Schema.user_schema input

Try to delete/swap lines of list of fields, to change the constructor or the user type. The compiler forces you to keep these things in sync.

Decoding doesn't validate the data, it just makes sure that the types are correct and translates strings to the correct static types.

Note that if decoding of a field fails, validation fails as well. Before a field is validated, it gets decoded.

Documentation

The documentation for the latest released version can be found here.

License

Copyright (c) 2020 Oxidizing Systems

Distributed under the MIT License. See LICENSE for more information.

Acknowledgements

The implementation of this project was inspired by archi and re-web.

Dependencies (2)

  1. ocaml >= "4.08.0"
  2. dune >= "2.4"

Dev Dependencies (3)

  1. ppx_fields_conv >= "v0.14.1" & with-test
  2. ppx_deriving >= "4.5" & with-test
  3. alcotest >= "1.2.3" & with-test

Used by

None

Conflicts

None