In the previous lesson, you used try/rescue to turn exceptions into {:ok, value} or {:error, reason}. Today, you will learn how to chain multiple such checks with the with statement. This helps you stop early on the first error and keeps your code clear.
What it does:
- Each line in
withpattern-matches on{:ok, value}. If a line returns{:error, reason}, thewithstops and jumps toelse. name,email, andageare bound only if the previous step succeeded.- The
elseblock returns the first error unchanged, keeping a consistent contract.
Note: You can add multiple patterns in else to transform different error shapes if needed. Here, a single {:error, reason} clause is enough.
What it does:
- Matches
nilfirst for a clear “required” error. - Uses guards to ensure the input is a binary (string) and checks length.
- Returns
{:ok, name}only when it is a valid string. - The final clause catches non-string types with a helpful message.
Design tip:
- Order matters. Place the most specific checks first, then the general catch-all last.
What it does:
- Email:
- Requires a string and checks for a basic "@" presence.
- Differentiates between “missing,” “wrong type,” and “bad format.”
- Age:
- Requires an integer and enforces a minimum value.
- Returns a uniform
{:error, reason}on any invalid input.
Notes:
- Keeping all validators returning the same tuple shapes makes
withsimple and predictable. - Use guards (
is_binary/1,is_integer/1) to fail fast and keep error messages clear.
You learned how with chains multiple validations and short-circuits on the first error while keeping a clean {:ok, value} | {:error, reason} flow. You also saw how to design small validator functions with guards and clear messages so that orchestration is simple.
You are ready to put this pattern into action. Head to the practice section and apply with to build tidy, reliable validation pipelines.
