Error Handling
Return consistent API errors across your services using the ApiError struct and the SendError helper.
Ginboot provides a clean, standardized approach to error handling across your microservices using the ApiError interface and the SendError utility.
The ApiError Struct
To ensure consistency in API responses, Ginboot defines an ApiError struct containing an error_code and a message.
type ApiError struct {
ErrorCode string `json:"error_code"`
Message string `json:"message"`
}Creating Custom Errors
You can define reusable domain errors within your application using ginboot.NewApiError(httpStatusCode, message):
import "github.com/klass-lk/ginboot"
var (
ErrUserNotFound = ginboot.NewApiError(404, "User with ID %s not found")
ErrInvalidInput = ginboot.NewApiError(400, "Invalid input provided")
)You can then format these errors dynamically at runtime:
// Creates an ApiError with Message: "User with ID 123 not found"
err := ErrUserNotFound.New("123")Sending Errors in Controllers
When an error occurs in your controller, you can use ginboot.SendError(c, err) to automatically format and send the response back to the client.
func (c *UserController) GetUser(ctx *gin.Context) {
userId := ctx.Param("id")
user, err := c.UserService.FindById(userId)
if err != nil {
// Automatically maps the HTTP status code from the ApiError
// and sends `{ "error_code": "404", "message": "User with ID 123 not found" }`
ginboot.SendError(ctx, ErrUserNotFound.New(userId))
return
}
ctx.JSON(200, user)
}If a standard Go error (not an ApiError) is passed to SendError, Ginboot will safely wrap it in a 500 Internal Server Error response to prevent exposing stack traces to clients.
Errors that write their own response
When your error bodies must follow another shape — for example while replacing
a service written in another framework — return an error that implements
ResponseError. SendError (and so any handler that returns it) hands the
request to the error instead of writing the default body. It is found through
errors.As, so wrapped errors work too.
type springError struct{ status int }
func (e springError) Error() string { return http.StatusText(e.status) }
func (e springError) WriteResponse(c *gin.Context) {
c.JSON(e.status, gin.H{"status": e.status, "error": http.StatusText(e.status), "path": c.Request.URL.Path})
}