Handler
In Plumego, a handler is the boundary.
It is the point where:
- HTTP-specific concerns end
- Application-specific logic begins
Handlers are intentionally simple and constrained.
They are not meant to be the center of your system — they are meant to be its edge.
The Role of a Handler
A Plumego handler exists to perform three tasks, in order:
- Read input from the request
- Invoke application logic
- Write the response
Nothing more.
If a handler does more than this, responsibilities are leaking.
A Minimal Handler Example
app.GET("/ping", func(ctx *plumego.Context) {
ctx.String(http.StatusOK, "pong")
})
This example is trivial, but it demonstrates the core idea:
- Input is implicit (no parameters)
- Application logic is trivial
- Output is explicit
As handlers grow more complex, the same structure should remain.
Handlers Are Not Business Logic
Handlers should not contain:
- Core business rules
- Complex decision trees
- Persistence logic
- Cross-request state
Instead, handlers should delegate to:
- Domain services
- Use cases
- Application services
Example:
func getUserHandler(ctx *plumego.Context) {
id := ctx.Param("id")
user, err := userService.GetByID(id)
if err != nil {
ctx.JSON(http.StatusNotFound, errorResponse(err))
return
}
ctx.JSON(http.StatusOK, user)
}
Here, the handler:
- Extracts input
- Calls a service
- Formats output
It does not decide what a user is or how it is retrieved.
Handlers as the HTTP Boundary
Handlers are allowed to know about:
- HTTP methods
- Status codes
- Headers
- Query parameters
- Request bodies
- Response formats
They should be the only place in your system where these concepts exist.
Domain and use-case code should remain HTTP-agnostic.
Error Handling in Handlers
Error handling in handlers should be:
- Explicit
- Local
- Predictable
A handler should decide:
- Which errors map to which HTTP status codes
- What response format to return
Plumego does not impose a global error-mapping mechanism by default.
This is a deliberate choice to keep behavior visible.
Handlers and Context Usage
Handlers receive a *plumego.Context.
Correct usage includes:
- Reading request data
- Accessing request-scoped metadata
- Writing responses
Incorrect usage includes:
- Passing context deeply into domain logic
- Storing long-lived state in context
- Treating context as a service locator
Context belongs at the boundary.
Handlers Should Be Thin
A useful guideline:
If a handler is hard to read, it is doing too much.
Signs a handler is too heavy:
- Large functions
- Nested conditionals
- Repeated logic across handlers
- Business terminology mixed with HTTP details
In these cases, extract logic into application services.
Handlers and Middleware: Clear Separation
Middleware and handlers serve different purposes.
- Middleware decides whether a request may proceed
- Handlers decide what the request does
If a handler performs authentication or authorization checks,
that logic likely belongs in middleware.
Testing Handlers
Because handlers are thin, they are easy to test:
- Mock or stub application services
- Simulate a request context
- Assert on response output
Well-structured handlers make HTTP-level testing straightforward.
What Handlers Deliberately Do Not Do
Plumego handlers do not:
- Automatically bind request bodies
- Perform validation implicitly
- Retry operations
- Manage transactions
- Trigger background jobs
All of these behaviors must be explicit.
Common Anti-Patterns
Fat Handlers
Handlers that contain most of the application logic are hard to maintain.
This often leads to:
- Duplication
- Tight coupling
- Poor testability
Passing Context Everywhere
Instead of:
service.Do(ctx)
Prefer:
service.Do(ctx.UserID())
Keep framework types at the edge.
Summary
In Plumego, handlers are:
- Explicit
- Thin
- Boundary-focused
- Responsible for HTTP concerns only
They connect the outside world to your application —
but they should never become your application.
Next
With handlers understood, the next concept is:
→ Router
This explains how requests are matched and dispatched to handlers.