Controller
Controller chứa business logic của một service Fountain. Mỗi domain nghiệp vụ có một package riêng nằm dưới biz/core/<domain>/, và mỗi controller implement interface f_core.CoreController để framework có thể phát hiện, cài đặt và kết nối nó trong quá trình khởi động. ftkit verify thực thi các quy ước được mô tả dưới đây.
Cấu trúc của một controller
Mỗi domain dưới biz/core/ khai báo controller của nó trong file controller.go. File đó phải implement f_core.CoreController — tối thiểu là các method InstallController() và RegisterCallback(), tùy chọn thêm AfterInstalledDone().
controller.go chỉ dành riêng cho phần plumbing của controller. Bộ verifier (verifyControllerFileContents) chỉ cho phép các khai báo sau trong đó:
InstallController(),RegisterCallback(),AfterInstalledDone()— các method của interfaceCoreController.init()— dùng để đăng ký controller (xem bên dưới).- một accessor
Get<Name>ControllerInstance()duy nhất.
Bất kỳ business method nào khác phải được tách sang một file riêng trong cùng package. Giữ controller.go gọn nhẹ giúp việc đọc và review phần wiring vòng đời dễ dàng hơn.
// biz/core/orders/controller.go
package orders
type OrdersController struct {
// các dependency được inject (DAO, controller khác) — không chứa data struct
}
func (c *OrdersController) InstallController() error { /* wire DAO, dependency */ }
func (c *OrdersController) RegisterCallback(cb any) { /* lắng nghe sự kiện */ }Đăng ký
Controller tự đăng ký thông qua hàm init() của package, hàm này gọi f_core.RegisterCoreController(...). Package chỉ trở nên hoạt động khi nó được blank-import (file biz/biz.go blank-import mọi package biz/core/* chính vì lý do này). ftkit verify (verifyControllers) kiểm tra rằng mỗi domain có gọi RegisterCoreController.
Bản thân instance là một singleton được bảo vệ bằng sync.Once, nên việc đăng ký và accessor của instance an toàn để gọi nhiều lần mà không tạo ra bản sao trùng lặp. Bộ verifier cảnh báo khi một controller không sử dụng sync.Once.
var (
once sync.Once
instance *OrdersController
)
func GetOrdersControllerInstance() *OrdersController {
once.Do(func() { instance = &OrdersController{} })
return instance
}
func init() {
f_core.RegisterCoreController(GetOrdersControllerInstance())
}Framework gọi InstallController() sau khi tất cả dependency (logger, cache, database, DAO, client, server) đã được cài đặt, và dùng RegisterCallback() để kết nối các sự kiện observer xuyên controller.
Giá trị trả về error
Các exported method của controller phải trả về *froto.RpcError, không bao giờ trả về interface error thuần. ftkit verify (verifyControllerErrors) kiểm tra mọi exported function và method trong biz/core/*/ và đánh dấu lỗi với bất kỳ hàm nào khai báo kiểu trả về error. Một *froto.RpcError có kiểu cụ thể mang theo mã lỗi và thông điệp có cấu trúc mà tầng transport cần để dựng một response RPC/HTTP nhất quán.
// Đúng — error RPC có kiểu cụ thể
func (c *OrdersController) GetOrder(id string) (*models.Order, *froto.RpcError) {
// ...
}
// Bị ftkit verify từ chối — trả về error thuần
func (c *OrdersController) GetOrder(id string) (*models.Order, error) {
// ...
}Một quy tắc liên quan (verifyNoInterfaceParamsInControllers): bên ngoài controller.go, các function của controller không được nhận tham số interface{} / any. controller.go được miễn vì RegisterCallback(cb any) là một phần của interface CoreController.
Không khai báo data struct ở đây
File controller mô tả hành vi, không phải dữ liệu. Các kiểu dữ liệu — payload request/response, entity nghiệp vụ, cấu trúc lưu trữ — thuộc về biz/dal/do hoặc biz/dal/models. ftkit verify (verifyNoDataStructs) parse mọi file controller và từ chối bất kỳ struct nào có tên không kết thúc bằng một trong các hậu tố được phép sau:
ControllerDAO/DaoCallbackObserverAPIHandlerImpl
Mọi thứ khác (ví dụ type Order struct { ... }) phải được định nghĩa dưới biz/dal/do hoặc biz/dal/models. Điều này giữ cho tầng controller tập trung vào việc điều phối và tầng dữ liệu là nguồn chân lý duy nhất cho các cấu trúc dữ liệu.