76 lines
1.9 KiB
Go
76 lines
1.9 KiB
Go
// Package httpresponse provides standard HTTP response types and helpers.
|
|
//
|
|
// This package implements an envelope pattern for consistent API responses:
|
|
//
|
|
// {
|
|
// "data": {...}, // Present on success
|
|
// "error": {...}, // Present on error
|
|
// "meta": {
|
|
// "request_id": "...",
|
|
// "trace_id": "...",
|
|
// "timestamp": "..."
|
|
// }
|
|
// }
|
|
//
|
|
// Usage:
|
|
//
|
|
// func GetUser(w http.ResponseWriter, r *http.Request) {
|
|
// user, err := svc.Get(ctx, id)
|
|
// if err != nil {
|
|
// httpresponse.NotFound(w, r, "user not found")
|
|
// return
|
|
// }
|
|
// httpresponse.OK(w, r, user)
|
|
// }
|
|
package httpresponse
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
"git.threesix.ai/jordan/sp4-test-1770498663/pkg/httpcontext"
|
|
)
|
|
|
|
// Response is the standard envelope for all API responses.
|
|
type Response struct {
|
|
Data any `json:"data,omitempty"`
|
|
Error *Error `json:"error,omitempty"`
|
|
Meta Meta `json:"meta"`
|
|
}
|
|
|
|
// Error represents an API error in the response envelope.
|
|
type Error struct {
|
|
Code string `json:"code"`
|
|
Message string `json:"message"`
|
|
Details any `json:"details,omitempty"`
|
|
}
|
|
|
|
// Meta contains response metadata.
|
|
type Meta struct {
|
|
RequestID string `json:"request_id,omitempty"`
|
|
TraceID string `json:"trace_id,omitempty"`
|
|
Timestamp string `json:"timestamp"`
|
|
}
|
|
|
|
// newMeta creates a Meta with current timestamp, request ID, and trace ID from context.
|
|
func newMeta(r *http.Request) Meta {
|
|
requestID, _ := httpcontext.GetRequestID(r.Context())
|
|
traceID, _ := httpcontext.GetTraceID(r.Context())
|
|
return Meta{
|
|
RequestID: requestID,
|
|
TraceID: traceID,
|
|
Timestamp: time.Now().UTC().Format(time.RFC3339),
|
|
}
|
|
}
|
|
|
|
// Error codes for machine-readable error classification.
|
|
const (
|
|
CodeBadRequest = "BAD_REQUEST"
|
|
CodeUnauthorized = "UNAUTHORIZED"
|
|
CodeForbidden = "FORBIDDEN"
|
|
CodeNotFound = "NOT_FOUND"
|
|
CodeConflict = "CONFLICT"
|
|
CodeInternal = "INTERNAL_ERROR"
|
|
CodeValidation = "VALIDATION_ERROR"
|
|
)
|