WeKnora Internal Handler Package: Controller Layer Architecture and Implementation
The internal/handler package in Tencent/WeKnora functions as the controller layer that exposes HTTP endpoints, enforces RBAC policies, translates incoming Gin requests into business logic operations, and manages asynchronous task queuing.
The internal/handler package implements the controller pattern in Tencent/WeKnora's Clean Architecture, sitting between the Gin HTTP router and the application service layer. This package handles request validation, permission checks, asynchronous job dispatching, and standardized error responses, ensuring that business logic remains pure and reusable across different transport mechanisms.
Core Responsibilities of the WeKnora Internal Handler Package
The WeKnora internal handler package manages six critical cross-cutting concerns that bridge the HTTP interface and domain logic.
HTTP Endpoint Exposure and Routing Integration
Each handler file defines a struct that implements Gin-compatible methods, which the router wires to specific paths. In internal/router/routes_knowledge.go, the RegisterKnowledgeRoutes function connects KnowledgeHandler methods to /knowledge endpoints:
r := router.Group("/api/v1")
g := router.NewRBACGuards(cfg)
handler.RegisterKnowledgeRoutes(r, knowledgeHandler, g)
The registration binds methods like CreateKnowledgeFromFile to their respective HTTP routes, keeping routing logic separate from request handling implementation.
Request Translation and Input Validation
Handlers extract and validate HTTP parameters before delegating to services. The CreateKnowledgeFromFile method in internal/handler/knowledge.go demonstrates this flow:
func (h *KnowledgeHandler) CreateKnowledgeFromFile(c *gin.Context) {
// Verify write permission on the target KB
kb, kbID, tenantID, _, err := h.validateKnowledgeBaseWriteAccessWithKBID(c, c.Param("id"))
if err != nil { return }
// Bind the multipart/form-data payload
var req types.KnowledgeFileRequest
if err := c.ShouldBind(&req); err != nil { /* handle error */ }
// Delegate to the service layer
knowledge, err := h.kgService.CreateFromFile(c.Request.Context(), kb, req)
if err != nil { /* handle error */ }
// Return success JSON
c.JSON(http.StatusCreated, gin.H{"success": true, "data": knowledge})
}
This pattern ensures that transport-layer concerns (JSON binding, context extraction) never leak into the service layer.
RBAC and Multi-Tenancy Enforcement
Before executing business operations, handlers verify authorization using middleware helpers. The internal/handler/knowledge.go file implements requireKBOwnershipOrAdmin and resolveKnowledgeAndValidateKBAccess to validate that callers own the target Knowledge Base or possess admin privileges. Similarly, internal/handler/auth.go enforces registration-mode restrictions during user signup flows.
These checks occur at the handler boundary, preventing unauthorized requests from reaching core business logic.
Asynchronous Task Management
For long-running operations, handlers enqueue background jobs using Asynq. The enqueueKnowledgeListDelete helper in internal/handler/knowledge.go constructs task payloads and dispatches them to the asynchronous processing queue:
func (h *KnowledgeHandler) enqueueKnowledgeListDelete(kbID uint, knowledgeIDs []uint) error {
payload := map[string]interface{}{
"kb_id": kbID,
"knowledge_ids": knowledgeIDs,
}
data, _ := json.Marshal(payload)
task := asynq.NewTask("knowledge:batch_delete", data)
_, err := h.asynqClient.Enqueue(task)
return err
}
This keeps HTTP response times fast while ensuring durable execution of expensive operations.
Standardized Error Handling and Response Formatting
The package centralizes error translation into the project's errors.AppError type. When services return failures, handlers convert them into consistent HTTP responses using constructors like errors.NewForbiddenError and errors.NewNotFoundError. The handleDuplicateKnowledgeError utility in internal/handler/knowledge.go provides reusable patterns for conflict scenarios, ensuring API consumers receive predictable JSON error structures.
Key Files in the WeKnora Handler Package
The controller layer comprises several specialized handler files and their router counterparts:
| File | Primary Responsibility |
|---|---|
internal/handler/knowledge.go |
Knowledge CRUD operations, permission helpers, and async task enqueueing |
internal/handler/auth.go |
Authentication endpoints, registration-mode validation, and user lifecycle |
internal/handler/knowledgebase.go |
Knowledge Base lifecycle management (create, copy, delete, update) |
internal/handler/chunk.go |
Document chunk operations including listing, updating, and deletion |
internal/router/routes_knowledge.go |
Route registration that wires handler methods to URL paths |
internal/router/router.go |
Gin engine initialization and RBAC guard injection |
Handler Initialization and Dependency Injection
Handlers receive their dependencies through constructor functions, facilitating testability and inversion of control. The NewKnowledgeHandler function accepts configuration, services, and infrastructure clients:
knowledgeHandler := handler.NewKnowledgeHandler(
cfg,
kgSvc, // Knowledge service
kbSvc, // Knowledge base service
kbShareSvc, // KB sharing service
agentShareSvc, // Agent sharing service
asynqClient, // Async task client
spanRepo, // Repository for knowledge spans
)
This explicit dependency injection pattern ensures handlers remain loosely coupled from their concrete implementations.
Summary
- The
internal/handlerpackage implements WeKnora's controller layer, sitting between the Gin router and application services. - Handlers validate incoming requests, enforce RBAC policies using helpers like
requireKBOwnershipOrAdmin, and extract validated inputs before calling services. - Asynchronous operations are dispatched via Asynq through helper methods like
enqueueKnowledgeListDelete, keeping HTTP responses immediate. - Consistent API error formatting is achieved through centralized utilities such as
handleDuplicateKnowledgeErrorand theerrors.AppErrortype system. - Key files including
knowledge.go,auth.go, andknowledgebase.goencapsulate domain-specific HTTP handling logic while maintaining clean architecture boundaries.
Frequently Asked Questions
How does the WeKnora internal handler package enforce security permissions?
The package implements permission checks through dedicated validation helpers defined in handler files. For example, internal/handler/knowledge.go contains validateKnowledgeBaseWriteAccessWithKBID and middleware-style functions like requireKBOwnershipOrAdmin that verify the caller is either the Knowledge Base creator or holds admin privileges before allowing write operations. These checks execute at the HTTP boundary before any service layer interaction occurs.
What is the relationship between handlers and the Gin router in WeKnora?
Handlers define methods that conform to Gin's handler signature (func(*gin.Context)), but route registration occurs separately in internal/router/routes_*.go files. The RegisterKnowledgeRoutes function in internal/router/routes_knowledge.go explicitly binds KnowledgeHandler instances to URL paths and applies RBAC guards. This separation keeps HTTP routing configuration distinct from request processing logic.
How does WeKnora handle long-running operations in the handler layer?
Handlers offload time-consuming tasks to background workers using Asynq. When processing batch deletions or other expensive operations, methods like enqueueKnowledgeListDelete create task payloads and enqueue them via asynq.NewTask. The handler returns an immediate HTTP response while the async worker processes the job durably, preventing request timeouts and improving API responsiveness.
Where is error handling standardized in the WeKnora handler package?
Error standardization occurs through the errors package integration and reusable handler utilities. When service calls fail, handlers wrap errors using typed constructors like errors.NewForbiddenError or errors.NewNotFoundError. The handleDuplicateKnowledgeError helper in internal/handler/knowledge.go demonstrates centralized patterns for specific error scenarios, ensuring all API responses follow a consistent JSON structure with appropriate HTTP status codes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →