diff --git a/.claudeignore b/.claudeignore new file mode 100644 index 0000000..4697882 --- /dev/null +++ b/.claudeignore @@ -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/ + diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..610900f --- /dev/null +++ b/AGENTS.md @@ -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. + diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..bbbeffd --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,4 @@ +# CLAUDE.md + +Follow the repository instructions in [AGENTS.md](./AGENTS.md). + diff --git a/Makefile b/Makefile index b7c2ead..6b22772 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,3 @@ - .PHONY: fmt fmt: go fmt ./... @@ -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: diff --git a/README.md b/README.md index 70c55c0..40aaec6 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/go.mod b/go.mod index 6598396..b3a3c5f 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/maxwu/chainer -go 1.24 +go 1.26 require ( github.com/maxwu/gotest-labels v1.1.1 diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..f3ba969 --- /dev/null +++ b/mise.toml @@ -0,0 +1,2 @@ +[tools] +go = "1.26"