Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .claudeignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Local agent/runtime state
.omx/
.history/

# VCS and editor metadata
.git/
.vscode/

# Generated test and coverage artifacts
coverage.*
*.out
*.test

# Vendored dependencies
vendor/

34 changes: 34 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# AGENTS.md

## Project

`github.com/maxwu/chainer` is a small Go package for composing `net/http`
middleware into a final `http.Handler`.

## Working Rules

- Keep changes small, focused, and easy to review.
- Prefer the existing standard-library-first style; do not add dependencies
unless the task explicitly needs one.
- Preserve the public API unless the user asks for an API change.
- Update README examples when public usage changes.
- Do not commit generated coverage artifacts.

## Toolchain

- Go version: 1.26.
- Local toolchain is managed by `mise.toml`.
- In sandboxed environments, set `GOCACHE` to a writable temp directory if Go
tries to use a restricted cache path.

## Verification

Run the project test target before claiming completion:

```sh
GOCACHE=/private/tmp/chainer-go-build mise exec -- make test
```

The target runs formatting, vet, and the CI-aligned test command with race
detection and atomic coverage.

4 changes: 4 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# CLAUDE.md

Follow the repository instructions in [AGENTS.md](./AGENTS.md).

3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

.PHONY: fmt
fmt:
go fmt ./...
Expand All @@ -9,7 +8,7 @@ vet:

.PHONY: test
test: fmt vet
go test -coverprofile=coverage.out github.com/maxwu/chainer/... -v -ginkgo.v -ginkgo.progress -test.v
go test -v -count=1 -race -coverprofile=coverage.out -covermode=atomic ./... -labels env=ci

.PHONY: coverage
coverage:
Expand Down
71 changes: 62 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,81 @@
[![codecov](https://codecov.io/gh/maxwu/chainer/graph/badge.svg?token=JG5TC3BJIR)](https://codecov.io/gh/maxwu/chainer)
[![Go Report Card](https://goreportcard.com/badge/github.com/maxwu/chainer)](https://goreportcard.com/report/github.com/maxwu/chainer)

Assemble HTTP middleware functions to a http.Handler which processes the request in chained middleware order.
Chainer is a tiny Go package for assembling `net/http` middleware into a single
`http.Handler`. Links run in the order they are passed to `NewChain`, and each
link decides whether to continue to the next handler.

## Requirements

- Go 1.26
- Optional: [mise](https://mise.jdx.dev/) for local toolchain management

## Usage

Install the package:

```sh
go get github.com/maxwu/chainer
```

Create middleware links and assemble them into a handler:

```go
package main

import (
"log"
"net/http"

"github.com/maxwu/chainer"
)

func logger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
})
}

func requireAuth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Authorization") == "" {
http.Error(w, "missing authorization", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}

func hello(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("hello"))
}

func main() {
http.Handle("/", chainer.Chain(
chainer.MiddlewareFunc(logger),
chainer.MiddlewareFunc(authenticator),
chainer.MiddlewareFunc(authorizer),
chainer.MiddlewareFunc(handler),
))
http.ListenAndServe(":8080", nil)
handler := chainer.NewChain(
chainer.LinkFunc(logger),
chainer.LinkFunc(requireAuth),
chainer.LinkFunc(func(_ http.Handler) http.Handler {
return http.HandlerFunc(hello)
}),
).GetHandler()

http.Handle("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
```

## Development

Use `mise install` to install the configured Go toolchain, then run:

```sh
make test
```

## References

This project also demonstrates how to use [gotest-labels](github.com/maxwu/gotest-labels) package to select tests by the tags in test case comment block.
The test suite demonstrates
[gotest-labels](https://github.com/maxwu/gotest-labels) for selecting tests by
labels in test comment blocks.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/maxwu/chainer

go 1.24
go 1.26

require (
github.com/maxwu/gotest-labels v1.1.1
Expand Down
2 changes: 2 additions & 0 deletions mise.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[tools]
go = "1.26"
Loading