149 lines
4.1 KiB
Go
149 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"expvar"
|
|
"log"
|
|
"runtime"
|
|
"time"
|
|
|
|
"github.com/FernandoVideira/LK_API_Temp/internal/auth"
|
|
"github.com/FernandoVideira/LK_API_Temp/internal/db"
|
|
"github.com/FernandoVideira/LK_API_Temp/internal/env"
|
|
"github.com/FernandoVideira/LK_API_Temp/internal/mailer"
|
|
"github.com/FernandoVideira/LK_API_Temp/internal/ratelimiter"
|
|
"github.com/FernandoVideira/LK_API_Temp/internal/store"
|
|
"github.com/FernandoVideira/LK_API_Temp/internal/store/cache"
|
|
"github.com/go-redis/redis/v8"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
const version = "1.0.2"
|
|
|
|
// @title LK API Template
|
|
// @description This is a template for building APIs with Go, Chi, and Swagger.
|
|
// @termsOfService http://swagger.io/terms/
|
|
|
|
// @contact.name API Support
|
|
// @contact.url http://www.swagger.io/support
|
|
// @contact.email [email protected]
|
|
|
|
// @license.name Apache 2.0
|
|
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
|
|
|
// @BasePath /v1
|
|
//
|
|
// @securityDefinitions.apikey ApiKeyAuth
|
|
// @in header
|
|
// @name Authorization
|
|
// @description
|
|
func main() {
|
|
cfg := config{
|
|
addr: env.GetString("ADDR", ":8080"),
|
|
apiURL: env.GetString("EXTERNAL_URL", "localhost:8080"),
|
|
frontEndURL: env.GetString("FRONTEND_URL", "http://localhost:5173"),
|
|
db: dbConfig{
|
|
addr: env.GetString("DB_ADDR", "postgres://postgres:postgres@localhost:5432/lk_tmpl?sslmode=disable"),
|
|
maxOpenConns: env.GetInt("DB_MAX_OPEN_CONNS", 30),
|
|
maxIdleConns: env.GetInt("DB_MAX_IDLE_CONNS", 30),
|
|
maxIdleTime: env.GetDuration("DB_MAX_IDLE_TIME", "15m"),
|
|
},
|
|
redisCfg: redisConfig{
|
|
addr: env.GetString("REDIS_ADDR", "localhost:6379"),
|
|
pw: env.GetString("REDIS_PASSWORD", ""),
|
|
db: env.GetInt("REDIS_DB", 0),
|
|
enabled: env.GetBool("REDIS_ENABLED", false),
|
|
},
|
|
env: env.GetString("ENV", "development"),
|
|
mail: mailConfig{
|
|
exp: time.Hour * 24 * 3,
|
|
fromEmail: env.GetString("FROM_EMAIL", ""),
|
|
sendGrid: sendGridConfig{
|
|
apiKey: env.GetString("SENDGRID_API_KEY", ""),
|
|
},
|
|
},
|
|
auth: authConfig{
|
|
basic: basicConfig{
|
|
username: env.GetString("BASIC_AUTH_USERNAME", "admin"),
|
|
password: env.GetString("BASIC_AUTH_PASSWORD", "admin"),
|
|
},
|
|
token: tokenConfig{
|
|
secret: env.GetString("AUTH_TOKEN_SECRET", "secret"),
|
|
exp: env.GetDuration("AUTH_TOKEN_EXP", "24h"),
|
|
iss: env.GetString("AUTH_TOKEN_ISS", "lkapi"),
|
|
aud: env.GetString("AUTH_TOKEN_AUD", "lkapi"),
|
|
},
|
|
},
|
|
rateLimiter: ratelimiter.Config{
|
|
RequestsPerTimeFrame: env.GetInt("RATE_LIMITER_REQS_COUNT", 20),
|
|
TimeFrame: env.GetDuration("RATE_LIMITER_TIME_FRAME", "1m"),
|
|
Enabled: env.GetBool("RATE_LIMITER_ENABLED", true),
|
|
},
|
|
}
|
|
|
|
// Logger
|
|
logger := zap.Must(zap.NewProduction()).Sugar()
|
|
defer logger.Sync()
|
|
|
|
// Database
|
|
db, err := db.New(
|
|
cfg.db.addr,
|
|
cfg.db.maxOpenConns,
|
|
cfg.db.maxIdleConns,
|
|
cfg.db.maxIdleTime,
|
|
)
|
|
if err != nil {
|
|
logger.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
logger.Info("database connection established")
|
|
|
|
// Cache
|
|
var redisDb *redis.Client
|
|
if cfg.redisCfg.enabled {
|
|
redisDb = cache.NewRedisClient(cfg.redisCfg.addr, cfg.redisCfg.pw, cfg.redisCfg.db)
|
|
logger.Info("redis connection established")
|
|
}
|
|
|
|
// Rate Limiter
|
|
rateLimiter := ratelimiter.NewFixedWindowLimiter(
|
|
cfg.rateLimiter.RequestsPerTimeFrame,
|
|
cfg.rateLimiter.TimeFrame,
|
|
)
|
|
|
|
store := store.NewStorage(db)
|
|
cacheStorage := cache.NewRedisStorage(redisDb)
|
|
mailer := mailer.NewSendGrid(cfg.mail.sendGrid.apiKey, cfg.mail.fromEmail)
|
|
|
|
jwtAuthenticator := auth.NewJWTAuthenticator(
|
|
cfg.auth.token.secret,
|
|
cfg.auth.token.aud,
|
|
cfg.auth.token.iss,
|
|
)
|
|
|
|
api := api{
|
|
config: cfg,
|
|
store: store,
|
|
cacheStore: cacheStorage,
|
|
logger: logger,
|
|
mailer: mailer,
|
|
authenticator: jwtAuthenticator,
|
|
rateLimiter: rateLimiter,
|
|
}
|
|
|
|
// Metrics Collected
|
|
expvar.NewString("version").Set(version)
|
|
expvar.Publish("database", expvar.Func(func() any {
|
|
return db.Stats()
|
|
}))
|
|
expvar.Publish("redis", expvar.Func(func() any {
|
|
return redisDb.Info(context.Background(), "keyspace")
|
|
}))
|
|
expvar.Publish("goroutines", expvar.Func(func() any {
|
|
return runtime.NumGoroutine()
|
|
}))
|
|
|
|
mux := api.mount()
|
|
log.Fatal(api.run(mux))
|
|
}
|