Skip to content

Instantly share code, notes, and snippets.

@jsidew
Last active January 14, 2021 12:57
Show Gist options
  • Save jsidew/573d3808306fdb6b6b4e269e4b2852ef to your computer and use it in GitHub Desktop.
Save jsidew/573d3808306fdb6b6b4e269e4b2852ef to your computer and use it in GitHub Desktop.
// This is a code snippet related to Jacopo Salvestrini's medium.com article
// https://medium.com/@jacoposalvestrini/fluent-middleware-in-golang-7ee7f20427fd
// * * *
// A Fluent evolution (check-out the diffs between commits)
// of the adapter pattern from Mat Ryer's article
// https://medium.com/@matryer/writing-middleware-in-golang-and-how-go-makes-it-so-much-fun-4375c1246e81
package main
import "net/http"
func Adapt(h http.Handler) *AdaptedHandler {
return &AdaptedHandler{h}
}
func AdaptFunc(f func(http.ResponseWriter, *http.Request)) *AdaptedHandler {
return &AdaptedHandler{http.HandlerFunc(f)}
}
type AdaptedHandler struct {
handler http.Handler
}
func (a *AdaptedHandler) With(adapters ...Adapter) http.Handler {
h := a.handler
last := len(adapters) - 1
for i := range adapters {
h = adapters[last-i](h)
}
return h
}
type Adapter func(http.Handler) http.Handler
package main
import (
"fmt"
"net/http"
)
type Index struct{}
func (Index) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World from a ServeHTTP ")
fmt.Fprintln(w, r.URL.Path)
}
func IndexHandlerFunc(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World from a func ")
fmt.Fprintln(w, r.URL.Path)
}
// This is a code snippet related to Jacopo Salvestrini's medium.com article
// https://medium.com/@jacoposalvestrini/fluent-middleware-in-golang-7ee7f20427fd
// * * *
// A Fluent evolution (check-out the diffs between commits)
// of the adapter pattern from Mat Ryer's article
// https://medium.com/@matryer/writing-middleware-in-golang-and-how-go-makes-it-so-much-fun-4375c1246e81
package main
import (
"fmt"
"io"
"net/http"
"github.com/gorilla/handlers"
)
type Logger interface {
Some(string)
GetWriter() io.Writer
}
type DataProvider interface {
Connect()
Close()
}
type AuthProvider interface {
Check(*http.Request) bool
}
func Notify(log Logger) Adapter {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer log.Some("Call end " + r.URL.Path)
log.Some("Call start " + r.URL.Path)
handlers.CombinedLoggingHandler(log.GetWriter(), h).ServeHTTP(w, r)
})
}
}
func CopyMgoSession(dp DataProvider) Adapter {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer dp.Close()
dp.Connect()
h.ServeHTTP(w, r)
})
}
}
func CheckAuth(provider AuthProvider) Adapter {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !provider.Check(r) {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprintln(w, "Get out of here!")
return
}
h.ServeHTTP(w, r)
})
}
}
func AddHeader(name, value string) Adapter {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set(name, value)
h.ServeHTTP(w, r)
})
}
}
func Compress(level int) Adapter {
return func(h http.Handler) http.Handler {
return handlers.CompressHandlerLevel(h, level)
}
}
package main
import (
"fmt"
"io"
"net/http"
)
type Log struct {
out io.Writer
}
func (l Log) Some(thing string) {
fmt.Fprintln(l.out, thing)
}
func (l Log) GetWriter() io.Writer {
return l.out
}
type DB struct{}
func (d DB) Connect() {
fmt.Println("connection to MongoDB established")
}
func (d DB) Close() {
fmt.Println("connection to MongoDB closed")
}
type Auth struct{}
func (p Auth) Check(r *http.Request) bool {
fmt.Printf("checking request header %v\n", r.Header)
return true
}
// This is a code snippet related to Jacopo Salvestrini's medium.com article
// https://medium.com/@jacoposalvestrini/fluent-middleware-in-golang-7ee7f20427fd
// * * *
// A Fluent evolution (check-out the diffs between commits)
// of the adapter pattern from Mat Ryer's article
// https://medium.com/@matryer/writing-middleware-in-golang-and-how-go-makes-it-so-much-fun-4375c1246e81
package main
import (
"net/http"
"os"
"github.com/gorilla/mux"
)
func main() {
var (
logger = Log{os.Stdout}
db = DB{}
provider = Auth{}
indexHandler = Index{}
)
r := mux.NewRouter()
r.Handle("/hello", Adapt(indexHandler).With(
CopyMgoSession(db),
CheckAuth(provider),
))
// No Auth check for this endpoint
r.Handle("/hellofunc", AdaptFunc(IndexHandlerFunc).With(
CopyMgoSession(db),
))
if err := http.ListenAndServe(":8080", Adapt(r).With(
Notify(logger),
Compress(5),
AddHeader("Server", "Mine"),
)); err != nil {
panic(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment