package api import ( "errors" "fmt" "net/http" "time" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/favicon" "github.com/gofiber/fiber/v2/middleware/filesystem" "github.com/gofiber/fiber/v2/middleware/logger" recover "github.com/gofiber/fiber/v2/middleware/recover" "prayertimes/pkg/prayer" "prayertimes/templates" ) type httpError struct { Message string `json:"message"` } type Services struct { TimesProvider prayer.TimesProvider LocationTimesProvider prayer.LocationTimesProvider } func New(services Services) *fiber.App { app := fiber.New(fiber.Config{ Immutable: true, DisableStartupMessage: false, ReadTimeout: time.Second * 10, WriteTimeout: time.Second * 30, ErrorHandler: func(ctx *fiber.Ctx, err error) error { if errors.Is(err, prayer.ErrInvalidLocation) { return ctx.Status(http.StatusUnprocessableEntity).JSON(httpError{ Message: err.Error(), }) } return fiber.DefaultErrorHandler(ctx, err) }, }) app.Use( favicon.New(), recover.New(recover.Config{EnableStackTrace: true}), logger.New(), cors.New(), ) app.Get("/healthz", func(ctx *fiber.Ctx) error { return ctx.SendString("OK") }) app.Get("/api/v1/diyanet/prayertimes", func(ctx *fiber.Ctx) error { var times []prayer.Times var err error locationID := ctx.Query("location_id") var loc struct { Latitude float64 `query:"latitude"` Longitude float64 `query:"longitude"` } if locationID != "" { times, err = services.TimesProvider.Get(ctx.Context(), locationID) } else if err := ctx.QueryParser(&loc); err == nil { times, err = services.LocationTimesProvider.GetByCoords(ctx.Context(), prayer.Coordinates{ Latitude: loc.Latitude, Longitude: loc.Longitude, }) } else { return fmt.Errorf("%w: missing location id or coordinates", fiber.ErrBadRequest) } if err != nil { return err } ctx.Response().Header.Add(fiber.HeaderCacheControl, "max-age=86400") return ctx.JSON(times) }) app.Use("/", filesystem.New(filesystem.Config{ Root: templates.HttpFS(), })) return app }