Chuyển tới nội dung chính

Module

A Module in Tinh Tinh is a fundamental building block that encapsulates a cohesive set of controllers, providers (services), middleware, guards, and configuration. Modules enable you to organize your code into logical, reusable, and testable units, supporting both small and large-scale applications.

image

Modules can be composed, imported, and exported, allowing for hierarchical and feature-based app architecture—similar to dependency injection systems in other modern frameworks.


Module Features

  • Encapsulation: Bundle related controllers, providers, middleware, and guards in a single unit.
  • Dependency Injection: Register and inject services/providers with support for different lifecycles (Global, Request, Transient).
  • Composable Imports/Exports: Import other modules and export services/providers for reusability.
  • Hierarchical Structure: Model your app as a tree of modules, with clear boundaries and dependencies.
  • Custom Initialization: Use OnInit hooks for module-level bootstrapping.
  • Scoping: Define the visibility and lifecycle of providers within and across modules.
  • Middleware & Guards: Attach middleware and guards at module-level.
  • Extensibility: Add custom consumers, global interceptors, and more.

Creating a Module

The most common way is using core.NewModule with core.NewModuleOptions:

import "github.com/tinh-tinh/tinhtinh/v2/core"

func NewAppModule() core.Module {
return core.NewModule(core.NewModuleOptions{
Controllers: []core.Controllers{UserController, ArticleController},
Providers: []core.Providers{UserService},
Middlewares: []core.Middleware{LoggerMiddleware},
Imports: []core.Modules{OtherModule},
Exports: []core.Providers{UserService}, // Export providers for other modules
Scope: core.Global, // or core.Request, core.Transient
})
}

Passing Parameters to a Module

When initializing a module, you can pass configuration via the NewModuleOptions struct. Each module receives its own options, which can include:

  • Controllers: Array of controller constructors.
  • Providers: Array of provider/service constructors.
  • Imports: Other modules to import dependencies from.
  • Exports: Which providers/services to export.
  • Middlewares: Functions to run on all requests within the module.
  • Guards: Access control functions.
  • Scope: Singleton, per-request, or per-injection (Global, Request, Transient).
  • Custom Options: You can extend the pattern to accept custom configs in your own code.

Example:

type MyConfig struct {
Debug bool
}

// Pass as needed when constructing providers or wiring up modules
core.NewModule(core.NewModuleOptions{
Providers: []core.Providers{
func(module core.Module) core.Provider {
return module.NewProvider(core.ProviderOptions{
Name: "config",
Value: &MyConfig{Debug: true},
})
},
},
})

Hierarchical Modules: Multi-Module Initialization

Modules can import other modules, forming a tree-like structure. This enables clear separation of features and easy reusability.

func SubModule(module core.Module) core.Module {
sub := module.New(core.NewModuleOptions{
Controllers: []core.Controllers{SubController},
Providers: []core.Providers{SubService},
Exports: []core.Providers{SubService},
})
return sub
}

func ParentModule(module core.Module) core.Module {
parent := module.New(core.NewModuleOptions{
Imports: []core.Modules{SubModule},
Controllers: []core.Controllers{ParentController},
Providers: []core.Providers{ParentService},
Exports: []core.Providers{ParentService},
})
return parent
}

func AppModule() core.Module {
return core.NewModule(core.NewModuleOptions{
Imports: []core.Modules{ParentModule},
Controllers: []core.Controllers{AppController},
})
}
  • Importing: Use the Imports option to compose features.
  • Exporting: Use Exports to make providers/services available to parent modules.
  • Dependency Resolution: Providers and controllers can inject dependencies from their own module or any imported/exported modules.

Example: Minimal Module Setup

package app

import "github.com/tinh-tinh/tinhtinh/v2/core"

func NewModule() core.Module {
appModule := core.NewModule(core.NewModuleOptions{
Controllers: []core.Controllers{NewController},
Providers: []core.Providers{NewService},
})
return appModule
}

Module Hooks

  • OnInit: Register initialization hooks for setup logic inside the module.

Middleware and Guards

  • Use: Attach middleware to all controllers/routes inside the module.
  • Guard: Attach guards (authorization logic) to all controllers/routes inside the module.

Summary

  • Modules are the foundation of Tinh Tinh's architecture.
  • They enable encapsulation, hierarchy, dependency injection, and easy code organization.
  • Compose modules hierarchically to scale your application while maintaining separation of concerns and reusability.

For advanced patterns, see the source code and test files in /core.