@frty

Как правильно обрабатывать ошибку в go?

Грубо говоря структура такая:

auth
--handler_v1.go
--auth.go

otp
--sms.go

// auth
type HandlerV1 struct {
	userAuthService *Auth
}


func (h *HandlerV1) GetOtp(c *fiber.Ctx) error {
	err := h.userAuthService.getOtp(c.IP(), "79999999999")
	// how handle error
}

type Auth struct {
	otpSender otp.Sender //by interface
}
func (a *Auth) getOtp(ip, destination string) error {
	err := a.otpSender.SendWithTTL(ip, destination, a.ttl)
	// how handle error
}

//otp
var (
	ErrRedisSave     = errors.New("Error saving data to Redis")
	ErrKeyNotFound   = errors.New("Key not found")
	ErrRedisRetrieve = errors.New("Error retrieving data from Redis")
)

type (
	KeyExistError struct {
		ttl string
	}
	Sender interface {
		SendWithTTL(ip, destination string, ttl Second) error
	}
	SMSSender struct {
		...
	}

)



func (e KeyExistError) Error() string {
	return fmt.Sprintf("Отправить код нельзя раньше чем через %s сек.", e.ttl)
}


func (s SMSSender) SendWithTTL(ip, phone string, ttl Second) error {
	// Тут могут возникнуть ошибки 2 видов
	либо KeyExistError либо обычная 
}


В сервисе SMSSender, методе SendWithTTL, могут возникнуть разные ошибки.
Если это ошибка KeyExistError, контроллер HandlerV1 должен вернуть ошибку на фронт со статус кодом 400.
Иначе ошибку Internal Server Error со статус кодом 500.

Как правильно организовать обработку ошибок?
  • Вопрос задан
  • 108 просмотров
Решения вопроса 1
Для таких случаев в пакете errors есть методы Is и As

Is проверяет, что указанная ошибка соответствует возвращенной (включая возможность вложенности ошибок)

As может заполнять структуру ошибки при соответствии типа (тоже включая возможную вложенность)

https://go.dev/play/p/3j9O079sj97

Развернуть код
package main

import (
	"errors"
	"fmt"
)

func main() {
	err := someFunc()
	{
		keyExistsErr := &KeyExistError{}
		if errors.As(err, keyExistsErr) {
			fmt.Println("Мы получили ttl:", keyExistsErr.ttl)
		}
	}
}

type KeyExistError struct {
	ttl string
}

func (e KeyExistError) Error() string {
	return fmt.Sprint("Отправить код нельзя раньше чем через ", e.ttl, " сек.")
}

func someFunc() error {
	return KeyExistError{
		ttl: "4",
	}
}


Причем, оно будет работать даже если обернуть ошибку через %w или через errors.Wrap, итд...
https://go.dev/play/p/x2b_AZKI43t

Развернуть код

package main

import (
	"errors"
	"fmt"
)

func main() {
	err := someFunc()
	{
		keyExistsErr := &KeyExistError{}
		if errors.As(err, keyExistsErr) {
			fmt.Println("Мы получили ttl:", keyExistsErr.ttl)
		}
	}
}

type KeyExistError struct {
	ttl string
}

func (e KeyExistError) Error() string {
	return fmt.Sprint("Отправить код нельзя раньше чем через ", e.ttl, " сек.")
}

func someFunc() error {
	err := someOtherFunc()
	if err != nil {
		return fmt.Errorf("error calling someOtherFunc: %w", err)
	}
	return nil
}

func someOtherFunc() error {
	return KeyExistError{
		ttl: "4",
	}
}

Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы