gohttputil

package module
v1.9.1 Latest Latest
Warning

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

Go to latest
Published: May 15, 2026 License: GPL-3.0 Imports: 4 Imported by: 0

README

go-httputil

GitHub Tag Go Reference GitHub License Libraries.io dependency status for GitHub repo GitHub Actions Workflow Status Go Report Card

Simple HTTP utilities like middleware and pragmatic route builders based on standard library facilities.

This library heavily emphasizes utilization of built-in modules.

Index

  1. Features
  2. Middleware
  3. Routing & Mux
  4. Validation Middlewares
  5. Error Formatting Design
  6. Authentication & Authorization

Features

  • Wrapper around http.ServeMux for global, group and route-level middleware layering.
  • Bind and validate JSON, Form, Query and Path parameters.
  • Built-in JWT authentication and role-based authorization middlewares.
  • Automatic recovery and structured logging middlewares.
  • Structural error formatting mapping go-playground/validator errors directly into nested JSON shapes.

Middleware

In go-httputil, a middleware heavily embraces the standard library's definition, represented strictly as:

type Middleware func(http.Handler) http.Handler
Built-in Middlewares

The package includes several pragmatic middlewares out of the box (all are located under middlewares module):

  • Logger() / LoggerWithSkips(): Provides structured API request logging using log/slog.
  • Recover(): Gracefully catches panics during request handling and returns a clean 500 internal server error.
  • Authenticate(queryKeys...): Verifies JWT tokens and injects parsed payloads directly into the request context.
  • Authorize(AuthorizeFunc): Evaluates custom conditions (like RBAC) to determine if a request should proceed.
  • Validate...(): A family of native validation binders for JSON, UI Forms, Queries and Path parameters.

Routing & Mux

The Mux provides a thin pragmatic wrapper over Go's standard http.ServeMux. It allows chaining middlewares natively at the global, group or individual route level and handles CORS easily.

mux := gohttputil.New()

// Attach global middlewares
mux.Use(middlewares.Logger(), middlewares.Recover())

// Enable default or custom CORS
mux.EnableCORS()

// Define a root route
mux.Route("/health").Get(healthCheckHandler)

// Create an authenticated sub-group
authGroup := mux.Group("/admin").Use(authMiddleware)

// Define specific nested routes using a GroupRouter closure
authGroup.Route("/users", func(r gohttputil.RouteHandler) {
    r.Use(roleMiddleware)
    r.Get(listUsersHandler)
    r.Post(createUserHandler)
})

Validation Middlewares

The library provides middlewares out of the box to validate request payloads and bind them directly into contexts safely.

Validate JSON
type CreateUserDTO struct {
	Name  string `json:"name" validate:"required,min=3"`
	Age   int    `json:"age" validate:"required,gte=18"`
}

mux.Route("/users").
    Use(middlewares.ValidateJSON(CreateUserDTO{})).
    Post(func(w http.ResponseWriter, r *http.Request) {
        // Retrieve safely bound pointer from context
        payload := middlewares.JSONPayload(r).(*CreateUserDTO)
        fmt.Fprintf(w, "User %s created", payload.Name)
    })
Validate Query Parameters
type SearchQuery struct {
	Tags []string `form:"tags[]" validate:"required,min=1"`
}

mux.Route("/search", func(r gohttputil.RouteHandler) {
    // Bind URL queries natively
    r.Use(middlewares.ValidateQuery(SearchQuery{}))
    r.Get(handleSearch)
})
Validate Form Data
type SubmitForm struct {
	Title string `form:"title" validate:"required"`
}

mux.Route("/submit").
    // Bind form-data and application/x-www-form-urlencoded
    Use(middlewares.ValidateForm(SubmitForm{})).
    Post(handleSubmit)

Note: Form validation only binds scalar values and arrays. For file uploads via multipart/form-data use the standard r.FormFile() or r.ParseMultipartForm() directly from the *http.Request in your handler.

Validate URL Path Values
type UserPathInfo struct {
	Id int `path:"id" validate:"required,gt=0"`
}

mux.Route("/users/{id}").
    Use(middlewares.ValidatePathValue(UserPathInfo{})).
    Get(func(w http.ResponseWriter, r *http.Request) {
        pathData := middlewares.PathValuePayload(r).(*UserPathInfo)
        fmt.Fprintf(w, "Fetching User ID: %d", pathData.Id)
    })

Error Formatting Design

When validation fails, go-httputil automatically formats the validation errors to structurally mirror the layout of your input DTO. This eliminates the need for clients to parse flat string paths ("Data.Addresses[0].Street").

Example Structure

Given a complex nested payload:

type Address struct {
	Street string `json:"street" validate:"required"`
}

type User struct {
	UserName  string    `json:"userName" validate:"required"`
	Addresses []Address `json:"addresses" validate:"required,dive"`
}

If the client submits an invalid payload, the middleware responds with a JSON error structure that identically maps the error keys back to the structure:

{
  "message": "Validation error",
  "status": false,
  "data": {
    "userName": "userName is a required field",
    "addresses": [
      {
        "street": "street is a required field"
      }
    ]
  }
}

This ensures frontend frameworks can dynamically map errors directly to form inputs using standard JSON layouts without custom parsers.

Extending Validation, Translations & Transformations

You can seamlessly register custom validation rules, translations, modifiers and scrubbers into the underlying go-playground/validator and go-playground/mold engines by using the provided wrapper functions.

import (
    "github.com/asif-mahmud/go-httputil/validator"
    vd "github.com/go-playground/validator/v10"
)

// 1. Register a custom validation tag
validator.RegisterValidator("is_awesome", func(fl vd.FieldLevel) bool {
    return fl.Field().String() == "awesome"
})

// 2. Register a custom error translation for a tag
validator.RegisterTranslation(validator.Translation{
    Tag:         "is_awesome",
    Translation: "{0} must be awesome",
    Override:    true,
})

// 3. Register a data modifier (e.g. data normalization before validation)
validator.RegisterModifier("uppercase", func(ctx context.Context, fl mold.FieldLevel) error {
    fl.Field().SetString(strings.ToUpper(fl.Field().String()))
    return nil
})

// 4. Register a data scrubber (e.g. sanitizing sensitive inputs)
validator.RegisterScrubber("redact", func(ctx context.Context, fl mold.FieldLevel) error {
    fl.Field().SetString("[REDACTED]")
    return nil
})

Authentication & Authorization

You can configure JWT settings globally and then chain standard JWT validation alongside Role-Based Access Control logic cleanly before your routes.

type UserClaims struct {
    Role string `json:"role"`
}

// 1. Setup global JWT configuration once
middlewares.SetupJWT(
	middlewares.JWTWithSecret("secret-key"),
	middlewares.JWTWithPayloadType(UserClaims{}), // Automatically map payload into context
)

mux := gohttputil.New()

// 2. Chain Authenticate and Authorize middlewares to specific routes
mux.Route("/admin").
    // Authenticate verifies the "Authorization" Bearer token
    Use(middlewares.Authenticate()).
    // Authorize natively checks the payload to enforce custom RBAC
    Use(middlewares.Authorize(func(r *http.Request) bool {
        claims := middlewares.JWTPayload(r).(*UserClaims)
        return claims.Role == "admin"
    })).
    Get(adminDashboardHandler)

Documentation

Overview

Example (Cors)

Example_cors sets up CORS preflight handler globally.

package main

import (
	"log"
	"net/http"

	gohttputil "github.com/asif-mahmud/go-httputil"
	"github.com/rs/cors"
)

func main() {
	// create mux instance
	m := gohttputil.New()

	// enable CORS handler globally with default
	// all allowed option
	m.EnableCORS()

	// or enable CORS handler with your own option
	m.EnableCORS(cors.Options{})

	// you can use the created mux now
	log.Fatal(http.ListenAndServe(":3000", m))

	// or you can use http.Server with handler set to the mux
	server := http.Server{
		Handler: m,
		Addr:    ":3000",
	}
	log.Fatal(server.ListenAndServe())
}
Example (Group)

Example_group shows grouping multiple routes

// create mux instance
m := gohttputil.New()

// define a group of routes
m.Group("/api/v1").
	// group level middlewares. these middlewares
	// will be applied to all routes defined in this group
	Use(groupMiddleware1).
	Use(groupMiddleware2).

	// define handlers for a route
	Route("/orders", func(rh gohttputil.RouteHandler) {
		rh.
			// no route level middleware will be applied to GET handler
			Get(handler1).

			// middleware1 will be applied to POST handler
			Use(middleware1).
			Post(handler1).

			// no middleware applied to PUT method handler
			Put(handler1)
	}).

	// define handlers for another route under same group
	Route("/users", func(rh gohttputil.RouteHandler) {
		rh.
			// no route level middleware will be applied to GET handler
			Get(handler1).

			// middleware1 will be applied to POST handler
			Use(middleware1).
			Post(handler1).

			// no middleware applied to PUT method handler
			Put(handler1)
	})
Example (SimpleRouting)

Example_simpleRouting shows defining routes

// create mux instance
m := gohttputil.New()

// add global middlewares.
// these middlewares will be applied to all routes.
m.
	Use(globalMiddleware1).
	Use(globalMiddleware2)

// define routes
m.Route("/api/order").
	// no middleware applied to GET method handler
	Get(handler1).

	// middleware1 and middleware2 are applied to POST method handler
	Use(middleware1).
	Use(middleware2).
	Post(handler2).

	// no middleware applied to PUT method handler
	Put(handler1).

	// only middleware1 applied to DELETE method handler
	Use(middleware1).
	Delete(handler2)

// you can use the created mux now
log.Fatal(http.ListenAndServe(":3000", m))

// or you can use http.Server with handler set to the mux
server := http.Server{
	Handler: m,
	Addr:    ":3000",
}
log.Fatal(server.ListenAndServe())

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Group

type Group interface {
	// Use adds middlewares to group level middleware list.
	// These middlewares are applied to all routes defined under this group.
	// This acts like global middlewares but applied only for this group.
	Use(...Middleware) Group

	// Route creates a new RouteHandler under the current Group and calls GroupRouter with it.
	// This lets user to define one or more routes under the current Group.
	Route(string, GroupRouter) Group
}

Group defines group level routing methods.

type GroupRouter

type GroupRouter func(RouteHandler)

GroupRouter defines function signature for group level router.

type Grouper

type Grouper interface {
	Group(string) Group
}

Grouper defines interface to create a new Group.

type Middleware

type Middleware func(http.Handler) http.Handler

Middleware defines simple middleware signature

type Mux

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

Mux is a wrapper around the http.ServeMux. It provides a http.Handler implementation that basically calls http.ServeMux.ServeHTTP with or without CORS wrapper.

Any route handler attached through this Mux adds that route to the internal http.ServeMux by wrapping middlewares from different levels (global, group level or route level).

Global middlewares are added by Mux.Use method. These middlewares are applied to all routes defined by this instance of the Mux.

Group level middlewares are only applied to the group routes.

Route level middlewares are applied per route per method.

func New

func New() *Mux

New creates a new instance of Mux.

func (*Mux) EnableCORS added in v0.9.0

func (m *Mux) EnableCORS(opt ...cors.Options)

EnableCORS wraps the internal http.ServeMux with CORS handler. Without any option in argument, it allows all methods, origins and headers.

func (*Mux) Group

func (m *Mux) Group(prefix string) Group

Group implements Grouper.

func (*Mux) Route

func (r *Mux) Route(route string) RouteHandler

Route implements Router.

func (*Mux) ServeHTTP

func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler. This calls the internal http.ServeMux.ServeHTTP with or without CORS wrapper handler.

func (*Mux) Use

func (r *Mux) Use(middlewares ...Middleware) *Mux

Use appends middlewares to global middlewares.

type RouteHandler

type RouteHandler interface {
	// Use adds middlewares to be used for the current route and current method.
	// This should be called before calling any of the http method handlers (Get,
	// Post, Put, Patch or Delete method). After calling an http method handler
	// this list of middlewares are cleared so that user can define different set
	// of middlewares for next http method handler. Soel middlewares
	// are defined per route per http method.
	Use(...Middleware) RouteHandler

	// Get attaches handler to http GET method
	Get(http.HandlerFunc) RouteHandler

	// Post attaches handler to http POST method
	Post(http.HandlerFunc) RouteHandler

	// Put attaches handler to http PUT method
	Put(http.HandlerFunc) RouteHandler

	// Patch attaches handler to http PATCH method
	Patch(http.HandlerFunc) RouteHandler

	// Delete attaches handler to http DELETE method
	Delete(http.HandlerFunc) RouteHandler
}

RouteHandler interface to configure route handlers.

type Router

type Router interface {
	Route(string) RouteHandler
}

Router interface to create a RouteHandler

Directories

Path Synopsis
Package helpers contains utility functions which are highly opionated and probably only applicable for specific use cases.
Package helpers contains utility functions which are highly opionated and probably only applicable for specific use cases.

Jump to

Keyboard shortcuts

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