-module(dream@http@error). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/dream/http/error.gleam"). -export([to_status_code/1, message/1]). -export_type([error/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Dream unified error type\n" "\n" " A single error type used throughout Dream applications for both\n" " HTTP-level validation errors and domain-level operation errors.\n" " This eliminates the need for error conversion between layers.\n" "\n" " ## Philosophy\n" "\n" " Instead of having separate error types for HTTP validation, database operations,\n" " and business logic, Dream uses one unified Error type. This means you can return\n" " errors from any layer without conversion, and the type system tracks them naturally.\n" "\n" " ## Usage\n" "\n" " Return errors from controllers, models, or operations using the same type:\n" "\n" " ```gleam\n" " import dream/http/error.{type Error, BadRequest, NotFound}\n" " import gleam/result\n" "\n" " pub fn get_user(db: Connection, id: Int) -> Result(User, Error) {\n" " query_user(db, id)\n" " |> result.replace_error(NotFound(\"User not found\"))\n" " }\n" "\n" " pub fn create_user(db: Connection, name: String) -> Result(User, Error) {\n" " case validate_name(name) {\n" " True -> insert_user(db, name)\n" " False -> Error(BadRequest(\"Name must not be empty\"))\n" " }\n" " }\n" " ```\n" "\n" " ## Converting to Responses\n" "\n" " Use `to_status_code()` and `message()` to convert errors to HTTP responses:\n" "\n" " ```gleam\n" " import dream/http/error.{type Error, message, to_status_code}\n" " import dream/http/response.{type Response, json_response}\n" " import gleam/json\n" "\n" " let result = get_user(db, id)\n" " \n" " case result {\n" " Ok(user) -> json_response(200, user_to_json(user))\n" " Error(err) -> create_error_response(err)\n" " }\n" " \n" " fn create_error_response(err: Error) -> Response {\n" " let error_json = json.object([#(\"error\", json.string(message(err)))])\n" " json_response(to_status_code(err), error_json)\n" " }\n" " ```\n" ). -type error() :: {bad_request, binary()} | {unauthorized, binary()} | {forbidden, binary()} | {not_found, binary()} | {unprocessable_content, binary()} | {internal_server_error, binary()}. -file("src/dream/http/error.gleam", 164). ?DOC( " Convert Error to HTTP status code\n" "\n" " Maps each error variant to its corresponding HTTP status code.\n" " Use this when building HTTP responses from errors.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import dream/http/error.{type Error, NotFound}\n" " import dream/http/response\n" "\n" " let err = NotFound(\"User not found\")\n" " let status = error.to_status_code(err) // Returns 404\n" " response.json_response(status, error_json(err))\n" " ```\n" ). -spec to_status_code(error()) -> integer(). to_status_code(Error) -> case Error of {bad_request, _} -> 400; {unauthorized, _} -> 401; {forbidden, _} -> 403; {not_found, _} -> 404; {unprocessable_content, _} -> 422; {internal_server_error, _} -> 500 end. -file("src/dream/http/error.gleam", 195). ?DOC( " Extract the error message from an Error\n" "\n" " Returns the message string from any error variant.\n" " Useful when building error responses or logging.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import dream/http/error.{type Error, BadRequest}\n" " import gleam/json\n" "\n" " let err = BadRequest(\"Invalid email format\")\n" " let msg = error.message(err) // Returns \"Invalid email format\"\n" "\n" " // Build JSON error response\n" " json.object([\n" " #(\"error\", json.string(msg)),\n" " #(\"status\", json.int(error.to_status_code(err)))\n" " ])\n" " ```\n" ). -spec message(error()) -> binary(). message(Error) -> case Error of {bad_request, Msg} -> Msg; {unauthorized, Msg@1} -> Msg@1; {forbidden, Msg@2} -> Msg@2; {not_found, Msg@3} -> Msg@3; {unprocessable_content, Msg@4} -> Msg@4; {internal_server_error, Msg@5} -> Msg@5 end.