Error Handling
Ginji provides a robust error handling system with structured errors and validation support.
HTTPError
Create HTTP errors with status codes and messages:
go
app.Get("/users/:id", func(c *ginji.Context) {
id := c.Param("id")
user, err := db.FindUser(id)
if err != nil {
c.AbortWithError(ginji.NewHTTPError(
ginji.StatusNotFound,
"User not found",
))
return
}
c.JSON(ginji.StatusOK, user)
})Error with Details
Add structured error details:
go
err := ginji.NewHTTPError(ginji.StatusBadRequest, "Invalid request").
WithDetails(ginji.H{
"field": "email",
"reason": "already exists",
})
c.AbortWithError(err)Error Handler Middleware
Use the default error handler:
go
app.Use(ginji.DefaultErrorHandler())Response format:
json
{
"error": "User not found",
"status": 404
}With details:
json
{
"error": "Invalid request",
"status": 400,
"details": {
"field": "email",
"reason": "already exists"
}
}Validation Errors
Validation errors are automatically formatted:
go
type CreateUserRequest struct {
Email string `json:"email" ginji:"required,email"`
Password string `json:"password" ginji:"required,min=8"`
Age int `json:"age" ginji:"required,gte=18"`
}
app.Post("/users", func(c *ginji.Context) {
var req CreateUserRequest
if err := c.BindJSON(&req); err != nil {
// Validation errors are automatically returned
return
}
// Proceed with valid data
createUser(req)
})Validation error response:
json
{
"error": "Validation failed",
"status": 400,
"errors": [
{
"field": "email",
"constraint": "email",
"message": "email validation failed"
},
{
"field": "password",
"constraint": "min",
"message": "min validation failed (expected: 8)"
}
]
}Custom Error Handler
Create your own error handler:
go
app.Use(func(next ginji.Handler) ginji.Handler {
return func(c *ginji.Context) {
next(c)
if c.IsAborted() {
if err := c.Error(); err != nil {
// Handle HTTPError
if httpErr, ok := err.(*ginji.HTTPError); ok {
c.JSON(httpErr.Status, ginji.H{
"success": false,
"error": httpErr.Message,
"code": httpErr.Status,
})
return
}
// Handle other errors
c.JSON(ginji.StatusInternalServerError, ginji.H{
"success": false,
"error": "Internal server error",
})
}
}
}
})Debug Mode
Enable debug mode for detailed errors:
go
ginji.SetMode(ginji.DebugMode)In debug mode, errors include stack traces.
Common HTTP Errors
Helper functions for common errors:
go
// 400 Bad Request
ginji.NewBadRequestError("Invalid input")
// 401 Unauthorized
ginji.NewUnauthorizedError("Authentication required")
// 403 Forbidden
ginji.NewForbiddenError("Access denied")
// 404 Not Found
ginji.NewNotFoundError("Resource not found")
// 500 Internal Server Error
ginji.NewInternalServerError("Something went wrong")Complete Example
go
package main
import (
"github.com/ginjigo/ginji"
"github.com/ginjigo/ginji/middleware"
)
type User struct {
Email string `json:"email" ginji:"required,email"`
Password string `json:"password" ginji:"required,min=8"`
Age int `json:"age" ginji:"required,gte=18"`
}
func main() {
app := ginji.New()
// Enable error handler
app.Use(ginji.DefaultErrorHandler())
app.Use(middleware.Recovery())
app.Post("/users", func(c *ginji.Context) {
var user User
// Validation errors are handled automatically
if err := c.BindJSON(&user); err != nil {
return
}
// Check if user exists
if userExists(user.Email) {
c.AbortWithError(
ginji.NewHTTPError(ginji.StatusConflict, "User already exists").
WithDetails(ginji.H{"email": user.Email}),
)
return
}
// Create user
if err := createUser(user); err != nil {
c.AbortWithError(
ginji.NewInternalServerError("Failed to create user"),
)
return
}
c.JSON(ginji.StatusCreated, ginji.H{"message": "User created"})
})
app.Listen(":8080")
}Best Practices
- Use HTTPError - For predictable error responses
- Add details - Include relevant context in errors
- Validate early - Use validation tags on structs
- Log errors - Log internal errors for debugging
- Don't expose internals - Hide sensitive error details from clients
- Use appropriate status codes - Follow HTTP conventions