package main import ( "fmt" "log/slog" "net/http" "os" "time" "github.com/go-chi/chi/v5" chimw "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" "github.com/go-chi/httprate" "github.com/vectordns/server/internal/config" "github.com/vectordns/server/internal/handler" "github.com/vectordns/server/internal/middleware" ) func main() { cfg := config.Load() if cfg.LogFormat == "json" { slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, nil))) } r := chi.NewRouter() // Middleware stack r.Use(chimw.Recoverer) r.Use(chimw.RequestID) r.Use(chimw.RealIP) r.Use(slogMiddleware) r.Use(cors.Handler(cors.Options{ AllowedOrigins: cfg.CORSOrigins, AllowedMethods: []string{"GET", "POST", "OPTIONS"}, AllowedHeaders: []string{"Content-Type", "Authorization", "X-API-Key"}, MaxAge: 86400, })) r.Use(httprate.LimitByIP(60, time.Minute)) // Public routes r.Get("/healthz", handler.Health) // API routes (with API key auth) r.Route("/api/v1", func(r chi.Router) { r.Use(middleware.APIKey(cfg.APIKey)) r.Post("/dns/lookup", handler.DNSLookup) }) addr := fmt.Sprintf(":%s", cfg.Port) slog.Info("starting server", "addr", addr) if err := http.ListenAndServe(addr, r); err != nil { slog.Error("server failed", "error", err) os.Exit(1) } } func slogMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() ww := chimw.NewWrapResponseWriter(w, r.ProtoMajor) next.ServeHTTP(ww, r) slog.Info("request", "method", r.Method, "path", r.URL.Path, "status", ww.Status(), "duration_ms", time.Since(start).Milliseconds(), "request_id", chimw.GetReqID(r.Context()), ) }) }