Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I cleanly separate user-facing errors from internal errors in Golang?

Tags:

go

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?

like image 771
william Avatar asked Jul 13 '16 21:07

william


People also ask

How do you handle errors in Golang?

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.

Which of the following is considered good practices when handling errors in Golang?

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).

How should you log an error in Golang?

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.

Does Golang have exception handling?

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".


1 Answers

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
        }
    }
}
like image 160
Tim Cooper Avatar answered Sep 29 '22 15:09

Tim Cooper