ErrorHandling.vala 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. using Astralis;
  2. using Invercargill;
  3. using Invercargill.DataStructures;
  4. /**
  5. * ErrorHandling Example
  6. *
  7. * Demonstrates error handling and status codes in Astralis.
  8. * Uses Invercargill data structures for error logging and management.
  9. */
  10. // Root handler
  11. class RootHandler : Object, RouteHandler {
  12. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  13. return new HttpStringResult("""Error Handling Demo
  14. This example demonstrates various error handling patterns in Astralis:
  15. Endpoints:
  16. GET /ok - 200 OK response
  17. GET /not-found - 404 Not Found
  18. GET /bad-request - 400 Bad Request
  19. GET /internal-error - 500 Internal Server Error
  20. GET /validation - Input validation example
  21. GET /resource/{id} - Resource lookup with error handling
  22. GET /api/{endpoint} - API endpoint simulation
  23. GET /custom-error - Custom error response
  24. GET /timeout - Simulated timeout
  25. GET /unauthorized - 401 Unauthorized
  26. GET /forbidden - 403 Forbidden
  27. GET /method-not-allowed - 405 Method Not Allowed
  28. """);
  29. }
  30. }
  31. // 200 OK response
  32. class OkHandler : Object, RouteHandler {
  33. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  34. return new HttpStringResult(@"{ \"status\": \"success\", \"message\": \"Request completed successfully\" }")
  35. .set_header("Content-Type", "application/json");
  36. }
  37. }
  38. // 404 Not Found
  39. class NotFoundHandler : Object, RouteHandler {
  40. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  41. return new HttpStringResult(@"{ \"error\": \"Not Found\", \"message\": \"The requested resource was not found\" }")
  42. .set_header("Content-Type", "application/json");
  43. }
  44. }
  45. // 400 Bad Request
  46. class BadRequestHandler : Object, RouteHandler {
  47. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  48. return new HttpStringResult(@"{ \"error\": \"Bad Request\", \"message\": \"The request could not be understood\" }")
  49. .set_header("Content-Type", "application/json");
  50. }
  51. }
  52. // 500 Internal Server Error
  53. class InternalErrorHandler : Object, RouteHandler {
  54. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  55. return new HttpStringResult(@"{ \"error\": \"Internal Server Error\", \"message\": \"An unexpected error occurred\" }")
  56. .set_header("Content-Type", "application/json");
  57. }
  58. }
  59. // Input validation example
  60. class ValidationHandler : Object, RouteHandler {
  61. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  62. var email = http_context.request.get_query("email");
  63. var age_str = http_context.request.get_query("age");
  64. var error_list = new List<string>();
  65. if (email == null || !is_valid_email(email)) {
  66. error_list.append("Invalid email address");
  67. }
  68. if (age_str == null) {
  69. error_list.append("Age parameter is required");
  70. } else {
  71. var age = int.parse(age_str);
  72. if (age < 0 || age > 150) {
  73. error_list.append("Age must be between 0 and 150");
  74. }
  75. }
  76. if (error_list.length() > 0) {
  77. var json_parts = new StringBuilder();
  78. json_parts.append("{ \"error\": \"Validation Failed\", \"errors\": [");
  79. bool first = true;
  80. error_list.foreach((err) => {
  81. if (!first) {
  82. json_parts.append(", ");
  83. }
  84. json_parts.append("\"");
  85. json_parts.append(err);
  86. json_parts.append("\"");
  87. first = false;
  88. });
  89. json_parts.append("] }");
  90. var json_string = json_parts.str;
  91. return new HttpStringResult(json_string)
  92. .set_header("Content-Type", "application/json");
  93. }
  94. return new HttpStringResult(@"{ \"status\": \"success\", \"email\": \"$email\", \"age\": $age_str }")
  95. .set_header("Content-Type", "application/json");
  96. }
  97. }
  98. // Resource lookup with error handling
  99. class ResourceHandler : Object, RouteHandler {
  100. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  101. var id_str = route_context.get_segment("id");
  102. int id;
  103. if (!int.try_parse(id_str, out id)) {
  104. return error_response(@"Invalid resource ID: $id_str", StatusCode.BAD_REQUEST);
  105. }
  106. // Simulate resource lookup using array
  107. var resource_array = new Resource[3];
  108. resource_array[0] = new Resource(1, "Resource One", "Description of resource one");
  109. resource_array[1] = new Resource(2, "Resource Two", "Description of resource two");
  110. resource_array[2] = new Resource(3, "Resource Three", "Description of resource three");
  111. Resource? resource = null;
  112. foreach (var r in resource_array) {
  113. if (r.id == id) {
  114. resource = r;
  115. break;
  116. }
  117. }
  118. if (resource == null) {
  119. return error_response(@"Resource with ID $id not found", StatusCode.NOT_FOUND);
  120. }
  121. return new HttpStringResult(resource.to_json())
  122. .set_header("Content-Type", "application/json");
  123. }
  124. }
  125. // API endpoint simulation
  126. class ApiEndpointHandler : Object, RouteHandler {
  127. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  128. var endpoint = route_context.get_segment("endpoint");
  129. // Simulate different API responses
  130. switch (endpoint) {
  131. case "users":
  132. return new HttpStringResult(@"{ \"users\": [{\"id\": 1, \"name\": \"Alice\"}, {\"id\": 2, \"name\": \"Bob\"}] }")
  133. .set_header("Content-Type", "application/json");
  134. case "posts":
  135. return new HttpStringResult(@"{ \"posts\": [{\"id\": 1, \"title\": \"First Post\"}, {\"id\": 2, \"title\": \"Second Post\"}] }")
  136. .set_header("Content-Type", "application/json");
  137. case "invalid":
  138. return error_response("Invalid API endpoint", StatusCode.NOT_FOUND);
  139. default:
  140. return error_response(@"Unknown endpoint: $endpoint", StatusCode.NOT_FOUND);
  141. }
  142. }
  143. }
  144. // Custom error response
  145. class CustomErrorHandler : Object, RouteHandler {
  146. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  147. var error_code = http_context.request.get_query_or_default("code", "CUSTOM_ERROR");
  148. var message = http_context.request.get_query_or_default("message", "A custom error occurred");
  149. var timestamp = new DateTime.now_local().format_iso8601();
  150. var request_id = generate_request_id();
  151. var json = @"{
  152. \"error\": \"$error_code\",
  153. \"message\": \"$message\",
  154. \"timestamp\": \"$timestamp\",
  155. \"request_id\": \"$request_id\"
  156. }";
  157. return new HttpStringResult(json)
  158. .set_header("Content-Type", "application/json");
  159. }
  160. }
  161. // Simulated timeout (actually returns 408)
  162. class TimeoutHandler : Object, RouteHandler {
  163. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  164. return new HttpStringResult(@"{ \"error\": \"Request Timeout\", \"message\": \"The request took too long to complete\" }")
  165. .set_header("Content-Type", "application/json");
  166. }
  167. }
  168. // 401 Unauthorized
  169. class UnauthorizedHandler : Object, RouteHandler {
  170. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  171. var auth_header = http_context.request.get_header("Authorization");
  172. if (auth_header == null) {
  173. return new HttpStringResult(@"{ \"error\": \"Unauthorized\", \"message\": \"Authentication required\" }")
  174. .set_header("Content-Type", "application/json")
  175. .set_header("WWW-Authenticate", "Bearer realm=\"api\"");
  176. }
  177. // Check auth token (simplified)
  178. if (!auth_header.contains("valid-token")) {
  179. return new HttpStringResult(@"{ \"error\": \"Unauthorized\", \"message\": \"Invalid authentication token\" }")
  180. .set_header("Content-Type", "application/json")
  181. .set_header("WWW-Authenticate", "Bearer error=\"invalid_token\"");
  182. }
  183. return new HttpStringResult(@"{ \"status\": \"success\", \"message\": \"Authenticated\" }")
  184. .set_header("Content-Type", "application/json");
  185. }
  186. }
  187. // 403 Forbidden
  188. class ForbiddenHandler : Object, RouteHandler {
  189. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  190. var user_role = http_context.request.get_cookie("role") ?? "guest";
  191. if (user_role != "admin") {
  192. return new HttpStringResult(@"{ \"error\": \"Forbidden\", \"message\": \"You don't have permission to access this resource\" }")
  193. .set_header("Content-Type", "application/json");
  194. }
  195. return new HttpStringResult(@"{ \"status\": \"success\", \"message\": \"Admin access granted\" }")
  196. .set_header("Content-Type", "application/json");
  197. }
  198. }
  199. // 405 Method Not Allowed
  200. class MethodNotAllowedHandler : Object, RouteHandler {
  201. public async HttpResult handle_route(HttpContext http_context, RouteContext route_context) throws Error {
  202. return new HttpStringResult(@"{ \"error\": \"Method Not Allowed\", \"message\": \"GET method is not allowed for this endpoint\" }")
  203. .set_header("Content-Type", "application/json")
  204. .set_header("Allow", "POST, PUT, DELETE");
  205. }
  206. }
  207. void main() {
  208. var router = new Router();
  209. var server = new Server(8088, router);
  210. // Register routes
  211. router.get("/", new RootHandler());
  212. router.get("/ok", new OkHandler());
  213. router.get("/not-found", new NotFoundHandler());
  214. router.get("/bad-request", new BadRequestHandler());
  215. router.get("/internal-error", new InternalErrorHandler());
  216. router.get("/validation", new ValidationHandler());
  217. router.get("/resource/{id}", new ResourceHandler());
  218. router.get("/api/{endpoint}", new ApiEndpointHandler());
  219. router.get("/custom-error", new CustomErrorHandler());
  220. router.get("/timeout", new TimeoutHandler());
  221. router.get("/unauthorized", new UnauthorizedHandler());
  222. router.get("/forbidden", new ForbiddenHandler());
  223. router.get("/method-not-allowed", new MethodNotAllowedHandler());
  224. print("Error Handling Demo Server running on port 8088\n");
  225. print("Try these endpoints:\n");
  226. print(" - http://localhost:8088/\n");
  227. print(" - http://localhost:8088/ok\n");
  228. print(" - http://localhost:8088/not-found\n");
  229. print(" - http://localhost:8088/bad-request\n");
  230. print(" - http://localhost:8088/internal-error\n");
  231. print(" - http://localhost:8088/validation?email=test&age=25\n");
  232. print(" - http://localhost:8088/resource/1\n");
  233. print(" - http://localhost:8088/resource/999\n");
  234. print(" - http://localhost:8088/api/users\n");
  235. print(" - http://localhost:8088/custom-error?code=TEST&message=Test+error\n");
  236. print(" - http://localhost:8088/timeout\n");
  237. print(" - http://localhost:8088/unauthorized\n");
  238. print(" - http://localhost:8088/forbidden\n");
  239. print(" - http://localhost:8088/method-not-allowed\n");
  240. server.run();
  241. }
  242. // Helper functions
  243. HttpResult error_response(string message, StatusCode status) {
  244. var json = @"{ \"error\": \"Error\", \"message\": \"$message\" }";
  245. return new HttpStringResult(json)
  246. .set_header("Content-Type", "application/json");
  247. }
  248. string generate_request_id() {
  249. var timestamp = new DateTime.now_local().to_unix();
  250. var random = Random.next_int();
  251. return @"req-$timestamp-$random";
  252. }
  253. bool is_valid_email(string email) {
  254. // Simple email validation
  255. return email.contains("@") && email.contains(".") && email.length > 5;
  256. }
  257. // Helper classes
  258. class Resource {
  259. public int id { get; private set; }
  260. public string name { get; private set; }
  261. public string description { get; private set; }
  262. public Resource(int id, string name, string description) {
  263. this.id = id;
  264. this.name = name;
  265. this.description = description;
  266. }
  267. public string to_json() {
  268. return @"{ \"id\": $id, \"name\": \"$name\", \"description\": \"$description\" }";
  269. }
  270. }