0

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.

0

1 Answer 1

1

In Go, we can define custom types from any primitive types, example:

type A int
type Person struct{}

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.

package main

import (
    "errors"
    "fmt"
)

type IntFun func(a,b int) error
func main(){
    var addFunc IntFun
    addFunc = func(a, b int) error {
        if a ==0 || b == 0 {
            return errors.New(`zero valued inputs`)
        }
        fmt.Println(`sum := `, a+b)
        return nil
    }

    addFunc.Add(5, 3) //Output: sum :=  8
    addFunc.Add(0, 0) //Output: zero valued inputs
}

func (fn IntFun) Add(a, b int)  {
    err := fn(a,b)
    if err != nil {
        fmt.Println(err)
        return
    }
}

and also refer user-defined-function-type-go

In your case,

func init() {
    http.Handle("/view", appHandler(viewRecord))
}

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 in net/http Go package. So that's why app handler type have ServeHttp function.

viewRecord function is also compatible with type appHandler function type. it handle the request coming to "/view" endpoint. So it is casted to appHandler type and passed to http.Handle("/view", appHandler(viewRecord)) Handle function.

I think this will explain the scenario. Please comment if anything not clear.

Sign up to request clarification or add additional context in comments.

2 Comments

The name of the language is Go, not golang.
Sorry @Volker. I have corrected it. Appreciate your comment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.