mach

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

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

Go to latest
Published: Feb 28, 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
  • 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")
}

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 (c *Context) Body() ([]byte, error)

Body reads the request body

func (*Context) ClientIP

func (c *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 (c *Context) Context() context.Context

Context returns the request original context from context.Context

func (*Context) Cookie

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

Cookie gets a request cookie by name

func (*Context) Data

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

Data sends raw bytes

func (*Context) DecodeJSON

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

DecodeJSON decodes a request body into a struct

func (*Context) DecodeXML

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

DecodeXML decodes a request body into a struct

func (*Context) DefaultQuery

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

DefaultQuery gets query param with default value

func (*Context) DownloadFile

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

DownloadFile sends a downloadable file response with the specified filename

func (*Context) File

func (c *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 (c *Context) Form(name string) string

Form gets a form value

func (*Context) GetHeader

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

GetHeader retrieves a request header by key

func (*Context) HTML

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

func (*Context) JSON

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

JSON sends a JSON response

func (*Context) Method

func (c *Context) Method() string

Method returns the request method

func (*Context) NoContent

func (c *Context) NoContent(status int)

NoContent sends a response with no body

func (*Context) Param

func (c *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 (c *Context) Path() string

Path retrieves the request path

func (*Context) Query

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

Query returns a named query parameter

func (*Context) Redirect

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

Redirect redirects to a URL

func (*Context) SaveFile

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

SaveFile saves an uploaded file to the specified destination path.

func (*Context) ServeStatic

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

func (*Context) SetCookie

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

SetCookie sets a response cookie

func (*Context) SetHeader

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

SetHeader sets a response header

func (*Context) StreamFile

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

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

func (*Context) Text

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

Text sends a plain text response

func (*Context) XML

func (c *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 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

WithReadTimeout 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

WithReadTimeout 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