using Astralis; using Invercargill; using Invercargill.DataStructures; /** * ErrorHandling Example * * Demonstrates error handling and status codes in Astralis. * Uses Invercargill data structures for error logging and management. */ // Root handler class RootHandler : Object, RouteHandler { public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error { return new BufferedHttpResult.from_string( """Error Handling Demo This example demonstrates various error handling patterns in Astralis: Endpoints: GET /ok - 200 OK response GET /not-found - 404 Not Found GET /bad-request - 400 Bad Request GET /internal-error - 500 Internal Server Error GET /validation - Input validation example GET /resource/{id} - Resource lookup with error handling GET /api/{endpoint} - API endpoint simulation GET /custom-error - Custom error response GET /timeout - Simulated timeout GET /unauthorized - 401 Unauthorized GET /forbidden - 403 Forbidden GET /method-not-allowed - 405 Method Not Allowed """ ); } } // 200 OK response class OkHandler : Object, RouteHandler { public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error { return new BufferedHttpResult.from_string( @"{ \"status\": \"success\", \"message\": \"Request completed successfully\" }", StatusCode.OK, get_json_headers() ); } } // 404 Not Found class NotFoundHandler : Object, RouteHandler { public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error { return new BufferedHttpResult.from_string( @"{ \"error\": \"Not Found\", \"message\": \"The requested resource was not found\" }", StatusCode.NOT_FOUND, get_json_headers() ); } } // 400 Bad Request class BadRequestHandler : Object, RouteHandler { public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error { return new BufferedHttpResult.from_string( @"{ \"error\": \"Bad Request\", \"message\": \"The request could not be understood\" }", StatusCode.BAD_REQUEST, get_json_headers() ); } } // 500 Internal Server Error class InternalErrorHandler : Object, RouteHandler { public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error { return new BufferedHttpResult.from_string( @"{ \"error\": \"Internal Server Error\", \"message\": \"An unexpected error occurred\" }", StatusCode.INTERNAL_SERVER_ERROR, get_json_headers() ); } } // Input validation example class ValidationHandler : Object, RouteHandler { public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error { var email = http_context.request.get_query("email"); var age_str = http_context.request.get_query("age"); var error_list = new List(); if (email == null || !is_valid_email(email)) { error_list.append("Invalid email address"); } if (age_str == null) { error_list.append("Age parameter is required"); } else { var age = int.parse(age_str); if (age < 0 || age > 150) { error_list.append("Age must be between 0 and 150"); } } if (error_list.length() > 0) { var json_parts = new StringBuilder(); json_parts.append("{ \"error\": \"Validation Failed\", \"errors\": ["); bool first = true; error_list.foreach((err) => { if (!first) { json_parts.append(", "); } json_parts.append("\""); json_parts.append(err); json_parts.append("\""); first = false; }); json_parts.append("] }"); var json_string = json_parts.str; return new BufferedHttpResult.from_string( json_string, StatusCode.BAD_REQUEST, get_json_headers() ); } return new BufferedHttpResult.from_string( @"{ \"status\": \"success\", \"email\": \"$email\", \"age\": $age_str }", StatusCode.OK, get_json_headers() ); } } // Resource lookup with error handling class ResourceHandler : Object, RouteHandler { public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error { var id_str = route_context.get_segment("id"); int id; if (!int.try_parse(id_str, out id)) { return error_response(@"Invalid resource ID: $id_str", StatusCode.BAD_REQUEST); } // Simulate resource lookup using array var resource_array = new Resource[3]; resource_array[0] = new Resource(1, "Resource One", "Description of resource one"); resource_array[1] = new Resource(2, "Resource Two", "Description of resource two"); resource_array[2] = new Resource(3, "Resource Three", "Description of resource three"); Resource? resource = null; foreach (var r in resource_array) { if (r.id == id) { resource = r; break; } } if (resource == null) { return error_response(@"Resource with ID $id not found", StatusCode.NOT_FOUND); } return new BufferedHttpResult.from_string( resource.to_json(), StatusCode.OK, get_json_headers() ); } } // API endpoint simulation class ApiEndpointHandler : Object, RouteHandler { public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error { var endpoint = route_context.get_segment("endpoint"); // Simulate different API responses switch (endpoint) { case "users": return new BufferedHttpResult.from_string( @"{ \"users\": [{\"id\": 1, \"name\": \"Alice\"}, {\"id\": 2, \"name\": \"Bob\"}] }", StatusCode.OK, get_json_headers() ); case "posts": return new BufferedHttpResult.from_string( @"{ \"posts\": [{\"id\": 1, \"title\": \"First Post\"}, {\"id\": 2, \"title\": \"Second Post\"}] }", StatusCode.OK, get_json_headers() ); case "invalid": return error_response("Invalid API endpoint", StatusCode.NOT_FOUND); default: return error_response(@"Unknown endpoint: $endpoint", StatusCode.NOT_FOUND); } } } // Custom error response class CustomErrorHandler : Object, RouteHandler { public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error { var error_code = http_context.request.get_query_or_default("code", "CUSTOM_ERROR"); var message = http_context.request.get_query_or_default("message", "A custom error occurred"); var timestamp = new DateTime.now_local().format_iso8601(); var request_id = generate_request_id(); var json = @"{ \"error\": \"$error_code\", \"message\": \"$message\", \"timestamp\": \"$timestamp\", \"request_id\": \"$request_id\" }"; return new BufferedHttpResult.from_string( json, StatusCode.BAD_REQUEST, get_json_headers() ); } } // Simulated timeout (actually returns 408) class TimeoutHandler : Object, RouteHandler { public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error { return new BufferedHttpResult.from_string( @"{ \"error\": \"Request Timeout\", \"message\": \"The request took too long to complete\" }", StatusCode.INTERNAL_SERVER_ERROR, get_json_headers() ); } } // 401 Unauthorized class UnauthorizedHandler : Object, RouteHandler { public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error { var auth_header = http_context.request.get_header("Authorization"); if (auth_header == null) { var headers = new Catalogue(); headers.add("WWW-Authenticate", "Bearer realm=\"api\""); return new BufferedHttpResult.from_string( @"{ \"error\": \"Unauthorized\", \"message\": \"Authentication required\" }", StatusCode.UNAUTHORIZED, headers ); } // Check auth token (simplified) if (!auth_header.contains("valid-token")) { var headers = new Catalogue(); headers.add("WWW-Authenticate", "Bearer error=\"invalid_token\""); return new BufferedHttpResult.from_string( @"{ \"error\": \"Unauthorized\", \"message\": \"Invalid authentication token\" }", StatusCode.UNAUTHORIZED, headers ); } return new BufferedHttpResult.from_string( @"{ \"status\": \"success\", \"message\": \"Authenticated\" }", StatusCode.OK, get_json_headers() ); } } // 403 Forbidden class ForbiddenHandler : Object, RouteHandler { public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error { var user_role = http_context.request.get_cookie("role") ?? "guest"; if (user_role != "admin") { return new BufferedHttpResult.from_string( @"{ \"error\": \"Forbidden\", \"message\": \"You don't have permission to access this resource\" }", StatusCode.FORBIDDEN, get_json_headers() ); } return new BufferedHttpResult.from_string( @"{ \"status\": \"success\", \"message\": \"Admin access granted\" }", StatusCode.OK, get_json_headers() ); } } // 405 Method Not Allowed class MethodNotAllowedHandler : Object, RouteHandler { public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error { var headers = new Catalogue(); headers.add("Allow", "POST, PUT, DELETE"); return new BufferedHttpResult.from_string( @"{ \"error\": \"Method Not Allowed\", \"message\": \"GET method is not allowed for this endpoint\" }", StatusCode.METHOD_NOT_ALLOWED, headers ); } } void main() { var router = new Router(); var server = new Server(8088, router); // Register routes router.get("/", new RootHandler()); router.get("/ok", new OkHandler()); router.get("/not-found", new NotFoundHandler()); router.get("/bad-request", new BadRequestHandler()); router.get("/internal-error", new InternalErrorHandler()); router.get("/validation", new ValidationHandler()); router.get("/resource/{id}", new ResourceHandler()); router.get("/api/{endpoint}", new ApiEndpointHandler()); router.get("/custom-error", new CustomErrorHandler()); router.get("/timeout", new TimeoutHandler()); router.get("/unauthorized", new UnauthorizedHandler()); router.get("/forbidden", new ForbiddenHandler()); router.get("/method-not-allowed", new MethodNotAllowedHandler()); print("Error Handling Demo Server running on port 8088\n"); print("Try these endpoints:\n"); print(" - http://localhost:8088/\n"); print(" - http://localhost:8088/ok\n"); print(" - http://localhost:8088/not-found\n"); print(" - http://localhost:8088/bad-request\n"); print(" - http://localhost:8088/internal-error\n"); print(" - http://localhost:8088/validation?email=test&age=25\n"); print(" - http://localhost:8088/resource/1\n"); print(" - http://localhost:8088/resource/999\n"); print(" - http://localhost:8088/api/users\n"); print(" - http://localhost:8088/custom-error?code=TEST&message=Test+error\n"); print(" - http://localhost:8088/timeout\n"); print(" - http://localhost:8088/unauthorized\n"); print(" - http://localhost:8088/forbidden\n"); print(" - http://localhost:8088/method-not-allowed\n"); server.run(); } // Helper functions BufferedHttpResult error_response(string message, StatusCode status) { var json = @"{ \"error\": \"Error\", \"message\": \"$message\" }"; return new BufferedHttpResult.from_string( json, status, get_json_headers() ); } Catalogue get_json_headers() { var headers = new Catalogue(); headers.add("Content-Type", "application/json"); return headers; } string generate_request_id() { var timestamp = new DateTime.now_local().to_unix(); var random = Random.next_int(); return @"req-$timestamp-$random"; } bool is_valid_email(string email) { // Simple email validation return email.contains("@") && email.contains(".") && email.length > 5; } // Helper classes class Resource { public int id { get; private set; } public string name { get; private set; } public string description { get; private set; } public Resource(int id, string name, string description) { this.id = id; this.name = name; this.description = description; } public string to_json() { return @"{ \"id\": $id, \"name\": \"$name\", \"description\": \"$description\" }"; } }