gorilla/mux

repository·main·Indexed 12 days ago

https://github.com/gorilla/mux

A powerful HTTP request multiplexer for Go that provides advanced routing capabilities beyond the standard library's ServeMux. It implements the http.Handler interface and supports matching requests based on URL host, path, schemes, headers, query values, and HTTP methods. Key features include dynamic routing with variables, subrouters for grouping, URL reversal, and middleware support via MiddlewareFunc.

Tokens
6.2K
Snippets
31
Records
36
Agent score
94%

What's inside gorilla/mux

  1. What is gorilla/mux?

    main

    The gorilla/mux package is an HTTP request multiplexer (router and dispatcher). It matches incoming requests to their respective handlers based on various conditions.

    Key features include:

    • Standard Library Compatibility: Implements the http.Handler interface, making it a drop-in replacement for http.ServeMux.
    • Advanced Matching: Matches requests based on URL host, path, path prefix, schemes, headers, query values, HTTP methods, or custom matchers.
    • Dynamic Routing: Supports variables in URL hosts, paths, and query values, with optional regular expression constraints.
    • URL Reversal: Allows building (reversing) registered URLs to maintain references to resources.
    • Subrouters: Supports nested routes that are only evaluated if the parent route matches. This allows grouping routes by common attributes (like host or path prefix) and optimizes matching performance.
  2. Implement middleware

    main

    Middleware in mux are functions with the signature type MiddlewareFunc func(http.Handler) http.Handler. They are executed in the order they are added via Router.Use(). A middleware can intercept a request, perform actions (like logging or authentication), and then either call next.ServeHTTP(w, r) to continue the chain or stop the chain by returning early (e.g., writing an error response).

    func loggingMiddleware(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            log.Println(r.RequestURI)
            next.ServeHTTP(w, r)
        })
    }
    
    r := mux.NewRouter()
    r.Use(loggingMiddleware)
    r.HandleFunc("/", handler)
  3. Use subrouters for grouping and namespacing

    main

    Subrouters allow you to group routes that share common matching requirements (like a specific Host or PathPrefix). This optimizes request matching and allows you to create namespaces. When a subrouter is created from a PathPrefix, the inner routes use that prefix as their base path.

    r := mux.NewRouter()
    // All routes in 's' will only match if the host is www.example.com
    s := r.Host("www.example.com").Subrouter()
    s.HandleFunc("/products/", ProductsHandler)
    
    // Using PathPrefix to create a namespace
    api := r.PathPrefix("/api").Subrouter()
    api.HandleFunc("/users", UsersHandler) // matches /api/users
  4. Match routes by Host, Method, Scheme, and other attributes

    main

    Routes can be restricted using various matchers. Matchers are applied to the route and can be chained. Routes are tested in the order they were added; the first match wins.

    Available matchers include:

    • Host(pattern): Matches a domain or subdomain (e.g., r.Host("www.example.com") or r.Host("{subdomain}.example.com")).
    • PathPrefix(pattern): Matches a path prefix (e.g., r.PathPrefix("/products/")).
    • Methods(methods...): Matches HTTP methods (e.g., r.Methods("GET", "POST")).
    • Schemes(schemes...): Matches URL schemes (e.g., r.Schemes("https")).
    • Headers(key, value): Matches specific header values.
    • HeadersRegexp(key, pattern): Matches headers using a regular expression.
    • Queries(key, value): Matches query parameters.
    • MatcherFunc(func): Uses a custom function for matching.

    You can combine these by chaining calls on the route object.

    r.HandleFunc("/products", ProductsHandler).
      Host("www.example.com").
      Methods("GET").
      Schemes("http")
  5. Serve static files

    main

    To serve static files, use PathPrefix() combined with http.StripPrefix and http.FileServer. The PathPrefix acts as a wildcard for everything following the prefix.

    r := mux.NewRouter()
    // Serves files from the local directory under the /static/ URL path
    r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
  6. Register basic routes and use URL variables

    main

    You can register URL paths to handlers using r.HandleFunc(). Paths can include variables defined with the {name} or {name:pattern} syntax. If no pattern is provided, the variable matches everything until the next slash. Use mux.Vars(r) to retrieve a map of these variables from the request.

    func main() {
        r := mux.NewRouter()
        r.HandleFunc("/products/{key}", ProductHandler)
        r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
        http.Handle("/", r)
    }
    
    func ArticleHandler(w http.ResponseWriter, r *http.Request) {
        vars := mux.Vars(r)
        category := vars["category"]
        id := vars["id"]
        // ...
    }
  7. Create a basic server with gorilla/mux

    main

    To build a basic HTTP server using mux, initialize a new router with mux.NewRouter(). You define routes by associating a path pattern with a handler function using r.HandleFunc(path, handler). Finally, pass the router instance to http.ListenAndServe to start the server.

    Note: The router implements the http.Handler interface, so it can be used anywhere a standard Go handler is expected.

    package main
    
    import (
        "net/http"
        "log"
        "github.com/gorilla/mux"
    )
    
    func YourHandler(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Gorilla!\n"))
    }
    
    func main() {
        r := mux.NewRouter()
        // Routes consist of a path and a handler function.
        r.HandleFunc("/", YourHandler)
    
        // Bind to a port and pass our router in
        log.Fatal(http.ListenAndServe(":8000", r))
    }
  8. Reverse routes to build URLs

    main

    You can name routes using .Name("name") and then generate URLs (reverse routing) using r.Get("name"). The .URL(...) method takes key/value pairs for the route variables. This ensures generated URLs always match the registered route patterns.

    • URL(key, value...): Builds the full URL (including host, path, and queries).
    • URLHost(key, value...): Builds only the host part.
    • URLPath(key, value...): Builds only the path part.
    • GetVarNames(): Returns the names of all required variables for a route.
    r := mux.NewRouter()
    r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).Name("article")
    
    // Build the full URL
    url, err := r.Get("article").URL("category", "technology", "id", "42")
    // Result: /articles/technology/42
    
    // Get variable names
    names := r.Get("article").GetVarNames()
    // Result: [category id]
  9. Handle CORS with CORSMethodMiddleware

    main

    The mux.CORSMethodMiddleware simplifies setting the Access-Control-Allow-Methods header. It automatically sets the header to match the methods defined in your route matchers.

    Important: You must include an OPTIONS method matcher on the route for the middleware to function correctly. You are still responsible for setting other CORS headers like Access-Control-Allow-Origin in your actual handler.

    r := mux.NewRouter()
    // Must include OPTIONS in the methods
    r.HandleFunc("/foo", fooHandler).Methods("GET", "POST", "OPTIONS")
    
    r.Use(mux.CORSMethodMiddleware(r))
    
    func fooHandler(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        if r.Method == http.MethodOptions {
            return
        }
        w.Write([]byte("foo"))
    }
  10. Walk all registered routes

    main

    The Walk method allows you to iterate over every route registered in the router. This is useful for debugging or inspecting the routing table. The callback function receives the *mux.Route, the *mux.Router, and a slice of ancestors (the route hierarchy).

    err := r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
        path, _ := route.GetPathTemplate()
        fmt.Println("Route path template:", path)
        return nil
    })
  11. Initialize a new Router with NewRouter()

    main

    Use mux.NewRouter() to create a new instance of a Router. The Router implements the http.Handler interface, allowing it to be passed directly to http.Handle or http.ListenAndServe. It manages route registration, matching, and middleware execution.

    var router = mux.NewRouter()
    
    func main() {
        http.Handle("/", router)
        http.ListenAndServe(":8080", nil)
    }