package runtime import ( "context" "os" "git.sendico.io/tech/sxchnge/product/app/api" amr "git.sendico.io/tech/sxchnge/product/app/health" "git.sendico.io/tech/sxchnge/product/app/health/status" httptransport "git.sendico.io/tech/sxchnge/product/app/http" "git.sendico.io/tech/sxchnge/product/app/urls" "git.sendico.io/tech/sxchnge/product/sessions/browser" "git.sendico.io/tech/sxchnge/shared/database" "git.sendico.io/tech/sxchnge/shared/errors" "git.sendico.io/tech/sxchnge/shared/logging" "git.sendico.io/tech/sxchnge/shared/service" "github.com/go-chi/chi/v5" "go.uber.org/zap" ) func CreateAPI( ctx context.Context, logger mlogger.Logger, config *api.Config, db db.Factory, rootRouter, apiRouter *chi.Mux, debug bool, runtime api.RuntimeConfig, ) (_ mservice.MicroService, result error) { if config == nil || config.Mw == nil { return nil, merrors.InvalidArgument("API middleware configuration is required") } endpoint := os.Getenv(config.Mw.EndPointEnv) mounts, err := resolveMounts(config.Versions, endpoint, runtime.Versions) if err != nil { return nil, err } if runtime.Bootstrap == nil { return nil, merrors.InvalidArgument("runtime bootstrap is required") } // Resolve every URL before opening resources or publishing routes. scopes := make([]api.Scope, len(mounts)) for i, mount := range mounts { urls, err := domainprovider.CreateDomainProvider(logger, os.Getenv(config.Mw.DomainEnv), os.Getenv(config.Mw.APIProtocolEnv), mount.Path) if err != nil { return nil, err } scopes[i] = api.Scope{Router: chi.NewRouter(), Mount: mount.Path, URLs: urls, Logger: logger.With(zap.String("api_version", mount.Version), zap.String("mount", mount.Path))} scopes[i].Router.Use(browser.Scope(mount.Path)) } a := &instance{logger: logger.Named("api").With(zap.String("runtime", runtime.RuntimeName()))} defer func() { if result != nil { if err := a.Finish(context.Background()); err != nil { a.logger.Warn("Failed startup resource cleanup", zap.Error(err)) } } }() a.mw, err = httptransport.CreateMiddleware(logger, apiRouter, config.Mw, endpoint, debug) if err != nil { return nil, err } deps, cleanup, err := runtime.Bootstrap(ctx, a.logger, config, db) a.cleanup = cleanup if err != nil { return nil, err } for i, mount := range mounts { if err := runtime.Versions[mount.Version](scopes[i], deps); err != nil { return nil, merrors.OpaqueWrap(merrors.ErrInternal, err, "API version installation failed: "+mount.Version) } } // Attach only after every installer succeeds. for i, mount := range mounts { apiRouter.Mount(mount.Path, scopes[i].Router) scopes[i].Logger.Info("API version installed") } a.health, err = amr.NewHealthRouter(a.logger, rootRouter, endpoint) if err != nil { return nil, err } a.logger.Info("API installation complete", zap.Int("versions", len(mounts))) a.health.SetStatus(health.SSRunning) return a, nil }