{"action":"created","issue":{"url":"https://api.github.com/repos/gin-gonic/gin/issues/274","labels_url":"https://api.github.com/repos/gin-gonic/gin/issues/274/labels{/name}","comments_url":"https://api.github.com/repos/gin-gonic/gin/issues/274/comments","events_url":"https://api.github.com/repos/gin-gonic/gin/issues/274/events","html_url":"https://github.com/gin-gonic/gin/issues/274","id":72010033,"number":274,"title":"Question: Handling errors","user":{"login":"elliotlings","id":1894100,"avatar_url":"https://avatars.githubusercontent.com/u/1894100?v=3","gravatar_id":"","url":"https://api.github.com/users/elliotlings","html_url":"https://github.com/elliotlings","followers_url":"https://api.github.com/users/elliotlings/followers","following_url":"https://api.github.com/users/elliotlings/following{/other_user}","gists_url":"https://api.github.com/users/elliotlings/gists{/gist_id}","starred_url":"https://api.github.com/users/elliotlings/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elliotlings/subscriptions","organizations_url":"https://api.github.com/users/elliotlings/orgs","repos_url":"https://api.github.com/users/elliotlings/repos","events_url":"https://api.github.com/users/elliotlings/events{/privacy}","received_events_url":"https://api.github.com/users/elliotlings/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/gin-gonic/gin/labels/question","name":"question","color":"cc317c"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":13,"created_at":"2015-04-29T22:45:19Z","updated_at":"2015-05-07T19:22:26Z","closed_at":null,"body":"I'm in the process of writing a REST API which returns JSON. I've found my route handlers can get quite cluttered with error handling. I've been looking at ways I can reduce and simply error handling and would appreciate anyone's opinions or advice on what I've come up with.\r\n\r\nI'm following the JSON API standard for error returning, http://jsonapi.org/format/#errors, they contain a bit more than the standard Error in Go, so when I initiate an error it can get quite big.\r\n\r\nI have created an APIError struct, some helper functions and some default errors:\r\n\r\n```go\r\ntype APIErrors struct {\r\n    Errors      []*APIError `json:\"errors\"`\r\n}\r\n\r\nfunc (errors *APIErrors) Status() int {\r\n    return errors.Errors[0].Status\r\n}\r\n\r\ntype APIError struct {\r\n    Status      int         `json:\"status\"`\r\n    Code        string      `json:\"code\"`\r\n    Title       string      `json:\"title\"`\r\n    Details     string      `json:\"details\"`\r\n    Href        string      `json:\"href\"`\r\n}\r\n\r\nfunc newAPIError(status int, code string, title string, details string, href string) *APIError {\r\n    return &APIError{\r\n        Status:     status,\r\n        Code:       code,\r\n        Title:      title,\r\n        Details:    details,\r\n        Href:       href,\r\n    }\r\n}\r\n\r\nvar (\r\n    errDatabase         = newAPIError(500, \"database_error\", \"Database Error\", \"An unknown error occurred.\", \"\")\r\n    errInvalidSet       = newAPIError(404, \"invalid_set\", \"Invalid Set\", \"The set you requested does not exist.\", \"\")\r\n    errInvalidGroup     = newAPIError(404, \"invalid_group\", \"Invalid Group\", \"The group you requested does not exist.\", \"\")\r\n)\r\n```\r\n\r\nAll of my other funcs in my app return their err but when it get backs to my handler I need to handle how I return it to the client. As far as I'm aware I can't return to middleware so I've added my own Recovery middleware which handles APIError that I panic from my handlers, i.e.\r\n\r\n```go\r\nfunc Recovery() gin.HandlerFunc {\r\n    return func(c *gin.Context) {\r\n        defer func() {\r\n            if err := recover(); err != nil {\r\n                switch err.(type) {\r\n                    case *APIError:\r\n                        apiError := err.(*APIError)\r\n                        apiErrors := &APIErrors{\r\n                            Errors: []*APIError{apiError},\r\n                        }\r\n                        c.JSON(apiError.Status, apiErrors)\r\n                    case *APIErrors:\r\n                        apiErrors := err.(*APIErrors)\r\n                        c.JSON(apiErrors.Status(), apiErrors)\r\n                }\r\n                panic(err)\r\n            }\r\n        }()\r\n\r\n        c.Next()\r\n    }\r\n}\r\n```\r\n\r\nThen in my handler I can do something like this:\r\n\r\n```go\r\n    // Grab the set from storage\r\n    set, err := storage.GetSet(set_uuid)\r\n\r\n    if (err == database.RecordNotFound) {\r\n        panic(errInvalidSet)\r\n    } else {\r\n        panic(errDatabase)\r\n    }\r\n```\r\n\r\nwhich, in my opinion, keeps things really tidy and reduces repetition. I've seen that people recommend you try to use panic as little as possible, but I'm not sure if it works well in this situation? I wonder what people think of this, whether it's a good way to go about it and, if my method isn't great, whether there's any recommended alternatives?"},"comment":{"url":"https://api.github.com/repos/gin-gonic/gin/issues/comments/99987911","html_url":"https://github.com/gin-gonic/gin/issues/274#issuecomment-99987911","issue_url":"https://api.github.com/repos/gin-gonic/gin/issues/274","id":99987911,"user":{"login":"nazwa","id":4353913,"avatar_url":"https://avatars.githubusercontent.com/u/4353913?v=3","gravatar_id":"","url":"https://api.github.com/users/nazwa","html_url":"https://github.com/nazwa","followers_url":"https://api.github.com/users/nazwa/followers","following_url":"https://api.github.com/users/nazwa/following{/other_user}","gists_url":"https://api.github.com/users/nazwa/gists{/gist_id}","starred_url":"https://api.github.com/users/nazwa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nazwa/subscriptions","organizations_url":"https://api.github.com/users/nazwa/orgs","repos_url":"https://api.github.com/users/nazwa/repos","events_url":"https://api.github.com/users/nazwa/events{/privacy}","received_events_url":"https://api.github.com/users/nazwa/received_events","type":"User","site_admin":false},"created_at":"2015-05-07T19:22:26Z","updated_at":"2015-05-07T19:22:26Z","body":"It's definitely a step in the right direction. It's a shame go doesn't allow 'return void' style calls, so even with the above, we are back to square one with 3 lines of code for every error in a handler :D (error + fail + return)\r\n"}}