Custom Error Messages in PureScript Argonaut

purescript-argonaut-codecs computes in the Either monad putting errors in the Left constructor. If I want to change the error message or throw it away, I can map over the Left side of Either, throwing away the result or changing it. To illustrate how this works here are some helper functions I use when working with PureScript Argonaut.

import Prelude
import Data.Bifunctor (class Bifunctor, lmap)
import Data.Either (Left(..))
import Data.Maybe (Maybe(..))

maybeFail :: forall a b. String -> Maybe a -> Either String a
maybeFail s m = case m of
  Just mm -> Right mm
  Nothing -> Left s

failWith :: forall f c. (Bifunctor f) => String -> f String c -> f String c
failWith s = lmap (\a -> s)

failAppend :: forall f c. (Bifunctor f) => String -> f String c -> f String c
failAppend s = lmap (_ <> s)

failPrepend :: forall f c. (Bifunctor f) => String -> f String c -> f String c
failPrepend s = lmap (s <> _)

Then if I'm decoding an Account type with fields "id" and "users", I can decode an Account from Json, and have it return the appropriate error messages if there is a problem.

instance decodeAccount :: DecodeJson Account where
  decodeJson json = do
    obj <- maybeFail "Account must be an object." (toObject json)
    id <- failWith "Account is missing 'id' field." $ getField obj "id"
    users <- (failWith "Account is missing 'users' field.") (getField obj "users")
    pure $ Account {id, users}