2

I'm coming from node express, and I was able to pass in as many middleware as possible, for example: routes.use('/*', ensureAuth, logImportant, ... n);

How can I do something similar when using r.GET("/", HomeIndex)?

Am I forced to do something like EnsureAuth(HomeIndex)? Because I can get that to work. Unfortunately, I'm not sure what would be a good way to add as many middlewares as I want without chaining functions together.

Is there a more elegant way so I could somehow use variadic type function to do r.GET("/", applyMiddleware(HomeIndex, m1, m2, m3, m4)? I'm trying that out right now, but I feel like there's a better way to do this.

I've looked at the httprouter issues page, can't find anything :(

Thanks!

a person
  • 1,518
  • 3
  • 17
  • 26
  • just a question, do you strictly need httprouter? – stevenferrer Nov 07 '17 at 06:15
  • i'm new to Go and I read some articles and read that for JSON api httprouter would be fast performance and easy to use. – a person Nov 07 '17 at 06:17
  • how about your middlewares, are they of this signature `func(http.Handler) http.Handler`? – stevenferrer Nov 07 '17 at 06:19
  • yes. Well, I'm returning `httprouter.Handle`, and passing in `handle` of type `httprouter.Handle`. – a person Nov 07 '17 at 06:21
  • can you please provide a sample code? – stevenferrer Nov 07 '17 at 06:23
  • yeah. actually, i will update my post tomorrow. gonna work on writing this ApplyMiddleware function for now and see if it actually maybe resolves my problem. should I close? – a person Nov 07 '17 at 06:24
  • 2
    see if this package could help you https://github.com/justinas/alice – stevenferrer Nov 07 '17 at 06:25
  • Wooo.. that is probably exactly what I need! Thanks! I'm gonna try that out. I'm still gonna give this ApplyMiddleware a shot first though haha :D THanks! Alice seems very promising. – a person Nov 07 '17 at 06:27
  • [alice](https://github.com/justinas/alice) works very nice, here I use it within a router https://violetear.org/post/middleware/ hope can give you some ideas. – nbari Nov 07 '17 at 10:01

1 Answers1

3

Here is an example how I did it:

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"

    "github.com/julienschmidt/httprouter"
    "github.com/justinas/alice"
)

// m1 is middleware 1
func m1(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        //do something with m1
        log.Println("m1 start here")
        next.ServeHTTP(w, r)
        log.Println("m1 end here")
    })
}

// m2 is middleware 2
func m2(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        //do something with m2
        log.Println("m2 start here")
        next.ServeHTTP(w, r)
        log.Println("m2 end here")
    })
}

func index(w http.ResponseWriter, r *http.Request) {
    // get httprouter.Params from request context
    ps := r.Context().Value("params").(httprouter.Params)
    fmt.Fprintf(w, "Hello, %s", ps.ByName("name"))
}

// wrapper wraps http.Handler and returns httprouter.Handle
func wrapper(next http.Handler) httprouter.Handle {
    return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
        //pass httprouter.Params to request context
        ctx := context.WithValue(r.Context(), "params", ps)
        //call next middleware with new context
        next.ServeHTTP(w, r.WithContext(ctx))
    }
}

func main() {
    router := httprouter.New()

    chain := alice.New(m1, m2)

    //need to wrap http.Handler to be compatible with httprouter.Handle
    router.GET("/user/:name", wrapper(chain.ThenFunc(index)))

    log.Fatal(http.ListenAndServe(":9000", router))
}

Link to code (you can't run it from play.golang.org though): https://play.golang.org/p/BOCt97xcoY

stevenferrer
  • 2,504
  • 1
  • 22
  • 33