### Pattern Match on Error Codes Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/tutorials/getting_started.md Demonstrates how to use pattern matching to specifically handle different error codes returned by functions. This example differentiates between a `:not_found` error and other potential errors from `UserRepository.find_user/1`. ```elixir case UserRepository.find_user(123) do {:ok, user} -> # Process the user IO.puts("Found user: #{user.name}") {:error, %ErrorMessage{code: :not_found}} -> # Handle not found specifically IO.puts("User not found, creating a new one") create_new_user(123) {:error, error} -> # Handle other errors IO.puts("Error: #{error.message}") end ``` -------------------------------- ### Create a Basic Error Message Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/tutorials/getting_started.md Demonstrates the creation of a simple error message using the `ErrorMessage.not_found/1` function. This generates an `%ErrorMessage{}` struct with a predefined code and a custom message. ```elixir # Create a basic not_found error error = ErrorMessage.not_found("Resource not found") ``` -------------------------------- ### Convert Error Messages to Strings for Logging Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/tutorials/getting_started.md Illustrates how to log error messages by leveraging the `String.Chars` protocol implemented by `ErrorMessage`. The `Logger.error/1` function can directly interpolate the error struct into a string. ```elixir require Logger def process_user(id) do case UserRepository.find_user(id) do {:ok, user} -> {:ok, process(user)} {:error, error} = result -> Logger.error("Failed to find user: #{error}") result end end ``` -------------------------------- ### Return Error Messages from Functions Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/tutorials/getting_started.md Shows a common Elixir pattern of returning `{:ok, result}` or `{:error, error_message}` from functions. This example uses `ErrorMessage.not_found/2` within a `find_user` function to indicate when a user is not found in the database. ```elixir defmodule UserRepository do def find_user(id) do case Database.get_user(id) do nil -> {:error, ErrorMessage.not_found("User not found", %{user_id: id})} user -> {:ok, user} end end end ``` -------------------------------- ### Create an Error Message with Details Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/tutorials/getting_started.md Illustrates how to add contextual details to an error message. The `ErrorMessage.not_found/2` function accepts a map of details, which is useful for providing more information about the error. Ensure details are JSON serializable if targeting API responses. ```elixir # Create an error with details error = ErrorMessage.not_found("User not found", %{user_id: 123}) ``` -------------------------------- ### Install ErrorMessage dependency Source: https://github.com/mikaak/elixir_error_message/blob/main/README.md Add the error_message package to your project by including it in the dependencies list within your mix.exs file. ```elixir def deps do [ {:error_message, "~> 0.2.0"} ] end ``` -------------------------------- ### Error Handling in Elixir GenServer with ErrorMessage Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/how-to-guides/error_handling_patterns.md Demonstrates how to integrate `ErrorMessage` into a GenServer implementation for handling client requests. The example shows returning specific `ErrorMessage` types like `not_found` when a requested resource is not present. ```elixir defmodule MyApp.UserManager do use GenServer # Client API def start_link(opts) do GenServer.start_link(__MODULE__, opts, name: __MODULE__) end def get_user(id) do GenServer.call(__MODULE__, {:get_user, id}) end # Server Callbacks def init(opts) do {:ok, %{users: opts[:initial_users] || %{}}} end def handle_call({:get_user, id}, _from, state) do case Map.get(state.users, id) do nil -> {:reply, {:error, ErrorMessage.not_found("User not found", %{user_id: id})}, state} user -> {:reply, {:ok, user}, state} end end end ``` -------------------------------- ### Convert Error Messages to JSON for API Responses Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/tutorials/getting_started.md Shows how to convert an `ErrorMessage` struct into a JSON-serializable map using `ErrorMessage.to_jsonable_map/1`. This is typically used in web API contexts to send structured error information to clients. ```elixir defmodule MyAPI.ErrorView do def render("error.json", %{error: error}) do ErrorMessage.to_jsonable_map(error) end end ``` -------------------------------- ### Install ErrorMessage Dependency in Mix.exs Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/overview.md This snippet shows how to add the ErrorMessage library as a dependency in your Elixir project's `mix.exs` file. Ensure you use the correct version string for compatibility. ```elixir def deps do [ {:error_message, "~> 0.3.2"} ] end ``` -------------------------------- ### Integrate ErrorMessage with Phoenix and Ecto Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/explanation/error_handling_in_elixir.md Examples of mapping ErrorMessage to HTTP responses in Phoenix controllers and converting Ecto changeset errors into structured ErrorMessage formats. ```elixir # HTTP Integration def render_error(conn, %ErrorMessage{} = error) do conn |> put_status(ErrorMessage.http_code(error)) |> json(ErrorMessage.to_jsonable_map(error)) end # Ecto integration case Repo.insert(changeset) do {:ok, user} -> {:ok, user} {:error, changeset} -> errors = Ecto.Changeset.traverse_errors(changeset, &translate_error/1) {:error, ErrorMessage.unprocessable_entity("Invalid user data", errors)} end # Phoenix FallbackController def call(conn, {:error, %ErrorMessage{} = error}) do conn |> put_status(ErrorMessage.http_code(error)) |> put_view(MyApp.ErrorView) |> render("error.json", error: error) end ``` -------------------------------- ### Elixir: Phoenix JSON Error Response Rendering Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/reference/serialization.md Provides an example of integrating ErrorMessage with Phoenix to render JSON error responses. It shows a basic `ErrorView` implementation using `ErrorMessage.to_jsonable_map/1`. ```elixir defmodule MyApp.ErrorView do use MyApp, :view def render("error.json", %{error: error}) do ErrorMessage.to_jsonable_map(error) end end ``` -------------------------------- ### Elixir: JSON Serialization of Error Messages to Map Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/reference/serialization.md Shows how to convert ErrorMessage structs into maps suitable for JSON serialization using `to_jsonable_map/1`. Includes examples with basic and complex details, demonstrating data type conversions. ```elixir iex> error = ErrorMessage.not_found("User not found", %{user_id: 123}) iex> ErrorMessage.to_jsonable_map(error) %{code: :not_found, message: "User not found", details: %{user_id: 123}} iex> 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]} ...> }) iex> 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" } } }} ``` -------------------------------- ### Error Handling with `with/1` and ErrorMessage in Elixir Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/how-to-guides/error_handling_patterns.md Illustrates using Elixir's `with/1` special form to chain operations that may return errors. It shows how to specifically handle `ErrorMessage` instances with certain codes and details, and provides a general fallback for other errors. ```elixir def create_order(user_id, product_id, quantity) do with {:ok, user} <- find_user(user_id), {:ok, product} <- find_product(product_id), {:ok, _} <- check_inventory(product, quantity), {:ok, order} <- create_order_record(user, product, quantity) do {:ok, order} else {:error, %ErrorMessage{code: :not_found, details: %{user_id: _}}} -> {:error, ErrorMessage.bad_request("Invalid user", %{user_id: user_id})} {:error, %ErrorMessage{code: :not_found, details: %{product_id: _}}} -> {:error, ErrorMessage.bad_request("Invalid product", %{product_id: product_id})} {:error, error} -> # Pass through any other errors {:error, error} end end ``` -------------------------------- ### Create and use ErrorMessage structs Source: https://github.com/mikaak/elixir_error_message/blob/main/README.md Demonstrates how to instantiate ErrorMessage structs with specific HTTP-like codes, messages, and metadata details. ```elixir id = 1 ErrorMessage.not_found("no user with id #{id}", %{user_id: id}) ErrorMessage.internal_server_error("critical internal error", %{ reason: :massive_issue_with_x }) ``` -------------------------------- ### Pattern Matching on Error Codes with ErrorMessage in Elixir Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/how-to-guides/error_handling_patterns.md Demonstrates how to use pattern matching with the `case` statement to handle different `ErrorMessage` structures and other error tuples. This approach allows for specific error code handling and a fallback for unexpected errors. ```elixir def process_result(result) do # Generally we won't be returning atoms through our # system but as an example of how we can handle them case result do {:ok, value} -> # Handle success case {:ok, process_value(value)} {:error, %ErrorMessage{code: :not_found}} -> # Handle not found specifically {:error, :resource_missing} {:error, %ErrorMessage{code: :unauthorized}} -> # Handle unauthorized specifically {:error, :permission_denied} {:error, %ErrorMessage{} = error} -> # Handle any other error Logger.error("Unexpected error: #{error}") {:error, :unexpected_error} end end ``` -------------------------------- ### Pattern Matching and Control Flow with ErrorMessage Source: https://context7.com/mikaak/elixir_error_message/llms.txt Shows how to use pattern matching on error codes for resilient error handling and how to use the 'with' macro to handle multi-step operations with specific error contexts. ```elixir case UserService.find_user(123) do {:ok, user} -> IO.puts("Found user: #{user.name}") {:error, %ErrorMessage{code: :not_found}} -> IO.puts("User not found") {:error, %ErrorMessage{} = error} -> IO.puts("Unexpected error: #{error}") end # Using with/1 with {:ok, user} <- find_user(user_id), {:ok, product} <- find_product(product_id) do {:ok, order} else {:error, %ErrorMessage{code: :not_found, details: %{user_id: _}}} -> {:error, :invalid_user} end ``` -------------------------------- ### Test Elixir Error Handling Flow with Scenarios Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/tutorials/error_handling_workflow.md Provides a demo module to test the error handling logic defined in the UserController. It simulates various scenarios, including different user roles, invalid inputs, and non-existent users, to verify the error reporting mechanism. This module uses mock connections and asserts the expected outcomes. ```elixir defmodule MyApp.ErrorHandlingDemo do @moduledoc """ Demo module to show the error handling flow """ alias MyApp.UserController @doc """ Run the demo with different scenarios """ def run do # Setup mock connection and users admin_conn = %{assigns: %{current_user: %{id: 1, role: :admin}}} user_conn = %{assigns: %{current_user: %{id: 2, role: :user}}} IO.puts("\n=== Scenario 1: Admin accessing own profile ===") case UserController.show(admin_conn, %{"id" => "1"}) do {:ok, profile} -> IO.puts("Success: #{inspect(profile)}") {:error, error} -> IO.puts("Error: #{error}") end IO.puts("\n=== Scenario 2: Admin accessing another user's profile ===") case UserController.show(admin_conn, %{"id" => "2"}) do {:ok, profile} -> IO.puts("Success: #{inspect(profile)}") {:error, error} -> IO.puts("Error: #{error}") end IO.puts("\n=== Scenario 3: Regular user accessing own profile ===") case UserController.show(user_conn, %{"id" => "2"}) do {:ok, profile} -> IO.puts("Success: #{inspect(profile)}") {:error, error} -> IO.puts("Error: #{error}") end IO.puts("\n=== Scenario 4: Regular user accessing admin's profile ===") case UserController.show(user_conn, %{"id" => "1"}) do {:ok, profile} -> IO.puts("Success: #{inspect(profile)}") {:error, error} -> IO.puts("Error: #{error}") end IO.puts("\n=== Scenario 5: Invalid ID format ===") case UserController.show(admin_conn, %{"id" => "abc"}) do {:ok, profile} -> IO.puts("Success: #{inspect(profile)}") {:error, error} -> IO.puts("Error: #{error}") end IO.puts("\n=== Scenario 6: Non-existent user ===") case UserController.show(admin_conn, %{"id" => "999"}) do {:ok, profile} -> IO.puts("Success: #{inspect(profile)}") {:error, error} -> IO.puts("Error: #{error}") end IO.puts("\n=== Scenario 7: Update with invalid role ===") case UserController.update(admin_conn, %{"id" => "2", "user" => %{"role" => "superuser"}}) do {:ok, profile} -> IO.puts("Success: #{inspect(profile)}") {:error, error} -> IO.puts("Error: #{error}") end end end ``` -------------------------------- ### Create Error Messages with ErrorMessage Source: https://context7.com/mikaak/elixir_error_message/llms.txt Demonstrates how to instantiate ErrorMessage structs for various HTTP status codes. These functions accept a message and optional context details to provide structured error information. ```elixir ErrorMessage.not_found("User not found") ErrorMessage.not_found("User not found", %{user_id: 123}) ErrorMessage.internal_server_error("Database connection failed", %{table: "users", reason: :connection_timeout}) ErrorMessage.unprocessable_entity("Validation failed", %{email: "is invalid", password: "is too short"}) ErrorMessage.too_many_requests("Rate limit exceeded", %{retry_after: 60, limit: 100}) ErrorMessage.unauthorized("Invalid credentials") ErrorMessage.forbidden("Access denied", %{required_role: :admin}) ``` -------------------------------- ### Run Error Handling Demo in Elixir Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/tutorials/error_handling_workflow.md Executes a demonstration of various error scenarios within an Elixir application. This function call is intended to be run in a script or an IEx session to observe the output of different error conditions. ```elixir MyApp.ErrorHandlingDemo.run() ``` -------------------------------- ### Pattern match on ErrorMessage codes Source: https://github.com/mikaak/elixir_error_message/blob/main/README.md Shows how to use the 'with' statement to catch specific error codes, allowing for predictable error handling and fallback logic. ```elixir with {:error, %ErrorMessage{code: :not_found}} <- find_user(%{name: "bill"}) do create_user(%{name: "bill"}) end ``` -------------------------------- ### Implement Error Handling in GenServer Source: https://context7.com/mikaak/elixir_error_message/llms.txt Shows how to integrate ErrorMessage within a GenServer to return structured error responses during process calls. This approach maintains consistency across concurrent application processes. ```elixir defmodule MyApp.UserManager do use GenServer def handle_call({:get_user, id}, _from, state) do case Map.get(state.users, id) do nil -> {:reply, {:error, ErrorMessage.not_found("User not found", %{user_id: id})}, state} user -> {:reply, {:ok, user}, state} end end def handle_call({:create_user, attrs}, _from, state) do case validate_user(attrs) do :ok -> id = generate_id() user = Map.put(attrs, :id, id) new_state = put_in(state.users[id], user) {:reply, {:ok, user}, new_state} {:error, reasons} -> error = ErrorMessage.unprocessable_entity("Invalid user data", reasons) {:reply, {:error, error}, state} end end end ``` -------------------------------- ### Handle HTTP Client Errors with ErrorMessage Source: https://context7.com/mikaak/elixir_error_message/llms.txt Demonstrates how to map various HTTP response statuses to standardized ErrorMessage structures. This pattern ensures consistent error reporting when interacting with external APIs. ```elixir def handle_http_response(response) do case response do {:ok, %{status: 200, body: body}} -> {:ok, body} {:ok, %{status: 404}} -> {:error, ErrorMessage.not_found("Remote resource not found")} {:ok, %{status: 429, headers: headers}} -> retry_after = get_header(headers, "retry-after") {:error, ErrorMessage.too_many_requests("Rate limited", %{retry_after: retry_after})} {:ok, %{status: status}} when status >= 500 -> {:error, ErrorMessage.bad_gateway("Upstream server error", %{status: status})} {:error, reason} -> {:error, ErrorMessage.service_unavailable("Service unavailable", %{reason: reason})} end end ``` -------------------------------- ### Handle Errors with Tagged Tuples and Exceptions in Elixir Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/explanation/error_handling_in_elixir.md Demonstrates the standard Elixir patterns for error handling using tagged tuples for expected errors and try/rescue blocks for exceptional circumstances. ```elixir # Success case {:ok, result} # Error case {:error, reason} # Pattern matching case MyModule.some_function() do {:ok, result} -> handle_success(result) {:error, reason} -> handle_error(reason) end # Exceptions try do some_function_that_might_raise() rescue e in SomeError -> handle_error(e) end ``` -------------------------------- ### Basic ErrorMessage Usage in Elixir Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/overview.md Demonstrates fundamental operations with the ErrorMessage library, including creating errors with messages and details, retrieving HTTP status codes, converting errors to strings for logging, and transforming them into JSON-serializable maps. ```elixir # Create a not_found error with a message and details error = ErrorMessage.not_found("User not found", %{user_id: 123}) # %ErrorMessage{code: :not_found, message: "User not found", details: %{user_id: 123}} # Get the HTTP status code ErrorMessage.http_code(error) # Returns 404 # Convert to string for logging to_string(error) # Returns "not_found - User not found\nDetails: \n%{user_id: 123}" # Convert to a map for JSON serialization ErrorMessage.to_jsonable_map(error) # %{code: :not_found, message: "User not found", details: %{user_id: 123}} ``` -------------------------------- ### Handle Concurrent Operations in Elixir Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/how-to-guides/error_handling_patterns.md Demonstrates how to execute multiple tasks concurrently using Task.async and aggregate the results. It splits the outcomes into successes and errors, returning a multi-status error if any task fails. ```elixir def process_items(items) do items |> Enum.map(fn item -> Task.async(fn -> process_item(item) end) end) |> Task.await_many() |> Enum.split_with(fn {:ok, _} -> true {:error, _} -> false end) |> case do {successes, []} -> {:ok, Enum.map(successes, fn {:ok, result} -> result end)} {_, errors} -> error_details = Enum.map(errors, fn {:error, error} -> %{item_id: error.details.item_id, reason: error.message} end) {:error, ErrorMessage.multi_status("Some operations failed", %{errors: error_details})} end end ``` -------------------------------- ### Implement Structured Errors with ErrorMessage Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/explanation/error_handling_in_elixir.md Shows how to define and use the ErrorMessage struct to provide consistent error codes, human-readable messages, and additional context. ```elixir %ErrorMessage{ code: :error_code, message: "Human-readable message", details: additional_context } # Pattern matching on error codes case result do {:ok, value} -> handle_success(value) {:error, %ErrorMessage{code: :not_found}} -> handle_not_found() {:error, %ErrorMessage{code: :unauthorized}} -> handle_unauthorized() {:error, _} -> handle_other_errors() end # Creating rich context ErrorMessage.not_found("User not found", %{ user_id: id, search_params: params, timestamp: DateTime.utc_now() }) ``` -------------------------------- ### Update Controller to Use Error Logger in Elixir Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/tutorials/error_handling_workflow.md Illustrates how to integrate the `MyApp.ErrorLogger` into a controller's error rendering function. This snippet shows the call to `log_error` before rendering the actual error response, ensuring errors are logged with context. ```elixir defp render_error(conn, %ErrorMessage{} = error) do # Log the error MyApp.ErrorLogger.log_error(error, "UserController") # Render the error response # ... end ``` -------------------------------- ### Convert ErrorMessage to String Source: https://context7.com/mikaak/elixir_error_message/llms.txt Shows how to utilize the String.Chars protocol for logging and debugging. This allows for easy string interpolation and integration with the Elixir Logger. ```elixir error = ErrorMessage.not_found("User not found") ErrorMessage.to_string(error) # String interpolation "Error occurred: #{error}" # Usage with Logger require Logger Logger.error("[MyModule] #{error}") ``` -------------------------------- ### Define Domain Logic with Error Handling in Elixir Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/tutorials/error_handling_workflow.md This module implements user retrieval and update logic using ErrorMessage to return structured error tuples. It demonstrates handling 'not found' and 'unprocessable entity' scenarios within a functional domain layer. ```elixir defmodule MyApp.Users do @moduledoc "User management functionality" @users %{ 1 => %{id: 1, name: "Alice", email: "alice@example.com", role: :admin}, 2 => %{id: 2, name: "Bob", email: "bob@example.com", role: :user} } @spec get_user(integer()) :: {:ok, map()} | {:error, ErrorMessage.t()} def get_user(id) when is_integer(id) do case Map.get(@users, id) do nil -> {:error, ErrorMessage.not_found("User not found", %{user_id: id})} user -> {:ok, user} end end @spec update_user(integer(), map()) :: {:ok, map()} | {:error, ErrorMessage.t()} def update_user(id, params) when is_integer(id) and is_map(params) do with {:ok, user} <- get_user(id), {:ok, updated_user} <- validate_update(user, params) do {:ok, updated_user} end end defp validate_update(user, %{role: role} = params) do case role do role when role in [:admin, :user] -> {:ok, Map.merge(user, Map.take(params, [:name, :email, :role]))} _ -> {:error, ErrorMessage.unprocessable_entity("Invalid role", %{ allowed_roles: [:admin, :user], provided_role: role })} end end end ``` -------------------------------- ### Elixir Pattern Matching for Robust Error Handling Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/explanation/error_design_principles.md Demonstrates the difference between fragile string-based error matching and robust pattern matching using the ErrorMessage struct. This approach enhances maintainability by decoupling error handling logic from specific error message strings. ```elixir ```elixir # Fragile approach (depends on exact message text) case result do {:error, "User not found: " <> _} -> handle_not_found() # ... end # Robust approach with ErrorMessage case result do {:error, %ErrorMessage{code: :not_found}} -> handle_not_found() # ... end ``` ``` -------------------------------- ### Convert HTTP Status Codes and Atoms Source: https://context7.com/mikaak/elixir_error_message/llms.txt Utilities to map between HTTP status integers and their corresponding atom representations used within the library. ```elixir ErrorMessage.http_code(ErrorMessage.not_found("Not found")) ErrorMessage.http_code(:not_found) ErrorMessage.http_code_reason_atom(404) ErrorMessage.http_code_reason_atom(500) ``` -------------------------------- ### Elixir: Direct JSON Encoding with Jason Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/reference/serialization.md Illustrates direct JSON encoding of ErrorMessage structs using the `Jason.Encoder` protocol. This requires the Jason library to be available. Shows encoding with and without details. ```elixir iex> # With Jason available iex> Jason.encode!(ErrorMessage.not_found("User not found")) "{\"code\":\"not_found\",\"message\":\"User not found\"}" iex> # With details iex> Jason.encode!(ErrorMessage.not_found("User not found", %{user_id: 123})) "{\"code\":\"not_found\",\"message\":\"User not found\",\"details\":{\"user_id\":123}}" ``` -------------------------------- ### Create Elixir Phoenix Controller for User Endpoints Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/tutorials/error_handling_workflow.md Defines a controller module for handling HTTP requests related to user profiles in a Phoenix application. It includes functions for showing and updating user profiles, with error handling for invalid IDs and service layer errors. Dependencies include MyApp.UserService and ErrorMessage. ```elixir defmodule MyApp.UserController do @moduledoc """ Controller for user endpoints """ # In a real Phoenix app, you would use: use MyApp.Web, :controller alias MyApp.UserService @doc """ Get user profile """ def show(conn, %{"id" => id_string}) do # Get the current user from the session/token (simplified for this example) current_user = conn.assigns.current_user with {:ok, id} <- parse_id(id_string), {:ok, profile} <- UserService.get_profile(id, current_user) do # In a real Phoenix app: render(conn, "show.json", user: profile) {:ok, profile} else {:error, error} -> render_error(conn, error) end end @doc """ Update user profile """ def update(conn, %{"id" => id_string, "user" => user_params}) do current_user = conn.assigns.current_user with {:ok, id} <- parse_id(id_string), {:ok, profile} <- UserService.update_profile(id, user_params, current_user) do # In a real Phoenix app: render(conn, "show.json", user: profile) {:ok, profile} else {:error, error} -> render_error(conn, error) end end # Helper functions defp parse_id(id_string) do case Integer.parse(id_string) do {id, ""} -> {:ok, id} _ -> {:error, ErrorMessage.bad_request("Invalid ID format", %{id: id_string})} end end defp render_error(conn, %ErrorMessage{} = error) do # In a real Phoenix app: # conn # |> put_status(ErrorMessage.http_code(error)) # |> put_view(MyApp.ErrorView) # |> render("error.json", error: error) # For this example, we'll just return the error {:error, error} end end ``` -------------------------------- ### Converting Ecto and File Errors to ErrorMessage in Elixir Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/how-to-guides/error_handling_patterns.md Provides functions to convert errors from Ecto changesets and standard Elixir file operations into the `ErrorMessage` format. This ensures consistent error representation across different parts of an application. ```elixir def handle_ecto_errors(changeset) do errors = Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} -> Enum.reduce(opts, msg, fn {key, value}, acc -> String.replace(acc, "%{#{key}}", to_string(value)) end) end) ErrorMessage.unprocessable_entity("Validation failed", errors) end def handle_file_errors(file_path) do case File.read(file_path) do {:ok, content} -> {:ok, content} {:error, :enoent} -> {:error, ErrorMessage.not_found("File not found", %{path: file_path})} {:error, :eacces} -> {:error, ErrorMessage.forbidden("Permission denied", %{path: file_path})} {:error, reason} -> {:error, ErrorMessage.internal_server_error("File error", %{reason: reason, path: file_path})} end end ``` -------------------------------- ### Convert External Errors to ErrorMessage Source: https://context7.com/mikaak/elixir_error_message/llms.txt Provides patterns for mapping external library errors, such as Ecto changesets or File system errors, into the standard ErrorMessage format. ```elixir def handle_file_errors(file_path) do case File.read(file_path) do {:ok, content} -> {:ok, content} {:error, :enoent} -> {:error, ErrorMessage.not_found("File not found", %{path: file_path})} {:error, reason} -> {:error, ErrorMessage.internal_server_error("File error", %{reason: reason})} end end ``` -------------------------------- ### Log ErrorMessage instances Source: https://github.com/mikaak/elixir_error_message/blob/main/README.md Utilizes the String.Chars protocol implementation of ErrorMessage to log errors directly using Elixir's Logger. ```elixir case do_thing() do {:ok, value} -> {:ok, do_other_thing(value)} {:error, e} = res -> Logger.error("[MyModule] #{e}") Logger.warn(to_string(e)) res end ``` -------------------------------- ### Serialize ErrorMessage to JSON Source: https://context7.com/mikaak/elixir_error_message/llms.txt Demonstrates how to convert an ErrorMessage struct into a map for JSON serialization, including automatic inclusion of Logger metadata like request_id. ```elixir Logger.metadata(request_id: "FzMx0iBDvDDJ-GkAAAfh") error = ErrorMessage.not_found("Not found") # Convert to map map = ErrorMessage.to_jsonable_map(error) # Encode to JSON string json = Jason.encode!(map) ``` -------------------------------- ### Compose Error Handlers in Elixir Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/how-to-guides/error_handling_patterns.md Helper functions for managing error flows including logging, fallback mechanisms, and conditional retries. These functions wrap operations to provide consistent error handling logic across an application. ```elixir defmodule MyApp.ErrorHelpers do require Logger def with_logging(result, context) do case result do {:ok, _} = success -> success {:error, %ErrorMessage{} = error} -> Logger.error("[#{context}] #{error}") {:error, error} end end def with_fallback(result, fallback_fn) do case result do {:ok, _} = success -> success {:error, %ErrorMessage{code: :not_found}} -> fallback_fn.() {:error, _} = error -> error end end def with_retry(operation, retry_count \\ 3) do retry_with_count(operation, retry_count) end defp retry_with_count(operation, count) when count > 0 do case operation.() do {:ok, _} = success -> success {:error, %ErrorMessage{code: code} = error} when code in [:service_unavailable, :gateway_timeout] -> Process.sleep(100) retry_with_count(operation, count - 1) {:error, _} = error -> error end end defp retry_with_count(_operation, 0) do {:error, ErrorMessage.service_unavailable("Operation failed after multiple retries")} end end ``` -------------------------------- ### Elixir: Logger Configuration for Request ID Metadata Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/how-to-guides/phoenix_integration.md This Elixir configuration snippet demonstrates how to set up the Logger to include request_id in its metadata for console output. This ensures that request IDs are available for ErrorMessage to include in error responses, aiding in error correlation. ```elixir config :logger, :console, format: "$time $metadata[$level] $message\n", metadata: [:request_id] ``` -------------------------------- ### Phoenix Framework Integration Source: https://context7.com/mikaak/elixir_error_message/llms.txt Integrates ErrorMessage with Phoenix controllers using custom error views and action_fallback for consistent API error responses. ```elixir defmodule MyApp.FallbackController do use Phoenix.Controller def call(conn, {:error, %ErrorMessage{} = error}) do conn |> put_status(ErrorMessage.http_code(error)) |> render(MyApp.ErrorView, "error.json", error: error) end end ``` -------------------------------- ### Elixir: Phoenix Fallback Controller for ErrorMessage and Ecto.Changeset Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/how-to-guides/phoenix_integration.md This Elixir module implements a fallback controller in Phoenix for handling various error types, including ErrorMessage and Ecto.Changeset. It translates Ecto.Changeset errors into an ErrorMessage struct for consistent rendering. Dependencies include Phoenix.Controller, MyApp.ErrorHandler, and Ecto.Changeset. ```elixir defmodule MyApp.FallbackController do use Phoenix.Controller import MyApp.ErrorHandler def call(conn, {:error, %ErrorMessage{} = error}) do render_error(conn, error) end # Handle other error types def call(conn, {:error, %Ecto.Changeset{} = changeset}) do # Convert Ecto.Changeset errors to ErrorMessage errors = Ecto.Changeset.traverse_errors(changeset, &translate_error/1) error = ErrorMessage.unprocessable_entity("Invalid parameters", errors) render_error(conn, error) end defp translate_error({msg, opts}) do Enum.reduce(opts, msg, fn {key, value}, acc -> String.replace(acc, "%{#{key}}", to_string(value)) end) end end ``` -------------------------------- ### Log Errors with Severity in Elixir Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/tutorials/error_handling_workflow.md Defines a module `MyApp.ErrorLogger` to log errors with appropriate severity levels based on the error code. It uses Elixir's `Logger` module and pattern matching to determine the log level for different error codes. The function takes an `ErrorMessage` struct and context as input. ```elixir defmodule MyApp.ErrorLogger do require Logger @doc """ Log an error with appropriate severity based on the error code """ def log_error(%ErrorMessage{} = error, context) do log_level = get_log_level(error.code) Logger.log(log_level, "[#{context}] #{error}") error end defp get_log_level(code) when code in [:internal_server_error, :service_unavailable] do :error end defp get_log_level(code) when code in [:bad_request, :unauthorized, :forbidden, :not_found] do :info end defp get_log_level(_code) do :warn end end ``` -------------------------------- ### Create Service Layer with Authorization in Elixir Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/tutorials/error_handling_workflow.md This service layer wraps domain logic with authorization checks, utilizing ErrorMessage to return forbidden errors when access is denied. It acts as an orchestration layer between the domain and the external interface. ```elixir defmodule MyApp.UserService do alias MyApp.Users @spec get_profile(integer(), map()) :: {:ok, map()} | {:error, ErrorMessage.t()} def get_profile(user_id, current_user) do with {:ok, user} <- Users.get_user(user_id), :ok <- authorize_profile_access(user, current_user) do {:ok, format_profile(user)} end end defp authorize_profile_access(user, current_user) do cond do current_user.id == user.id -> :ok current_user.role == :admin -> :ok true -> {:error, ErrorMessage.forbidden("Not authorized to view this profile")} end end defp format_profile(user) do Map.take(user, [:id, :name, :email, :role]) end end ``` -------------------------------- ### Implement Jason.Encoder protocol for ErrorMessage Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/reference/api_reference.md Conditionally derives the Jason.Encoder protocol if the Jason library is present, enabling direct JSON serialization of error messages. ```elixir if Enum.any?(Application.loaded_applications(), fn {dep_name, _, _} -> dep_name === :jason end) do @derive Jason.Encoder end # Example usage: # iex> Jason.encode!(ErrorMessage.not_found("User not found")) # "{\"code\":\"not_found\",\"message\":\"User not found\"}" ``` -------------------------------- ### Elixir: Using ErrorMessage in Phoenix Controllers Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/how-to-guides/phoenix_integration.md This Elixir module demonstrates how to use the ErrorMessage struct within Phoenix controllers for handling successful operations and errors. It integrates with a custom ErrorHandler to render errors consistently. Dependencies include MyApp.ErrorHandler and Phoenix controllers. ```elixir defmodule MyApp.UserController do use MyApp, :controller import MyApp.ErrorHandler def show(conn, %{"id" => id}) do case MyApp.Accounts.get_user(id) do {:ok, user} -> render(conn, "show.json", user: user) {:error, %ErrorMessage{} = error} -> render_error(conn, error) end end def create(conn, %{"user" => user_params}) do case MyApp.Accounts.create_user(user_params) do {:ok, user} -> conn |> put_status(:created) |> render("show.json", user: user) {:error, %ErrorMessage{} = error} -> render_error(conn, error) end end end ``` -------------------------------- ### Standard HTTP Error Functions Source: https://context7.com/mikaak/elixir_error_message/llms.txt A reference list of available functions in the ErrorMessage library corresponding to standard HTTP status codes for 3xx, 4xx, and 5xx errors. ```elixir ErrorMessage.not_found(message, details \\ nil) # 404 ErrorMessage.unprocessable_entity(message, details \\ nil) # 422 ErrorMessage.too_many_requests(message, details \\ nil) # 429 ErrorMessage.internal_server_error(message, details \\ nil) # 500 ErrorMessage.bad_gateway(message, details \\ nil) # 502 ``` -------------------------------- ### Implement String.Chars protocol for ErrorMessage Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/reference/api_reference.md Enables string conversion for ErrorMessage structs, allowing usage in string interpolation and to_string calls. ```elixir defimpl String.Chars do def to_string(%ErrorMessage{} = e) do ErrorMessage.to_string(e) end end # Example usage: # iex> "Error: #{ErrorMessage.not_found("User not found")}" # "Error: not_found - User not found" ``` -------------------------------- ### Create HTTP Error Messages in Elixir Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/reference/api_reference.md Functions for generating specific HTTP error structs. Each function accepts a message string and optional details, returning an ErrorMessage struct. ```elixir ErrorMessage.bad_request(message, details \\ nil) ErrorMessage.unauthorized(message, details \\ nil) ErrorMessage.forbidden(message, details \\ nil) ErrorMessage.not_found(message, details \\ nil) ErrorMessage.method_not_allowed(message, details \\ nil) ErrorMessage.not_acceptable(message, details \\ nil) ErrorMessage.request_timeout(message, details \\ nil) ErrorMessage.conflict(message, details \\ nil) ErrorMessage.gone(message, details \\ nil) ErrorMessage.unprocessable_entity(message, details \\ nil) ErrorMessage.too_many_requests(message, details \\ nil) ErrorMessage.internal_server_error(message, details \\ nil) ErrorMessage.not_implemented(message, details \\ nil) ErrorMessage.bad_gateway(message, details \\ nil) ErrorMessage.service_unavailable(message, details \\ nil) ErrorMessage.gateway_timeout(message, details \\ nil) ``` -------------------------------- ### Elixir: String Serialization of Error Messages Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/reference/serialization.md Demonstrates converting ErrorMessage structs to strings using the `String.Chars` protocol. Handles errors with and without details, and shows string interpolation. ```elixir iex> error = ErrorMessage.not_found("User not found") iex> to_string(error) "not_found - User not found" iex> error = ErrorMessage.internal_server_error("Database error", %{table: "users", reason: :connection_lost}) iex> to_string(error) "internal_server_error - Database error\nDetails: \n%{reason: :connection_lost, table: \"users\"}" iex> "Error occurred: #{error}" "Error occurred: internal_server_error - Database error\nDetails: \n%{reason: :connection_lost, table: \"users\"}" ``` -------------------------------- ### Render ErrorMessage in Phoenix Controllers Source: https://github.com/mikaak/elixir_error_message/blob/main/README.md Integrates ErrorMessage with Phoenix by mapping the error code to an HTTP status and converting the struct to a JSON-compatible map. ```elixir defmodule MyController do def index(conn, param) do case find_thing(params) do {:ok, res} -> json(conn, res) {:error, e} -> json_error(conn, e) end end defp json_error(conn, %ErrorMessage{code: code} = e) do conn |> put_status(code) |> json(ErrorMessage.to_jsonable_map(e)) end end ``` -------------------------------- ### Elixir: Render ErrorResponse using ErrorMessage in Phoenix Controller Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/how-to-guides/phoenix_integration.md This Elixir module provides a function to render error responses in a Phoenix controller using the ErrorMessage struct. It sets the HTTP status, specifies an error view, and renders the error in JSON format. Dependencies include Plug.Conn and Phoenix.Controller. ```elixir defmodule MyApp.ErrorHandler do import Plug.Conn import Phoenix.Controller @doc """ Renders an error response using the ErrorMessage struct """ def render_error(conn, %ErrorMessage{} = error) do conn |> put_status(ErrorMessage.http_code(error)) |> put_view(MyApp.ErrorView) |> render("error.json", error: error) end end ``` -------------------------------- ### Elixir: Phoenix Error View for ErrorMessage Struct Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/how-to-guides/phoenix_integration.md This Elixir module defines a Phoenix view for rendering errors, specifically handling the ErrorMessage struct. It converts the ErrorMessage to a JSON-serializable map and includes fallback templates for common HTTP error codes. It depends on the ErrorMessage struct and Phoenix views. ```elixir defmodule MyApp.ErrorView do use MyApp, :view @doc """ Renders an error message from an ErrorMessage struct """ def render("error.json", %{error: error}) do ErrorMessage.to_jsonable_map(error) end # Keep your existing error templates def render("404.json", _assigns) do %{errors: %{detail: "Not Found"}} end def render("500.json", _assigns) do %{errors: %{detail: "Internal Server Error"}} end end ``` -------------------------------- ### Elixir: Phoenix Endpoint Configuration for RequestId Plug Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/how-to-guides/phoenix_integration.md This Elixir code snippet shows how to configure a Phoenix endpoint to include the Plug.RequestId plug. This is essential for automatically adding request IDs to logger metadata, which can then be included in ErrorMessage responses. ```elixir defmodule MyApp.Endpoint do use Phoenix.Endpoint, otp_app: :my_app plug Plug.RequestId # ... end ``` -------------------------------- ### Map Errors to HTTP Status Codes Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/reference/api_reference.md Utility functions to retrieve the integer HTTP status code from an error message or atom, and vice versa. ```elixir @spec http_code(error_code :: code) :: non_neg_integer() @spec http_code(error_message :: t) :: non_neg_integer() iex> ErrorMessage.http_code(:not_found) 404 iex> ErrorMessage.http_code_reason_atom(404) :not_found ``` -------------------------------- ### Enforce Type Safety with ErrorMessage Specifications Source: https://context7.com/mikaak/elixir_error_message/llms.txt Utilizes ErrorMessage type specifications in function signatures to ensure consistent return types for repository operations, improving code reliability and IDE support. ```elixir @spec find_user(integer()) :: ErrorMessage.t_res(User.t()) def find_user(id) do case Database.get_user(id) do nil -> {:error, ErrorMessage.not_found("User not found", %{user_id: id})} user -> {:ok, user} end end ``` -------------------------------- ### Serialize ErrorMessage to JSON-compatible Map Source: https://context7.com/mikaak/elixir_error_message/llms.txt Converts ErrorMessage structs into plain maps suitable for JSON serialization. It automatically handles complex Elixir types like dates, times, and structs. ```elixir error = ErrorMessage.bad_request("Invalid data", %{ date: ~D[2023-01-15], time: ~T[14:30:00], datetime: ~U[2023-01-15 14:30:00Z], tuple: {:error, :timeout}, struct: %URI{host: "example.com", path: "/api"} }) ErrorMessage.to_jsonable_map(error) ``` -------------------------------- ### Convert ErrorMessage to String Source: https://github.com/mikaak/elixir_error_message/blob/main/docs/reference/api_reference.md Converts an ErrorMessage struct into a human-readable string format. Useful for logging or debugging purposes. ```elixir @spec to_string(error_message :: t) :: String.t() iex> ErrorMessage.to_string(ErrorMessage.not_found("User not found")) "not_found - User not found" iex> ErrorMessage.to_string(ErrorMessage.internal_server_error("Error", %{reason: :timeout})) "internal_server_error - Error\nDetails: \n%{reason: :timeout}" ```