A module must implement:
type Module interface {
Name() string
Mount(Router) error
Start(context.Context) error
Stop() error
}The functions run in this order. If Mount runs, Start has completed.
Start(context.Context)- start background goroutines or services.Mount(Router)- attach HTTP routes.Stop()- clean up and stop all background work.
The context passed to the Start function may be used to invoke
platform.FromContext(ctx) *Platform. This may then use the Find api to get a
reference to a side-loaded module. It can be used with interfaces.
An example of that would be a user module that provides a certain API.
type SessionService interface {
IsLoggedIn(context.Context) bool
GetSessionUser(context.Context) (*model.User, error)
}
var api SessionService
ok := platform.FromContext(r.Context()).Find(&api)Or it may expose its complete storage API:
type UserService interface {
SessionStorage() model.SessionStorage
UserStorage() model.UserStorage
}This allows API usage behind interfaces. In our case, we can expose
module-scoped functionality from the individual modules. It's also
possible to get a concrete *user.Handler type (no firewall).
Embed platform.UnimplementedModule to reduce boilerplate and override only methods you need:
type StaticModule struct {
platform.UnimplementedModule
}
func (m *StaticModule) Name() string { return "static" }
func (m *StaticModule) Mount(r platform.Router) error {
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("static page"))
})
return nil
}func main() {
// Register common middleware.
platform.Use(loggingMiddleware)
platform.Register(&StaticModule{})
if err := platform.Start(); err != nil {
log.Fatalf("exit error: %v", err)
}
}loggingMiddleware example:
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println(r.Method, r.URL.Path)
next.ServeHTTP(w, r)
})
}