1
0
mirror of https://github.com/raseels-repos/golang-saas-starter-kit.git synced 2025-08-08 22:36:41 +02:00

completed updating web-api

This commit is contained in:
Lee Brown
2019-08-14 12:53:40 -08:00
parent e45dd56149
commit 04e73c8f4e
17 changed files with 444 additions and 239 deletions

View File

@ -6,7 +6,6 @@ import (
"encoding/json"
"expvar"
"fmt"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
"log"
"net"
"net/http"
@ -21,18 +20,30 @@ import (
"geeks-accelerator/oss/saas-starter-kit/cmd/web-api/docs"
"geeks-accelerator/oss/saas-starter-kit/cmd/web-api/handlers"
"geeks-accelerator/oss/saas-starter-kit/internal/account"
"geeks-accelerator/oss/saas-starter-kit/internal/account/account_preference"
"geeks-accelerator/oss/saas-starter-kit/internal/mid"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/devops"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/flag"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/notify"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
"geeks-accelerator/oss/saas-starter-kit/internal/project"
"geeks-accelerator/oss/saas-starter-kit/internal/project_route"
"geeks-accelerator/oss/saas-starter-kit/internal/signup"
"geeks-accelerator/oss/saas-starter-kit/internal/user"
"geeks-accelerator/oss/saas-starter-kit/internal/user_account"
"geeks-accelerator/oss/saas-starter-kit/internal/user_account/invite"
"geeks-accelerator/oss/saas-starter-kit/internal/user_auth"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/go-redis/redis"
"github.com/gorilla/securecookie"
"github.com/kelseyhightower/envconfig"
"github.com/lib/pq"
"github.com/pkg/errors"
"golang.org/x/crypto/acme"
"golang.org/x/crypto/acme/autocert"
awstrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/aws/aws-sdk-go/aws"
@ -66,10 +77,9 @@ func main() {
// =========================================================================
// Logging
log.SetFlags(log.LstdFlags|log.Lmicroseconds|log.Lshortfile)
log.SetPrefix(service+" : ")
log := log.New(os.Stdout, log.Prefix() , log.Flags())
log.SetFlags(log.LstdFlags | log.Lmicroseconds | log.Lshortfile)
log.SetPrefix(service + " : ")
log := log.New(os.Stdout, log.Prefix(), log.Flags())
// =========================================================================
// Configuration
@ -87,16 +97,21 @@ func main() {
DisableHTTP2 bool `default:"false" envconfig:"DISABLE_HTTP2"`
}
Service struct {
Name string `default:"web-api" envconfig:"NAME"`
Project string `default:"" envconfig:"PROJECT"`
Name string `default:"web-api" envconfig:"SERVICE"`
BaseUrl string `default:"" envconfig:"BASE_URL" example:"http://api.example.saasstartupkit.com"`
HostNames []string `envconfig:"HOST_NAMES" example:"alternative-subdomain.example.saasstartupkit.com"`
EnableHTTPS bool `default:"false" envconfig:"ENABLE_HTTPS"`
TemplateDir string `default:"./templates" envconfig:"TEMPLATE_DIR"`
WebAppBaseUrl string `default:"http://127.0.0.1:3000" envconfig:"WEB_APP_BASE_URL" example:"www.example.saasstartupkit.com"`
DebugHost string `default:"0.0.0.0:4000" envconfig:"DEBUG_HOST"`
ShutdownTimeout time.Duration `default:"5s" envconfig:"SHUTDOWN_TIMEOUT"`
}
Project struct {
Name string `default:"" envconfig:"PROJECT"`
SharedTemplateDir string `default:"../../resources/templates/shared" envconfig:"SHARED_TEMPLATE_DIR"`
SharedSecretKey string `default:"" envconfig:"SHARED_SECRET_KEY"`
EmailSender string `default:"test@example.saasstartupkit.com" envconfig:"EMAIL_SENDER"`
WebAppBaseUrl string `default:"http://127.0.0.1:3000" envconfig:"WEB_APP_BASE_URL" example:"www.example.saasstartupkit.com"`
}
Redis struct {
Host string `default:":6379" envconfig:"HOST"`
DB int `default:"1" envconfig:"DB"`
@ -185,8 +200,8 @@ func main() {
// deployments and distributed to each instance of the service running.
if cfg.Aws.SecretsManagerConfigPrefix == "" {
var pts []string
if cfg.Service.Project != "" {
pts = append(pts, cfg.Service.Project)
if cfg.Project.Name != "" {
pts = append(pts, cfg.Project.Name)
}
pts = append(pts, cfg.Env, cfg.Service.Name)
@ -276,6 +291,37 @@ func main() {
awsSession = awstrace.WrapSession(awsSession)
}
// =========================================================================
// Shared Secret Key used for encrypting sessions and links.
// Set the secret key if not provided in the config.
if cfg.Project.SharedSecretKey == "" {
// AWS secrets manager ID for storing the session key. This is optional and only will be used
// if a valid AWS session is provided.
secretID := filepath.Join(cfg.Aws.SecretsManagerConfigPrefix, "sharedSecretKey")
// If AWS is enabled, check the Secrets Manager for the session key.
if awsSession != nil {
cfg.Project.SharedSecretKey, err = devops.SecretManagerGetString(awsSession, secretID)
if err != nil && errors.Cause(err) != devops.ErrSecreteNotFound {
log.Fatalf("main : Session : %+v", err)
}
}
// If the session key is still empty, generate a new key.
if cfg.Project.SharedSecretKey == "" {
cfg.Project.SharedSecretKey = string(securecookie.GenerateRandomKey(32))
if awsSession != nil {
err = devops.SecretManagerPutString(awsSession, secretID, cfg.Project.SharedSecretKey)
if err != nil {
log.Fatalf("main : Session : %+v", err)
}
}
}
}
// =========================================================================
// Start Redis
// Ensure the eviction policy on the redis cluster is set correctly.
@ -346,6 +392,31 @@ func main() {
}
defer masterDb.Close()
// =========================================================================
// Notify Email
var notifyEmail notify.Email
if awsSession != nil {
// Send emails with AWS SES. Alternative to use SMTP with notify.NewEmailSmtp.
notifyEmail, err = notify.NewEmailAws(awsSession, cfg.Project.SharedTemplateDir, cfg.Project.EmailSender)
if err != nil {
log.Fatalf("main : Notify Email : %+v", err)
}
err = notifyEmail.Verify()
if err != nil {
switch errors.Cause(err) {
case notify.ErrAwsSesIdentityNotVerified:
log.Printf("main : Notify Email : %s\n", err)
case notify.ErrAwsSesSendingDisabled:
log.Printf("main : Notify Email : %s\n", err)
default:
log.Fatalf("main : Notify Email Verify : %+v", err)
}
}
} else {
notifyEmail = notify.NewEmailDisabled()
}
// =========================================================================
// Init new Authenticator
var authenticator *auth.Authenticator
@ -360,11 +431,41 @@ func main() {
}
// =========================================================================
// Load middlewares that need to be configured specific for the service.
var serviceMiddlewares = []web.Middleware{
mid.Translator(webcontext.UniversalTranslator()),
// Init repositories and AppContext
projectRoute, err := project_route.New(cfg.Service.BaseUrl, cfg.Project.WebAppBaseUrl)
if err != nil {
log.Fatalf("main : project routes : %+v", cfg.Service.BaseUrl, err)
}
usrRepo := user.NewRepository(masterDb, projectRoute.UserResetPassword, notifyEmail, cfg.Project.SharedSecretKey)
usrAccRepo := user_account.NewRepository(masterDb)
accRepo := account.NewRepository(masterDb)
accPrefRepo := account_preference.NewRepository(masterDb)
authRepo := user_auth.NewRepository(masterDb, authenticator, usrRepo, usrAccRepo, accPrefRepo)
signupRepo := signup.NewRepository(masterDb, usrRepo, usrAccRepo, accRepo)
inviteRepo := invite.NewRepository(masterDb, usrRepo, usrAccRepo, accRepo, projectRoute.UserInviteAccept, notifyEmail, cfg.Project.SharedSecretKey)
prjRepo := project.NewRepository(masterDb)
appCtx := &handlers.AppContext{
Log: log,
Env: cfg.Env,
MasterDB: masterDb,
Redis: redisClient,
UserRepo: usrRepo,
UserAccountRepo: usrAccRepo,
AccountRepo: accRepo,
AccountPrefRepo: accPrefRepo,
AuthRepo: authRepo,
SignupRepo: signupRepo,
InviteRepo: inviteRepo,
ProjectRepo: prjRepo,
Authenticator: authenticator,
}
// =========================================================================
// Load middlewares that need to be configured specific for the service.
// Init redirect middleware to ensure all requests go to the primary domain contained in the base URL.
if primaryServiceHost != "127.0.0.1" && primaryServiceHost != "localhost" {
redirect := mid.DomainNameRedirect(mid.DomainNameRedirectConfig{
@ -380,9 +481,12 @@ func main() {
DomainName: primaryServiceHost,
HTTPSEnabled: cfg.Service.EnableHTTPS,
})
serviceMiddlewares = append(serviceMiddlewares, redirect)
appCtx.PostAppMiddleware = append(appCtx.PostAppMiddleware, redirect)
}
// Add the translator middleware for localization.
appCtx.PostAppMiddleware = append(appCtx.PostAppMiddleware, mid.Translator(webcontext.UniversalTranslator()))
// =========================================================================
// Start Tracing Support
th := fmt.Sprintf("%s:%d", cfg.Trace.Host, cfg.Trace.Port)
@ -443,7 +547,7 @@ func main() {
if cfg.HTTP.Host != "" {
api := http.Server{
Addr: cfg.HTTP.Host,
Handler: handlers.API(shutdown, log, cfg.Env, masterDb, redisClient, authenticator, serviceMiddlewares...),
Handler: handlers.API(shutdown, appCtx),
ReadTimeout: cfg.HTTP.ReadTimeout,
WriteTimeout: cfg.HTTP.WriteTimeout,
MaxHeaderBytes: 1 << 20,
@ -460,7 +564,7 @@ func main() {
if cfg.HTTPS.Host != "" {
api := http.Server{
Addr: cfg.HTTPS.Host,
Handler: handlers.API(shutdown, log, cfg.Env, masterDb, redisClient, authenticator, serviceMiddlewares...),
Handler: handlers.API(shutdown, appCtx),
ReadTimeout: cfg.HTTPS.ReadTimeout,
WriteTimeout: cfg.HTTPS.WriteTimeout,
MaxHeaderBytes: 1 << 20,