I am coming from the world of Node.js where I learn a lot from building web application using Express and there, there is a good way, I think, to handle when dealing with error and in case of unexpected error, there is a awesome way to catch it.
So, I looked for the same thing in Go. I don't know if I have already found it, but what I found come from this link https://astaxie.gitbooks.io/build-web-application-with-golang/content/en/11.1.html and from some articles I read, it seems like many developers are using the same approach.
My concern, and not a real one, is that I don't understand some part of that code below.
type appHandler func(http.ResponseWriter, *http.Request) error
func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if err := fn(w, r); err != nil {
http.Error(w, err.Error(), 500)
}
}
I know that it's possible to create custom type in go, but seriously I don't understand what this one means or how to understand it in the http.Serve
type appHandler func(http.ResponseWriter, *http.Request) error
and one of the thing that I don't catch is
func (fn AppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
In most of the code I read, generally, it's a struct or a replaced type (I mean type Account int
) but here, it's a function.
I would like to understand how is it going to help in handling errors.
Inside the implementation of the ServeHTTP
up there, we have this line err := fn(w, r)
.
Please, can you explain it?
From the same article, we have this code
func viewRecord(w http.ResponseWriter, r *http.Request) error {
c := appengine.NewContext(r)
key := datastore.NewKey(c, "Record", r.FormValue("id"), 0, nil)
record := new(Record)
if err := datastore.Get(c, key, record); err != nil {
return err
}
return viewTemplate.Execute(w, record)
}
and this line
func init() {
http.Handle("/view", appHandler(viewRecord))
}
Please, could you help me to understand this appHandler(viewRecord)
? What is it exactly? It is an instantiation, is it casting?
What is it supposed to do? I mean, how to understand that line that seems critical?
One last question, please. Is it possible to catch an error that might happen anywhere during the treatment of a request? In Node.js, you can just do something like
const app = express()
const errorHandler = (
err: Error,
req: Request,
res: Response,
next: NextFunction
) => {
if (err instanceof CustomError) {
return res.status(err.statusCode).send({ errors: err.serializeErrors() });
}
res.status(500).send({
errors: [{ message: err.message || 'Something went wrong' }]
});
}
app.use(errorHandler())
Something like that, is it possible in Go?
Thank you.
In Go, we can define custom types from any primitive types, example:
This is common for functions al well. You can define a Go type with desired function signature like in
appHandler
type in above example. I have added simple example below.and also refer user-defined-function-type-go
In your case,
This is the http endpoint handling part.
"/view"
is the path pattern and other argument is the handler for the request. That parameter should implement Handler interface innet/http
Go package. So that's why app handler type haveServeHttp
function.viewRecord
function is also compatible with typeappHandler
function type. it handle the request coming to "/view" endpoint. So it is casted toappHandler
type and passed tohttp.Handle("/view", appHandler(viewRecord))
Handle function.I think this will explain the scenario. Please comment if anything not clear.