Просмотр исходного кода

refactor: implement express router

Sv443 2 лет назад
Родитель
Сommit
8eb1ff5bea
5 измененных файлов с 58 добавлено и 45 удалено
  1. 20 5
      src/routes/index.ts
  2. 4 4
      src/routes/search.ts
  3. 4 4
      src/routes/translations.ts
  4. 27 32
      src/server.ts
  5. 3 0
      src/types.d.ts

+ 20 - 5
src/routes/index.ts

@@ -1,7 +1,22 @@
-import { initSearchEndpoints } from "./search";
-import { initTranslationsEndpoints } from "./translations";
+import { Application, Router } from "express";
+import packageJson from "../../package.json";
 
-export const endpointFuncs = [
-    initSearchEndpoints,
-    initTranslationsEndpoints,
+import { initSearchRoutes } from "./search";
+import { initTranslationsRoutes } from "./translations";
+
+const routeFuncs: ((router: Router) => unknown)[] = [
+    initSearchRoutes,
+    initTranslationsRoutes,
 ];
+
+const router = Router();
+
+export function initRouter(app: Application) {
+    for(const initRoute of routeFuncs)
+        initRoute(router);
+
+    // redirect to GitHub page
+    router.get("/", (_req, res) => res.redirect(packageJson.homepage));
+
+    app.use("/", router);
+}

+ 4 - 4
src/routes/search.ts

@@ -1,10 +1,10 @@
-import { Application } from "express";
+import { Router } from "express";
 import { paramValid, respond } from "../utils";
 import { getMeta } from "../songData";
 import { langCodes } from "../constants";
 
-export function initSearchEndpoints(app: Application) {
-    app.get("/search", async (req, res) => {
+export function initSearchRoutes(router: Router) {
+    router.get("/search", async (req, res) => {
         try
         {
             const { q, artist, song, format: fmt, threshold: thr, preferLang: prLang } = req.query;
@@ -43,7 +43,7 @@ export function initSearchEndpoints(app: Application) {
         }
     });
 
-    app.get("/search/top", async (req, res) => {
+    router.get("/search/top", async (req, res) => {
         try
         {
             const { q, artist, song, format: fmt, threshold: thr, preferLang: prLang } = req.query;

+ 4 - 4
src/routes/translations.ts

@@ -1,16 +1,16 @@
-import { Application } from "express";
+import { Router } from "express";
 import { paramValid, respond } from "../utils";
 import { getTranslations } from "../songData";
 import { langCodes } from "../constants";
 
-export function initTranslationsEndpoints(app: Application) {
-    app.get("/translations", (req, res) => {
+export function initTranslationsRoutes(router: Router) {
+    router.get("/translations", (req, res) => {
         const format: string = req.query.format ? String(req.query.format) : "json";
 
         return respond(res, "clientError", "No song ID provided", format);
     });
 
-    app.get("/translations/:songId", async (req, res) => {
+    router.get("/translations/:songId", async (req, res) => {
         try
         {
             const { songId } = req.params;

+ 27 - 32
src/server.ts

@@ -8,7 +8,7 @@ import cors from "cors";
 
 import packageJson from "../package.json";
 import { error } from "./error";
-import { endpointFuncs } from "./routes";
+import { initRouter } from "./routes";
 import { respond } from "./utils";
 
 const app = express();
@@ -18,6 +18,8 @@ app.use(helmet());
 app.use(express.json());
 app.use(compression());
 
+app.disable("x-powered-by");
+
 const rateLimiter = new RateLimiterMemory({
     points: 5,
     duration: 10,
@@ -42,33 +44,31 @@ export async function init()
             return next();
     });
 
-    const listener = app.listen(port, host, () => {
-        app.disable("x-powered-by");
-
-        // rate limiting
-        app.use(async (req, res, next) => {
-            const fmt = req?.query?.format ? String(req.query.format) : undefined;
-            const { authorization } = req.headers;
-            const authHeader = authorization?.startsWith("Bearer ") ? authorization.substring(7) : authorization;
+    // rate limiting
+    app.use(async (req, res, next) => {
+        const fmt = req?.query?.format ? String(req.query.format) : undefined;
+        const { authorization } = req.headers;
+        const authHeader = authorization?.startsWith("Bearer ") ? authorization.substring(7) : authorization;
 
-            res.setHeader("API-Info", `geniURL v${packageJson.version} (${packageJson.homepage})`);
+        res.setHeader("API-Info", `geniURL v${packageJson.version} (${packageJson.homepage})`);
 
-            if(authHeader && authTokens.has(authHeader))
-                return next();
+        if(authHeader && authTokens.has(authHeader))
+            return next();
 
-            rateLimiter.consume(req.ip)
-                .catch((err) => {
-                    if(err instanceof RateLimiterRes) {
-                        res.set("Retry-After", String(Math.ceil(err.msBeforeNext / 1000)));
-                        return respond(res, 429, { message: "You are being rate limited" }, fmt);
-                    }
-                    else
-                        return respond(res, 500, { message: "Internal error in rate limiting middleware. Please try again later." }, fmt);
-                })
-                .finally(next);
-        });
+        rateLimiter.consume(req.ip)
+            .catch((err) => {
+                if(err instanceof RateLimiterRes) {
+                    res.set("Retry-After", String(Math.ceil(err.msBeforeNext / 1000)));
+                    return respond(res, 429, { message: "You are being rate limited" }, fmt);
+                }
+                else
+                    return respond(res, 500, { message: "Internal error in rate limiting middleware. Please try again later." }, fmt);
+            })
+            .finally(next);
+    });
 
-        registerEndpoints();
+    const listener = app.listen(port, host, () => {
+        registerRoutes();
 
         console.log(k.green(`Listening on ${host}:${port}`));
     });
@@ -76,20 +76,15 @@ export async function init()
     listener.on("error", (err) => error("General server error", err, true));
 }
 
-function registerEndpoints()
+function registerRoutes()
 {
     try
     {
-        app.get("/", (_req, res) => {
-            res.redirect(packageJson.homepage);
-        });
-
-        for(const func of endpointFuncs)
-            func(app);
+        initRouter(app);
     }
     catch(err)
     {
-        error("Error while registering endpoints", err instanceof Error ? err : undefined, true);
+        error("Error while initializing router", err instanceof Error ? err : undefined, true);
     }
 }
 

+ 3 - 0
src/types.d.ts

@@ -147,3 +147,6 @@ type ArtistObj = {
     name: string;
     url: string;
 }
+
+//#SECTION internal
+export type SupportedMethods = "GET";