Docs Handler

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:

  1. Read input from the request
  2. Invoke application logic
  3. 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.