package main /* * website/api | API server for my personal website * written by ngn (https://ngn.tf) (2025) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ import ( "net/http" "github.com/gofiber/fiber/v2" "github.com/ngn13/website/api/config" "github.com/ngn13/website/api/database" "github.com/ngn13/website/api/routes" "github.com/ngn13/website/api/status" "github.com/ngn13/website/api/util" ) func main() { var ( app *fiber.App stat status.Type conf config.Type db database.Type err error ) if err = conf.Load(); err != nil { util.Fail("failed to load the configuration: %s", err.Error()) return } if !conf.GetBool("debug") { util.Debg = func(m string, v ...any) {} } if err = db.Load(); err != nil { util.Fail("failed to load the database: %s", err.Error()) return } if err = stat.Setup(&conf, &db); err != nil { util.Fail("failed to setup the status checker: %s", err.Error()) return } app = fiber.New(fiber.Config{ AppName: "ngn's website", DisableStartupMessage: true, ServerHeader: "", }) app.Use("*", func(c *fiber.Ctx) error { // CORS stuff c.Set("Access-Control-Allow-Origin", "*") c.Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") c.Set("Access-Control-Allow-Methods", "PUT, DELETE, GET") // POST can be sent from HTML forms, so I prefer PUT for API endpoints c.Locals("status", &stat) c.Locals("config", &conf) c.Locals("database", &db) return c.Next() }) // index route app.Get("/", routes.GET_Index) // version groups v1 := app.Group("v1") // v1 user routes v1.Get("/services", routes.GET_Services) v1.Get("/projects", routes.GET_Projects) v1.Get("/metrics", routes.GET_Metrics) v1.Get("/news/:lang", routes.GET_News) // v1 admin routes v1.Use("/admin", routes.AuthMiddleware) v1.Get("/admin/logs", routes.GET_AdminLogs) v1.Get("/admin/service/check", routes.GET_CheckService) v1.Put("/admin/service/add", routes.PUT_AddService) v1.Delete("/admin/service/del", routes.DEL_DelService) v1.Put("/admin/project/add", routes.PUT_AddProject) v1.Delete("/admin/project/del", routes.DEL_DelProject) v1.Put("/admin/news/add", routes.PUT_AddNews) v1.Delete("/admin/news/del", routes.DEL_DelNews) // 404 route app.All("*", func(c *fiber.Ctx) error { return util.JSON(c, http.StatusNotFound, fiber.Map{ "error": "Endpoint not found", }) }) // start the status checker if err = stat.Run(); err != nil { util.Fail("failed to start the status checker: %s", err.Error()) return } // start the app util.Info("starting web server on %s", conf.GetStr("host")) if err = app.Listen(conf.GetStr("host")); err != nil { util.Fail("failed to start the web server: %s", err.Error()) } stat.Stop() }