dream/http/error
Dream unified error type
A single error type used throughout Dream applications for both HTTP-level validation errors and domain-level operation errors. This eliminates the need for error conversion between layers.
Philosophy
Instead of having separate error types for HTTP validation, database operations, and business logic, Dream uses one unified Error type. This means you can return errors from any layer without conversion, and the type system tracks them naturally.
Usage
Return errors from controllers, models, or operations using the same type:
import dream/http/error.{type Error, BadRequest, NotFound}
import gleam/result
pub fn get_user(db: Connection, id: Int) -> Result(User, Error) {
query_user(db, id)
|> result.replace_error(NotFound("User not found"))
}
pub fn create_user(db: Connection, name: String) -> Result(User, Error) {
case validate_name(name) {
True -> insert_user(db, name)
False -> Error(BadRequest("Name must not be empty"))
}
}
Converting to Responses
Use to_status_code() and message() to convert errors to HTTP responses:
import dream/http/error.{type Error, message, to_status_code}
import dream/http/response.{type Response, json_response}
import gleam/json
let result = get_user(db, id)
case result {
Ok(user) -> json_response(200, user_to_json(user))
Error(err) -> create_error_response(err)
}
fn create_error_response(err: Error) -> Response {
let error_json = json.object([#("error", json.string(message(err)))])
json_response(to_status_code(err), error_json)
}
Types
Unified error type for Dream applications
Maps semantic error types to HTTP status codes. Each variant includes a message string for context-specific error details.
Variants
BadRequest: Client sent invalid data (malformed, missing required fields)Unauthorized: Authentication is required but not providedForbidden: Authenticated but lacks permission for this actionNotFound: Requested resource doesn’t existUnprocessableContent: Valid syntax but fails business logic validationInternalServerError: Unexpected server error (database, external API, etc.)
pub type Error {
BadRequest(String)
Unauthorized(String)
Forbidden(String)
NotFound(String)
UnprocessableContent(String)
InternalServerError(String)
}
Constructors
-
BadRequest(String)400 Bad Request - Invalid or missing parameter, validation failure
Use when client sends malformed data, missing required fields, or syntactically invalid input (e.g., “abc” when expecting integer).
Example
Error(BadRequest("Field 'email' is required")) Error(BadRequest("ID must be a positive integer")) -
Unauthorized(String)401 Unauthorized - Authentication required
Use when request requires valid authentication credentials. Despite the name, this means “not authenticated” (no valid credentials).
Example
Error(Unauthorized("Authentication token required")) Error(Unauthorized("Invalid or expired token")) -
Forbidden(String)403 Forbidden - Authenticated but not authorized
Use when user is authenticated but lacks permission for this action. Unlike Unauthorized, providing credentials won’t help.
Example
Error(Forbidden("Admin access required")) Error(Forbidden("Cannot delete another user's post")) -
NotFound(String)404 Not Found - Resource doesn’t exist
Use when requested resource doesn’t exist or user shouldn’t know it exists (to hide existence instead of returning 403).
Example
Error(NotFound("User not found")) Error(NotFound("Post with ID 123 does not exist")) -
UnprocessableContent(String)422 Unprocessable Content - Semantic validation failed
Use when request is syntactically valid but fails business logic validation (e.g., date in past, email already taken, invalid state).
Example
Error(UnprocessableContent("Email already registered")) Error(UnprocessableContent("Start date must be before end date")) -
InternalServerError(String)500 Internal Server Error - Unexpected error (database, external service, etc)
Use for unexpected server errors: database failures, external API errors, filesystem errors, etc. Should be logged for investigation.
Example
Error(InternalServerError("Database connection failed")) Error(InternalServerError("External payment API unavailable"))
Values
pub fn message(error: Error) -> String
Extract the error message from an Error
Returns the message string from any error variant. Useful when building error responses or logging.
Example
import dream/http/error.{type Error, BadRequest}
import gleam/json
let err = BadRequest("Invalid email format")
let msg = error.message(err) // Returns "Invalid email format"
// Build JSON error response
json.object([
#("error", json.string(msg)),
#("status", json.int(error.to_status_code(err)))
])
pub fn to_status_code(error: Error) -> Int
Convert Error to HTTP status code
Maps each error variant to its corresponding HTTP status code. Use this when building HTTP responses from errors.
Example
import dream/http/error.{type Error, NotFound}
import dream/http/response
let err = NotFound("User not found")
let status = error.to_status_code(err) // Returns 404
response.json_response(status, error_json(err))