package api import ( "encoding/json" "errors" "fmt" "net/http" ) // Common error codes const ( CodeSuccess = 0 CodeInvalidParams = 400 CodeUnauthorized = 401 CodeForbidden = 403 CodeNotFound = 404 CodeInternalError = 500 CodeServiceUnavail = 503 ) // Error represents an API error type Error struct { Code int `json:"code"` Message string `json:"message"` } // Error implements the error interface func (e *Error) Error() string { return fmt.Sprintf("code: %d, message: %s", e.Code, e.Message) } // NewError creates a new API error func NewError(code int, message string) *Error { return &Error{ Code: code, Message: message, } } // Response represents a standard API response type Response struct { Code int `json:"code"` Message string `json:"message"` Data interface{} `json:"data,omitempty"` } // ResponseWriter wraps common response writing functions type ResponseWriter struct { http.ResponseWriter } // NewResponseWriter creates a new ResponseWriter func NewResponseWriter(w http.ResponseWriter) *ResponseWriter { return &ResponseWriter{w} } // WriteJSON writes a JSON response func (w *ResponseWriter) WriteJSON(code int, data interface{}) error { w.Header().Set("Content-Type", "application/json") w.WriteHeader(code) return json.NewEncoder(w).Encode(data) } // WriteSuccess writes a success response func (w *ResponseWriter) WriteSuccess(data interface{}) error { return w.WriteJSON(http.StatusOK, Response{ Code: CodeSuccess, Message: "success", Data: data, }) } // WriteError writes an error response func (w *ResponseWriter) WriteError(err error) error { var apiErr *Error if errors.As(err, &apiErr) { return w.WriteJSON(getHTTPStatus(apiErr.Code), Response{ Code: apiErr.Code, Message: apiErr.Message, }) } // Handle unknown errors return w.WriteJSON(http.StatusInternalServerError, Response{ Code: CodeInternalError, Message: "Internal Server Error", }) } // WriteErrorWithCode writes an error response with a specific code func (w *ResponseWriter) WriteErrorWithCode(code int, message string) error { return w.WriteJSON(getHTTPStatus(code), Response{ Code: code, Message: message, }) } // getHTTPStatus maps API error codes to HTTP status codes func getHTTPStatus(code int) int { switch code { case CodeSuccess: return http.StatusOK case CodeInvalidParams: return http.StatusBadRequest case CodeUnauthorized: return http.StatusUnauthorized case CodeForbidden: return http.StatusForbidden case CodeNotFound: return http.StatusNotFound case CodeServiceUnavail: return http.StatusServiceUnavailable default: return http.StatusInternalServerError } } // Common errors var ( ErrInvalidParams = NewError(CodeInvalidParams, "Invalid parameters") ErrUnauthorized = NewError(CodeUnauthorized, "Unauthorized") ErrForbidden = NewError(CodeForbidden, "Forbidden") ErrNotFound = NewError(CodeNotFound, "Resource not found") ErrInternalError = NewError(CodeInternalError, "Internal server error") ErrServiceUnavail = NewError(CodeServiceUnavail, "Service unavailable") ) // ValidationError creates an error for invalid parameters func ValidationError(message string) *Error { return NewError(CodeInvalidParams, message) } // NotFoundError creates an error for not found resources func NotFoundError(resource string) *Error { return NewError(CodeNotFound, fmt.Sprintf("%s not found", resource)) } // ForbiddenError creates an error for forbidden actions func ForbiddenError(message string) *Error { return NewError(CodeForbidden, message) } // InternalError creates an error for internal server errors func InternalError(err error) *Error { if err == nil { return ErrInternalError } return NewError(CodeInternalError, err.Error()) }