Golang http mux change handler function
Asked Answered
B

3

11

I am fairly new to Go and have not been able to find any information on this, maybe it is just not possible at this time.

I am trying to delete or replace a mux route (using http.NewServeMux, or gorilla's mux.Router). My end goal is to be able to enable/disable a route or set of routes without having to restart the program.

I can probably accomplish this on a handler to handler basis and just return 404 if that feature is "disabled", but I would rather find a more general way to do this since I would like to implement it for every route in my application.

Or would I be better off just keeping track of disabled url patterns and using some middleware to prevent handler execution?

If someone can at least point me in the right direction, I will absolutely post code examples of a solution assuming there is one. Thanks!

Barman answered 16/6, 2014 at 21:27 Comment(0)
P
10

There's no built in way, but it is easy enough to implement play.

type HasHandleFunc interface { //this is just so it would work for gorilla and http.ServerMux
    HandleFunc(pattern string, handler func(w http.ResponseWriter, req *http.Request))
}
type Handler struct {
    http.HandlerFunc
    Enabled bool
}
type Handlers map[string]*Handler

func (h Handlers) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    path := r.URL.Path
    if handler, ok := h[path]; ok && handler.Enabled {
        handler.ServeHTTP(w, r)
    } else {
        http.Error(w, "Not Found", http.StatusNotFound)
    }
}

func (h Handlers) HandleFunc(mux HasHandleFunc, pattern string, handler http.HandlerFunc) {
    h[pattern] = &Handler{handler, true}
    mux.HandleFunc(pattern, h.ServeHTTP)
}

func main() {
    mux := http.NewServeMux()
    handlers := Handlers{}
    handlers.HandleFunc(mux, "/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("this will show once"))
        handlers["/"].Enabled = false
    })
    http.Handle("/", mux)
    http.ListenAndServe(":9020", nil)
}
Parfait answered 16/6, 2014 at 21:53 Comment(0)
A
0

Yes you can.

One way to do it is to have a sturct that implement http.Handle interface with the method ServeHTTP. Then have the struct contain another muxer like gorilla's and finally have an atomic Switch to enable/ disable the subrouting

This is a working example of what I mean:

package main

import (
    "fmt"
    "github.com/gorilla/mux"
    "net/http"
    "sync/atomic"
)

var recording int32

func isRecording() bool {
    return atomic.LoadInt32(&recording) != 0
}

func setRecording(shouldRecord bool) {
    if shouldRecord {
        atomic.StoreInt32(&recording, 1)
    } else {
        atomic.StoreInt32(&recording, 0)
    }
}

type SwitchHandler struct {
    mux http.Handler
}

func (s *SwitchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if isRecording() {
        fmt.Printf("Switch Handler is Recording\n")
        s.mux.ServeHTTP(w, r)
        return
    }

    fmt.Printf("Switch Handler is NOT Recording\n")
    w.WriteHeader(http.StatusNotFound)
    fmt.Fprintf(w, "NOT Recording\n")

}

func main() {
    router := mux.NewRouter()
    router.HandleFunc("/success/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Recording\n")
    })

    handler := &SwitchHandler{mux: router}

    setRecording(false)

    http.Handle("/", handler)

    http.ListenAndServe(":8080", nil)
}
Amalamalbena answered 16/6, 2014 at 21:54 Comment(0)
B
0

According to https://github.com/gorilla/mux/issues/82 it is suggested to swap the router instead of deleting routes. Existing connections will stay open.

Bascule answered 8/4, 2019 at 6:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.