Skip to content

Error Handling

Handle errors gracefully in api.zig applications.

Error Response Methods

MethodStatusDescription
Response.err(.bad_request, msg)400Invalid input
Response.err(.unauthorized, msg)401Auth required
Response.err(.forbidden, msg)403Access denied
Response.err(.not_found, msg)404Not found
Response.err(.method_not_allowed, msg)405Wrong method
Response.err(.conflict, msg)409Conflict
Response.err(.unprocessable_entity, msg)422Validation failed
Response.err(.too_many_requests, msg)429Rate limited
Response.err(.internal_server_error, msg)500Server error

Error Responses

Return error responses with appropriate status codes:

zig
fn notFound() api.Response {
    return api.Response.err(.not_found, "{\"error\":\"Resource not found\"}");
}

fn badRequest() api.Response {
    return api.Response.err(.bad_request, "{\"error\":\"Invalid input\"}");
}

fn unauthorized() api.Response {
    return api.Response.err(.unauthorized, "{\"error\":\"Authentication required\"}");
}

fn forbidden() api.Response {
    return api.Response.err(.forbidden, "{\"error\":\"Access denied\"}");
}

fn serverError() api.Response {
    return api.Response.err(.internal_server_error, "{\"error\":\"Internal server error\"}");
}

Example Output:

json
{"error":"Resource not found"}

Conditional Error Handling

zig
fn getUser(ctx: *api.Context) api.Response {
    const id = ctx.param("id") orelse {
        return api.Response.err(.bad_request, "{\"error\":\"Missing ID\"}");
    };

    const parsed_id = std.fmt.parseInt(u32, id, 10) catch {
        return api.Response.err(.bad_request, "{\"error\":\"Invalid ID format\"}");
    };

    // Simulate user not found
    if (parsed_id > 100) {
        return api.Response.err(.not_found, "{\"error\":\"User not found\"}");
    }

    return api.Response.jsonRaw("{\"id\":1,\"name\":\"John\"}");
}

Error Response Helper Functions

zig
const response = @import("response.zig");

// Use helper functions
response.badRequest("{\"error\":\"msg\"}")
response.unauthorized("{\"error\":\"msg\"}")
response.forbidden("{\"error\":\"msg\"}")
response.notFound("{\"error\":\"msg\"}")
response.internalError("{\"error\":\"msg\"}")

Custom Error Handler

Set a custom error handler for unhandled errors:

zig
fn customErrorHandler(ctx: *api.Context, err: anyerror) api.Response {
    _ = ctx;
    std.debug.print("Error: {}\n", .{err});
    return api.Response.err(.internal_server_error, "{\"error\":\"Something went wrong\"}");
}

// Set the handler
app.setErrorHandler(customErrorHandler);

Custom 404 Handler

zig
fn custom404(ctx: *api.Context) api.Response {
    const path = ctx.path();
    _ = path;
    return api.Response.err(.not_found, "{\"error\":\"Route not found\",\"status\":404}");
}

// Set the handler
app.setNotFoundHandler(custom404);

Reporting Library Bugs

If you encounter internal library errors:

zig
const report = api.report;

// Report an error (for internal library issues only)
report.reportInternalError("Unexpected state in parser");

// Report with error code
report.reportInternalErrorWithCode(error.OutOfMemory);

Error Status Codes

StatusCodeUse Case
Bad Request400Invalid input, validation errors
Unauthorized401Missing/invalid authentication
Forbidden403Authenticated but not authorized
Not Found404Resource doesn't exist
Method Not Allowed405Wrong HTTP method
Conflict409Resource conflict
Unprocessable Entity422Semantic errors
Too Many Requests429Rate limiting
Internal Server Error500Unexpected errors
Service Unavailable503Server overloaded

Structured Error Format

Recommend consistent error format:

json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Input validation failed",
    "details": [
      { "field": "email", "message": "Invalid email format" },
      { "field": "age", "message": "Must be at least 18" }
    ]
  }
}

Released under the MIT License.