I am running into a common pattern where I have a function that takes user input, and either returns a successful output value or an error. But it can return different types of errors, some of which are the result of bad user input and others which are the result of internal errors (DB unavailable, for instance).
My functions have signatures that look like this:
// ProcessInput takes a user-input string and returns a processed value
func ProcessInput(input string) (ProcessedValue, error, error) {}
The first return value is meaningful (not nil) if no errors were encountered, the second return value is an error if the user input failed validation, and the third return value is an error if an unexpected internal error occurred.
This works fine but it does not feel very clean, and it's not obvious from looking at the signature what the different errors are. I considered naming the error returns but I don't like the side-effects of naming return parameters.
Are there any other patterns I could apply that are cleaner? Should I have a single error return and distinguish by type on the caller side?
The most common way to handle errors is to return the error type as the last return value of a function call and check for the nil condition using an if statement.
Errors can be returned as nil , and in fact, it's the default, or “zero”, value of on error in Go. This is important since checking if err != nil is the idiomatic way to determine if an error was encountered (replacing the try / catch statements you may be familiar with in other programming languages).
Basic Logging in Golang package main import "log" func main() { log. Println("We are logging in Golang!") } When the above code is executed, the log package prints the output to the standard error (stderr) stream and automatically appends a timestamp to each log message.
Go does not have exceptions like many other programming languages, including Java and Javascript but has a comparable mechanism know as ,,Defer, panic and recover".
Returning multiple error
does not seem very Go-like to me.
Why not have an interface called UserError
that defines a method that returns a message suitable to show the user. If the returned error does not implement UserError
, show a standard "Internal Server Error" message. Example:
type UserError interface {
error
UserError() string
}
type emptyInput struct {}
func (e emptyInput) Error() string {
return e.UserError()
}
func (emptyInput) UserError() string {
return "Empty input"
}
func ProcessInput(input string) (*ProcessedValue, error) {
if input == "" {
return nil, &emptyInput{}
}
}
func httpHandler() {
val, err := ProcessInput(input)
if err != nil {
if userErr := err.(UserError); userErr != nil {
// show userError.UserError() to user
} else {
// Log error
// show Internal server error message
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With