Best practices for error handling and data validation

I’m building a API using Elixir + Phoenix and I have some questions about error handling and data validation.

Data validation
I want to do more precise validations in some fields of my schema, like if a email is really a email or if the taxId is valid. What is the best way to do that? Inside a controller? Logic layer?

Error handling
How can I send custom errors to the user? Like: error: "Invalid email", error: "Invalid taxID", error: "This user doesn't belong to you". Catch the errors from data validation for example and send them to the user

Embedded schemas are defined similarly to source-based schemas. For example, you can use an embedded schema to represent your UI, mapping and validating its inputs, and then you convert such embedded schema to other schemas that are persisted to the database.

https://hexdocs.pm/ecto/Ecto.Schema.html

:wave:

Both tasks are usually performed with the help of changesets,

What is the best way to do that? Inside a controller? Logic layer?

A changeset/_ function is usually added to the module defining the ecto schema and is called from a context before insert/update operations. So I guess it’s a logic layer.

Catch the errors from data validation for example and send them to the user

phoenix_html forms work well with changesets and can render their errors. For APIs other methods might be used, like traversing the errors in a changesets, and presenting them as a map of errors where keys are schema fields and values are lists of errors.