Error Serialization Reference
View SourceThis document provides detailed information about how ErrorMessage handles serialization of error messages to different formats.
String Serialization
ErrorMessage implements the String.Chars
protocol, which allows error messages to be converted to strings using to_string/1
or string interpolation.
Basic Format
The string representation of an error message follows this format:
- For errors without details:
"#{code} - #{message}"
- For errors with details:
"#{code} - #{message}\nDetails: \n#{inspect(details, pretty: true)}"
Examples
# Error without details
error = ErrorMessage.not_found("User not found")
to_string(error) # "not_found - User not found"
# Error with details
error = ErrorMessage.internal_server_error("Database error", %{table: "users", reason: :connection_lost})
to_string(error)
# "internal_server_error - Database error
# Details:
# %{reason: :connection_lost, table: "users"}"
# String interpolation
"Error occurred: #{error}"
# "Error occurred: internal_server_error - Database error
# Details:
# %{reason: :connection_lost, table: "users"}"
JSON Serialization
ErrorMessage provides the to_jsonable_map/1
function to convert error messages to maps suitable for JSON serialization.
Basic Format
The JSON representation of an error message follows this format:
{
"code": "error_code",
"message": "Error message",
"details": { ... }
}
If a request ID is available in the Logger metadata, it will be included:
{
"code": "error_code",
"message": "Error message",
"details": { ... },
"request_id": "FzMx0iBDvDDJ-GkAAAfh"
}
Data Type Handling
The ErrorMessage.Serializer module includes the ensure_json_serializable/1
function, which handles conversion of Elixir-specific data types to JSON-compatible formats:
Elixir Type | JSON Representation |
---|---|
Date | ISO 8601 date string |
Time | ISO 8601 time string |
DateTime | ISO 8601 datetime string |
NaiveDateTime | ISO 8601 datetime string |
Struct | {"struct": "StructName", "data": {...}} |
Tuple | Array |
PID | String representation (with registered name if available) |
Function | {"module": "Module", "function": "function_name", "arity": n} |
List | Array with each element converted recursively |
Map | Object with each value converted recursively |
Other types | Passed through as-is |
Examples
# Basic error
error = ErrorMessage.not_found("User not found", %{user_id: 123})
ErrorMessage.to_jsonable_map(error)
# %{code: :not_found, message: "User not found", details: %{user_id: 123}}
# Error with complex details
error = ErrorMessage.bad_request("Invalid data", %{
date: ~D[2023-01-15],
time: ~T[14:30:00],
callback: &String.length/1,
user: %UserStruct{name: "John", created_at: ~N[2023-01-01 00:00:00]}
})
ErrorMessage.to_jsonable_map(error)
# %{
# code: :bad_request,
# message: "Invalid data",
# details: %{
# date: "2023-01-15",
# time: "14:30:00",
# callback: %{module: "Elixir.String", function: "length", arity: 1},
# user: %{
# struct: "UserStruct",
# data: %{
# name: "John",
# created_at: "2023-01-01T00:00:00"
# }
# }
# }
# }
Direct JSON Encoding
If the Jason library is available, ErrorMessage automatically implements the Jason.Encoder
protocol, allowing error messages to be directly encoded to JSON:
# With Jason available
Jason.encode!(ErrorMessage.not_found("User not found"))
# "{\"code\":\"not_found\",\"message\":\"User not found\"}"
# With details
Jason.encode!(ErrorMessage.not_found("User not found", %{user_id: 123}))
# "{\"code\":\"not_found\",\"message\":\"User not found\",\"details\":{\"user_id\":123}}"
Note that when using Jason.encode!/1
directly on an %ErrorMessage{}
struct, the serialization of complex data types in the details field may not be handled as thoroughly as when using ErrorMessage.to_jsonable_map/1
first. For the most reliable JSON serialization, especially with complex data structures, use:
error
|> ErrorMessage.to_jsonable_map()
|> Jason.encode!()
Integration with Phoenix
When using ErrorMessage with Phoenix, you can easily render error messages as JSON responses:
defmodule MyApp.ErrorView do
use MyApp, :view
def render("error.json", %{error: error}) do
ErrorMessage.to_jsonable_map(error)
end
end
This will produce JSON responses with the appropriate structure and data type handling.