solnic / drops

🛠️ Tools for working with data effectively - data contracts using types, schemas, domain validation rules, type-safe casting, and more.
Other
257 stars 6 forks source link

Message backend with user-friendly errors #29

Closed solnic closed 1 year ago

solnic commented 1 year ago

This adds an error message backend that translates raw error tuples into user-friendly messages.

defmodule UserContract do
  use Drops.Contract

  schema do
    %{
      required(:name) => string(),
      required(:age) => integer(),
      required(:active) => boolean(),
      required(:tags) => list(string()),
      required(:settings) => map(:string),
      required(:address) => maybe(:string)
    }
  end
end

{:error, errors} = UserContract.conform(
  %{name: "Jane", age: 42, active: true, tags: ["red", :oops, "blue"], address: []}
)
{:error,
 [
   %Drops.Contract.Messages.Error.Sum{
     left: %Drops.Contract.Messages.Error.Type{
       path: [:address],
       text: "must be nil",
       meta: %{args: [nil, []], predicate: :type?}
     },
     right: %Drops.Contract.Messages.Error.Type{
       path: [:address],
       text: "must be a string",
       meta: %{args: [:string, []], predicate: :type?}
     }
   },
   %Drops.Contract.Messages.Error.Type{
     path: [:settings],
     text: "key must be present",
     meta: %{args: [:settings], predicate: :has_key?}
   },
   %Drops.Contract.Messages.Error.Type{
     path: [:tags, 1],
     text: "must be a string",
     meta: %{args: [:string, :oops], predicate: :type?}
   }
 ]}

Enum.map(errors, &to_string/1)
["address must be nil or address must be a string",
 "settings key must be present", "tags.1 must be a string"]