gen-errfuncs
A trivial tool to generate utility functions for a set of errors.
Install
go install github.com/ArnaudCalmettes/gen-errfuncs@v0.1.0
Use
It is pretty common to define precise error values in the core of an application.
Usually, such errors are a first class citizen in the business code, they convey meaning and
we even want to enforce that the right errors are returned when expected in our tests.
That said, I have often found myself writing errors.go
files that look like this:
package core
import "errors"
var (
ErrConfigNotFound = errors.New("config not found")
ErrUserAlreadyExists = errors.New("user already exists")
ErrInvalidUserName = errors.New("invalid user name")
)
For each of these errors, I like to create pairs of utility functions like this:
func ConfigNotFound(err error) error {
return errors.Join(ErrConfigNotFound, err)
}
func ConfigNotFoundf(msg string, args ...any) error {
return fmt.Errorf("%w: %s", ErrConfigNotFound, fmt.Sprintf(msg, args...))
}
That way, the business code can be made clearer using explicit error constructors,
provided that the client code will test our errors like this:
if errors.Is(err, ErrConfigNotFound) {
// handle err
}
That being said, those functions are nice to use, but at the cost of writing some
trivial boilerplate for every single error value.
This tool generates such functions. You can use it in the CLI:
$ gen-errfuncs core/errors.go
Or by putting the following comment in your "errors.go" file to work with go generate
:
//go:generate gen-errfuncs $GOFILE
This generates a file named zzz_errfuncs.go
in the same package as errors.go
:
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
// This file was generated by gen-errfuncs. DO NOT EDIT.
package core
import (
"errors"
"fmt"
)
func UserAlreadyExists(err error) error {
return errors.Join(ErrUserAlreadyExists, err)
}
func UserAlreadyExistsf(msg string, args ...any) error {
return fmt.Errorf("%w: %s", ErrUserAlreadyExists, fmt.Sprintf(msg, args...))
}
func InvalidUserName(err error) error {
return errors.Join(ErrInvalidUserName, err)
}
func InvalidUserNamef(msg string, args ...any) error {
return fmt.Errorf("%w: %s", ErrInvalidUserName, fmt.Sprintf(msg, args...))
}
func ConfigNotFound(err error) error {
return errors.Join(ErrConfigNotFound, err)
}
func ConfigNotFoundf(msg string, args ...any) error {
return fmt.Errorf("%w: %s", ErrConfigNotFound, fmt.Sprintf(msg, args...))
}
That's about all it does, and that's all I need.