Skip to content
Back to skills

Controller Handlers

ASecurity

Writing controller handler functions

  • 666 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added February 8, 2026
toolsgodebuggingsecurity

Security analysis

A100/100

Scanned February 10, 2026

npx -y skills add majiayu000/claude-skill-registry --skill controller-handlers --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Controller Handlers?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Controller Handlers
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-controller-handlers/badge)](https://www.skillsdirectory.com/skills/majiayu000-controller-handlers)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: controller-handlers
description: Writing controller handler functions
---

# Writing 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:

```go
func handlerName(_ http.ResponseWriter, req *http.Request) (*ModelType, int, error)
```

**Parameters:**
- `_` - ResponseWriter (unused, handled by wrapper)
- `req` - HTTP request with context, params, and body

**Returns:**
- `*ModelType/ResponseDataType` - The response data (nil on error)
- `int` - HTTP status code (200, 400, 404, etc.)
- `error` - Error object (nil on success)

## Simple Handler Example

```go
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

```go
return helpers.Success(data)
```

Returns: `(data, http.StatusOK, nil)`

### Admin Error Responses

For admin endpoints - returns full error details:

```go
// 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:

```go
// 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

```go
// Get URL parameter from route like /account/{id}
id := chi.URLParam(req, "id")
name := chi.URLParam(req, "name")
```

### Session Data

```go
// 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

```go
// 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

```go
// 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.

```go
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`:

```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:
```go
helpers.StandardRequestWrapper(adminHandler)
```

**Features:**
- Returns full error details
- No field filtering
- Detailed error messages for debugging

### StandardPublicRequestWrapper (Public)

For public/authenticated user endpoints:
```go
helpers.StandardPublicRequestWrapper(authHandler)
```

**Features:**
- Filters response fields based on `public:"view"` tags
- Validates update fields based on `public:"edit"` tags
- Returns sanitized error messages
- Prevents internal error leakage

## Security Best Practices

1. **Use appropriate wrappers**: Admin handlers with `StandardRequestWrapper`, public handlers with `StandardPublicRequestWrapper`

2. **Verify ownership**: In auth handlers, always verify the user owns the resource:
```go
if accountObj.ID_.Get() != session.AccountID {
    return helpers.PublicForbiddenError[*account.Account]()
}
```

3. **Principle of least privilege**: Use the lowest role required for each endpoint

4. **Don't mix admin and public logic**: Keep admin and auth handlers separate

## Related Skills

- [controller-roles](../controller-roles/SKILL.md) - Role-based access control
- [model-usage](../../model-usage/SKILL.md) - Working with models

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.