Select Git revision
service.go 2.86 KiB
package service
import (
"context"
"os"
"gitlab.com/uafrica/go-utils/audit"
"gitlab.com/uafrica/go-utils/errors"
"gitlab.com/uafrica/go-utils/logger"
"gitlab.com/uafrica/go-utils/string_utils"
)
type Service interface {
logger.Logger
IErrorReporter
audit.Auditor
WithStarter(name string, starter IStarter) Service
WithProducer(producer Producer) Service
WithAuditor(auditor audit.Auditor) Service
WithErrorReporter(reporter IErrorReporter) Service
NewContext(base context.Context, requestID string, values map[string]interface{}) (Context, error)
}
func New() Service {
env := os.Getenv("ENVIRONMENT") //todo: support config loading for local dev and env for lambda in prod
if env == "" {
env = "dev"
}
return service{
Logger: logger.New().WithFields(map[string]interface{}{"env": env}),
IErrorReporter: DoNotReportErrors{},
Auditor: audit.None(),
env: env,
starters: map[string]IStarter{},
}
}
type service struct {
logger.Logger //for logging outside of context
Producer //for sending async events
IErrorReporter
audit.Auditor
env string
starters map[string]IStarter
}
func (s service) Env() string {
return s.env
}
//adds a starter function to call in each new context
//they will be called in the sequence they were added (before api/cron/queue checks)
//and they do not have details about the event
//if starter returns error, processing fails
//if starter succeeds, and return !=nil data, it is stored against the name
// so your handler can retieve it with:
// checkData := ctx.Value(name).(expectedType)
// or
// checkData,ok := ctx.Value(name).(expectedType)
// if !ok { ... }
//you can implement one starter that does everything and return a struct or
//implement one for your db, one for rate limit, one for ...
//the name must be snake-case, e.g. "this_is_my_starter_name"
func (s service) WithStarter(name string, starter IStarter) Service {
if !string_utils.IsSnakeCase(name) {
panic(errors.Errorf("invalid starter name=\"%s\", expecting snake_case names only", name))
}
if starter == nil {
panic(errors.Errorf("starter(%s)==nil", name))
}
if _, ok := s.starters[name]; ok {
panic(errors.Errorf("starter(%s) already defined", name))
}
s.starters[name] = starter
return s
}
func (s service) WithProducer(producer Producer) Service {
if producer != nil {
s.Producer = producer
}
return s
}
func (s service) WithErrorReporter(reporter IErrorReporter) Service {
if reporter == nil {
panic(errors.Errorf("ErrorReporter==nil"))
}
s.IErrorReporter = reporter
return s
}
func (s service) WithAuditor(auditor audit.Auditor) Service {
if auditor != nil {
s.Auditor = auditor
}
return s
}
type IErrorReporter interface {
ReportError(fields map[string]interface{}, err error)
}
type DoNotReportErrors struct{}
func (DoNotReportErrors) ReportError(fields map[string]interface{}, err error) {}