We explore a Validator pattern for APIs that leverages Ecto Changesets to form a boundary layer of data in your system and return helpful error messages to your clients.
system • you want to establish a boundary layer past which you can say things for certain about the data. • these won't be the only validations you have in your system, and Let it Crash is still a reasonable attitude • this pattern only guarantees that types are correct and provides helpful error messages to your users. Which we should all be doing :)
known (ie, whitelisted) params are let into system • ensure required fields are present • coerce keys into atoms • coerce string values into meaningful types like DateTimes • return helpful errors Goals
coordinates are valid • the filters are legal (ie, restaurant_type is "sushi", not 5) • ^^ aren't business logic, exactly. whether "sushi" is a valid type is for elsewhere in the system Finding suitable restaurants near the user
do field :distance, :integer field :type_of_food, :string field :user_x, :float field :user_y, :float end @required [:distance, :type_of_food, :user_x, :user_y] def changeset(params) do __MODULE__ |> cast(params) |> validate_required(@required) |> validate_number(:distance, greater_than: 0) end end
• these modules don’t change much • avoid the temptation to get clever with macros • easy to customize error messages • fewer responsibilities for the controller Good things