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
}
InnerError
is an uncommon name,Err
orCause
might be alternatives to consider. \$\endgroup\$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\$New... functions
as they do nothing you could not do with a literal. I would get rid of them and writereturn nil, StoreArtisError{err}
or (see previous comment)return nil, ArtistError{Err: err, Kind: DownloadError}
\$\endgroup\$