| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- 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<string>();
-
- 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<string, string>();
- 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<string, string>();
- 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<string, string>();
- 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<string, string> get_json_headers() {
- var headers = new Catalogue<string, string>();
- 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\" }";
- }
- }
|