@hackage tagliatelle0.9.0

Tagged encodings that are not spaghetti

Tagliatelle

Simple codec-style library for ToJSON, FromJSON and ToSchema. Main design goals are:

  1. Fast and Lean: tagliatelle codecs are cheap to compile and cheap to run. The performance is comparable to hand-written ToJSON/FromJSON instances, even beating it for some types.
  2. Explicit: You control the representation, no automatic anything. This makes it eaiser to keep the API backwards compatible while the code itself evolves as needed.
  3. Easy to use: Tries to minimise the boilerplate you need to maintain your codecs.
  4. Domain Specific: it's meant for helping maintaining Haskell services with a large HTTP API; there won't be other formats. The librrary has been designed to make it easy to write codecs for Haskell datatypes in the sum-of-products with record accessors, because that's how I write most of my types.

This library was inspired by autodocodec; but I wanted something that did less, so I could get a lighter footprint.

Example

{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE LambdaCase #-}

data TaskBody =
  Unstructured {body :: Text}
  | Absent
  | SubtasksMap { subtasksMap :: Map.Map TaskId TaskBody }
  | SubtasksList { subtasksList :: [TaskBody] }
  deriving (Eq, Show)

newtype TaskId = TaskId { taskId :: Int32 }
  deriving newtype (Eq, Show, Ord, IsKey, HasCodec)

instance HasCodec TaskBody where
  codec = coprod @"type" "TaskBody"
    (\case
      Unstructured {} -> unstructuredFields
      Absent {} -> absentFields
      SubtasksList {} -> subtasksListFields
      SubtasksMap {} -> subtasksMapFields
    )
    [unstructuredFields, absentFields, subtasksListFields, subtasksMapFields]
    where
      unstructuredFields = Tagged "unstructured" $ Unstructured <$> field "body" body codec
      absentFields = Tagged "absent" $ pure Absent
      subtasksListFields = Tagged "subtasks_list" $ SubtasksList <$> field "subtasks" subtasksList codec
      subtasksMapFields = Tagged "subtasks_map" $ SubtasksMap <$> field "subtasks" subtasksMap codec

This codec will produce JSON that, once formatted, looks like:

{
  "type": "subtasks_map",
  "subtasks": {
    "42": {
      "type": "subtasks_list",
      "subtasks": [
        {
          "type": "unstructured",
          "body": "test 1"
        },
        {
          "type": "absent"
        },
        {
          "type": "unstructured",
          "body": "test 2"
        }
      ]
    }
  }
}

Note that each hardcoded Text only shows up once: this makes it impossible to have spelling errors on tags between encoder and decoder.