How to handle errors in a web application's request/response cycle in Go?

In Go, handling errors in a web application's request/response cycle involves returning appropriate HTTP status codes and error responses to the client. Here are the steps to handle errors effectively in a Go web application:

  1. Use structured error types: Define custom error types that provide more information than just a plain error message. You can include error codes, error details, or any other relevant data to help with debugging or understanding the error.
type AppError struct { Code int `json:"code"` Message string `json:"message"` Details string `json:"details,omitempty"` }
  1. Implement centralized error handling: Create a central error handling function that accepts the context and error. This function will handle logging the errors and sending the appropriate error response to the client.
func handleError(w http.ResponseWriter, err error) { // Log the error log.Println(err) // Extract error details if available code := http.StatusInternalServerError message := err.Error() if appErr, ok := err.(AppError); ok { code = appErr.Code message = appErr.Message } // Send error response to the client w.WriteHeader(code) json.NewEncoder(w).Encode(map[string]interface{}{ "error": map[string]interface{}{ "code": code, "message": message, }, }) }
  1. Wrap and propagate errors: Whenever an error occurs in your application, wrap it with additional information and propagate it up the call stack. This ensures that each layer of your application can handle and log errors appropriately.
func someHandler(w http.ResponseWriter, r *http.Request) { // ... // Example error handling when using some library or service resp, err := someLibrary.SomeFunction() if err != nil { handleError(w, AppError{ Code: http.StatusInternalServerError, Message: "Failed to perform operation.", Details: err.Error(), }) return } // ... }
  1. Use middleware for error handling: Middleware functions can be used to handle common error scenarios throughout your application. These functions are executed before or after the main handler and can handle or modify the response or perform any other necessary actions.
func errorHandlingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { handleError(w, AppError{ Code: http.StatusInternalServerError, Message: "Internal Server Error.", Details: fmt.Sprintf("%v", err), }) } }() next.ServeHTTP(w, r) }) }
  1. Properly handle HTTP status codes: Depending on the error scenario, return the most appropriate HTTP status code to the client. For example:
  • 200 OK: Request completed successfully
  • 400 Bad Request: Invalid request data or parameters
  • 401 Unauthorized: Unauthenticated user
  • 403 Forbidden: Authenticated user lacks necessary permissions
  • 404 Not Found: The requested resource does not exist
  • 500 Internal Server Error: Unexpected error occurred during processing

By following these steps, you can handle errors effectively within the request/response cycle of a web application in Go.