blue panther
blue panther

Reputation: 253

HTTP handler function

I saw some http handler function declarations are varied. Two of them I found are the standard function and the one returning anonymous function inside the handler. For example:

Using standard way:

func helloworld(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello World")
}

This the most straight way to declare a handler for an http api.

Another way is using anonym/closure function inside the handler function:

func helloworld2() http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
        fmt.Fprintln(w, "Hello World")
    })
}

What are the differences and the benefit? When to use one of them? What's the best practice?

Upvotes: 5

Views: 10354

Answers (3)

Oleg
Oleg

Reputation: 742

One of the most popular source of information about structure returning anonymous functions is a blog post from Mat Ryer How I write HTTP services after eight years

I sure it will be good to provide some quotes from his article here:

... handler functions don’t actually handle the requests, they return a function that does. This gives us a closure environment in which our handler can operate:

func (s *server) handleSomething() http.HandlerFunc {
    thing := prepareThing()
    return func(w http.ResponseWriter, r *http.Request) {
        // use thing        
    }
}

The prepareThing is called only once, so you can use it to do one-time per-handler initialisation, and then use the thing in the handler.

Also,

If an endpoint has its own request and response types, usually they’re only useful for that particular handler. If that’s the case, you can define them inside the function.

func (s *server) handleSomething() http.HandlerFunc {

  // you have these handy structs always visible to your handler and eyes 
  // and invisible to code that don't use them

  type request struct {
    Name string
  }

  type response struct {
    Greeting string `json:"greeting"`
  }

  return func(w http.ResponseWriter, r *http.Request) {
    // decode into request struct
    // validate
    // call business-logic 
    // encode response from business-logic into response struct 

  }

}

In practice, writing RESTy APIs you have handler named after resource, e.g. you have /maps resource and appropriate handler struct mapsHandler with injected dependencies (repositories, services containing some business-logic, loggers) into it. But sometimes you will also need to pass an additional dependency exclusively per one handle and suddenly realized that handler has strict signature, so you should wrap it. Then you have something like this

// RESTy routes for "maps" resource
router.Route("/maps", func(r chi.Router) {
    adHocDependency := newAdHocDependency(options)
    r.Post("/", mapsHandler.handleCreateMap(adHocDependency))
})

making your ad hoc dependency visible to your handler.

Hope it helps!

Upvotes: 2

Uvelichitel
Uvelichitel

Reputation: 8490

Pattern

func Middleware(next http.Handler) http.Handler{
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    // Do something
    next.ServeHTTP(w, r)
  })
}

often used to construct middleware chain like

http.Handle("/", middlewareOne(middlewareTwo(finalHandler)))

Upvotes: 10

Jonathan Hall
Jonathan Hall

Reputation: 79546

Returning an anonymous function is the only way to work with handlers that require additional arguments, by returning a closure. Example:

func fooHandler(db *someDatabase) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // do something with `db` variable
    }
}

Otherwise, there's typically no practical difference between the approaches. One may choose to use the anonymous function universally for consistency.

Upvotes: 7

Related Questions