Return error from deferred function when error is already returned - go

Update: I think now that there is no universal answer to this question. We can return both errors using the technique explained in the answer. I think that the most important thing here is not to forget the case when we have two errors and somehow handle it.
Notes: There are many questions on SO about how to return an error from deferred function. This is not a question here.
(In Go) What is the proper way to return an error from a deferred function when the function is already returning an error. For example
func errorMaker() (err error) {
defer func() {
err = errors.New("Deferred error")
}()
err = errors.New("Some error")
return
}
func main() {
err := errorMaker()
fmt.Printf("Error: %v\n", err)
}
In the code above the error returned by the deferred function overwrites the error returned by the function. What is the canonical way to return both errors? If another programmer uses my function what result might she expect from the function when the function returns 'two errors'?
Should I use Error wrapping for this?
Additional notes:
As #Volker says in his comment I write some application specific handling for this error. Because I know what should be done based on nature of the errors.
I think my question is - if I want to return all errors from the function what is the best way to combine them in my scenario?

Disclaimer: I don't know if the following advice can be seen as "standard" or "widely-accepted".
Should I use Error wrapping for this?
Short answer: yes (I would do so).
Go 1.12 and earlier
What I do when I need my errors to convey some specific meaning, without foregoing the error interface, I create a wrapper that implements the error interface - Error() string -. This wrapper contains all extra information I need.
If the caller is aware of the existence of those extra info, it can unwrap the error with a cast and find those info.
With the added benefit that unaware callers can just handle the error as a generic error.
type MyError struct {
DeferredError error
}
// Implements 'error' interface
func (e MyError) Error() string {
// format to string
}
func someFunc() error {
// might return an instance of MyError
}
...
// Caller code
err := someFunc()
if err != nil {
if myErr, ok := err.(*MyError); ok {
// here you can access the wrapped info
fmt.Println(myErr.DeferredError)
} else {
// otherwise handle the error generically
}
}
Go 1.13 onwards
With Go.13 you can use errors.As to unwrap an error. From the official docs:
[The method] As finds the first error in err's chain that matches target, and if so, sets target to that error value and returns true. The chain consists of err itself followed by the sequence of errors obtained by repeatedly calling Unwrap.
var myErr *MyError
if errors.As(err, &myErr) {
// here you can access the wrapped info
fmt.Println(myErr.DeferredError)
} else {
// otherwise handle the error generically
}
As the docs say the myErr variable is populated as a side-effect of calling As.

Related

How to pass objects around middleware(s) and handler in go echo?

I am using echo to build a web server in go. What is the best way to pass objects around middlewares and a handler apart from using context.Set method?
For example, let's consider the following case:
func mw(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Conext) error {
var value TypeX = // load value of type TypeX based on query parameters
c.Set("key", value)
return next(c)
}
}
func h1(c echo.context) error {
value := c.Get("key").(TypeX)
return c.JSON(http.StatusOk, value.H1())
}
func h2(c echo.context) error {
value := c.Get("key").(TypeX)
return c.JSON(http.StatusOk, value.H2())
}
func registerRoute(e *echo.Echo) {
e.Get("/test", h)
}
Is there any way to get rid of get/set methods? It seems like an unclean way of doing this operation. I am open to complete refactoring, creating new structures/interfaces to make this happen.
To take this example further, lets say my apis can fall into bucket1, bucket2, bucket3. Value would call the method b1, b2, b3 based on which bucked it falls in. These buckets can be identified by adding them as middleware mwB1, mwB2, mwB3 each of which calls the respective method. Hence, all my apis would first call the middleware mw; then one of mwB1, mwB2, mwB3 and finally the actual handler, something like, e.Get("/test", h, mw, mwB2). I don't want to load value everywhere and get/set seems unclean to me (unless that is the standard way of doing this).

Force error handling in Golang - or disallow ignoring return values

Say I have a func that returns an error:
func conditionalError() error {
if maybe {
return errors.New("here")
}
return nil
}
err := conditionalError()
but if we call it without handling the return value:
conditionalError()
is there a flag to get the compiler to complain, or maybe just an IDE setting in JetBrains or VSCode to warn about it?
There is an app for that! This type of functionality falls in the category of linters.
https://github.com/kisielk/errcheck

sensulib package interface as function param

I am trying to make use of this golang package: https://github.com/jefflaplante/sensulib
I want to get all the events from the sensu API. I've followed the example code and modified it slightly so it works:
config := sensu.DefaultConfig()
config.Address = "sensu-url:port"
onfig.Username = "admin"
config.Password = "password"
// Create a new API Client
sensuAPI, err := sensu.NewAPIClient(config)
if err != nil {
// do some stuff
}
Now I want to grab all the events from the API, and there's a neat function do to that, GetEvents
However, the function expects a parameter, out, which is an interface. Here's the function itself:
func (c *API) GetEvents(out interface{}) (*http.Response, error) {
resp, err := c.get(EventsURI, out)
return resp, err
}
What exactly is it expecting me to pass here? I guess the function wants to write the results to something, but I have no idea what I'm supposed to call the function with
I've read a bunch of stuff about interfaces, but it's not getting any clearer. Any help would be appreciated!
The empty interface interface{} is just a placeholder for anything. It's roughly the equivalent of object in Java or C# for instance. It means the library doesn't care about the type of the parameter you are going to pass. For hints about what the library does with that parameter, I suggest you look at the source code.

calling function from map[string]interface{} by giving key

I want to be able to pass function name to gin.Engine route handler. I have the following code;
// status service
type StatusService struct {
App *gin.Engine
}
func (s *StatusService) Ping(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "pong",
})
}
app := gin.Default()
// define services
statusService := &services.StatusService{
App: app,
}
ss := make(map[string]interface{})
ss["auth"] = statusService
app.GET("/ping", ss["auth"].Ping)
The compiler gives the following error;
./app.go:60: ss["auth"].Ping undefined (type interface {} has no field or method Ping)
Any ideas about how to fix that?
interface{} works for just about any type, the problem is that you've failed to assert which type the thing is. In this case you would need something like... ss["auth"].(*StatusService).Ping(myCtxInstance). This answer has a more thorough example which I'll refrain from duplicating; Go map of functions
Couple other things; if your real use case is as simple as your example just stop what you're doing and add func(ctx *gin.Context) as a second argument. Also, depending on the nature of the functions you want to use (like if they all have the same args and return types) then you might want to use a second arg for the delegates, map[string]func(argumentType) would be more appropriate.
The design you currently have pushes all errors to runtime which obviously is less desirable than the compile time safety you'd get from either of the options I touched on above.

Why embedded structs are not decoded when there is an Unmarshal implementation?

I have a type ServiceAccount which embeds two other types (User and Policy). However it seems the fields of the User type are totally ignored due the Unmarshaler implementation of the Policy type.
Is there any good reason for this behaviour? It looks like a bug to me because the json package can see through reflection that we have two types embedded and not only the type Policy.
I'm aware that I can "fix" the issue by implementing the Unmarshaler interface on type ServiceAccount too.
package main
import (
"encoding/json"
"fmt"
)
type ServiceAccount struct {
User
Policy
}
type User struct {
UserID string `json:"userID"`
}
type Policy struct {
Scopes string `json:"scopes,omitempty"`
}
// PolicyRaw is the Policy type as received from client.
type PolicyRaw struct {
Scopes string `json:"scopes,omitempty"`
}
func main() {
s := `{"userID":"xyz", "scopes":"some scopes"}`
srvAcc := &ServiceAccount{}
if err := json.Unmarshal([]byte(s), srvAcc); err != nil {
panic(err)
}
fmt.Printf("srvAcc %v", *srvAcc)
}
func (p *Policy) UnmarshalJSON(b []byte) error {
pr := new(PolicyRaw)
if err := json.Unmarshal(b, pr); err != nil {
return err
}
p.Scopes = pr.Scopes
return nil
}
Execute
I don't think it's a bug but just just how interfaces and embedding works. It just happens not to be what you want/expect here.
json.Unmarshal figures out to use the UnmarshalJSON method via this line:
if u, ok := v.Interface().(Unmarshaler); ok
As you know, something implements an interface if it has the right method set which *Policy and *ServiceAccount do. So it's expected that JSON decoding of the the outer type would just call the appropriate method and think it's done.
Interestingly, if you were to experiment and add a dummy method such as:
func (u *User) UnmarshalJSON([]byte) error {return errors.New("not impl")}
then although *User and *Policy would now both implement the interface,
*ServiceAccount will no longer implement that interface. The reason is clear if you try and explicitly call srvAcc.UnmarshalJSON which would then give a compiler error of "ambiguous selector srvAcc.UnmarshalJSON". Without such a call the code is legal and the method is just excluded from the method set.
So I think the solution is one of:
Just don't embed things that implement json.Unmarshaller if you want to marshal the result, e.g. use a named field instead.
Make sure you explicitly implement json.Unmarshaller for the outer type yourself when doing such embedding (e.g. add an UnmarshalJSON method to *ServiceAccount).
Make sure at least two embedded things implement json.Unmarshaller and then they'll work individually¹ but the "outer" type will get the default behaviour.
The last option seems like a hack to me. (And btw could be done on purpose with something like:
type ServiceAccount struct {
User
Policy
dummyMarshaller
}
type dummyMarshaller struct{}
func (dummyMarshaller) MarshalJSON([]byte) error {panic("ouch")}
but that looks really hacky to me).
See also:
https://golang.org/ref/spec#Struct_types
https://golang.org/doc/effective_go.html#embedding
¹ Further testing shows that decoding such anonymous (i.e. embedded fields), that their UnmarshalJSON methods do not get called.

Resources