0
\$\begingroup\$

I have a function which returns an error. I would like to handle this error on the caller function, so I need to know the reason of the error in the caller function.

Below there is my solution, but I am not sure, that it is ideomatic Go code and would be thankfull for any comments.

Here is the function:

func (e *Engine) returnOrCreateArtist(musicService musicservices.IMusicService, serviceArtistId string) (*core.Artist, error) {

    artist, err := e.DataRepository.ArtistRepository.GetByArtistId(serviceArtistId)
    if err != nil {
        artist, err = musicService.DownloadArtist(serviceArtistId)
        if err != nil {
            return nil, NewDownloadArtistError(err)
        }

        artist, err = e.DataRepository.ArtistRepository.Store(artist)
        if err != nil {
            return nil, NewStoreArtistError(err)
        }
    }

    return artist, nil
}

It can returns errors of two types, so I have created two structs to distinct two types of my error:

type DownloadArtistError struct {
    InnerError error
}

func (e *DownloadArtistError) Error() string {
    return e.InnerError.Error()
}

func NewDownloadArtistError(e error) *DownloadArtistError {
    return &DownloadArtistError{InnerError: e}
}

type StoreArtistError struct {
    InnerError error
}

func (e *StoreArtistError) Error() string {
    return e.InnerError.Error()
}

func NewStoreArtistError(e error) *StoreArtistError {
    return &StoreArtistError{InnerError: e}
}

And here is a part of caller function:

artist, err := e.returnOrCreateArtist(musicService, track.ServiceArtistId)
if err != nil {
     switch e := err.(type) {
         case *DownloadArtistError:
            logger.With(zap.Error(e)).Errorw("не удалось получить исполнителя на музыкальном сервисе",
                "Track.ServiceId", track.TrackId,
                "Track.PlaylistId", track.PlaylistId,
                "Track.ArtistId", track.ServiceArtistId)
         case *StoreArtistError:
            logger.With(zap.Error(err)).Errorw("не удалось сохранить исполнителя",
                "Track.ServiceId", track.TrackId,
                "Track.PlaylistId", track.PlaylistId,
                "Track.ArtistId", track.ServiceArtistId)
            }
        continue
    }
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Basically fine. Minor things: There is no real need to have Error operate on pointer receivers, values would lead to less typing. InnerError is an uncommon name, Err or Cause might be alternatives to consider. \$\endgroup\$
    – Volker
    Sep 24, 2019 at 7:39
  • \$\begingroup\$ Instead of different type and type-switching you could do a type ArtistError struct {Err error; Kind int} where the different kinds of errors are distinguished by the Kind field (some enum, or a string, you choose). \$\endgroup\$
    – Volker
    Sep 24, 2019 at 7:41
  • 1
    \$\begingroup\$ I'm not a big fan of the New... functions as they do nothing you could not do with a literal. I would get rid of them and write return nil, StoreArtisError{err} or (see previous comment) return nil, ArtistError{Err: err, Kind: DownloadError} \$\endgroup\$
    – Volker
    Sep 24, 2019 at 7:48

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.