Files
LK_API_Temp/cmd/api/main.go
T
2025-03-31 18:05:01 +00:00

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))
}