julienschmidt / httprouter

A high performance HTTP request router that scales well
https://pkg.go.dev/github.com/julienschmidt/httprouter
BSD 3-Clause "New" or "Revised" License
16.64k stars 1.47k forks source link

Middleware to go with HandlerFunc #281

Closed bentcoder closed 5 years ago

bentcoder commented 5 years ago

Hi,

Apologies in advance as this is my issue not the package's issue.

I am looking for a way to use chain of middleware for routes(endpoints) I have but couldn't find an example. Is what I am trying to do below possible?

NOTE: I want to stick with (rw http.ResponseWriter, rq *http.Request) signature without params though. Otherwise it is very easy to create middleware.

Thanks

package route

import (
    "fmt"
    "net/http"
)

func Home(rw http.ResponseWriter, rq *http.Request) {
    fmt.Println("Welcome home")
}

func Admin(rw http.ResponseWriter, rq *http.Request) {
    fmt.Println("Welcome admin")
}

func SuperAdmin(rw http.ResponseWriter, rq *http.Request) {
    fmt.Println("Welcome superadmin")
}
package http

import (
    "net/http"
    "github.com/julienschmidt/httprouter"
)

func router() http.Handler {
    rtr := httprouter.New()

    rtr.HandlerFunc("GET", "/", Home)
    rtr.HandlerFunc("POST", "/admin", middleware.Admin(Admin))
    rtr.HandlerFunc("POST", "/superadmin", middleware.Admin(middleware.Super(Admin)))

    return rtr // Using this for "Handler" param of http.Server package.
}

These tries ones didn't work - I know some of them are irrelevant but just trying to explain what I mean if my explanation above wasn't clear enough.

package middleware

import (
    "fmt"
    "net/http"
)

func Admin(h http.Handler) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        h.ServeHTTP(w, r)
    }
}

func Admin(h httprouter.Handle) httprouter.Handle {
    return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
        h(w, r, ps)
    }
}

func Admin(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        h.ServeHTTP(w, r)
    })
}

...
julienschmidt commented 5 years ago

Sure that should work somehow. Just stick to one type (http.Handler, http.HandlerFunc or httprouter.Handle) consistently:

func Admin(rw http.ResponseWriter, rq *http.Request) {
    fmt.Println("Welcome admin")
}

func Middleware1(h http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        h(w, r)
    }
}

func Middleware2(h http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        h(w, r)
    }
}

rtr.HandlerFunc("POST", "/admin", Middleware2(Middleware1(Admin)))

Or am I not understanding your question correctly?

bentcoder commented 5 years ago

You got it right, thank you!