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. */ void main() { var router = new Router(); var server = new Server(8088, router); // Root endpoint router.map_func("/", (context) => { 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 router.map_func("/ok", (context) => { return new BufferedHttpResult.from_string( @"{ \"status\": \"success\", \"message\": \"Request completed successfully\" }", StatusCode.OK, get_json_headers() ); }); // 404 Not Found router.map_func("/not-found", (context) => { return new BufferedHttpResult.from_string( @"{ \"error\": \"Not Found\", \"message\": \"The requested resource was not found\" }", StatusCode.NOT_FOUND, get_json_headers() ); }); // 400 Bad Request router.map_func("/bad-request", (context) => { 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 router.map_func("/internal-error", (context) => { return new BufferedHttpResult.from_string( @"{ \"error\": \"Internal Server Error\", \"message\": \"An unexpected error occurred\" }", StatusCode.INTERNAL_SERVER_ERROR, get_json_headers() ); }); // Input validation example router.map_func("/validation", (context) => { var email = context.request.get_query("email"); var age_str = 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 router.map_func("/resource/", (context) => { var components = context.request.path_components.to_vector(); if (components.count() < 2) { return error_response("Resource ID is required", StatusCode.BAD_REQUEST); } var id_str = components[1]; 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 router.map_func("/api/", (context) => { var components = context.request.path_components.to_vector(); if (components.count() < 2) { return error_response("API endpoint required", StatusCode.BAD_REQUEST); } var endpoint = components[1]; // 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 router.map_func("/custom-error", (context) => { var error_code = context.request.get_query_or_default("code", "CUSTOM_ERROR"); var message = 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) router.map_func("/timeout", (context) => { 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 router.map_func("/unauthorized", (context) => { var auth_header = 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 router.map_func("/forbidden", (context) => { var user_role = 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 router.map_func("/method-not-allowed", (context) => { 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 ); }); 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, int 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\" }"; } }