From acdd29a70165a9084069152ab431753bc8888a5d Mon Sep 17 00:00:00 2001 From: Suhaib Date: Fri, 1 May 2026 15:52:19 -0700 Subject: [PATCH] docs: add AGENTS.md and refactor examples to use new() - Add comprehensive AGENTS.md documentation for Codex agents with build commands, architecture overview, and design patterns - Replace custom router.Ptr() helper with idiomatic Go new() function in examples for pointer creation --- AGENTS.md | 118 ++++++++++++++++++++++ README.md | 12 +-- docs/authentication.md | 10 +- docs/configuration.md | 2 +- docs/generic-routes.md | 2 +- docs/middleware.md | 2 +- docs/routing.md | 6 +- examples/auth-levels/main.go | 6 +- examples/auth/main.go | 2 +- examples/handler-error-middleware/main.go | 8 +- examples/nested-subrouters/main.go | 16 +-- examples/simple/main.go | 4 +- examples/subrouter-generic-routes/main.go | 8 +- examples/user-auth/main.go | 8 +- pkg/router/auth_middleware_test.go | 2 +- pkg/router/config.go | 7 +- pkg/router/handler_error_test.go | 8 +- pkg/router/register_generic_route_test.go | 4 +- pkg/router/subrouter_test.go | 20 ++-- 19 files changed, 179 insertions(+), 66 deletions(-) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..4e15a61 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,118 @@ +# AGENTS.md + +This file provides guidance to Codex (Codex.ai/code) when working with code in this repository. + +## Commands + +### Build and Development +```bash +# Run all tests +go test ./... + +# Run tests with verbose output +go test -v ./... + +# Run tests with coverage +go test -coverprofile=coverage.out ./... +go tool cover -html=coverage.out + +# Run a single test +go test -run TestName ./pkg/router + +# Run tests for a specific package +go test ./pkg/router/... + +# Build examples +cd examples/simple && go build +``` + +### Code Quality +```bash +# Format code +go fmt ./... + +# Run Go vet +go vet ./... + +# Install and run golangci-lint (if needed) +go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest +golangci-lint run +``` + +## Architecture Overview + +SRouter is a high-performance HTTP router framework built on `julienschmidt/httprouter` with Go generics support (requires Go 1.24.0+). The codebase follows a layered architecture with clear separation of concerns. + +### Core Type Parameters +Throughout the codebase, `T` represents the UserID type (must be comparable) and `U` represents the User object type. These generic parameters enable type-safe authentication and context management. + +### Package Structure +- **pkg/router/**: Core routing engine with generic route registration, middleware orchestration, and request handling +- **pkg/middleware/**: Authentication providers, rate limiting, tracing, and database transaction middleware +- **pkg/codec/**: Request/response marshaling interfaces and implementations (JSON, Protocol Buffers) +- **pkg/metrics/**: Interface-based metrics system for pluggable backends +- **pkg/scontext/**: Centralized context management with SRouterContext[T,U] wrapper +- **pkg/common/**: Shared types like Middleware, RateLimitConfig + +### Request Flow +1. HTTP Request → Router.ServeHTTP +2. CORS handling (if configured) +3. Client IP extraction based on IPConfig +4. Metrics and trace ID injection +5. httprouter path matching +6. Middleware chain execution (Recovery → Auth → RateLimit → Route-specific → Global → Timeout → Handler) +7. Generic handler marshaling/unmarshaling (if applicable) + +### Key Design Patterns +- **Middleware Chain**: Composable middleware with configurable execution order +- **Configuration Hierarchy**: Global → SubRouter → Route with cascading overrides +- **Generic Routes**: Type-safe handlers with automatic codec-based marshaling +- **Context Wrapper**: Single SRouterContext avoids deep context nesting + +### Testing Approach +The codebase maintains >90% coverage with comprehensive unit tests. Tests often use generic test helpers and mock interfaces (e.g., in router/internal/mocks/). + +## Important Concepts + +### Authentication Levels +Routes support three authentication levels: +- `NoAuth`: No authentication required +- `AuthOptional`: Authentication attempted but not required +- `AuthRequired`: Authentication mandatory + +Authentication is typically handled by middleware that populates the context using scontext helpers. + +### Rate Limiting +Flexible rate limiting with strategies: +- `StrategyIP`: Based on client IP +- `StrategyUser`: Based on authenticated user ID +- `StrategyCustom`: Custom key extraction + +Uses Uber's ratelimit library with leaky bucket algorithm. + +### Generic Route Registration +Generic routes should be registered using `NewGenericRouteDefinition` within SubRouterConfig.Routes for declarative configuration: +```go +router.NewGenericRouteDefinition[ReqType, RespType, UserIDType, UserType]( + router.RouteConfig[ReqType, RespType]{...} +) +``` + +### Context Access +Always use scontext package helpers for type-safe context access: +```go +userID, ok := scontext.GetUserIDFromRequest[T, U](r) +user, ok := scontext.GetUserFromRequest[T, U](r) // Returns *U +traceID := scontext.GetTraceIDFromRequest[T, U](r) +handlerErr, ok := scontext.GetHandlerErrorFromRequest[T, U](r) // For generic routes +``` + +### Handler Error Context +Generic routes automatically store handler errors in the request context, allowing middleware to access them after handler execution. This is useful for: +- Transaction rollback decisions +- Custom error logging +- Circuit breaker patterns +- Error metrics collection + +### Trace ID Generation +Enable trace ID generation by setting `TraceIDBufferSize > 0` in RouterConfig. This creates a background ID generator for efficient UUID generation and automatic request correlation. \ No newline at end of file diff --git a/README.md b/README.md index 094c36f..9b38b90 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,7 @@ apiV1SubRouter := router.SubRouterConfig{ router.RouteConfig[CreateUserReq, CreateUserResp]{ Path: "/users", // Path relative to the sub-router prefix (/api/v1/users) Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.AuthRequired), + AuthLevel: new(router.AuthRequired), Codec: codec.NewJSONCodec[CreateUserReq, CreateUserResp](), Handler: CreateUserHandler, // Middlewares, Timeout, MaxBodySize, RateLimit can be set here too @@ -291,7 +291,7 @@ router.RegisterGenericRoute[CreateUserReq, CreateUserResp, string, string](r, router.RouteConfig[CreateUserReq, CreateUserResp]{ Path: "/standalone/users", Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.AuthRequired), // Use Ptr helper + AuthLevel: new(router.AuthRequired), // Use Ptr helper Codec: codec.NewJSONCodec[CreateUserReq, CreateUserResp](), Handler: CreateUserHandler, }, @@ -700,9 +700,9 @@ When using the built-in `AuthOptional`/`AuthRequired` middleware, the token is e ```go // Example route configurations -routePublic := router.RouteConfigBase{ AuthLevel: router.Ptr(router.NoAuth), ... } -routeOptional := router.RouteConfigBase{ AuthLevel: router.Ptr(router.AuthOptional), ... } -routeProtected := router.RouteConfigBase{ AuthLevel: router.Ptr(router.AuthRequired), ... } +routePublic := router.RouteConfigBase{ AuthLevel: new(router.NoAuth), ... } +routeOptional := router.RouteConfigBase{ AuthLevel: new(router.AuthOptional), ... } +routeProtected := router.RouteConfigBase{ AuthLevel: new(router.AuthRequired), ... } ``` #### Authentication Middleware @@ -1060,7 +1060,7 @@ xmlRouteDef := router.NewGenericRouteDefinition[CreateUserReq, CreateUserResp, s router.RouteConfig[CreateUserReq, CreateUserResp]{ Path: "/api/users", Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.NoAuth), // Use Ptr helper + AuthLevel: new(router.NoAuth), // Use Ptr helper Codec: NewXMLCodec[CreateUserReq, CreateUserResp](), Handler: CreateUserHandler, // Assume handler exists }, diff --git a/docs/authentication.md b/docs/authentication.md index a560b14..f9a0ed4 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -27,23 +27,23 @@ routePublic := router.RouteConfigBase{ Path: "/public/info", // AuthLevel: nil, // Defaults to NoAuth // Or explicitly: - AuthLevel: router.Ptr(router.NoAuth), + AuthLevel: new(router.NoAuth), // ... handler, methods } routeOptional := router.RouteConfigBase{ Path: "/user/profile", // Maybe shows generic profile if not logged in, specific if logged in - AuthLevel: router.Ptr(router.AuthOptional), + AuthLevel: new(router.AuthOptional), // ... handler, methods } routeProtected := router.RouteConfig[UpdateSettingsReq, UpdateSettingsResp]{ Path: "/user/settings", - AuthLevel: router.Ptr(router.AuthRequired), // Must be logged in + AuthLevel: new(router.AuthRequired), // Must be logged in // ... handler, methods, codec } ``` -*(Note: `router.Ptr()` is a simple helper function to get a pointer to an `AuthLevel` value, as the config fields expect pointers)* +*(Note: `new()` is a simple helper function to get a pointer to an `AuthLevel` value, as the config fields expect pointers)* ## Authentication Functions (`NewRouter`) @@ -140,7 +140,7 @@ dummyGetIDFunc := func(user *MyUserType) string { return "" } // UserIDType and UserObjectType for NewRouter must match what MyApiKeyMiddleware puts in context r := router.NewRouter[string, MyUserType](routerConfig, dummyAuthFunc, dummyGetIDFunc) -// Routes using this custom middleware might set AuthLevel: router.Ptr(router.NoAuth) +// Routes using this custom middleware might set AuthLevel: new(router.NoAuth) // if MyApiKeyMiddleware handles all required/optional logic itself. ``` diff --git a/docs/configuration.md b/docs/configuration.md index 4aa8b39..d9dae9a 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -301,7 +301,7 @@ const ( ) // Ptr returns a pointer to an AuthLevel value (helper for config). -func Ptr(level AuthLevel) *AuthLevel { +funcnew(level AuthLevel) *AuthLevel { return &level } ``` diff --git a/docs/generic-routes.md b/docs/generic-routes.md index b0895e0..75364d4 100644 --- a/docs/generic-routes.md +++ b/docs/generic-routes.md @@ -50,7 +50,7 @@ type CreateUserResp struct { createUserRoute := router.RouteConfig[CreateUserReq, CreateUserResp]{ Path: "/users", Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.AuthRequired), // Example: Requires authentication + AuthLevel: new(router.AuthRequired), // Example: Requires authentication Codec: codec.NewJSONCodec[CreateUserReq, CreateUserResp](), // Specify the codec Handler: CreateUserHandler, // Assign the generic handler // Optional overrides for timeout, body size, or rate limit diff --git a/docs/middleware.md b/docs/middleware.md index 032aa0a..7c86a91 100644 --- a/docs/middleware.md +++ b/docs/middleware.md @@ -176,7 +176,7 @@ routerConfig := router.RouterConfig{ mymiddleware.LogUserIDMiddleware(logger), // Route: Runs last before handler }, Handler: GetUsersHandler, - AuthLevel: router.Ptr(router.AuthRequired), // Example: Requires authentication + AuthLevel: new(router.AuthRequired), // Example: Requires authentication }, // ... other v1 routes }, diff --git a/docs/routing.md b/docs/routing.md index d84fd13..3840388 100644 --- a/docs/routing.md +++ b/docs/routing.md @@ -39,7 +39,7 @@ apiV1SubRouter := router.SubRouterConfig{ router.RouteConfig[CreateUserReq, CreateUserResp]{ Path: "/users", // Path relative to the sub-router prefix (/api/v1/users) Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.AuthRequired), // Example: Requires authentication + AuthLevel: new(router.AuthRequired), // Example: Requires authentication Codec: codec.NewJSONCodec[CreateUserReq, CreateUserResp](), // Assume codec exists Handler: CreateUserHandler, // Assume this generic handler exists // Middlewares, Overrides can be set here too, overriding sub-router settings @@ -163,7 +163,7 @@ err := router.RegisterGenericRouteOnSubRouter[CreateUserReq, CreateUserResp]( router.RouteConfig[CreateUserReq, CreateUserResp]{ Path: "/users", // Path relative to the sub-router prefix Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.AuthRequired), + AuthLevel: new(router.AuthRequired), Codec: codec.NewJSONCodec[CreateUserReq, CreateUserResp](), Handler: CreateUserHandler, }, @@ -190,7 +190,7 @@ r := router.NewRouter[string, string](routerConfig, authFunction, userIdFromUser // Define a new sub-router adminSubRouter := router.SubRouterConfig{ PathPrefix: "/admin", - AuthLevel: router.Ptr(router.AuthRequired), // All admin routes require auth by default + AuthLevel: new(router.AuthRequired), // All admin routes require auth by default Routes: []router.RouteDefinition{ router.RouteConfigBase{ Path: "/users", diff --git a/examples/auth-levels/main.go b/examples/auth-levels/main.go index 9f89169..162eaff 100644 --- a/examples/auth-levels/main.go +++ b/examples/auth-levels/main.go @@ -126,13 +126,13 @@ func main() { router.RouteConfigBase{ Path: "/no-auth", Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.NoAuth), // Changed + AuthLevel: new(router.NoAuth), // Changed Handler: noAuthHandler, }, router.RouteConfigBase{ // Add explicit type Path: "/optional-auth", Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.AuthOptional), // Authentication is optional. OPTIONS requests are automatically allowed. + AuthLevel: new(router.AuthOptional), // Authentication is optional. OPTIONS requests are automatically allowed. Middlewares: []common.Middleware{ middleware.AuthenticationWithUser[*User](customUserAuth), // Middleware to add user to context if authenticated }, @@ -141,7 +141,7 @@ func main() { router.RouteConfigBase{ // Add explicit type Path: "/required-auth", Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.AuthRequired), // Authentication is required. OPTIONS requests are automatically allowed. + AuthLevel: new(router.AuthRequired), // Authentication is required. OPTIONS requests are automatically allowed. Middlewares: []common.Middleware{ middleware.AuthenticationWithUser[*User](customUserAuth), // Middleware to add user to context if authenticated }, diff --git a/examples/auth/main.go b/examples/auth/main.go index 74d6d32..40326d3 100644 --- a/examples/auth/main.go +++ b/examples/auth/main.go @@ -94,7 +94,7 @@ func main() { router.RouteConfigBase{ Path: "/resource", Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.AuthRequired), // Uses the router's internal authRequiredMiddleware. OPTIONS requests are automatically allowed. + AuthLevel: new(router.AuthRequired), // Uses the router's internal authRequiredMiddleware. OPTIONS requests are automatically allowed. Handler: protectedHandler, }, }, diff --git a/examples/handler-error-middleware/main.go b/examples/handler-error-middleware/main.go index bec8e4b..df9ba72 100644 --- a/examples/handler-error-middleware/main.go +++ b/examples/handler-error-middleware/main.go @@ -111,7 +111,7 @@ func main() { router.RegisterGenericRoute(r, router.RouteConfig[CreateUserRequest, CreateUserResponse]{ Path: "/users/success", Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.NoAuth), + AuthLevel: new(router.NoAuth), Middlewares: []common.Middleware{ TransactionMiddleware, ErrorLoggingMiddleware(logger), @@ -135,7 +135,7 @@ func main() { router.RegisterGenericRoute(r, router.RouteConfig[CreateUserRequest, CreateUserResponse]{ Path: "/users/validation-error", Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.NoAuth), + AuthLevel: new(router.NoAuth), Middlewares: []common.Middleware{ TransactionMiddleware, ErrorLoggingMiddleware(logger), @@ -154,7 +154,7 @@ func main() { router.RegisterGenericRoute(r, router.RouteConfig[CreateUserRequest, CreateUserResponse]{ Path: "/users/internal-error", Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.NoAuth), + AuthLevel: new(router.NoAuth), Middlewares: []common.Middleware{ TransactionMiddleware, ErrorLoggingMiddleware(logger), @@ -194,7 +194,7 @@ func main() { router.RegisterGenericRoute(r, router.RouteConfig[CreateUserRequest, CreateUserResponse]{ Path: "/users/custom-transaction", Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.NoAuth), + AuthLevel: new(router.NoAuth), Middlewares: []common.Middleware{ customTransactionMiddleware, ErrorLoggingMiddleware(logger), diff --git a/examples/nested-subrouters/main.go b/examples/nested-subrouters/main.go index bf15916..439bb85 100644 --- a/examples/nested-subrouters/main.go +++ b/examples/nested-subrouters/main.go @@ -122,7 +122,7 @@ func main() { router.RouteConfigBase{ // This type was already added, just confirming context Path: "", // Becomes /api/v1/users Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.NoAuth), // Changed + AuthLevel: new(router.NoAuth), // Changed Handler: func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"users":[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"},{"id":3,"name":"Charlie"}]}`)) @@ -139,7 +139,7 @@ func main() { router.RouteConfigBase{ // Add explicit type Path: "/hello", // Becomes /api/v1/hello Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.NoAuth), // Changed + AuthLevel: new(router.NoAuth), // Changed Handler: func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"message":"Hello from API v1!"}`)) @@ -169,7 +169,7 @@ func main() { router.RouteConfigBase{ // Add explicit type Path: "/hello", // Becomes /api/v2/hello Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.NoAuth), // Changed + AuthLevel: new(router.NoAuth), // Changed Handler: func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"message":"Hello from API v2!"}`)) @@ -186,7 +186,7 @@ func main() { router.RouteConfigBase{ // Add explicit type Path: "/status", // Becomes /api/status Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.NoAuth), // Changed + AuthLevel: new(router.NoAuth), // Changed Handler: func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"status":"ok"}`)) @@ -220,7 +220,7 @@ func main() { router.RouteConfig[GreetingRequest, GreetingResponse]{ Path: "/greet", // Relative path Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.NoAuth), // Changed + AuthLevel: new(router.NoAuth), // Changed Codec: greetingCodec, Handler: greetingHandler, }, @@ -236,7 +236,7 @@ func main() { router.RouteConfig[UserRequest, UserResponse]{ Path: "/info", // Relative path Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.NoAuth), // Changed + AuthLevel: new(router.NoAuth), // Changed Codec: userCodec, Handler: userHandler, }, @@ -252,7 +252,7 @@ func main() { router.RouteConfig[UserRequest, UserResponse]{ Path: "/info", // Relative path Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.NoAuth), // Changed + AuthLevel: new(router.NoAuth), // Changed Codec: userCodec, Handler: userHandler, }, @@ -268,7 +268,7 @@ func main() { router.RouteConfig[ProfileRequest, ProfileResponse]{ Path: "/profile", // Relative path Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.AuthRequired), // Changed - This route requires authentication + AuthLevel: new(router.AuthRequired), // Changed - This route requires authentication Codec: profileCodec, Handler: profileHandler, }, diff --git a/examples/simple/main.go b/examples/simple/main.go index feb0a95..ecfc935 100644 --- a/examples/simple/main.go +++ b/examples/simple/main.go @@ -65,7 +65,7 @@ func main() { router.RouteConfigBase{ Path: "/health", Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.NoAuth), // Changed + AuthLevel: new(router.NoAuth), // Changed Handler: HealthCheckHandler, }, }, @@ -100,7 +100,7 @@ func main() { userRouteConfig := router.RouteConfig[CreateUserReq, CreateUserResp]{ Path: "/users", // Relative path Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.AuthRequired), // Changed + AuthLevel: new(router.AuthRequired), // Changed Overrides: common.RouteOverrides{ Timeout: 3 * time.Second, // Route-specific override (will be used by getEffectiveTimeout) }, diff --git a/examples/subrouter-generic-routes/main.go b/examples/subrouter-generic-routes/main.go index 4ad0b2a..1e1695d 100644 --- a/examples/subrouter-generic-routes/main.go +++ b/examples/subrouter-generic-routes/main.go @@ -93,7 +93,7 @@ func main() { router.RouteConfigBase{ Path: "/hello", Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.NoAuth), + AuthLevel: new(router.NoAuth), Handler: func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"message":"Hello from API v1!"}`)) @@ -104,7 +104,7 @@ func main() { router.RouteConfig[GreetingRequest, GreetingResponse]{ Path: "/greet", // Path relative to the sub-router prefix Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.NoAuth), + AuthLevel: new(router.NoAuth), Codec: greetingCodec, Handler: greetingHandler, }, @@ -121,7 +121,7 @@ func main() { router.RouteConfig[UserRequest, UserResponse]{ Path: "/users", Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.NoAuth), + AuthLevel: new(router.NoAuth), Codec: userCodec, Handler: userHandler, }, @@ -131,7 +131,7 @@ func main() { router.RouteConfig[GreetingRequest, GreetingResponse]{ Path: "/greet", Methods: []router.HttpMethod{router.MethodPost}, - AuthLevel: router.Ptr(router.NoAuth), + AuthLevel: new(router.NoAuth), Codec: greetingCodec, Handler: greetingHandler, }, diff --git a/examples/user-auth/main.go b/examples/user-auth/main.go index e2d9d57..729b298 100644 --- a/examples/user-auth/main.go +++ b/examples/user-auth/main.go @@ -134,7 +134,7 @@ func main() { router.RouteConfigBase{ Path: "/resource", Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.NoAuth), // Changed + AuthLevel: new(router.NoAuth), // Changed Handler: publicHandler, }, }, @@ -145,7 +145,7 @@ func main() { router.RouteConfigBase{ Path: "/resource", Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.AuthRequired), // Changed + AuthLevel: new(router.AuthRequired), // Changed Middlewares: []common.Middleware{ middleware.AuthenticationBool[*User, User](func(r *http.Request) bool { // Simple boolean authentication @@ -168,7 +168,7 @@ func main() { router.RouteConfigBase{ Path: "/custom", Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.AuthRequired), // Changed + AuthLevel: new(router.AuthRequired), // Changed Middlewares: []common.Middleware{ // Uncommented middleware middleware.AuthenticationWithUser[*User, User](customUserAuth), }, @@ -177,7 +177,7 @@ func main() { router.RouteConfigBase{ // Add explicit type Path: "/bearer", Methods: []router.HttpMethod{router.MethodGet}, - AuthLevel: router.Ptr(router.AuthRequired), // Changed + AuthLevel: new(router.AuthRequired), // Changed Middlewares: []common.Middleware{ // Uncommented middleware middleware.NewBearerTokenWithUserMiddleware[*User, User](bearerTokenUserAuth, logger), }, diff --git a/pkg/router/auth_middleware_test.go b/pkg/router/auth_middleware_test.go index 17b65d3..c3c9e44 100644 --- a/pkg/router/auth_middleware_test.go +++ b/pkg/router/auth_middleware_test.go @@ -417,7 +417,7 @@ func TestAuthMiddlewareIntegration(t *testing.T) { r.RegisterRoute(RouteConfigBase{ Path: "/protected", Methods: []HttpMethod{MethodGet}, // Use HttpMethod enum - AuthLevel: Ptr(AuthRequired), + AuthLevel: new(AuthRequired), Handler: func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("Protected")) diff --git a/pkg/router/config.go b/pkg/router/config.go index 5ae1f0d..06586a4 100644 --- a/pkg/router/config.go +++ b/pkg/router/config.go @@ -8,6 +8,7 @@ import ( "github.com/Suhaibinator/SRouter/pkg/codec" "github.com/Suhaibinator/SRouter/pkg/common" + // Removed: "github.com/Suhaibinator/SRouter/pkg/middleware" "go.uber.org/zap" ) @@ -231,9 +232,3 @@ type RouteConfig[T any, U any] struct { // When used with RegisterGenericRoute, the framework automatically handles decoding the // request and encoding the response using the specified Codec. type GenericHandler[T any, U any] func(r *http.Request, data T) (U, error) - -// Ptr returns a pointer to the given AuthLevel value. -// Useful for setting AuthLevel fields in configurations. -func Ptr(level AuthLevel) *AuthLevel { - return &level -} diff --git a/pkg/router/handler_error_test.go b/pkg/router/handler_error_test.go index afc5120..862558b 100644 --- a/pkg/router/handler_error_test.go +++ b/pkg/router/handler_error_test.go @@ -61,7 +61,7 @@ func TestGenericRouteHandlerError(t *testing.T) { RegisterGenericRoute(router, RouteConfig[TestRequest, TestResponse]{ Path: "/error", Methods: []HttpMethod{MethodGet}, - AuthLevel: Ptr(NoAuth), + AuthLevel: new(NoAuth), Middlewares: []common.Middleware{errorCheckingMiddleware}, Handler: func(r *http.Request, req TestRequest) (TestResponse, error) { return TestResponse{}, expectedErr @@ -101,7 +101,7 @@ func TestGenericRouteHandlerError(t *testing.T) { RegisterGenericRoute(router, RouteConfig[TestRequest, TestResponse]{ Path: "/success", Methods: []HttpMethod{MethodGet}, - AuthLevel: Ptr(NoAuth), + AuthLevel: new(NoAuth), Middlewares: []common.Middleware{errorCheckingMiddleware}, Handler: func(r *http.Request, req TestRequest) (TestResponse, error) { return TestResponse{Result: "success"}, nil @@ -146,7 +146,7 @@ func TestGenericRouteHandlerError(t *testing.T) { RegisterGenericRoute(router, RouteConfig[TestRequest, TestResponse]{ Path: "/custom-error", Methods: []HttpMethod{MethodGet}, - AuthLevel: Ptr(NoAuth), + AuthLevel: new(NoAuth), Middlewares: []common.Middleware{errorCheckingMiddleware}, Handler: func(r *http.Request, req TestRequest) (TestResponse, error) { return TestResponse{}, customErr @@ -217,7 +217,7 @@ func TestHandlerErrorWithMultipleMiddleware(t *testing.T) { RegisterGenericRoute(router, RouteConfig[TestRequest, TestResponse]{ Path: "/multi-middleware", Methods: []HttpMethod{MethodGet}, - AuthLevel: Ptr(NoAuth), + AuthLevel: new(NoAuth), Middlewares: []common.Middleware{ createMiddleware("outer"), createMiddleware("inner"), diff --git a/pkg/router/register_generic_route_test.go b/pkg/router/register_generic_route_test.go index e2b7169..0b9fa95 100644 --- a/pkg/router/register_generic_route_test.go +++ b/pkg/router/register_generic_route_test.go @@ -285,7 +285,7 @@ func TestRegisterGenericRouteWithAuthRequired(t *testing.T) { Codec: codec.NewJSONCodec[RequestType, ResponseType](), Handler: testGenericHandler[RequestType, ResponseType], SourceType: Body, - AuthLevel: Ptr(AuthRequired), // Changed + AuthLevel: new(AuthRequired), // Changed }, time.Duration(0), int64(0), nil) // Added effective settings reqBody := RequestType{ID: "123", Name: "John"} @@ -323,7 +323,7 @@ func TestRegisterGenericRouteWithAuthOptional(t *testing.T) { Codec: codec.NewJSONCodec[RequestType, ResponseType](), Handler: testGenericHandler[RequestType, ResponseType], SourceType: Body, - AuthLevel: Ptr(AuthOptional), // Changed + AuthLevel: new(AuthOptional), // Changed }, time.Duration(0), int64(0), nil) // Added effective settings // With valid token diff --git a/pkg/router/subrouter_test.go b/pkg/router/subrouter_test.go index fb11bd3..dd1b6ce 100644 --- a/pkg/router/subrouter_test.go +++ b/pkg/router/subrouter_test.go @@ -34,7 +34,7 @@ func TestRegisterSubRouterWithCaching(t *testing.T) { Path: "/hello", Methods: []HttpMethod{MethodGet}, Handler: handler, - AuthLevel: Ptr(NoAuth), // Changed + AuthLevel: new(NoAuth), // Changed }, }, } @@ -97,7 +97,7 @@ func TestRegisterSubRouterWithCachingNonGetMethod(t *testing.T) { Path: "/hello", Methods: []HttpMethod{MethodPost}, // Non-GET method Handler: handler, - AuthLevel: Ptr(NoAuth), // Changed + AuthLevel: new(NoAuth), // Changed }, }, } @@ -146,7 +146,7 @@ func TestRegisterSubRouterWithCachingErrorCoverage(t *testing.T) { // Renamed to Path: "/hello", Methods: []HttpMethod{MethodGet}, Handler: handler, - AuthLevel: Ptr(NoAuth), // Changed + AuthLevel: new(NoAuth), // Changed }, }, } @@ -240,7 +240,7 @@ func TestRegisterSubRouter(t *testing.T) { RouteConfigBase{ Path: "/users", Methods: []HttpMethod{MethodGet}, - AuthLevel: Ptr(NoAuth), // Changed + AuthLevel: new(NoAuth), // Changed Handler: func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -250,7 +250,7 @@ func TestRegisterSubRouter(t *testing.T) { RouteConfigBase{ // Add explicit type Path: "/protected", Methods: []HttpMethod{MethodGet}, - AuthLevel: Ptr(AuthRequired), // Changed + AuthLevel: new(AuthRequired), // Changed Handler: func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -260,7 +260,7 @@ func TestRegisterSubRouter(t *testing.T) { RouteConfigBase{ // Add explicit type Path: "/custom-timeout", Methods: []HttpMethod{MethodGet}, - AuthLevel: Ptr(NoAuth), // Changed + AuthLevel: new(NoAuth), // Changed Overrides: common.RouteOverrides{Timeout: 1 * time.Second}, // Override sub-router timeout Handler: func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") @@ -271,7 +271,7 @@ func TestRegisterSubRouter(t *testing.T) { RouteConfigBase{ // Add explicit type Path: "/custom-body-size", Methods: []HttpMethod{MethodPost}, - AuthLevel: Ptr(NoAuth), // Changed + AuthLevel: new(NoAuth), // Changed Overrides: common.RouteOverrides{MaxBodySize: 512}, // Override sub-router max body size Handler: func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") @@ -282,7 +282,7 @@ func TestRegisterSubRouter(t *testing.T) { RouteConfigBase{ // Add explicit type Path: "/custom-rate-limit", Methods: []HttpMethod{MethodGet}, - AuthLevel: Ptr(NoAuth), // Changed + AuthLevel: new(NoAuth), // Changed Overrides: common.RouteOverrides{ RateLimit: &common.RateLimitConfig[any, any]{ // Use common.RateLimitConfig Limit: 5, @@ -298,7 +298,7 @@ func TestRegisterSubRouter(t *testing.T) { RouteConfigBase{ // Add explicit type Path: "/custom-middleware", Methods: []HttpMethod{MethodGet}, - AuthLevel: Ptr(NoAuth), // Changed + AuthLevel: new(NoAuth), // Changed Middlewares: []common.Middleware{ func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -410,7 +410,7 @@ func TestRegisterSubRouterWithoutCaching(t *testing.T) { RouteConfigBase{ Path: "/users", Methods: []HttpMethod{MethodGet}, - AuthLevel: Ptr(NoAuth), // Changed + AuthLevel: new(NoAuth), // Changed Handler: func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK)