DEV Community

Gaurav Saini
Gaurav Saini

Posted on

Help needed with subrouting in Go

Hello šŸ‘‹

I've started learning Go a couple days ago. Currently, I'm building Rest APIs using net/http package.

I have figured out most of the basic stuff, but struggling a bit with subrouting. When I add a subrouter using like this

var mux1 = http.NewServeMux()
mux1.HandleFunc(...)

var mux2 = http.NewServeMux()
mux2.HandleFunc(...)
mux1.Handle("/", middleware.IsAuthenticated(mux2))
Enter fullscreen mode Exit fullscreen mode

I'm trying to add a protected set of routes to a router using a middleware. But, the routes defined in the subrouter are not accessible without adding a trailing slash in the URL when making the request. eg:

Screenshot of curl outputs with and without trailing slash

My Code

// cmd/main/main.go
package main

import (
    "fmt"
    "net/http"

    "rest-api/internal/middleware"
    "rest-api/internal/routes"
    "rest-api/internal/utils"
)

func main() {
    var middlewareStack = utils.CreateStack(middleware.LogRequest)

    var v1Router = http.NewServeMux()
    v1Router.Handle("/v1/", http.StripPrefix("/v1", routes.EchoRouter()))

    var usersRouter = routes.UsersRouter()
    v1Router.Handle("/users/", http.StripPrefix("/users", usersRouter))

    var server = &http.Server{
        Addr:    ":8080",
        Handler: middlewareStack(v1Router),
    }

    fmt.Println("starting server on port 8080")
    server.ListenAndServe()
}

// internal/routes/users.go
package routes

import (
    "encoding/json"
    "net/http"

    "rest-api/internal/middleware"
)

type User struct {
    Name  string
    Email string
}

func UsersRouter() http.Handler {
    var usersMux = http.NewServeMux()
    usersMux.HandleFunc("GET /", getUsers)

    var protectedMux = http.NewServeMux()
    protectedMux.HandleFunc("POST /", createUser)
    usersMux.Handle("/", middleware.IsAuthenticated(protectedMux))

    return usersMux
}

func getUsers(res http.ResponseWriter, _ *http.Request) {
    res.Write([]byte("users list"))
}

func createUser(res http.ResponseWriter, req *http.Request) {
    var newUser User
    var err = json.NewDecoder(req.Body).Decode(&newUser)

    if err != nil {
        res.WriteHeader(http.StatusBadRequest)
        res.Write([]byte(err.Error()))
        return
    }
    res.WriteHeader(http.StatusCreated)
    res.Write([]byte("new user created, name: " + newUser.Name + ", email: " + newUser.Email))
}
Enter fullscreen mode Exit fullscreen mode

PS

I can achieve the desired behaviour by using the /users prefix in the users.go file instead of the main.go file, but I was wondering if it can be done this way too šŸ¤”

Thanks!

Top comments (0)