Мой обычный подход - использовать функцию обтекания.Это имеет преимущество (по сравнению с ответом Адриана - что также неплохо, кстати), оставляя обработку ошибок в более идиоматической форме Go (return result, err
, по сравнению с засорением вашего кода вызовами типа handleError(err)
)и все же консолидирую его в одном месте.
func DeleteAPI(c *gin.Context) {
num, err := deleteAPI(c)
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"deleted": num})
}
func deleteAPI(c *gin.Context) (int, error) {
var db = c.MustGet("db").(*sql.DB)
query := "DELETE FROM table WHERE some condition"
tx, err := db.Begin()
if err != nil {
return 0, err
}
defer tx.Rollback()
result, err := tx.Exec(query)
if err != nil {
return 0, err
}
num, err := result.RowsAffected()
if err != nil {
return 0, err
}
err = tx.Commit()
if err != nil {
return 0, err
}
return num, nil
}
Для меня (и, как правило, для кодеров Go), приоритет - читаемость кода над DRY.И из трех вариантов (ваш оригинальный, Адриан и мой), на мой взгляд, моя версия более читабельна, по той простой причине, что ошибки обрабатываются совершенно идиоматическим образом, и они всплывают в верхнем обработчике.Этот же подход работает одинаково хорошо, если ваш контроллер заканчивает тем, что вызывает другие функции, которые возвращают ошибки.Перемещая всю обработку ошибок в верхнюю функцию, вы освобождаетесь от беспорядка обработки ошибок (кроме простой конструкции if err! = Nil {return err} `) во всем остальном коде.
Стоит также отметить, что этот подход может быть эффективно объединен с подходом Адриана, особенно для использования с несколькими обработчиками, путем изменения функции «обтекания» следующим образом:
func DeleteAPI(c *gin.Context) {
result, err := deleteAPI(c)
if handleError(c, err) {
return
}
c.JSON(200, gin.H{"deleted": num})
}