Skip to content

Conversation

@kolkov
Copy link
Contributor

@kolkov kolkov commented Nov 24, 2025

Summary

Fixes critical routing bug where routes with :param followed by multiple static segments would panic.

Problem

Routes like /users/:id/activate + /users/:id/deactivate caused panic at line 147 in tree.go:

panic: internal error: no common prefix between "/deactivate" and ":id"

Root Cause

Common prefix check compared /deactivate with :id and found no match.

Solution

Implemented httprouter's production-quality pattern:

  • Create empty placeholder child nodes after param nodes
  • Bypass common prefix check for param node children
  • Use direct children assignment (n.children = []*node{child}) to allow empty path placeholders

Changes

  • internal/radix/tree.go (lines 118-138): Added special case handling for param node children
  • internal/radix/tree_param_static_test.go (new file): 6 comprehensive test cases
  • CHANGELOG.md: Documented v0.3.3 release

Testing

✅ All 650+ tests passing with race detector (WSL2 Gentoo)
✅ Coverage: 88.4% internal/radix, 91.7% overall (maintained)
✅ Linter: 0 issues (golangci-lint clean)
✅ Performance: No regressions (256 ns/op static, 326 ns/op parametric)
✅ CI: GREEN

Test Cases Added

  1. TestTree_ParamWithMultipleStaticChildren - Original bug case
  2. TestTree_NestedParams - Nested params (/users/:user_id/posts/:post_id/comments)
  3. TestTree_AlternatingParamStatic - Alternating pattern (/a/:b/c/:d/e)
  4. TestTree_ParamWithLongStaticTail - Long static tails (/:a/b/c/d/e/f/g)
  5. TestTree_ConsecutiveParams - Consecutive params (/:a/:b/:c/d)
  6. TestTree_StaticVsParam - Static priority over params

Reference

Studied httprouter implementation (tree.go lines 217-270, 180-184) for production-quality reference solution.

Checklist

  • Tests added and passing
  • Race detector passed
  • Linter clean
  • CHANGELOG updated
  • Performance validated
  • CI passing

## v0.2.0 Highlights (2025-01-18)

**Validator Plugin** (94.3% coverage)
- go-playground/validator/v10 integration
- Automatic request validation with 100+ tags
- RFC 9457 Problem Details error conversion
- 40+ default error messages, custom messages support

**Documentation Enhancements** (7,000+ lines)
- Middleware section in README.md (all 8 middleware)
- Automatic Validation section with examples
- Content Negotiation section (RFC 9110, AI agent support)
- Observability section (OpenTelemetry integration)
- llms.md - Complete AI agent guide (1,716 lines)

**Examples** (11 total, 5,000+ lines of code)
- Basic: 01-hello-world, 02-rest-api-crud
- Advanced: 04-content-negotiation, 05-middleware, 06-opentelemetry
- Validation: 6 progressive examples (3,762 lines)
- examples/README.md navigation guide

**Developer Experience**
- Progressive learning path (Beginner → Intermediate → Advanced)
- Total learning time: ~3.5 hours across all examples
- AI agent friendly documentation
- OPUS visibility fix - all middleware now discoverable

**Statistics**
- 25 commits squashed on develop branch
- 91.7% overall coverage (maintained)
- 94.3% validator plugin coverage
- 0 linter issues
- All pre-release checks passed
- Real-time: SSE + WebSocket via stream v0.1.0 integration
- Database: plugins/database with dbcontext pattern, transaction support
- Production: DDD boilerplate with 60%+ coverage, Docker support
- 4 new examples: SSE, WebSocket, Database, Production
- 650+ tests, 93.1% core coverage (+4.2%)
- Zero breaking changes, fully backward compatible
- Remove local path replace directive from go.mod
- Delete broken examples/09-rest-api-with-db/main.go (syntax errors)
- Format 9 files with gofmt (examples and production-boilerplate)
- Clean up go.mod dependencies (remove unused stream imports)

All pre-release checks now pass:
- ✅ Code formatting
- ✅ go vet
- ✅ Tests with race detector (91.7% coverage)
- ✅ golangci-lint (0 issues)
- Delete plugins_integration_test.go from root (redundant)
- Integration tests already exist in plugins/database/
- Core now has ONLY 2 dependencies: JWT + RateLimit
- Minimal dependencies policy fully enforced

This removes ~10 transitive deps from core module.
Fixes critical routing bug where routes with :param followed by multiple
static segments would panic. For example, registering both /users/:id/activate
and /users/:id/deactivate caused panic at line 147 in tree.go.

Root cause: Common prefix check compared /deactivate with :id and found
no match, causing "internal error: no common prefix" panic.

Solution: Implemented httprouter's pattern of creating empty placeholder
child nodes after param nodes and bypassing common prefix check when
inserting children of param nodes.

Changes:
- internal/radix/tree.go (lines 118-138): Added special case handling
  for param node children following httprouter's approach
- internal/radix/tree_param_static_test.go: Added 6 comprehensive test
  cases covering all param+static patterns

Testing:
- All 650+ tests passing with race detector (WSL2 Gentoo)
- Coverage maintained: 88.4% internal/radix, 91.7% overall
- Linter: 0 issues (golangci-lint clean)
- Performance: No regressions (256 ns/op static, 326 ns/op parametric)

Studied httprouter implementation (tree.go lines 217-270, 180-184) for
production-quality reference solution.
@codecov
Copy link

codecov bot commented Nov 24, 2025

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

ℹ️ You can also turn on project coverage checks and project coverage reporting on Pull Request comment

Thanks for integrating Codecov - We've got you covered ☂️

@kolkov
Copy link
Contributor Author

kolkov commented Nov 24, 2025

Closing PR - need to sync develop with main first before creating hotfix PR

@kolkov kolkov closed this Nov 24, 2025
@kolkov kolkov deleted the hotfix/v0.3.3 branch November 24, 2025 00:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants