This is the library that defines errors and error handlers for Golang API application
- Step 1:
$ export GOPRIVATE=github.com/anhvietnguyennva/go-error
- Step 2: Add file
tools/tools.go
with content:
package tools
import (
_ "github.com/anhvietnguyennva/go-error/tools"
)
- Step 3:
$ go mod tidy
$ go mod vendor
$ go get -u github.com/anhvietnguyennva/go-error
$ go mod vendor
These errors should be used in the infra layer (repository) of your service.
These errors should be used in the domain layer of your service.
These errors should be used in the application interface of your service.
package main
import (
"fmt"
"github.com/anhvietnguyennva/go-error/pkg/errors"
t "github.com/anhvietnguyennva/go-error/pkg/transformer"
)
func main() {
domainErr := errors.NewDomainErrorNotFound(nil)
transformer := t.RestTransformerInstance()
apiErr := transformer.DomainErrToRestAPIErr(domainErr)
fmt.Println(apiErr.Error())
}
- NOTE
- Transforming
InfraError
toDomainError
is done in a similar way. - Transform errors flow:
InfraError
(if exists) =>DomainError
=>ClientError (RestAPIError, RPCError)
- Transforming
- There are functions can be used to create customized errors. With
DomainError
, it'serrors.NewDomainError(code string, message string, entities []string, rootCause error)
and it'serrors.NewRestAPIError(httpStatus int, code int, message string, entities []string, rootCause error)
withRestAPIError
. - You can use these above functions to create your customized errors directly. But you should define new constructors for your custom errors, so it can be reused. For example:
package main
import (
"net/http"
"github.com/anhvietnguyennva/go-error/pkg/errors"
)
const (
DomainErrCodeCustomized = "DOMAIN:CUSTOMIZED"
DomainErrMsgCustomized = "Customized domain error"
ClientErrCodeCustomized = 40099
ClientErrMsgCustomized = "Customized client error"
)
func NewDomainErrCustomized(rootCause error, entities ...string) *errors.DomainError {
return errors.NewDomainError(DomainErrCodeCustomized, DomainErrMsgCustomized, entities, rootCause)
}
func NewRestAPIErrCustomized(rootCause error, entities ...string) *errors.RestAPIError {
message := errors.AppendEntitiesToErrMsg(ClientErrMsgCustomized, entities)
return errors.NewRestAPIError(http.StatusBadRequest, ClientErrCodeCustomized, message, entities, rootCause)
}
- After defining your custom errors, you have to register the function used to transform your custom
DomainError
to your customRestAPIError
. For example:
package main
import (
"net/http"
"github.com/anhvietnguyennva/go-error/pkg/errors"
"github.com/anhvietnguyennva/go-error/pkg/transformer"
)
const (
DomainErrCodeCustomized = "DOMAIN:CUSTOMIZED"
DomainErrMsgCustomized = "Customized domain error"
ClientErrCodeCustomized = 40099
ClientErrMsgCustomized = "Customized client error"
)
func NewDomainErrCustomized(rootCause error, entities ...string) *errors.DomainError {
return errors.NewDomainError(DomainErrCodeCustomized, DomainErrMsgCustomized, entities, rootCause)
}
func NewRestAPIErrCustomized(rootCause error, entities ...string) *errors.RestAPIError {
message := errors.AppendEntitiesToErrMsg(ClientErrMsgCustomized, entities)
return errors.NewRestAPIError(http.StatusBadRequest, ClientErrCodeCustomized, message, entities, rootCause)
}
func main() {
t := transformer.RestTransformerInstance()
t.RegisterTransformFunc(DomainErrCodeCustomized, NewRestAPIErrCustomized)
}
- NOTE:
- Each error should have a unique error code. Otherwise, it can lead to unexpected results when transforming. So You should not define your custom error code as one of the predefined error codes in "go-error".
- The
ClientErrorCode
should contain information about HTTP Status. It makes the error code more meaningful - Registering new
InfraError
is done in a similar way
- This lib provides the function
ValidationErrToRestAPIErr(err error)
which can be used when binding and validating the request.