Initialize base
This commit is contained in:
@@ -0,0 +1,304 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
|
||||
"tm/internal/infrastructure"
|
||||
)
|
||||
|
||||
// Logger interface defines logging methods
|
||||
type Logger interface {
|
||||
Debug(msg string, fields map[string]interface{})
|
||||
Info(msg string, fields map[string]interface{})
|
||||
Warn(msg string, fields map[string]interface{})
|
||||
Error(msg string, fields map[string]interface{})
|
||||
Fatal(msg string, fields map[string]interface{})
|
||||
WithFields(fields map[string]interface{}) Logger
|
||||
Sync() error // Flush any buffered log entries
|
||||
}
|
||||
|
||||
// ZapLogger wraps zap logger
|
||||
type ZapLogger struct {
|
||||
logger *zap.Logger
|
||||
sugar *zap.SugaredLogger
|
||||
fields map[string]interface{}
|
||||
}
|
||||
|
||||
// NewLogger creates a new logger instance with Zap and Lumberjack
|
||||
func NewLogger(config *infrastructure.LoggingConfig) Logger {
|
||||
// Parse log level
|
||||
level := parseLogLevel(config.Level)
|
||||
|
||||
// Create encoder config
|
||||
encoderConfig := createEncoderConfig(config.Format)
|
||||
|
||||
// Create encoder
|
||||
encoder := createEncoder(config.Format, encoderConfig)
|
||||
|
||||
// Create writer
|
||||
writer := createWriter(config)
|
||||
|
||||
// Create core
|
||||
core := zapcore.NewCore(encoder, writer, level)
|
||||
|
||||
// Create logger with caller information
|
||||
logger := zap.New(core,
|
||||
zap.AddCaller(),
|
||||
zap.AddCallerSkip(1),
|
||||
zap.AddStacktrace(zapcore.ErrorLevel),
|
||||
)
|
||||
|
||||
return &ZapLogger{
|
||||
logger: logger,
|
||||
sugar: logger.Sugar(),
|
||||
fields: make(map[string]interface{}),
|
||||
}
|
||||
}
|
||||
|
||||
// createWriter creates the appropriate writer based on configuration
|
||||
func createWriter(config *infrastructure.LoggingConfig) zapcore.WriteSyncer {
|
||||
switch config.Output {
|
||||
case "stdout":
|
||||
return zapcore.AddSync(os.Stdout)
|
||||
case "stderr":
|
||||
return zapcore.AddSync(os.Stderr)
|
||||
case "file":
|
||||
return createFileWriter(config.File)
|
||||
default:
|
||||
// Default to stdout
|
||||
return zapcore.AddSync(os.Stdout)
|
||||
}
|
||||
}
|
||||
|
||||
// createFileWriter creates a file writer with rotation using lumberjack
|
||||
func createFileWriter(fileConfig infrastructure.LogFileConfig) zapcore.WriteSyncer {
|
||||
// Ensure log directory exists
|
||||
logDir := filepath.Dir(fileConfig.Path)
|
||||
if err := os.MkdirAll(logDir, 0755); err != nil {
|
||||
// Fallback to stdout if can't create directory
|
||||
return zapcore.AddSync(os.Stdout)
|
||||
}
|
||||
|
||||
// Create lumberjack logger for rotation
|
||||
lumberjackLogger := &lumberjack.Logger{
|
||||
Filename: fileConfig.Path,
|
||||
MaxSize: fileConfig.MaxSize, // MB
|
||||
MaxBackups: fileConfig.MaxBackups,
|
||||
MaxAge: fileConfig.MaxAge, // days
|
||||
Compress: fileConfig.Compress,
|
||||
}
|
||||
|
||||
// Create multi-writer to write to both file and stdout
|
||||
multiWriter := io.MultiWriter(lumberjackLogger, os.Stdout)
|
||||
|
||||
return zapcore.AddSync(multiWriter)
|
||||
}
|
||||
|
||||
// createEncoderConfig creates encoder configuration
|
||||
func createEncoderConfig(format string) zapcore.EncoderConfig {
|
||||
config := zap.NewProductionEncoderConfig()
|
||||
|
||||
// Customize timestamp format
|
||||
config.TimeKey = "timestamp"
|
||||
config.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||
|
||||
// Customize level encoding
|
||||
config.EncodeLevel = zapcore.LowercaseLevelEncoder
|
||||
|
||||
// Customize caller encoding
|
||||
config.EncodeCaller = zapcore.ShortCallerEncoder
|
||||
|
||||
// Customize duration encoding
|
||||
config.EncodeDuration = zapcore.StringDurationEncoder
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// createEncoder creates the appropriate encoder
|
||||
func createEncoder(format string, config zapcore.EncoderConfig) zapcore.Encoder {
|
||||
switch format {
|
||||
case "json":
|
||||
return zapcore.NewJSONEncoder(config)
|
||||
case "console", "text":
|
||||
return zapcore.NewConsoleEncoder(config)
|
||||
default:
|
||||
return zapcore.NewJSONEncoder(config)
|
||||
}
|
||||
}
|
||||
|
||||
// parseLogLevel converts string level to zapcore.Level
|
||||
func parseLogLevel(level string) zapcore.Level {
|
||||
switch level {
|
||||
case "debug":
|
||||
return zapcore.DebugLevel
|
||||
case "info":
|
||||
return zapcore.InfoLevel
|
||||
case "warn", "warning":
|
||||
return zapcore.WarnLevel
|
||||
case "error":
|
||||
return zapcore.ErrorLevel
|
||||
case "fatal":
|
||||
return zapcore.FatalLevel
|
||||
case "panic":
|
||||
return zapcore.PanicLevel
|
||||
default:
|
||||
return zapcore.InfoLevel
|
||||
}
|
||||
}
|
||||
|
||||
// convertFields converts map[string]interface{} to zap fields
|
||||
func convertFields(fields map[string]interface{}) []zap.Field {
|
||||
zapFields := make([]zap.Field, 0, len(fields))
|
||||
for key, value := range fields {
|
||||
zapFields = append(zapFields, zap.Any(key, value))
|
||||
}
|
||||
return zapFields
|
||||
}
|
||||
|
||||
// Debug logs a debug message
|
||||
func (l *ZapLogger) Debug(msg string, fields map[string]interface{}) {
|
||||
allFields := l.mergeFields(fields)
|
||||
l.logger.Debug(msg, convertFields(allFields)...)
|
||||
}
|
||||
|
||||
// Info logs an info message
|
||||
func (l *ZapLogger) Info(msg string, fields map[string]interface{}) {
|
||||
allFields := l.mergeFields(fields)
|
||||
l.logger.Info(msg, convertFields(allFields)...)
|
||||
}
|
||||
|
||||
// Warn logs a warning message
|
||||
func (l *ZapLogger) Warn(msg string, fields map[string]interface{}) {
|
||||
allFields := l.mergeFields(fields)
|
||||
l.logger.Warn(msg, convertFields(allFields)...)
|
||||
}
|
||||
|
||||
// Error logs an error message
|
||||
func (l *ZapLogger) Error(msg string, fields map[string]interface{}) {
|
||||
allFields := l.mergeFields(fields)
|
||||
l.logger.Error(msg, convertFields(allFields)...)
|
||||
}
|
||||
|
||||
// Fatal logs a fatal message and exits
|
||||
func (l *ZapLogger) Fatal(msg string, fields map[string]interface{}) {
|
||||
allFields := l.mergeFields(fields)
|
||||
l.logger.Fatal(msg, convertFields(allFields)...)
|
||||
}
|
||||
|
||||
// WithFields returns a logger with predefined fields
|
||||
func (l *ZapLogger) WithFields(fields map[string]interface{}) Logger {
|
||||
newFields := make(map[string]interface{})
|
||||
|
||||
// Copy existing fields
|
||||
for k, v := range l.fields {
|
||||
newFields[k] = v
|
||||
}
|
||||
|
||||
// Add new fields
|
||||
for k, v := range fields {
|
||||
newFields[k] = v
|
||||
}
|
||||
|
||||
return &ZapLogger{
|
||||
logger: l.logger,
|
||||
sugar: l.sugar,
|
||||
fields: newFields,
|
||||
}
|
||||
}
|
||||
|
||||
// Sync flushes any buffered log entries
|
||||
func (l *ZapLogger) Sync() error {
|
||||
return l.logger.Sync()
|
||||
}
|
||||
|
||||
// mergeFields merges instance fields with provided fields
|
||||
func (l *ZapLogger) mergeFields(fields map[string]interface{}) map[string]interface{} {
|
||||
if len(l.fields) == 0 {
|
||||
return fields
|
||||
}
|
||||
|
||||
merged := make(map[string]interface{})
|
||||
|
||||
// Add instance fields first
|
||||
for k, v := range l.fields {
|
||||
merged[k] = v
|
||||
}
|
||||
|
||||
// Add provided fields (they override instance fields)
|
||||
for k, v := range fields {
|
||||
merged[k] = v
|
||||
}
|
||||
|
||||
return merged
|
||||
}
|
||||
|
||||
// Global logger instance
|
||||
var globalLogger Logger
|
||||
|
||||
// InitLogger initializes the global logger
|
||||
func InitLogger(config *infrastructure.LoggingConfig) {
|
||||
globalLogger = NewLogger(config)
|
||||
}
|
||||
|
||||
// GetLogger returns the global logger instance
|
||||
func GetLogger() Logger {
|
||||
if globalLogger == nil {
|
||||
// Fallback configuration
|
||||
config := &infrastructure.LoggingConfig{
|
||||
Level: "info",
|
||||
Format: "json",
|
||||
Output: "stdout",
|
||||
File: infrastructure.LogFileConfig{
|
||||
Path: "./logs/app.log",
|
||||
MaxSize: 100,
|
||||
MaxBackups: 5,
|
||||
MaxAge: 30,
|
||||
Compress: true,
|
||||
},
|
||||
}
|
||||
globalLogger = NewLogger(config)
|
||||
}
|
||||
return globalLogger
|
||||
}
|
||||
|
||||
// Cleanup flushes and closes the logger
|
||||
func Cleanup() {
|
||||
if globalLogger != nil {
|
||||
globalLogger.Sync()
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions for convenience
|
||||
func Debug(msg string, fields map[string]interface{}) {
|
||||
GetLogger().Debug(msg, fields)
|
||||
}
|
||||
|
||||
func Info(msg string, fields map[string]interface{}) {
|
||||
GetLogger().Info(msg, fields)
|
||||
}
|
||||
|
||||
func Warn(msg string, fields map[string]interface{}) {
|
||||
GetLogger().Warn(msg, fields)
|
||||
}
|
||||
|
||||
func Error(msg string, fields map[string]interface{}) {
|
||||
GetLogger().Error(msg, fields)
|
||||
}
|
||||
|
||||
func Fatal(msg string, fields map[string]interface{}) {
|
||||
GetLogger().Fatal(msg, fields)
|
||||
}
|
||||
|
||||
func WithFields(fields map[string]interface{}) Logger {
|
||||
return GetLogger().WithFields(fields)
|
||||
}
|
||||
|
||||
func Sync() error {
|
||||
return GetLogger().Sync()
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
|
||||
"tm/internal/domain"
|
||||
"tm/pkg/logger"
|
||||
"tm/pkg/response"
|
||||
)
|
||||
|
||||
// AuthMiddleware creates JWT authentication middleware for both customers and users
|
||||
func AuthMiddleware(customerAuthService domain.CustomerAuthService, userAuthService domain.UserAuthService, logger logger.Logger) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
// Skip authentication for public routes
|
||||
if isPublicRoute(c.Path(), c.Request().Method) {
|
||||
return next(c)
|
||||
}
|
||||
|
||||
// Get Authorization header
|
||||
authHeader := c.Request().Header.Get("Authorization")
|
||||
if authHeader == "" {
|
||||
logger.Warn("Missing authorization header", map[string]interface{}{
|
||||
"path": c.Path(),
|
||||
"method": c.Request().Method,
|
||||
})
|
||||
return response.Unauthorized(c, "Authorization header required")
|
||||
}
|
||||
|
||||
// Check Bearer format
|
||||
const bearerPrefix = "Bearer "
|
||||
if !strings.HasPrefix(authHeader, bearerPrefix) {
|
||||
logger.Warn("Invalid authorization header format", map[string]interface{}{
|
||||
"path": c.Path(),
|
||||
"method": c.Request().Method,
|
||||
})
|
||||
return response.Unauthorized(c, "Invalid authorization header format")
|
||||
}
|
||||
|
||||
// Extract token
|
||||
token := strings.TrimPrefix(authHeader, bearerPrefix)
|
||||
if token == "" {
|
||||
return response.Unauthorized(c, "Token required")
|
||||
}
|
||||
|
||||
// Try to validate as customer first (for mobile routes)
|
||||
if strings.HasPrefix(c.Path(), "/api/mobile/") || strings.HasPrefix(c.Path(), "/mobile/") {
|
||||
customer, err := customerAuthService.ValidateToken(c.Request().Context(), token)
|
||||
if err == nil && customer != nil {
|
||||
// Store customer in context
|
||||
c.Set("customer", customer)
|
||||
c.Set("customer_id", customer.ID.String())
|
||||
c.Set("company_id", customer.CompanyID.String())
|
||||
c.Set("user_type", "customer")
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
|
||||
// Try to validate as panel user (for admin routes)
|
||||
if strings.HasPrefix(c.Path(), "/api/admin/") || strings.HasPrefix(c.Path(), "/admin/") {
|
||||
user, err := userAuthService.ValidateToken(c.Request().Context(), token)
|
||||
if err == nil && user != nil {
|
||||
// Store user in context
|
||||
c.Set("user", user)
|
||||
c.Set("user_id", user.ID.String())
|
||||
c.Set("user_type", "user")
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
|
||||
// For other routes, try both types
|
||||
if customer, err := customerAuthService.ValidateToken(c.Request().Context(), token); err == nil && customer != nil {
|
||||
c.Set("customer", customer)
|
||||
c.Set("customer_id", customer.ID.String())
|
||||
c.Set("company_id", customer.CompanyID.String())
|
||||
c.Set("user_type", "customer")
|
||||
return next(c)
|
||||
}
|
||||
|
||||
if user, err := userAuthService.ValidateToken(c.Request().Context(), token); err == nil && user != nil {
|
||||
c.Set("user", user)
|
||||
c.Set("user_id", user.ID.String())
|
||||
c.Set("user_type", "user")
|
||||
return next(c)
|
||||
}
|
||||
|
||||
logger.Warn("Token validation failed", map[string]interface{}{
|
||||
"path": c.Path(),
|
||||
})
|
||||
return response.Unauthorized(c, "Invalid or expired token")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CustomerOnlyMiddleware ensures only customers can access the route
|
||||
func CustomerOnlyMiddleware() echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
customer, ok := c.Get("customer").(*domain.Customer)
|
||||
if !ok || customer == nil {
|
||||
return response.Unauthorized(c, "Customer authentication required")
|
||||
}
|
||||
|
||||
if !customer.IsActive {
|
||||
return response.Forbidden(c, "Account is inactive")
|
||||
}
|
||||
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UserOnlyMiddleware ensures only panel users can access the route
|
||||
func UserOnlyMiddleware() echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
user, ok := c.Get("user").(*domain.User)
|
||||
if !ok || user == nil {
|
||||
return response.Unauthorized(c, "Panel user authentication required")
|
||||
}
|
||||
|
||||
if !user.IsActive {
|
||||
return response.Forbidden(c, "Account is inactive")
|
||||
}
|
||||
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CustomerRoleMiddleware creates role-based authorization middleware for customers
|
||||
func CustomerRoleMiddleware(allowedRoles ...domain.CustomerRole) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
customer, ok := c.Get("customer").(*domain.Customer)
|
||||
if !ok {
|
||||
return response.Unauthorized(c, "Customer authentication required")
|
||||
}
|
||||
|
||||
// Check if customer has required role
|
||||
for _, role := range allowedRoles {
|
||||
if customer.Role == role {
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
|
||||
return response.Forbidden(c, "Insufficient permissions")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UserRoleMiddleware creates role-based authorization middleware for panel users
|
||||
func UserRoleMiddleware(allowedRoles ...domain.UserRole) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
user, ok := c.Get("user").(*domain.User)
|
||||
if !ok {
|
||||
return response.Unauthorized(c, "Panel user authentication required")
|
||||
}
|
||||
|
||||
// Check if user has required role
|
||||
for _, role := range allowedRoles {
|
||||
if user.Role == role {
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
|
||||
return response.Forbidden(c, "Insufficient permissions")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UserPermissionMiddleware creates permission-based authorization middleware for panel users
|
||||
func UserPermissionMiddleware(requiredPermissions ...string) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
user, ok := c.Get("user").(*domain.User)
|
||||
if !ok {
|
||||
return response.Unauthorized(c, "Panel user authentication required")
|
||||
}
|
||||
|
||||
// Admin has all permissions
|
||||
if user.IsAdmin() {
|
||||
return next(c)
|
||||
}
|
||||
|
||||
// Check if user has all required permissions
|
||||
for _, permission := range requiredPermissions {
|
||||
if !user.HasPermission(permission) {
|
||||
return response.Forbidden(c, "Insufficient permissions")
|
||||
}
|
||||
}
|
||||
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isPublicRoute checks if a route should be accessible without authentication
|
||||
func isPublicRoute(path, method string) bool {
|
||||
// Debug logging
|
||||
fmt.Printf("Checking public route: %s %s\n", method, path)
|
||||
|
||||
// Also log to stderr to ensure we see it
|
||||
fmt.Fprintf(os.Stderr, "DEBUG: Checking public route: %s %s\n", method, path)
|
||||
|
||||
publicRoutes := map[string][]string{
|
||||
// Mobile customer auth routes
|
||||
"/api/v1/mobile/auth/register": {"POST"},
|
||||
"/api/v1/mobile/auth/login": {"POST"},
|
||||
"/api/v1/mobile/auth/refresh": {"POST"},
|
||||
"/api/v1/mobile/auth/resend-verification": {"POST"},
|
||||
"/api/mobile/auth/register": {"POST"},
|
||||
"/api/mobile/auth/login": {"POST"},
|
||||
"/api/mobile/auth/refresh": {"POST"},
|
||||
"/api/mobile/auth/resend-verification": {"POST"},
|
||||
"/mobile/auth/register": {"POST"},
|
||||
"/mobile/auth/login": {"POST"},
|
||||
"/mobile/auth/refresh": {"POST"},
|
||||
"/mobile/auth/resend-verification": {"POST"},
|
||||
|
||||
// Panel user auth routes
|
||||
"/api/v1/admin/auth/login": {"POST"},
|
||||
"/api/v1/admin/auth/refresh": {"POST"},
|
||||
"/api/admin/auth/login": {"POST"},
|
||||
"/api/admin/auth/refresh": {"POST"},
|
||||
"/admin/auth/login": {"POST"},
|
||||
"/admin/auth/refresh": {"POST"},
|
||||
|
||||
// Legacy auth routes (for backward compatibility)
|
||||
"/auth/register": {"POST"},
|
||||
"/auth/login": {"POST"},
|
||||
"/auth/refresh": {"POST"},
|
||||
|
||||
// Health and documentation routes
|
||||
"/health": {"GET"},
|
||||
"/metrics": {"GET"},
|
||||
"/api/docs": {"GET"},
|
||||
"/api/docs/*": {"GET"},
|
||||
"/swagger/*": {"GET"},
|
||||
}
|
||||
|
||||
if methods, exists := publicRoutes[path]; exists {
|
||||
for _, allowedMethod := range methods {
|
||||
if method == allowedMethod {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for wildcard routes
|
||||
for route, methods := range publicRoutes {
|
||||
if strings.HasSuffix(route, "/*") {
|
||||
prefix := strings.TrimSuffix(route, "/*")
|
||||
if strings.HasPrefix(path, prefix) {
|
||||
for _, allowedMethod := range methods {
|
||||
if method == allowedMethod {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package response
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
// APIResponse represents a standard API response structure
|
||||
type APIResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
Error *APIError `json:"error,omitempty"`
|
||||
Meta *Meta `json:"meta,omitempty"`
|
||||
}
|
||||
|
||||
// APIError represents error details in API response
|
||||
type APIError struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Details string `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
// Meta represents metadata for paginated responses
|
||||
type Meta struct {
|
||||
Total int `json:"total,omitempty"`
|
||||
Limit int `json:"limit,omitempty"`
|
||||
Offset int `json:"offset,omitempty"`
|
||||
Page int `json:"page,omitempty"`
|
||||
Pages int `json:"pages,omitempty"`
|
||||
}
|
||||
|
||||
// Success returns a successful response
|
||||
func Success(c echo.Context, data interface{}, message string) error {
|
||||
return c.JSON(http.StatusOK, APIResponse{
|
||||
Success: true,
|
||||
Message: message,
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
// SuccessWithMeta returns a successful response with metadata
|
||||
func SuccessWithMeta(c echo.Context, data interface{}, meta *Meta, message string) error {
|
||||
return c.JSON(http.StatusOK, APIResponse{
|
||||
Success: true,
|
||||
Message: message,
|
||||
Data: data,
|
||||
Meta: meta,
|
||||
})
|
||||
}
|
||||
|
||||
// Created returns a 201 Created response
|
||||
func Created(c echo.Context, data interface{}, message string) error {
|
||||
return c.JSON(http.StatusCreated, APIResponse{
|
||||
Success: true,
|
||||
Message: message,
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
// BadRequest returns a 400 Bad Request response
|
||||
func BadRequest(c echo.Context, message, details string) error {
|
||||
return c.JSON(http.StatusBadRequest, APIResponse{
|
||||
Success: false,
|
||||
Message: "Bad Request",
|
||||
Error: &APIError{
|
||||
Code: "BAD_REQUEST",
|
||||
Message: message,
|
||||
Details: details,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Unauthorized returns a 401 Unauthorized response
|
||||
func Unauthorized(c echo.Context, message string) error {
|
||||
return c.JSON(http.StatusUnauthorized, APIResponse{
|
||||
Success: false,
|
||||
Message: "Unauthorized",
|
||||
Error: &APIError{
|
||||
Code: "UNAUTHORIZED",
|
||||
Message: message,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Forbidden returns a 403 Forbidden response
|
||||
func Forbidden(c echo.Context, message string) error {
|
||||
return c.JSON(http.StatusForbidden, APIResponse{
|
||||
Success: false,
|
||||
Message: "Forbidden",
|
||||
Error: &APIError{
|
||||
Code: "FORBIDDEN",
|
||||
Message: message,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// NotFound returns a 404 Not Found response
|
||||
func NotFound(c echo.Context, message string) error {
|
||||
return c.JSON(http.StatusNotFound, APIResponse{
|
||||
Success: false,
|
||||
Message: "Not Found",
|
||||
Error: &APIError{
|
||||
Code: "NOT_FOUND",
|
||||
Message: message,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Conflict returns a 409 Conflict response
|
||||
func Conflict(c echo.Context, message string) error {
|
||||
return c.JSON(http.StatusConflict, APIResponse{
|
||||
Success: false,
|
||||
Message: "Conflict",
|
||||
Error: &APIError{
|
||||
Code: "CONFLICT",
|
||||
Message: message,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// ValidationError returns a 422 Unprocessable Entity response
|
||||
func ValidationError(c echo.Context, message, details string) error {
|
||||
return c.JSON(http.StatusUnprocessableEntity, APIResponse{
|
||||
Success: false,
|
||||
Message: "Validation Error",
|
||||
Error: &APIError{
|
||||
Code: "VALIDATION_ERROR",
|
||||
Message: message,
|
||||
Details: details,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// InternalServerError returns a 500 Internal Server Error response
|
||||
func InternalServerError(c echo.Context, message string) error {
|
||||
return c.JSON(http.StatusInternalServerError, APIResponse{
|
||||
Success: false,
|
||||
Message: "Internal Server Error",
|
||||
Error: &APIError{
|
||||
Code: "INTERNAL_SERVER_ERROR",
|
||||
Message: message,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// ServiceUnavailable returns a 503 Service Unavailable response
|
||||
func ServiceUnavailable(c echo.Context, message string) error {
|
||||
return c.JSON(http.StatusServiceUnavailable, APIResponse{
|
||||
Success: false,
|
||||
Message: "Service Unavailable",
|
||||
Error: &APIError{
|
||||
Code: "SERVICE_UNAVAILABLE",
|
||||
Message: message,
|
||||
},
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user