Как правильно обрабатывать ошибки в веб-сервисе gin / golang - PullRequest
0 голосов
/ 31 мая 2018

Я пишу простой REST API в go с использованием джина.Я прочитал много постов и текстов о том, как сделать обработку ошибок менее повторяющейся на ходу, но я не могу сосредоточиться на том, как сделать это в обработчиках джина.

Все, что мне делает служба, - это запускает некоторые запросы к базе данных.и возвращает результаты в виде JSON, поэтому типичный обработчик выглядит следующим образом

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})
}

. Как видите, даже этот простой обработчик повторяет один и тот же шаблон "if err! = nil" четыре раза.В «избранных» API-интерфейсах у меня их вдвое больше, поскольку есть потенциальные ошибки при привязке входных данных и ошибки при маршалинге ответа в JSON.Есть ли хороший способ сделать это более СУХОЙ?

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

Мой обычный подход - использовать функцию обтекания.Это имеет преимущество (по сравнению с ответом Адриана - что также неплохо, кстати), оставляя обработку ошибок в более идиоматической форме 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})
}
0 голосов
/ 31 мая 2018

Вы можете сделать это немного больше СУХОГО с помощником:

func handleError(c *gin.Context, err error) bool {
    if err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return true
    }
    return false
}

Используется как:

err = tx.Commit()
if handleError(c,err) {
    return
}

Это только сокращает обработку ошибок количество строк от 4 до 3 строк, но делает абстрагирование повторяющейся логики, позволяя вам изменять обработку повторяющихся ошибок в одном месте, а не везде, где обрабатывается ошибка (например, если вы хотитедобавить ведение журнала ошибок или изменить ответ об ошибке и т. д.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...