I am writing a simple REST API in go using gin. I have read many posts and texts about making error handling less repetitive in go, but I cannot seem to wrap my mind around how to do it in gin handlers.
All my service does is run some queries against a database and return the results as JSON, so a typical handler looks like this
func DeleteAPI(c *gin.Context) {
var db = c.MustGet("db").(*sql.DB)
query := "DELETE FROM table WHERE some condition"
tx, err := db.Begin()
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
defer tx.Rollback()
result, err := tx.Exec(query)
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
num, err := result.RowsAffected()
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
err = tx.Commit()
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"deleted": num})
}
As you can see, even this simple handler repeats the same "if err != nil" pattern four times. In a "select" based APIs I have twice as many, since there are potential errors when binding the input data and errors when marshaling the response into JSON. Is there a good way to make this more DRY?
You can make it slightly more DRY with a helper:
func handleError(c *gin.Context, err error) bool {
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return true
}
return false
}
Used as:
err = tx.Commit()
if handleError(c,err) {
return
}
This only cuts the error handling line count from 4 lines to 3, but it does abstract away the repeated logic, allowing you to change the repeated error handling in one place instead of everywhere an error is handled (e.g. if you want to add error logging, or change the error response, etc.)