Version 1
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
package httpx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
chimiddleware "github.com/go-chi/chi/v5/middleware"
|
||||
|
||||
"royal-pop-backend/internal/config"
|
||||
"royal-pop-backend/internal/database"
|
||||
"royal-pop-backend/internal/inventory"
|
||||
"royal-pop-backend/internal/mailer"
|
||||
"royal-pop-backend/internal/orders"
|
||||
)
|
||||
|
||||
type RouterConfig struct {
|
||||
Config *config.Config
|
||||
DB *database.DB
|
||||
Orders *orders.Store
|
||||
Stock *inventory.Store
|
||||
Mailer *mailer.ResendMailer
|
||||
}
|
||||
|
||||
func NewRouter(cfg RouterConfig) http.Handler {
|
||||
router := chi.NewRouter()
|
||||
|
||||
router.Use(chimiddleware.RealIP)
|
||||
router.Use(chimiddleware.RequestID)
|
||||
router.Use(chimiddleware.Recoverer)
|
||||
router.Use(chimiddleware.Timeout(30 * time.Second))
|
||||
router.Use(corsMiddleware(cfg.Config.AllowedOrigins))
|
||||
|
||||
router.Get("/healthz", func(w http.ResponseWriter, _ *http.Request) {
|
||||
databaseStatus := "disabled"
|
||||
if cfg.DB != nil {
|
||||
healthCtx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
if err := cfg.DB.Health(healthCtx); err != nil {
|
||||
WriteJSON(w, http.StatusServiceUnavailable, map[string]any{
|
||||
"service": cfg.Config.AppName,
|
||||
"status": "degraded",
|
||||
"database": "unreachable",
|
||||
})
|
||||
return
|
||||
}
|
||||
databaseStatus = "ok"
|
||||
}
|
||||
|
||||
WriteJSON(w, http.StatusOK, map[string]any{
|
||||
"service": cfg.Config.AppName,
|
||||
"status": "ok",
|
||||
"database": databaseStatus,
|
||||
})
|
||||
})
|
||||
|
||||
router.Post("/webhooks/stripe", handleStripeWebhook(cfg.Config, cfg.Orders, cfg.Mailer))
|
||||
|
||||
router.Route("/v1", func(api chi.Router) {
|
||||
api.Get("/inventory", handleListPublicInventory(cfg.Stock))
|
||||
api.Get("/storefront/pricing", handleGetStorefrontPricing(cfg.Config))
|
||||
api.Get("/", func(w http.ResponseWriter, _ *http.Request) {
|
||||
WriteJSON(w, http.StatusOK, map[string]any{
|
||||
"service": cfg.Config.AppName,
|
||||
"status": "scaffolded",
|
||||
"version": "v1",
|
||||
})
|
||||
})
|
||||
|
||||
api.Post("/checkout/payment-intent", handleCreatePaymentIntent(cfg.Config, cfg.Orders))
|
||||
api.Get("/checkout/payment-intent/{paymentIntentID}", handleGetPaymentIntentStatus(cfg.Config, cfg.Orders))
|
||||
api.Get("/client/session", handleGetClientSession(cfg.Config))
|
||||
api.Post("/client/login", handleClientLogin(cfg.Config))
|
||||
api.Post("/client/logout", handleClientLogout(cfg.Config))
|
||||
|
||||
api.Group(func(client chi.Router) {
|
||||
client.Use(requireClientSession(cfg.Config))
|
||||
client.Get("/client/orders", handleListClientOrders(cfg.Orders))
|
||||
client.Get("/client/orders/{orderID}", handleGetClientOrder(cfg.Orders))
|
||||
client.Patch("/client/orders/{orderID}", handleUpdateClientOrder(cfg.Orders, cfg.Mailer))
|
||||
client.Get("/client/stock", handleListClientStock(cfg.Stock))
|
||||
client.Put("/client/stock", handleUpsertClientStock(cfg.Stock))
|
||||
client.Post("/client/reseed", handleClientReseed(cfg.DB))
|
||||
})
|
||||
})
|
||||
|
||||
router.NotFound(func(w http.ResponseWriter, _ *http.Request) {
|
||||
WriteError(w, http.StatusNotFound, "not_found", "The requested endpoint does not exist.")
|
||||
})
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
func corsMiddleware(allowedOrigins []string) func(http.Handler) http.Handler {
|
||||
normalized := make([]string, 0, len(allowedOrigins))
|
||||
for _, origin := range allowedOrigins {
|
||||
trimmed := strings.TrimSpace(origin)
|
||||
if trimmed == "" {
|
||||
continue
|
||||
}
|
||||
normalized = append(normalized, trimmed)
|
||||
}
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
origin := r.Header.Get("Origin")
|
||||
|
||||
if origin != "" {
|
||||
for _, allowedOrigin := range normalized {
|
||||
if allowedOrigin == "*" || strings.EqualFold(allowedOrigin, origin) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", origin)
|
||||
w.Header().Set("Vary", "Origin")
|
||||
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, OPTIONS")
|
||||
|
||||
if r.Method == http.MethodOptions {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user