Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang idiomatic error handling

Tags:

go

I have created a "base" repository struct for standalone and embedded use (e.g with CustomerRepository) to avoid having to check errors all the time, and to create an abstraction for Gorp (the database toolkit), and to create an API slightly more to my liking.

I check for errors in this base struct and panic if one is found, as if one does exist in my opinion it then indicates a dev error and the code may as well panic, seeing as validation etc. should happen before data gets to the Repository.

I found this question Go Error Handling Techniques, but it doesn't cover wrapping errors up in a base struct like I have done and just panicking.

Is what I have done idiomatic Go?

package repositories

import (
    "github.com/coopernurse/gorp"
)

type Repository struct {
    Gorp gorp.SqlExecutor
}

func (r *Repository) GetById(i interface{}, id int) interface{} {
    obj, err := r.Gorp.Get(i, id)
    if err != nil {
        panic(err)
    }
    return obj
}

func (r *Repository) Get(holder interface{}, query string, args ...interface{}) interface{} {
    if err := Gorp.SelectOne(holder, query, args); err != nil {
        panic(err)
    }
}

func (r *Repository) Select(i interface{}, query string, args ...interface{}) {
    if _, err := Gorp.Select(holder, query, args); err != nil {
        panic(err)
    }
}

func (r *Repository) Insert(list ...interface{}) {
    if err := r.Gorp.Insert(list...); err != nil {
        panic(err)
    }
}

func (r *Repository) Update(list ...interface{}) int64 {
    count, err := r.Gorp.Update(list...)
    if err != nil {
        panic(err)
    }
    return count
}

func (r *Repository) Delete(list ...interface{}) int64 {
    count, err := r.Gorp.Delete(list...)
    if err != nil {
        panic(err)
    }
    return count
}
like image 470
Lee Avatar asked Jan 21 '14 17:01

Lee


People also ask

What is err != Nil in Golang?

if err != nil { return err } > is outweighed by the value of deliberately handling each failure condition at the point at which they occur. Key to this is the cultural value of handling each and every error explicitly.

Why is there no error handling?

Go's built-in errors don't contain stack traces, nor do they support conventional try / catch methods to handle them. Instead, errors in Go are just values returned by functions, and they can be treated in much the same way as any other datatype - leading to a surprisingly lightweight and simple design.

What is Golang error type?

error is a built-in interface type in Go. An error variable represents any value that can describe itself as a string . The following is the error interface declaration: type error interface { Error() string.


2 Answers

Don't panic, this isn't the Go way. Instead, do something like this --

func (r *Repository) GetById(i interface{}, id int) (interface{}, error) {
    obj, err := r.Gorp.Get(i, id)
    if err != nil {
        return nil, err
    }
    return obj, nil
}

Then just handle the error in your caller. I see from your comments above that you are using these functions inside a Martini handler, so you would do something like this --

func MyHandler(parameters) (int, string) {
    obj, err := repository.GetById(something, id)
    if err == repository.ErrNotFound {
        return http.StatusNotFound, fmt.Sprintf("could not find by id: %d", id)
    }
    if err != nil {
        return http.StatusInternalError, err.Error()
    }
    return http.StatusOk, fmt.Printf("obj: %v", obj)
}

This is more like the Go way. Make sure that r.Gorp.Get does return specific errors that you declare inside your package.

var ErrNotFound = errors.New("not found")

Create as many as make sense to your code.

like image 143
adriaan.wiers Avatar answered Oct 18 '22 00:10

adriaan.wiers


The idiomatic way would be to return the error with the associated type value, i.e.

func (list ...interface{}) (v int46, err error) {}

... and subsequently check err != nil where these functions are called.

Ultimately using panic() will result in Exception-like error handling and more boiler-plate code (if you deem the error to be recoverable).

Idiomatic error handling is verbose in Go, but less so than emulating exceptions (which is fundamentally not the "Go way").

like image 28
Martin Gallagher Avatar answered Oct 18 '22 01:10

Martin Gallagher