noy

package module
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: May 9, 2026 License: MIT Imports: 1 Imported by: 0

README

noy

Go Reference

noy is a tiny typed layer over Go's standard net/http routing.

It keeps the standard library routing model, then adds one request-local state pointer that middleware and handlers can share without context.WithValue.

Install

go get github.com/ras0q/noy

What noy changes

In plain net/http, request-local application data usually moves through context.Context.

// In authentication middleware
ctx := context.WithValue(currentUserKey, authenticatedUser)
r = r.WithContext(ctx)

// In each handler
user := r.Context().Value(currentUserKey).(*User)

That works, but the compiler cannot prove that the key exists or that the value has the expected type.

With noy, your application declares one state type for request-local data.

type State struct {
	CurrentUser *User
	RequestID   string
}

Every typed middleware and handler receives *State.

See the _examples/ directory for more examples.

Request flow

For an authenticated API endpoint, the flow looks like this:

  1. A request enters noy.NewServeMux[State]().
  2. noy creates a fresh *State for that request.
  3. Auth middleware validates the Authorization header and sets state.CurrentUser.
  4. Other middleware can read or add request-local data, such as state.RequestID.
  5. The endpoint handler reads state.CurrentUser directly and writes the response.

The handler does not need to know how authentication loaded the user, and the authentication middleware does not need to hide values behind context keys.

func profile(state *State, w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, %s", state.CurrentUser.Name)
}

Middleware

Typed middleware wraps noy.HandlerFunc[State], so middleware can populate state before the final handler runs.

noymw provides small helpers for chaining typed middleware and adapting ordinary func(http.Handler) http.Handler middleware. See the noymw package documentation for details.

Standard net/http interop

noy stays close to the standard library:

  • route patterns and path values are handled by http.ServeMux
  • the mux can be passed anywhere an http.Handler is accepted
  • ordinary http.Handler and http.HandlerFunc values can still be mounted
  • existing standard middleware can be adapted with noymw

Documentation

Overview

Package noy adds typed, request-local state to applications built on net/http.

The core idea is that an application defines one state type for values that live for a single request. Middleware can populate that state with data such as authenticated users, request IDs, or loaded domain objects, and handlers can read those values through ordinary Go fields.

noy keeps routing and handler composition close to the standard library. The additional convention is explicit state passing, which keeps request-local data visible to the compiler instead of hiding it behind context keys.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type HandlerFunc

type HandlerFunc[State any] func(state *State, w http.ResponseWriter, r *http.Request)

HandlerFunc is a typed HTTP handler.

The state pointer is request-local and is passed before the ordinary http.ResponseWriter and *http.Request arguments.

type ServeMux

type ServeMux[State any] struct {
	// contains filtered or unexported fields
}

ServeMux is a typed wrapper around http.ServeMux.

Handlers registered with HandleFunc receive a new *State for every request. The mux still implements http.Handler, so it can be used anywhere a standard net/http handler is accepted.

func NewServeMux

func NewServeMux[State any]() *ServeMux[State]

NewServeMux creates a ServeMux whose typed handlers receive request-local state values of type State.

func (*ServeMux[State]) Handle

func (m *ServeMux[State]) Handle(pattern string, handler http.Handler)

Handle registers a standard http.Handler for pattern.

Use Handle for handlers that do not need typed state, or for mounting another mux that already owns its handler behavior.

func (*ServeMux[State]) HandleFunc

func (m *ServeMux[State]) HandleFunc(pattern string, handler HandlerFunc[State])

HandleFunc registers a typed handler for pattern.

Each request receives a fresh *State. Middleware and the final handler share that pointer for the lifetime of the request.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/ras0q/noy"
)

func main() {
	type User struct {
		Name string
	}
	type State struct {
		CurrentUser *User
	}

	users := map[string]*User{
		"secret": {Name: "Ada"},
	}
	authenticate := func(next noy.HandlerFunc[State]) noy.HandlerFunc[State] {
		return func(state *State, w http.ResponseWriter, r *http.Request) {
			token := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")
			user, ok := users[token]
			if !ok {
				http.Error(w, "unauthorized", http.StatusUnauthorized)
				return
			}

			state.CurrentUser = user
			next(state, w, r)
		}
	}
	mux := noy.NewServeMux[State]()
	mux.HandleFunc("GET /me", authenticate(func(state *State, w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "hello %s", state.CurrentUser.Name)
	}))

	req := httptest.NewRequest(http.MethodGet, "/me", nil)
	req.Header.Set("Authorization", "Bearer secret")
	res := httptest.NewRecorder()

	mux.ServeHTTP(res, req)

	fmt.Println(res.Body.String())

}
Output:
hello Ada

func (*ServeMux[State]) HandleStdFunc

func (m *ServeMux[State]) HandleStdFunc(pattern string, handler http.HandlerFunc)

HandleStdFunc registers a standard http.HandlerFunc for pattern.

Use HandleStdFunc for endpoints that should keep the ordinary net/http function signature.

func (*ServeMux[State]) ServeHTTP

func (m *ServeMux[State]) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler.

Directories

Path Synopsis
Package noymw provides middleware helpers for applications using noy.
Package noymw provides middleware helpers for applications using noy.

Jump to

Keyboard shortcuts

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