// Copyright 2024 Patial Tech (Ankit Patial). // // This file is part of code.patial.tech/go/appcore, which is MIT licensed. // See http://opensource.org/licenses/MIT package response import ( "encoding/json" "fmt" "log/slog" "net/http" "code.patial.tech/go/appcore/request" ) // Detail of api response type Detail struct { // Data of api response // // it will nil in case of error Data any `json:"data"` // Error if any occurred during api call Error *string `json:"error,omitempty"` // Pager is used for paged data response Pager *request.Pager `json:"pager,omitempty"` } // Done data response func Ok(w http.ResponseWriter, data any) { reply(w, data, nil) } // Paged data response func Paged(w http.ResponseWriter, data any, p request.Pager) { reply(w, data, &p) } func reply(w http.ResponseWriter, data any, p *request.Pager) { w.Header().Set("Content-Type", "application/json") // Requires the client to validate the response with the server before using the cached version, // ensuring data freshness. w.Header().Set("Cache-Control", "no-cache") // older HTTP header used for controlling caching behavior in HTTP/1.0, // primarily for backwards compatibility with older browsers and caches w.Header().Set("Pragma", "no-cache") // if data is nil, let's pass it on as null if data == nil { w.WriteHeader(http.StatusOK) _, writeErr := fmt.Fprint(w, "{\"data\":null}") if writeErr != nil { slog.Error(writeErr.Error()) } return } // json data... w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(Detail{ Data: data, Pager: p, }) } func BadRequest(w http.ResponseWriter, err error) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) _, writeErr := fmt.Fprintf(w, "{\"error\": %q}", err.Error()) if writeErr != nil { slog.Error(writeErr.Error()) } } func InternalServerError(w http.ResponseWriter, err error) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) _, writeErr := fmt.Fprintf(w, "{\"error\": %q}", err.Error()) if writeErr != nil { slog.Error(writeErr.Error()) } } func SessionExpired(w http.ResponseWriter) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusUnauthorized) _, writeErr := fmt.Fprint(w, "{\"error\": \"Session is expired, please login again\"}") if writeErr != nil { slog.Error(writeErr.Error()) } } func NotAutorized(w http.ResponseWriter) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) _, writeErr := fmt.Fprint(w, "{\"error\": \"You are not authorized to perform this action\"}") if writeErr != nil { slog.Error(writeErr.Error()) } } // Forbidden response error func Forbidden(w http.ResponseWriter, err error) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusForbidden) _, writeErr := fmt.Fprintf(w, "{\"error\": %q}", err.Error()) if writeErr != nil { slog.Error(writeErr.Error()) } }