mach

package module
v0.0.0-...-4f73167 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 17, 2026 License: MIT Imports: 21 Imported by: 0

README

Mach - A Lightweight Go Web Framework

Go Reference Go Report Card Release

Mach is a minimalist web framework for Go, inspired by Python's Bottle. My motivation for building this was to go deeper into the internals of the frameworks I've been using to build HTTP backend services. Rather than reinventing the wheel with a custom radix tree router, I leverage Go 1.22's enhanced net/http server, is incredibly fast with minimal allocations. The framework also uses context pooling to reduce allocations in the hot path. I hope you find this tool useful.

Features

  • Middleware chain - Global and route-specific middlewares
  • Route groups - Organize routes with common prefixes and middleware
  • HTMX support - Built-in helpers for HTMX request and response headers
  • Flexible configuration - Functional options for app and server setup
  • Graceful shutdown - Built-in support for clean server termination
  • Zero dependencies - Core framework uses only the standard library

Quick Start

Installation
go get github.com/mrshabel/mach
Basic Usage
package main

import (
    "github.com/mrshabel/mach"
)

func main() {
    // create app with default middleware (logger + recovery)
    app := mach.Default()

    // simple route
    app.GET("/", func(c *mach.Context) {
        c.Text(200, "Hello, Mach!")
    })

    // path parameters
    app.GET("/users/{id}", func(c *mach.Context) {
        id := c.Param("id")
        c.JSON(200, map[string]string{"user_id": id})
    })

    // JSON binding
    app.POST("/users", func(c *mach.Context) {
        var user struct {
            Name  string `json:"name"`
            Email string `json:"email"`
        }

        if err := c.DecodeJSON(&user); err != nil {
            c.JSON(400, map[string]string{"error": err.Error()})
            return
        }

        c.JSON(201, user)
    })

    app.Run(":8080")
}
HTMX Support

Mach provides built-in helpers for working with HTMX.

app.GET("/htmx-example", func(c *mach.Context) {
    h := c.HTMX()
    
    // check request headers
    if h.IsHTMX() {
        fmt.Println("HTMX request from:", h.CurrentURL())
        fmt.Println("Target element:", h.Target())
    }

    // set response headers
    h.PushURL("/new-url")
    h.TriggerResponse("my-event")
    
    // you can also pass objects for complex events
    h.TriggerResponse(map[string]string{"user-updated": "123"})
    
    c.HTML(200, "<div>Updated Content</div>")
})

Examples

Route Groups
app := mach.Default()

// public routes
app.GET("/", homeHandler)
app.GET("/about", aboutHandler)

// api group with CORS
api := app.Group("/api", mach.CORS("*"))
{
    // v1 endpoints
    v1 := api.Group("/v1")
    {
        v1.GET("/users", listUsers)
        v1.POST("/users", createUser)
        v1.GET("/users/{id}", getUser)
    }
}

// admin group with authentication
admin := app.Group("/admin", mach.BasicAuth("admin", "secret"))
{
    admin.GET("/dashboard", dashboardHandler)
    admin.GET("/settings", settingsHandler)
}
Custom Middleware
// custom logger middleware
func CustomLogger() mach.MiddlewareFunc {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            start := time.Now()

            next.ServeHTTP(w, r)

            log.Printf("%s %s (%v)", r.Method, r.URL.Path, time.Since(start))
        })
    }
}

app := mach.New()
app.Use(CustomLogger())
app.Use(mach.Recovery())
Configuration Options
// app with options
app := mach.New(
    mach.WithLogger(),
    mach.WithRecovery(),
    mach.WithDebug(),
)

// Server with options
app.Run(":8080",
    mach.WithReadTimeout(10*time.Second),
    mach.WithWriteTimeout(10*time.Second),
    mach.WithGracefulShutdown(30*time.Second),
)
Static Files
app := mach.Default()

// serve static files from ./public
app.Static("/static/", "./public")

// Access at http://localhost:8000/static/css/style.css

Context API

Request Data
app.GET("/example", func(c *mach.Context) {
    // path parameters
    id := c.Param("id")

    // query parameters
    page := c.Query("page")
    pageOrDefault := c.DefaultQuery("page", "1")

    // form data
    name := c.Form("name")

    // headers
    token := c.GetHeader("Authorization")

    // cookies
    cookie, err := c.Cookie("session")

    // client IP
    ip := c.ClientIP()

    // Request body
    body, err := c.Body()
})
Response Methods
// JSON response
c.JSON(200, map[string]string{"status": "ok"})

// text response
c.Text(200, "Hello, %s", name)

// HTML response
c.HTML(200, "<h1>Welcome</h1>")

// XML response
c.XML(200, data)

// Raw data
c.Data(200, "application/octet-stream", bytes)

// no content
c.NoContent(204)

// redirect
c.Redirect(302, "/login")
Binding
// JSON decoding
var user User
if err := c.DecodeJSON(&user); err != nil {
    c.JSON(400, map[string]string{"error": err.Error()})
    return
}

// XML decoding
var config Config
if err := c.DecodeXML(&config); err != nil {
    c.JSON(400, map[string]string{"error": err.Error()})
    return
}

Built-in Middleware

  • Logger() - Request logging with timing
  • Recovery() - Panic recovery with stack traces
  • CORS(origin) - CORS headers configuration
  • RequestID() - Unique request ID generation

Design Philosophy

Mach follows these principles:

  1. Leverage the standard library - Use Go 1.22's enhanced routing instead of custom implementations
  2. Performance matters - Context pooling and efficient middleware chaining
  3. Simplicity over features - Clean API inspired by Bottle's minimalism
  4. Standard Go patterns - No magic, just idiomatic Go code
  5. Zero core dependencies - Framework core uses only stdlib

Technical Details

Routing

Mach uses Go 1.22+'s net/http.ServeMux pattern matching:

// method-specific routes
GET /users/{id}
POST /users
PUT /users/{id}

// wildcard patterns
GET /files/{path...}

Pattern matching is handled by the standard library with precedence rules that ensure the most specific pattern wins.

Context Pooling

To minimize allocations, Context objects are pooled using sync.Pool:

type App struct {
    pool sync.Pool
}

func (app *App) handle(method, path string, handler HandlerFunc) {
    app.router.HandleFunc(method+" "+path, func(w http.ResponseWriter, r *http.Request) {
        c := app.pool.Get().(*Context)
        c.reset(w, r)
        handler(c)
		// return to pool
        app.pool.Put(c)
    })
}

This reduces GC pressure in high-throughput scenarios.

Middleware Chain

Middleware uses the standard func(http.Handler) http.Handler pattern:

func (app *App) buildHandler() http.Handler {
    handler := http.Handler(app.router)

    // apply middleware in reverse order
    for i := len(app.middleware) - 1; i >= 0; i-- {
        handler = app.middleware[i](handler)
    }

    return handler
}

This creates a chain where the first middleware added wraps all others, enabling proper before/after request handling.

Documentation

Full documentation is coming soon.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - see LICENSE for details.

Acknowledgments

Inspired by Bottle - Python's minimalist web framework.

Documentation

Overview

Package mach provides a lightweight web framework for Go.

Mach is built on Go 1.22's enhanced net/http router with zero dependencies. It provides a simple, intuitive API for building web applications while leveraging the standard library's performance and reliability.

Example usage:

app := mach.Default()

app.GET("/", func(c *mach.Context) {
    c.JSON(200, map[string]string{"message": "Hello, Mach!"})
})

app.Run(":8080")

Features:

  • Go 1.22+ native routing with method matching and path parameters
  • Standard http.Handler middleware pattern
  • Route groups for organization
  • Zero dependencies

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrEmptyRequestBody = errors.New("request body is empty")
)

Functions

This section is empty.

Types

type App

type App struct {
	// contains filtered or unexported fields
}

App is the main application instance.

func Default

func Default() *App

Default instantiates an app with common settings.

func New

func New(opts ...Option) *App

New instantiates a new app instance.

func (*App) DELETE

func (app *App) DELETE(path string, handler HandlerFunc)

DELETE registers a DELETE route.

func (*App) GET

func (app *App) GET(path string, handler HandlerFunc)

GET registers a GET route.

func (*App) Group

func (app *App) Group(prefix string, middlewares ...MiddlewareFunc) *Group

Group creates a route group with common prefix and middleware.

func (*App) HEAD

func (app *App) HEAD(path string, handler HandlerFunc)

HEAD registers a HEAD route.

func (*App) OPTIONS

func (app *App) OPTIONS(path string, handler HandlerFunc)

OPTIONS registers a OPTIONS route.

func (*App) PATCH

func (app *App) PATCH(path string, handler HandlerFunc)

PATCH registers a PATCH route.

func (*App) POST

func (app *App) POST(path string, handler HandlerFunc)

POST registers a POST route.

func (*App) PUT

func (app *App) PUT(path string, handler HandlerFunc)

PUT registers a PUT route.

func (*App) Route

func (app *App) Route(method, path string, handler HandlerFunc)

Route registers a handler for the given method and path.

func (*App) Run

func (app *App) Run(addr string, opts ...RunOption) error

Run starts the http server.

func (*App) RunTLS

func (app *App) RunTLS(addr, certFile, keyFile string, opts ...RunOption) error

RunTLS starts the HTTPS server.

func (*App) ServeHTTP

func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements the handler for serving each request.

func (*App) Static

func (app *App) Static(prefix, dir string)

func (*App) Use

func (app *App) Use(middlewares ...MiddlewareFunc)

Use adds a global middleware to the application.

type CORSConfig

type CORSConfig struct {
	AllowOrigins      []string
	AllowMethods      []string
	AllowHeaders      []string
	ExposeHeaders     []string
	AllowCredentials  bool
	MaxAge            int
	PreflightContinue bool
}

type Context

type Context struct {
	Request  *http.Request
	Response http.ResponseWriter

	IsFormParsed bool
	// contains filtered or unexported fields
}

Context adds helpful methods to the ongoing request.

func (*Context) Body

func (ctx *Context) Body() ([]byte, error)

Body reads the request body.

func (*Context) ClientIP

func (ctx *Context) ClientIP() string

ClientIP returns the client IP address. Use this if you trust request headers passed to the server (ie: reverse proxy sits before server) else use c.Request.RemoteAddr().

func (*Context) Context

func (ctx *Context) Context() context.Context

Context returns the request original context from context.Context.

func (*Context) Cookie

func (ctx *Context) Cookie(name string) (*http.Cookie, error)

Cookie gets a request cookie by name.

func (*Context) Data

func (ctx *Context) Data(status int, contentType string, data []byte) error

Data sends raw bytes.

func (*Context) DecodeJSON

func (ctx *Context) DecodeJSON(data interface{}) error

DecodeJSON decodes a request body into a struct.

func (*Context) DecodeXML

func (ctx *Context) DecodeXML(data interface{}) error

DecodeXML decodes a request body into a struct.

func (*Context) DefaultQuery

func (ctx *Context) DefaultQuery(name, defaultValue string) string

DefaultQuery gets query param with default value.

func (*Context) DownloadFile

func (ctx *Context) DownloadFile(filepath string, downloadName string) error

DownloadFile sends a downloadable file response with the specified filename.

func (*Context) File

func (ctx *Context) File(name string) (*multipart.FileHeader, error)

File gets an uploaded file by key name. The file header containing the file is returned.

func (*Context) Form

func (ctx *Context) Form(name string) string

Form gets a form value.

func (*Context) GetHeader

func (ctx *Context) GetHeader(key string) string

GetHeader retrieves a request header by key.

func (*Context) GetResponseHeader

func (ctx *Context) GetResponseHeader(key string) string

GetResponseHeader retrieves a response header by key.

func (*Context) HTML

func (ctx *Context) HTML(status int, html string) error

func (*Context) HTMX

func (ctx *Context) HTMX() *HTMX

HTMX returns the HTMX helper.

func (*Context) JSON

func (ctx *Context) JSON(status int, data interface{}) error

JSON sends a JSON response.

func (*Context) Method

func (ctx *Context) Method() string

Method returns the request method.

func (*Context) NoContent

func (ctx *Context) NoContent(status int)

NoContent sends a response with no body.

func (*Context) Param

func (ctx *Context) Param(name string) string

Param gets a path parameter by name. For example, this returns the value of id from /users/{id}.

func (*Context) Path

func (ctx *Context) Path() string

Path retrieves the request path.

func (*Context) Query

func (ctx *Context) Query(name string) string

Query returns a named query parameter.

func (*Context) Redirect

func (ctx *Context) Redirect(status int, url string)

Redirect redirects to a URL.

func (*Context) SaveFile

func (ctx *Context) SaveFile(file *multipart.FileHeader, path string) error

SaveFile saves an uploaded file to the specified destination path.

func (*Context) ServeStatic

func (ctx *Context) ServeStatic(dir string) error

func (*Context) SetCookie

func (ctx *Context) SetCookie(cookie *http.Cookie)

SetCookie sets a response cookie.

func (*Context) SetHeader

func (ctx *Context) SetHeader(key, value string)

SetHeader sets a response header.

func (*Context) StreamFile

func (ctx *Context) StreamFile(filepath string) error

StreamFile streams the content of a file in chunks to the client.

func (*Context) Text

func (ctx *Context) Text(status int, format string, values ...interface{}) error

Text sends a plain text response.

func (*Context) XML

func (ctx *Context) XML(status int, data interface{}) error

XML sends an XML response.

type Group

type Group struct {
	// contains filtered or unexported fields
}

Group is a route group with common named prefix.

func (*Group) DELETE

func (g *Group) DELETE(path string, handler HandlerFunc)

DELETE registers a DELETE route for the group.

func (*Group) GET

func (g *Group) GET(path string, handler HandlerFunc)

GET registers a GET route for the group.

func (*Group) Group

func (g *Group) Group(prefix string, middlewares ...MiddlewareFunc) *Group

Group creates a sub-group. Global middlewares come first in the chain.

func (*Group) HEAD

func (g *Group) HEAD(path string, handler HandlerFunc)

HEAD registers a HEAD route for the group.

func (*Group) OPTIONS

func (g *Group) OPTIONS(path string, handler HandlerFunc)

OPTIONS registers a OPTIONS route for the group.

func (*Group) PATCH

func (g *Group) PATCH(path string, handler HandlerFunc)

PATCH registers a PATCH route for the group.

func (*Group) POST

func (g *Group) POST(path string, handler HandlerFunc)

POST registers a POST route for the group.

func (*Group) PUT

func (g *Group) PUT(path string, handler HandlerFunc)

PUT registers a PUT route for the group.

func (*Group) Use

func (g *Group) Use(middlewares ...MiddlewareFunc)

Use registers middlewares to the group.

type HTMX

type HTMX struct {
	// contains filtered or unexported fields
}

HTMX helper provides methods for interacting with HTMX headers.

func (*HTMX) CurrentURL

func (h *HTMX) CurrentURL() string

CurrentURL returns the current URL of the browser.

func (*HTMX) IsBoosted

func (h *HTMX) IsBoosted() bool

IsBoosted returns true if the request is via an element using hx-boost.

func (*HTMX) IsHTMX

func (h *HTMX) IsHTMX() bool

IsHTMX returns true if the request is an HTMX request.

func (*HTMX) IsHistoryRestoreRequest

func (h *HTMX) IsHistoryRestoreRequest() bool

IsHistoryRestoreRequest returns true if the request is for history restoration after a miss in the local history cache.

func (*HTMX) Location

func (h *HTMX) Location(url string)

Location allows you to do a client-side redirect that does not do a full page reload.

func (*HTMX) Prompt

func (h *HTMX) Prompt() string

Prompt returns the user response to an hx-prompt.

func (*HTMX) PushURL

func (h *HTMX) PushURL(url string)

PushURL pushes a new URL into the browser location bar.

func (*HTMX) Redirect

func (h *HTMX) Redirect(url string)

Redirect allows you to do a client-side redirect to a new location.

func (*HTMX) Refresh

func (h *HTMX) Refresh()

Refresh triggers a client side full refresh of the page.

func (*HTMX) ReplaceURL

func (h *HTMX) ReplaceURL(url string)

ReplaceURL replaces the current URL in the browser location bar.

func (*HTMX) Reselect

func (h *HTMX) Reselect(selector string)

Reselect allows you to choose which part of the response is used to be swapped in.

func (*HTMX) Reswap

func (h *HTMX) Reswap(swap string)

Reswap allows you to specify how the response will be swapped.

func (*HTMX) Retarget

func (h *HTMX) Retarget(selector string)

Retarget allows you to target a different element on the page of the response.

func (*HTMX) Target

func (h *HTMX) Target() string

Target returns the id of the target element if it exists.

func (*HTMX) Trigger

func (h *HTMX) Trigger() string

Trigger returns the id of the triggered element if it exists.

func (*HTMX) TriggerAfterSettleResponse

func (h *HTMX) TriggerAfterSettleResponse(events any)

TriggerAfterSettleResponse allows you to trigger client side events after the settle step.

func (*HTMX) TriggerAfterSwapResponse

func (h *HTMX) TriggerAfterSwapResponse(events any)

TriggerAfterSwapResponse allows you to trigger client side events after the swap step.

func (*HTMX) TriggerName

func (h *HTMX) TriggerName() string

TriggerName returns the name of the triggered element if it exists.

func (*HTMX) TriggerResponse

func (h *HTMX) TriggerResponse(events any)

TriggerResponse allows you to trigger client side events. If events is a string, it sets it as the HX-Trigger header. If events is a map or struct, it serializes it to JSON and sets it as the HX-Trigger header. To avoid overwriting previously set events, this method appends to the existing HX-Trigger header if it exists.

type HandlerFunc

type HandlerFunc func(c *Context)

HandlerFunc is the handler signature.

type MiddlewareFunc

type MiddlewareFunc func(http.Handler) http.Handler

MiddlewareFunc is the middleware signature.

func CORS

func CORS(allowOrigins []string) MiddlewareFunc

func CORSWithConfig

func CORSWithConfig(config CORSConfig) MiddlewareFunc

func Logger

func Logger() MiddlewareFunc

func Recovery

func Recovery() MiddlewareFunc

type Option

type Option func(*App)

Option configures the app.

func WithDebug

func WithDebug() Option

WithDebug enables debug mode.

func WithLogger

func WithLogger() Option

WithLogger adds logger middleware.

func WithRecovery

func WithRecovery() Option

WithRecovery adds recovery middleware.

type RunOption

type RunOption func(*serverConfig)

RunOption configures the server.

func WithGracefulShutdown

func WithGracefulShutdown(timeout time.Duration) RunOption

WithGracefulShutdown sets the server graceful shutdown timeout.

func WithReadTimeout

func WithReadTimeout(duration time.Duration) RunOption

WithReadTimeout sets the server read timeout.

func WithWriteTimeout

func WithWriteTimeout(duration time.Duration) RunOption

WithWriteTimeout sets the server write timeout.

Directories

Path Synopsis
_examples
basic command
file-download command
file-upload command
middleware command
nested-routes command
rest-api command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL