package internal import ( "encoding/json" "fmt" "log/slog" "net/http" "runtime/debug" ) // encode writes a JSON-encoded response to the provided http.ResponseWriter. // // Parameters: // - w: The http.ResponseWriter where the response will be written. // - r: The *http.Request associated with the response. (Unused in this function but could be relevant for context.) // - status: The HTTP status code to send with the response. // - v: The value to encode and send as the JSON response. Can be of any type. // // Returns: // - An error if the JSON encoding or writing to the ResponseWriter fails, otherwise nil. func encode[T any](w http.ResponseWriter, r *http.Request, status int, v T) error { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) if err := json.NewEncoder(w).Encode(v); err != nil { return fmt.Errorf("encode json: %w", err) } return nil } // decode reads and decodes a JSON-encoded request body into a value of the specified type. // // Parameters: // - r: The *http.Request containing the JSON-encoded body to decode. // // Returns: // - The decoded value of type T. // - An error if decoding fails, or if the body contains invalid JSON. func decode[T any](r *http.Request) (T, error) { var v T if err := json.NewDecoder(r.Body).Decode(&v); err != nil { return v, fmt.Errorf("decode json: %w", err) } return v, nil } // serverError logs an internal server error and sends a 500 Internal Server Error // response to the client. // // Usage: // This function is intended for use when handling unexpected server-side errors. // It logs the error details along with the HTTP request method, URI, and a stack // trace for debugging purposes. After logging, it sends a standardized 500 Internal // Server Error response to the client. // // Parameters: // - logger: The *slog.Logger instance used for logging error details. // - w: The http.ResponseWriter to send the response to. // - r: The *http.Request that triggered the error. Used to extract method and URI. // - err: The error instance to log, providing context about the issue. // // Example: // // func handler(w http.ResponseWriter, r *http.Request) { // err := someOperation() // if err != nil { // serverError(logger, w, r, err) // return // } // // Handle request normally // } func serverError(logger *slog.Logger, w http.ResponseWriter, r *http.Request, err error) { var ( method = r.Method uri = r.URL.RequestURI() // Use debug.Stack() to get the stack trace. This returns a byte slice, which // we need to convert to a string so that it's readable in the log entry. trace = string(debug.Stack()) ) logger.Error(err.Error(), "method", method, "uri", uri, "trace", trace) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } // clientError sends an HTTP error response to the client with the specified // status code and its corresponding description. // // Usage: // This function is useful for handling HTTP errors in a consistent manner. // It sends the appropriate HTTP status text as the response body, along with // the given status code as the response status. This is typically used in web // applications to return standardized error messages for various client-side // errors. // // Parameters: // - w: The http.ResponseWriter to send the response to. // - status: The HTTP status code to return. It should be a valid HTTP status // code as defined in the http package. // // Example: // // func handler(w http.ResponseWriter, r *http.Request) { // if !isAuthorized(r) { // clientError(w, http.StatusForbidden) // Responds with "403 Forbidden" // return // } // // Handle request normally // } func clientError(w http.ResponseWriter, status int) { http.Error(w, http.StatusText(status), status) }