On this page

Getting Started with MuxMaster

This guide walks you through building a small but realistic REST API with MuxMaster from scratch. By the end you will have a working server with route groups, middleware, path parameters, JSON responses, and centralized error handling.

Prerequisites

  • Go 1.26 or later (download)
  • Familiarity with net/http and Go modules

Install

Create a new module and add MuxMaster as a dependency:

mkdir myapi && cd myapi
go mod init myapi
go get github.com/FlavioCFOliveira/MuxMaster

Step 1 — Hello, World

Create main.go:

package main

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

    "github.com/FlavioCFOliveira/MuxMaster"
)

func main() {
    mux := muxmaster.New()

    mux.GET("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Hello, World!")
    })

    log.Println("listening on :8080")
    log.Fatal(http.ListenAndServe(":8080", mux))
}

Run it and test it:

go run .
curl http://localhost:8080/
# Hello, World!

Step 2 — Path Parameters

Path parameters are named segments in the URL pattern prefixed with :. Use muxmaster.PathParam to read a single value, or muxmaster.ParamsFromContext to read all of them.

mux.GET("/users/:id", func(w http.ResponseWriter, r *http.Request) {
    id := muxmaster.PathParam(r, "id")
    fmt.Fprintf(w, "user: %s\n", id)
})
curl http://localhost:8080/users/42
# user: 42

To parse the value as an integer:

mux.GET("/users/:id", func(w http.ResponseWriter, r *http.Request) {
    ps := muxmaster.ParamsFromContext(r.Context())
    id, err := ps.Int("id")
    if err != nil {
        http.Error(w, "invalid id", http.StatusBadRequest)
        return
    }
    fmt.Fprintf(w, "user id: %d\n", id)
})

Step 3 — Add Middleware

Middleware wraps all routes registered after the Use call. The most common setup adds logging and panic recovery at the top of main:

import (
    "os"
    "github.com/FlavioCFOliveira/MuxMaster/middleware"
)

mux := muxmaster.New()
mux.Use(middleware.Logger(os.Stdout))
mux.Use(middleware.Recoverer)

After restarting, every request prints a log line:

2026-04-17T10:05:31Z GET /users/42 200 87.5µs

Step 4 — Route Groups

Use groups to share a path prefix and middleware across a set of related routes:

api := mux.Group("/api/v1")
api.Use(requireAPIKey) // only applies to routes in this group

api.GET("/users", listUsers)
api.POST("/users", createUser)
api.GET("/users/:id", getUser)
api.PUT("/users/:id", updateUser)
api.DELETE("/users/:id", deleteUser)

You can nest groups to add another layer of middleware:

admin := api.Group("/admin")
admin.Use(requireAdmin)
admin.GET("/stats", getStats)

Step 5 — JSON Responses

muxmaster.JSON marshals any value to JSON, sets Content-Type: application/json, and writes the status code in one call:

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

mux.GET("/users/:id", func(w http.ResponseWriter, r *http.Request) {
    id, _ := muxmaster.ParamsFromContext(r.Context()).Int("id")
    user := User{ID: id, Name: "Alice"}
    muxmaster.JSON(w, http.StatusOK, user)
})

Step 6 — Error-Returning Handlers

Repeat if err != nil { http.Error(...); return } quickly becomes noisy. HandlerFuncE lets handlers return an error instead:

mux.GETE("/users/:id", func(w http.ResponseWriter, r *http.Request) error {
    id, err := muxmaster.ParamsFromContext(r.Context()).Int("id")
    if err != nil {
        return muxmaster.Error(http.StatusBadRequest, err)
    }
    user, err := db.FindUser(id)
    if err != nil {
        return muxmaster.Error(http.StatusNotFound, errors.New("user not found"))
    }
    return muxmaster.JSON(w, http.StatusOK, user)
})

Set a custom error handler to produce consistent JSON error responses:

mux.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
    code := http.StatusInternalServerError
    var he muxmaster.HTTPError
    if errors.As(err, &he) {
        code = he.StatusCode()
    }
    muxmaster.JSON(w, code, map[string]string{"error": err.Error()})
}

Step 7 — Complete Example

Here is the full application combining everything from the steps above:

package main

import (
    "errors"
    "log"
    "net/http"
    "os"

    "github.com/FlavioCFOliveira/MuxMaster"
    "github.com/FlavioCFOliveira/MuxMaster/middleware"
)

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

var users = map[int]User{
    1: {ID: 1, Name: "Alice"},
    2: {ID: 2, Name: "Bob"},
}

func main() {
    mux := muxmaster.New()
    mux.Use(middleware.Logger(os.Stdout))
    mux.Use(middleware.Recoverer)

    mux.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
        code := http.StatusInternalServerError
        var he muxmaster.HTTPError
        if errors.As(err, &he) {
            code = he.StatusCode()
        }
        muxmaster.JSON(w, code, map[string]string{"error": err.Error()})
    }

    api := mux.Group("/api/v1")

    api.GET("/users", func(w http.ResponseWriter, r *http.Request) {
        list := make([]User, 0, len(users))
        for _, u := range users {
            list = append(list, u)
        }
        muxmaster.JSON(w, http.StatusOK, list)
    })

    api.GETE("/users/:id", func(w http.ResponseWriter, r *http.Request) error {
        id, err := muxmaster.ParamsFromContext(r.Context()).Int("id")
        if err != nil {
            return muxmaster.Error(http.StatusBadRequest, err)
        }
        u, ok := users[id]
        if !ok {
            return muxmaster.Error(http.StatusNotFound, errors.New("user not found"))
        }
        return muxmaster.JSON(w, http.StatusOK, u)
    })

    log.Fatal(http.ListenAndServe(":8080", mux))
}
curl http://localhost:8080/api/v1/users
curl http://localhost:8080/api/v1/users/1
curl http://localhost:8080/api/v1/users/99
# {"error":"user not found"}

Next Steps

  • Routing — complete pattern syntax and method reference
  • Middleware — built-in middleware and writing your own
  • Groups — advanced grouping and sub-router mounting
  • Error Handling — centralized error patterns
  • Cookbook — common production patterns

Common questions

How do I install MuxMaster in a new project?

Run go get github.com/FlavioCFOliveira/MuxMaster@v1.1.0 inside a module that targets Go 1.26 or later. The command updates go.sum and go.mod; no other dependency is added because MuxMaster ships with zero external imports.

What's the smallest working server I can write?

The seven-line program in step 1 above is the minimum. Construct the router with muxmaster.New(), register at least one route with mux.GET, and pass the router to http.ListenAndServe. MuxMaster implements http.Handler, so any Go HTTP infrastructure that accepts a handler accepts the router.

How do I read a path parameter?

Declare the parameter in the route pattern with a colon prefix (for example /users/:id) and read it inside the handler with muxmaster.PathParam(r, "id"). The helper returns the matched segment as a string; for a typed parameter use muxmaster.ParamsFromContext(r.Context()).Int("id") (and the matching .Bool, .UUID, and .Float helpers).