git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/controller-handlers" ~/.claude/skills/majiayu000-claude-skill-registry-controller-handlers && rm -rf "$T"
skills/data/controller-handlers/SKILL.mdWriting Controller Handlers
Controller handler functions follow a standardized pattern with consistent return types and error handling.
Handler Function Signature
All handler functions use this signature:
func handlerName(_ http.ResponseWriter, req *http.Request) (*ModelType, int, error)
Parameters:
- ResponseWriter (unused, handled by wrapper)_
- HTTP request with context, params, and bodyreq
Returns:
- The response data (nil on error)*ModelType/ResponseDataType
- HTTP status code (200, 400, 404, etc.)int
- Error object (nil on success)error
Simple Handler Example
func adminGet(_ http.ResponseWriter, req *http.Request) (*account.AccountJoined, int, error) { // Get the URL parameter id := chi.URLParam(req, "id") // Fetch the model using the repository pattern accountObj, err := account.GetJoined(req.Context(), types.UUID(id)) if err != nil { log.ErrorContext(err, req.Context()) return helpers.AdminBadRequestError[*account.AccountJoined](err) } // Return success with the model data return helpers.Success(accountObj) }
Return Type Helpers
Success Response
return helpers.Success(data)
Returns:
(data, http.StatusOK, nil)
Admin Error Responses
For admin endpoints - returns full error details:
// Bad request with error message return helpers.AdminBadRequestError[*ModelType](err) // Returns: (zeroValue, http.StatusBadRequest, err) // Not found return helpers.AdminNotFoundError[*ModelType]() // Returns: (zeroValue, http.StatusNotFound, standardError) // Forbidden return helpers.AdminForbiddenError[*ModelType]() // Returns: (zeroValue, http.StatusForbidden, standardError)
Public Error Responses
For public endpoints - returns sanitized error messages:
// Bad request (generic public error) return helpers.PublicBadRequestError[*ModelType]() // Returns: (zeroValue, http.StatusBadRequest, publicError) // Not found return helpers.PublicNotFoundError[*ModelType]() // Returns: (zeroValue, http.StatusNotFound, publicError) // Forbidden return helpers.PublicForbiddenError[*ModelType]() // Returns: (zeroValue, http.StatusForbidden, publicError)
Important: Public errors never expose internal error details to users.
Accessing Request Data
URL Parameters
// Get URL parameter from route like /account/{id} id := chi.URLParam(req, "id") name := chi.URLParam(req, "name")
Session Data
// Get the current user session (available in all authenticated endpoints) userSession := helpers.GetReqSession(req) // returns a session object userObj := helpers.GetLoadedUser(req) // returns the actual user object, not a session wrap
POST/PUT Request Body
// For POST/PUT endpoints that are not the standard crud, use a struct for the input input := &MyPostData{} err := router.GetJSONPostDataStruct(req,input) doSomething(input.SomeDataHere)
Query Parameters
// Access query string parameters queryParams := req.URL.Query() page := queryParams.Get("page") limit := queryParams.Get("limit") // embeeded route params id := chi.URLParam(req, "id")
Common Handler Patterns
Error Logging
Always log errors with the context before returning up. The controller is the log point.
if err != nil { log.ErrorContext(err, req.Context()) return helpers.AdminBadRequestError[*ModelType](err) }
This ensures errors are captured in logs with full request context.
Handler Wrapper Usage
Handlers are wrapped in
setup.go:
// Admin endpoint - shows full errors helpers.RoleHandler(helpers.RoleHandlerMap{ constants.ROLE_ADMIN: helpers.StandardRequestWrapper(adminCreate), }) // Public endpoint - sanitizes errors helpers.RoleHandler(helpers.RoleHandlerMap{ constants.ROLE_ANY_AUTHORIZED: helpers.StandardPublicRequestWrapper(authGet), })
Request Wrapper Types
StandardRequestWrapper (Admin)
For admin endpoints:
helpers.StandardRequestWrapper(adminHandler)
Features:
- Returns full error details
- No field filtering
- Detailed error messages for debugging
StandardPublicRequestWrapper (Public)
For public/authenticated user endpoints:
helpers.StandardPublicRequestWrapper(authHandler)
Features:
- Filters response fields based on
tagspublic:"view" - Validates update fields based on
tagspublic:"edit" - Returns sanitized error messages
- Prevents internal error leakage
Security Best Practices
-
Use appropriate wrappers: Admin handlers with
, public handlers withStandardRequestWrapperStandardPublicRequestWrapper -
Verify ownership: In auth handlers, always verify the user owns the resource:
if accountObj.ID_.Get() != session.AccountID { return helpers.PublicForbiddenError[*account.Account]() }
-
Principle of least privilege: Use the lowest role required for each endpoint
-
Don't mix admin and public logic: Keep admin and auth handlers separate
Related Skills
- controller-roles - Role-based access control
- model-usage - Working with models