diff --git a/07-behaviour_error_handling/internal/beer.go b/07-behaviour_error_handling/internal/beer.go index 4ed7c21..90b4da0 100644 --- a/07-behaviour_error_handling/internal/beer.go +++ b/07-behaviour_error_handling/internal/beer.go @@ -2,6 +2,8 @@ package beerscli import ( "encoding/json" + + "github.com/CodelyTV/golang-examples/07-behaviour_error_handling/internal/errors" ) // Beer representation of beer into data struct @@ -65,9 +67,11 @@ var toID = map[string]BeerType{ func (t *BeerType) UnmarshalJSON(b []byte) error { var j string err := json.Unmarshal(b, &j) + if err != nil { - return err + return errors.WrapConversionError(err, "Could not convert retrieved bytes to JSON") } + *t = toID[j] return nil } diff --git a/07-behaviour_error_handling/internal/cli/beers.go b/07-behaviour_error_handling/internal/cli/beers.go index 8f8e666..a3f7987 100644 --- a/07-behaviour_error_handling/internal/cli/beers.go +++ b/07-behaviour_error_handling/internal/cli/beers.go @@ -36,10 +36,20 @@ func runBeersFn(repository beerscli.BeerRepo) CobraFn { log.Fatal(err) } + if errors.IsFileHandlingError(err) { + log.Fatal(err) + } + id, _ := cmd.Flags().GetString(idFlag) if id != "" { - i, _ := strconv.Atoi(id) + var i int + i, err = strconv.Atoi(id) + + if errors.IsConversionError(err) { + log.Fatal(err) + } + for _, beer := range beers { if beer.ProductID == i { fmt.Println(beer) diff --git a/07-behaviour_error_handling/internal/errors/conversionerror.go b/07-behaviour_error_handling/internal/errors/conversionerror.go new file mode 100644 index 0000000..d48b822 --- /dev/null +++ b/07-behaviour_error_handling/internal/errors/conversionerror.go @@ -0,0 +1,28 @@ +package errors + +import ( + "github.com/pkg/errors" +) + +type conversionError struct { + error +} + +// WrapConversionError returns an error which wraps err that satisfies +// IsConversionError() +func WrapConversionError(err error, format string, args ...interface{}) error { + return &conversionError{errors.Wrapf(err, format, args...)} +} + +// NewConversionError returns an error which satisfies IsConversionError() +func NewConversionError(format string, args ...interface{}) error { + return &conversionError{errors.Errorf(format, args...)} +} + +// IsConversionError reports whether err was created with ConversionError() or +// NewConversionError() +func IsConversionError(err error) bool { + err = errors.Cause(err) + _, ok := err.(*conversionError) + return ok +} diff --git a/07-behaviour_error_handling/internal/errors/filehandlingerror.go b/07-behaviour_error_handling/internal/errors/filehandlingerror.go new file mode 100644 index 0000000..fec5e77 --- /dev/null +++ b/07-behaviour_error_handling/internal/errors/filehandlingerror.go @@ -0,0 +1,28 @@ +package errors + +import ( + "github.com/pkg/errors" +) + +type fileHandlingError struct { + error +} + +// WrapFileHandlingError returns an error which wraps err that satisfies +// IsFileHandlingError() +func WrapFileHandlingError(err error, format string, args ...interface{}) error { + return &fileHandlingError{errors.Wrapf(err, format, args...)} +} + +// NewFileHandlingError returns an error which satisfies IsFileHandlingError() +func NewFileHandlingError(format string, args ...interface{}) error { + return &fileHandlingError{errors.Errorf(format, args...)} +} + +// IsFileHandlingError reports whether err was created with FileHandlingError() or +// NewFileHandlingError() +func IsFileHandlingError(err error) bool { + err = errors.Cause(err) + _, ok := err.(*fileHandlingError) + return ok +} diff --git a/07-behaviour_error_handling/internal/errors/errortypes.go b/07-behaviour_error_handling/internal/errors/httperror.go similarity index 100% rename from 07-behaviour_error_handling/internal/errors/errortypes.go rename to 07-behaviour_error_handling/internal/errors/httperror.go diff --git a/07-behaviour_error_handling/internal/storage/csv/repository.go b/07-behaviour_error_handling/internal/storage/csv/repository.go index cb1e7cc..1072077 100644 --- a/07-behaviour_error_handling/internal/storage/csv/repository.go +++ b/07-behaviour_error_handling/internal/storage/csv/repository.go @@ -7,6 +7,7 @@ import ( "strings" beerscli "github.com/CodelyTV/golang-examples/07-behaviour_error_handling/internal" + "github.com/CodelyTV/golang-examples/07-behaviour_error_handling/internal/errors" ) type repository struct { @@ -19,15 +20,31 @@ func NewRepository() beerscli.BeerRepo { // GetBeers fetch beers data from csv func (r *repository) GetBeers() ([]beerscli.Beer, error) { - f, _ := os.Open("07-behaviour_error_handling/data/beers.csv") + const filePath = "07-behaviour_error_handling/data/beers.csv" + f, err := os.Open(filePath) + + if err != nil { + return nil, errors.WrapFileHandlingError(err, "error opening file %s", filePath) + } + reader := bufio.NewReader(f) var beers []beerscli.Beer - for line := readLine(reader); line != nil; line = readLine(reader) { + var line []byte + + for line, err = readLine(reader); line != nil; line, err = readLine(reader) { + if err != nil { + return nil, err + } values := strings.Split(string(line), ",") - productID, _ := strconv.Atoi(values[0]) + var productID int + productID, err = strconv.Atoi(values[0]) + + if err != nil { + return nil, errors.WrapConversionError(err, "error while converting 'productId' from ascii to integer: %s", values[0]) + } beer := beerscli.NewBeer( productID, @@ -45,7 +62,11 @@ func (r *repository) GetBeers() ([]beerscli.Beer, error) { return beers, nil } -func readLine(reader *bufio.Reader) (line []byte) { - line, _, _ = reader.ReadLine() +func readLine(reader *bufio.Reader) (line []byte, err error) { + line, _, err = reader.ReadLine() + + if err != nil { + return nil, errors.WrapFileHandlingError(err, "could not read next line of buffer") + } return }