{"id":19226570,"url":"https://github.com/alonsodomin/haskell-schema","last_synced_at":"2026-03-15T18:46:16.085Z","repository":{"id":59153077,"uuid":"138186691","full_name":"alonsodomin/haskell-schema","owner":"alonsodomin","description":"A library for describing Haskell data types and obtain free generators, JSON codecs, pretty printers, etc.","archived":false,"fork":false,"pushed_at":"2022-03-22T23:41:12.000Z","size":119,"stargazers_count":21,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-20T20:45:25.638Z","etag":null,"topics":["data-structures","haskell","haskell-library","higher-order","json","quickcheck","schema"],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alonsodomin.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-06-21T15:09:05.000Z","updated_at":"2025-07-09T13:33:11.000Z","dependencies_parsed_at":"2022-09-13T10:50:29.855Z","dependency_job_id":null,"html_url":"https://github.com/alonsodomin/haskell-schema","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/alonsodomin/haskell-schema","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alonsodomin%2Fhaskell-schema","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alonsodomin%2Fhaskell-schema/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alonsodomin%2Fhaskell-schema/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alonsodomin%2Fhaskell-schema/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alonsodomin","download_url":"https://codeload.github.com/alonsodomin/haskell-schema/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alonsodomin%2Fhaskell-schema/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279016888,"owners_count":26085884,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-structures","haskell","haskell-library","higher-order","json","quickcheck","schema"],"created_at":"2024-11-09T15:19:19.869Z","updated_at":"2025-10-13T19:16:36.129Z","avatar_url":"https://github.com/alonsodomin.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Haskell Schema\n\n[![Build Status](https://travis-ci.org/alonsodomin/haskell-schema.svg?branch=master)](https://travis-ci.org/alonsodomin/haskell-schema)\n[![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0)\n![Hackage](https://img.shields.io/hackage/v/hschema.svg)\n\n\nHaskell Schema (or `hschema`) is a library with the purpose of describing data (or domains) and use that information to automatically\n  derive serialization codecs (JSON, binary, etc.), arbitrary generators, pretty printers and much more. It is heavily inspired by\n  the Scala library [xenomorph](https://github.com/nuttycom/xenomorph) (in fact, it is a port of the same ideas), which was introduced\n  in the following talk at Scala World 2017:\n\n\u003ca href=\"http://www.youtube.com/watch?feature=player_embedded\u0026v=oRLkb6mqvVM\" target=\"_blank\"\u003e\u003cimg src=\"http://img.youtube.com/vi/oRLkb6mqvVM/0.jpg\" \nalt=\"Describing Data...with free applicative functors (and more)—Kris Nuttycombe\" width=\"240\" height=\"180\" border=\"10\" /\u003e\u003c/a\u003e\n\n## Motivation\n\nThe idea behind it is that, given a domain model you want to work with, you can use this library to build a description of it (or _schema_)\n  that is totally independent of the actual code representation of the given domain model. After that, you can leverage the mechanics\n  behind this library to generate QuickCheck generators, JSON parsers, binary codecs, etc.\n\n### Isn't that much work? What about deriving `Generic`?\n\nDeriving `Generic` from your data and deriving your encoders from there seems pretty reasonable, and it's usually very concise, isn't it?\n  But there is a problem with that, usually the data that you are going to be serializing over the wire (that's why you need your JSON,\n  binary, etc. codecs) forms part of your public protocol. That means that every time you modify one of those data items, you are in danger\n  of breaking your compatibility.\n\nOn top of that, what about supporting two versions of your protocol? That will get hairy quite quickly. By defining the schema separated\n  from the actual data types, you can evolve your domain model without modifying the actual schema, add a new schema version and even\n  define migrations between them.\n\n## How to use it?\n\nHaskell Schema is distributed as a set of packages that together provide a cohesive set of features:\n\n * `hschema`: This is the core package, defining the base building pieces\n * `hschema-aeson`: This is a package that provides JSON encoding and decoding using Aeson.\n * `hschema-quickcheck`: This package will provide with QuickCheck generators based on our schema.\n * `hschema-prettyprinter`: This package brings pretty priting utilities.\n\nIn the following example we are going to make use of all those packages.\n\n### Example\n\nLet's start by defining a some data types alongside some lenses:\n\n```haskell\n{-# LANGUAGE LambdaCase        #-}\n{-# LANGUAGE OverloadedStrings #-}\n{-# LANGUAGE TypeFamilies      #-}\n\nimport Control.Lens\nimport Data.Time (UTCTime)\n\ndata Role =\n    UserRole UserRole\n  | AdminRole AdminRole\n  deriving (Eq, Show)\n\ndata UserRole = UserRole'\n  deriving (Eq, Show)\n\ndata AdminRole = AdminRole' { department :: String, subordinateCount :: Int }\n  deriving (Eq, Show)\n\n_UserRole :: Prism' Role UserRole\n_UserRole = prism' UserRole $ \\case\n    UserRole x -\u003e Just x\n    _          -\u003e Nothing\n\n_AdminRole :: Prism' Role AdminRole\n_AdminRole = prism' AdminRole $ \\case\n    AdminRole x -\u003e Just x\n    _           -\u003e Nothing\n\ndata Person = Person { personName :: String, birthDate :: Maybe UTCTime, roles :: [Role] }\n  deriving (Eq, Show)\n```\n\nNow, defining the schema for the `Person` data type, you define each of the fields individually (name, type and getter) and combine them using\n  an applicative:\n\n```haskell\nimport           Data.Convertible\nimport qualified Data.Schema             as S\nimport           Data.Schema.JSON\nimport qualified Data.Schema.JSON.Simple as JSON\n\nutcTimeSchema :: JsonSchema UTCTime\nutcTimeSchema = S.alias (iso convert convert) (JSON.int :: JsonSchema Integer)\n\npersonSchema :: JsonSchema Person\npersonSchema = S.record\n             ( Person\n             \u003c$\u003e S.field    \"name\"      JSON.string         (to personName)\n             \u003c*\u003e S.optional \"birthDate\" utcTimeSchema       (to birthDate)\n             \u003c*\u003e S.field    \"roles\"     (S.list roleSchema) (to roles)\n             )\n```\n\nThe schema for the `Role` data type is defined as a list of alternatives alongside a prism as an accessor:\n\n```haskell\nadminRole :: JsonSchema AdminRole\nadminRole = S.record\n          ( AdminRole'\n          \u003c$\u003e S.field \"department\"       JSON.string (to department)\n          \u003c*\u003e S.field \"subordinateCount\" JSON.int    (to subordinateCount)\n          )\n\nroleSchema :: JsonSchema Role\nroleSchema = S.oneOf\n           [ S.alt \"user\"  (S.const UserRole') _UserRole\n           , S.alt \"admin\" adminRole           _AdminRole\n           ]\n```\n\nOnce you have defined the schema, by proving an instance for the `HasSchema` typeclass,\n  you'll get JSON decoders, encoders, generators, etc. for free right away.\n\n```haskell\nimport Data.Schema (HasSchema(..))\n\ninstance HasSchema Person where\n  type PrimitivesOf Person = JsonType\n\n  getSchema = personSchema\n```\n\n### Pretty Printer\n\nThere is also built-in support for pretty printing schemas:\n\n```haskell\nimport Data.Schema.PrettyPrint\n\nputSchema' personSchema\n```\n\nThat will produce an output similar to the following:\n\n```\n* roles :: [\n  - user\n  - admin\n    * subordinateCount :: Number\n    * department :: Text\n]\n* birthDate ?:: Number\n* name :: Text\n```\n\nNot happy with that? What about a pretty printer based on the given schema? Just use the `prettyPrinter` function, which will\n  return you a `a -\u003e IO ()` function that you can use to print your data types:\n\n```haskell\npprintPerson :: Person -\u003e IO ()\npprintPerson = prettyPrinter' personSchema\n```\n\n## Credits\n\nAll thanks to [Kris Nuttycombe](https://github.com/nuttycom) for his excellent work in `xenomorph`, this project would be have\n  been impossible without his work.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falonsodomin%2Fhaskell-schema","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falonsodomin%2Fhaskell-schema","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falonsodomin%2Fhaskell-schema/lists"}