add multiple params in http.HandlerFunc - go

hi i am trying tr write unit test for a post request using
"net/http"
"net/http/httptest"
if in my handler i have extra parameter other than w http.ResponseWriter, r *http.Request like db , kafka, etc
func ResponseHandler(w http.ResponseWriter, r *http.Request, db *dynamo.DB, p *Confluent.Producer)
how can i do
handler := http.HandlerFunc(handlername) any idea ?
I m getting
***cannot convert ResponseHandler (type func(http.ResponseWriter, http.Request, dynamo.DB, "github.com/confluentinc/confluent-kafka-go/kafka".Producer)) to type http.HandlerFunc

Your handler needs to implement the http.Handler signature, meaning it cannot have other arguments or return anything.
The way to provide it with other arguments is to have them come from an outer scope. So, assuming your not-really-a-Handler looks like:
func ResponseHandler(w http.ResponseWriter, r *http.Request, db *dynamo.DB, p *Confluent.Producer)
...you will need to generate an actual Handler calling your not-really-a-Handler. Supposing you already obtained the DB and Producer in your router initialization function, you can route like this:
var db *dynamo.DB = someDBFactory()
var p *Confluent.Producer = giveMeAProducer()
responseHandler := func(w http.ResponseWriter, r *http.Request) {
return ResponseHandler(w, r, db, p)
})
http.HandleFunc(somePath, responseHandler)
You could also pass the parameters explicitly instead of relying on the outer scope, using a higher-order function:
var db *dynamo.DB := someDBFactory()
var p *Confluent.Producer := giveMeAProducer()
newResponseHandler := func(db *dynamo.DB, p *Confluent.Producer) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
return ResponseHandler(w, r, db, p)
})
})
http.HandleFunc(somePath, newResponseHandler(db, p))

Wrap the HandlerFunc with your custom function as
func ResponseHandler(w http.ResponseWriter, r *http.Request, db *dynamo.DB, p *Confluent.Producer)func(http.ResponseWriter, *http.Request){
return func(http.ResponseWriter, *http.Request){
// your code goes here
}}

I may wrong, but the two "extra" parameters (db *dynamo.DB and p *Confluent.Producer) don't seem request-specific. If the handler depends on them to handle requests, you could make those dependencies available to the handler in several ways. Seasoned Gophers tend to "inject" dependencies through a method receiver.
You could declare a custom struct type whose fields are the dependencies needed by your handler(s):
type API struct {
db *dynamo.DB
p *Confluent.Producer
}
You can drop the extra two parameters and turn your ResponseHandler function into a method on your custom API type, thereby making it compatible with the http.HandlerFunc type:
func (api *API) ResponseHandler(w http.ResponseWriter, r *http.Request) {
// ...
}
Finally, you only have to wire the dependencies in an API variable in main.

Related

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?
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)))
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.
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!

Use function that accepts io.Writer as HandleFunc

I would like to make a function that can be a HandleFunc for http but also be called with another writer.
Since http.ResponseWriter implements io.Writer and my function does not need to set HTTP headers, I thought it might be possible:
func doit(w io.Writer, r *http.Request) {
w.Write([]byte("Hello"))
}
http.HandleFunc("/", doit)
But no:
cannot use doit (type func(io.Writer, *http.Request)) as type func(http.ResponseWriter, *http.Request) in argument to http.HandleFunc
That makes sense, because it would require a type assertion to make an io.Writer compatible with an expected http.ResponseWriter.
Is something like that possible with functions?
Spec: Function types:
A function type denotes the set of all functions with the same parameter and result types.
Your doit() function does not qualify to be an http.HandlerFunc because parameter types do not match. The types io.Writer and http.ResponseWriter are 2 completely different types, so the function types taking these types are also different.
Using an anonymous function value
However, since the method set of the interface type io.Writer is a subset of the method set of http.ResponseWriter, a value of the latter type can be assigned to the variable of the former type.
You may wrap it in an anonymous function of type http.HandlerFunc which may simply call doit(), and then you may use it as an http.HandlerFunc:
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
doit(w, r)
})
Anonymous function value with helper function
If you need this many times, you may create a helper function to produce the http.HandlerFunc function value:
func wrap(f func(w io.Writer, r *http.Request)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
f(w, r)
}
}
And then using it is simply:
http.HandleFunc("/", wrap(doit))
With custom Handler type
Another option would be to define your own function type, to which you can attach a simple method to implement http.Handler (namely ServeHTTP()), and that way with a simple type conversion you can register your function as a handler:
type SimpleHandler func(io.Writer, *http.Request)
func (sh SimpleHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
sh(w, r)
}
Using it:
http.Handle("/", SimpleHandler(doit))
Note that the expression SimpleHandler(doit) is simply a type conversion, it's not a function call. So there are no new values or anonymous functions created here in the background, this solution is the most efficient.

How to implement HandlerFunc without using DefaultServeMux

If I were to use the DefaultServeMux (which I designate by passing nil as the second argument to ListenAndServe), then I have access to http.HandleFunc, which you see used below in this example from the Go wiki:
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
In my current code, I am not able to use the DefaultServeMux i.e. I'm passing a custom handler to ListenAndServe
h := &mypackage.Handler{
Database: mydb
}
http.ListenAndServe(":8080", h)
so I don't get the http.HandleFunc built in. However, I have to adapt some authorization code to my code base that requires something like http.HandleFunc. For example, if I had been using DefaultServeMux, when I hit the "/protected" route, I would want to go to the Protected handler, but only after passing through the h.AuthorizationHandlerFunc like this
h.AuthorizationHandlerFunc(Protected)
However, since I'm not using DefaultServeMux, it's not working i.e. I'm not able to pass the Protected function (and have it called) to the AuthorizationHandlerFunc. This is the implementation of the AuthorizationHandlerFunc below. You can see below that Protected never gets called.
Question: how do I implement HandlerFunc in this situation (without using DefaultServeMux)?
func (h *Handler) AuthorizationHandlerFunc(next http.HandlerFunc) http.Handler{
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
h.AuthorizationMiddleWare(w, r, next)
})
}
func (h *Handler) AuthorizationMiddleWare(w http.ResponseWriter, r *http.Request, next http.HandlerFunc){
//other stuff happens
log.Println("this is never getting called")
next(w,r)
}
func (h *Handler)Protected(w http.ResponseWriter, r *http.Request){
log.Println("this is never getting called")
}
Update
ServeHTTP is implemented on mypackage.Handler. Why is the Protected function not getting called, or, for that matter, the relevant code in the AuthorizationMiddleWare?
Re-implement your authorization middleware as a http.Handler :
type auth struct {
DB *sql.DB
UnauthorizedHandler http.Handler
}
func NewAuth(db *sql.DB, unauthorized http.Handler) *auth {
return auth{db, unauthorized}
}
func (a *auth) Protected(h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
// Check whether the request is valid
// If it's invalid, call your error func and make sure to *return* early!
if !valid {
a.UnauthorizedHandler.ServeHTTP(w, r)
return
}
// Call the next handler on success
h.ServeHTTP(w, r)
return
}
return http.HandlerFunc(fn)
}
func someHandler(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello!\n")
}
func main() {
auth := NewAuth(db, errorHandler)
r := http.NewServeMux()
// We have a http.Handler implementation that wraps a http.HandlerFunc
// ... so we call r.Handle on our ServeMux and type-cast the wrapped func
r.Handle("/protected", auth.Protected(http.HandlerFunc(someHandler)))
// Just a simple http.HandlerFunc here
r.HandleFunc("/public", someOtherHandler)
log.Fatal(http.ListenAndServe(":8000", r))
}
Take a look at the httpauth lib I wrote for a different example with a ServeHTTP method. Both the above and explicitly creating a ServeHTTP method on your type are valid approaches.

Passing context to sub-directory

I have a Context struct that is used for the Application Context. The ConfigureRouter function receives the context as a parameter and sets the global variable c so middleware in the same file can use it.
var c *core.Context
func ConfigureRouter(ctx *core.Context, router *httprouter.Router) {
c = ctx //make context available in all middleware
router.POST("/v1/tokens/create", token.Create) //using httprouter
}
The one route listed above calls token.Create ( from the token package which is a sub-directory) but it needs the context too.
//token/token.go
func Create(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
//Help! I need the context to do things
}
How can I pass the context to the token package?
You can redefine your Create function as a function that returns the handler function:
func Create(ctx *core.Context) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
// Now you have the context to do things
}
}
Where httprouter.Handle is a func type defined by httprouter to be type Handle func(http.ResponseWriter, *http.Request, Params).
And then you would use it like this in ConfigureRouter:
func ConfigureRouter(ctx *core.Context, router *httprouter.Router) {
router.POST("/v1/tokens/create", token.Create(ctx))
}

Difference between http.Handle and http.HandleFunc?

The Go docs have the following example for the http package:
http.Handle("/foo", fooHandler)
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
I'm having sort of a difficulty understanding the difference between Handle and HandleFunc and why two are needed. Can somebody try to explain to a new Gopher in clear words?
Basically, the HTTP server's "mux" has a map of path -> handler interface
Interfaces are used here, I assume, to allow you to implement complex path handlers that have state.
For example the file server from the standard package is a struct that contains the root dir for file service and implements the handler interface.
That said, for simple stuff, a func is easier and more clear. So they added a special generator so you can easily pass in a func.
Take a look at: server.go
from line: 1216 (as of today)
1216 type HandlerFunc func(ResponseWriter, *Request)
1217
1218 // ServeHTTP calls f(w, r).
1219 func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
1220 f(w, r)
1221 }
What they are doing is implementing the interface on a custom type (which happens to match the api of the interface) that just calls itself.
In simple terms:
Problem: I want to create an object (type) that responds to HTTP requests.
Solution: Use http.Handle for that. It accepts an http.Handler as the second argument.
http.Handler is an interface and should implement ServeHTTP from the http package.
Problem: I want a function to respond to my HTTP request.
Solution: Use http.HandleFunc for that. It accepts an http.HandlerFunc as the second argument.
http.HandlerFunc is a function type and should implement ServeHTTP from the http package.
No, it's different. Let's examine:
func Handle(pattern string, handler Handler) {
DefaultServeMux.Handle(pattern, handler)
}
Handle expects us to pass a Handler. Handler is an interface
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
if any type implements ServeHTTP(ResponseWriter, *Request) for example:
myCustomHandler then we can pass it like Handle(pattern string, myCustomHandler).
In the second scenario:
HandleFunc(pattern string, func(w ResponseWriter, r *Request) {
// do some stuff
}
HandleFunc expects a function where Handle expects a Handler interface.
So, if you just want to pass a function then you can use http.HandleFunc(..). Like #David showed that behind the scenes it implements Handler interface by calling ServeHTTP.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
Handler functions are merely convenient ways of creating handlers.
While both of them can be used to create handlers, but because, using handler functions is cleaner and it does the job just as well, why use handlers at all? It all boils down to design. If you have an existing interface or if you want a type that can also be used as a handler, simply add a ServeHTTP method to that interface and you’ll get a handler that you can assign to a URL. It can also allow you to
build web applications that are more modular.
Using Handle
package main
import (
"fmt"
"net/http"
)
type HelloHandler struct{}
func (h *HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
type WorldHandler struct{}
func (h *WorldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "World!")
}
func main() {
hello := HelloHandler{}
world := WorldHandler{}
http.Handle("/hello", &hello)
http.Handle("/world", &world)
http.ListenAndServe(":8080", nil)
}
Using HandleFunc
package main
import (
"fmt"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
func world(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "World!")
}
func main() {
http.HandleFunc("/hello", hello)
http.HandleFunc("/world", world)
http.ListenAndServe(":8080", nil)
}
Additional information:
http.Handler is an interface with method ServeHTTP(),
// net/http/server.go
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
And here's a ServeHTTP information,
// net/http/server.go
ServeHTTP(w http.ResponseWriter, r *http.Request)
// where,
// http.ResponseWriter is a writer interface, and,
// http.Request is a structure with request details.
Now lets look at HandlerFunc,
// net/http/server.go
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request){
f(w, r)
}
That means, http.HandlerFunc is a type that has ServeHTTP method implemented.
http.HandlerFunc(someFunc)
// where,
// 1. someFunc() must have a signature,
func someFunc(w http.ResponseWriter, r *http.Request)
// 2. That means, http.HandlerFunc(someFunc) is just a type casting of type http.HandlerFunc on a someFunc() and not a function call.
Now lets go to the http.Handle(),
// net/http/server.go
// Handle registers the handler for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func Handle(pattern string, handler Handler) {
DefaultServeMux.Handle(pattern, handler)
}
By looking at above snippet, you may have noticed that,
2nd argument accepts a Handler interface, that means, you can create any type and implement a ServeHTTP() method for it to satisfy this. Refer below example for proof.
type MyHandler struct{}
func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
}
func main() {
handler := MyHandler{}
http.Handle("/hello", &handler)
http.ListenAndServe()
}

Resources