recipes2/internal/app/httpSrv/httpSrv.go

93 lines
2.6 KiB
Go
Raw Permalink Normal View History

2024-01-25 14:35:04 +02:00
package httpsrv
import (
"context"
"log/slog"
"net/http"
"recipes/internal/config"
"recipes/internal/http-server/handlers/recipe"
recipeimage "recipes/internal/http-server/handlers/recipeImage"
"recipes/internal/http-server/handlers/recipes"
recipes_by_category "recipes/internal/http-server/handlers/recipesByCategory"
mwLogger "recipes/internal/http-server/middleware/logger"
"recipes/internal/lib/logger/sl"
"time"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
2024-01-31 09:18:29 +02:00
"github.com/go-chi/cors"
2024-01-25 14:35:04 +02:00
)
type App struct {
log *slog.Logger
router *chi.Mux
srv *http.Server
}
type Storage interface {
recipe.RecipeProvider
recipes.RecipesProvider
recipes_by_category.RecipesProvider
}
type MediaStorage interface {
recipeimage.ImageProvider
}
func New(log *slog.Logger, cfg *config.HTTPServerConfig, storage Storage, mediaStorage MediaStorage) *App {
// init router
router := chi.NewRouter()
// middlewares
router.Use(middleware.RequestID)
router.Use(mwLogger.New(log))
router.Use(middleware.Recoverer)
2024-01-31 09:18:29 +02:00
// Basic CORS
router.Use(cors.Handler(cors.Options{
AllowedOrigins: []string{"https://*", "http://*"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
ExposedHeaders: []string{"Link"},
AllowCredentials: false,
MaxAge: 300, // Maximum value not ignored by any of major browsers
}))
2024-01-25 14:35:04 +02:00
// routes
2024-01-31 09:18:29 +02:00
router.Post("/recipe", recipe.New(log, storage))
router.Post("/recipes_page", recipes.New(log, storage))
router.Post("/recipes_by_category", recipes_by_category.New(log, storage))
2024-01-25 14:35:04 +02:00
router.Get("/recipe_img", recipeimage.New(log, mediaStorage))
// server config
srv := &http.Server{
Addr: cfg.Address,
Handler: router,
ReadTimeout: cfg.Timeout,
WriteTimeout: cfg.Timeout,
IdleTimeout: cfg.IdleTimeout,
}
return &App{
log: log,
router: router,
srv: srv,
}
}
// MustRun starts http server or panic in case of error. Blocking function.
func (app *App) MustRun() {
const op = "app.httpSrv.Stop"
if err := app.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
2024-01-25 14:44:38 +02:00
app.log.Error("failed to start server", slog.String("op", op), sl.Err(err))
2024-01-25 14:35:04 +02:00
panic(err)
}
app.log.Info("HTTP server stopped")
}
func (app *App) Stop() {
const op = "app.httpSrv.Stop"
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second)
err := app.srv.Shutdown(shutdownCtx)
if err != nil {
2024-01-25 14:44:38 +02:00
app.log.Error("failed to stop server", slog.String("op", op), sl.Err(err))
2024-01-25 14:35:04 +02:00
}
shutdownCancel()
}