From 443b19c7c0ffe0a8e992bd928658db8e88f66dfa Mon Sep 17 00:00:00 2001 From: Sanjib Sen Date: Thu, 16 Jan 2025 14:38:12 +0600 Subject: [PATCH] structured --- src/api/index.ts | 72 ++++++++++++++++++++ src/api/routes/index.ts | 6 ++ src/api/{ => routes}/note/note.controller.ts | 4 +- src/api/{ => routes}/note/note.model.ts | 2 +- src/api/{ => routes}/note/note.route.ts | 13 +++- src/index.ts | 61 +++++++++++------ src/lib/utils/common.ts | 32 ++++----- 7 files changed, 143 insertions(+), 47 deletions(-) create mode 100644 src/api/index.ts create mode 100644 src/api/routes/index.ts rename src/api/{ => routes}/note/note.controller.ts (97%) rename src/api/{ => routes}/note/note.model.ts (95%) rename src/api/{ => routes}/note/note.route.ts (89%) diff --git a/src/api/index.ts b/src/api/index.ts new file mode 100644 index 0000000..9d50552 --- /dev/null +++ b/src/api/index.ts @@ -0,0 +1,72 @@ +import { Elysia, t } from "elysia"; + +import { betterAuthView } from "../lib/auth/auth-view"; +import { getAuthConfig, getBaseConfig } from "../lib/utils/env"; +import { router } from "./routes"; + +const baseConfig = getBaseConfig(); +const authConfig = getAuthConfig(); + +export const api = new Elysia({ + name: baseConfig.SERVICE_NAME, + prefix: "/api", + detail: { + summary: `Get status`, + description: `Get status for ${baseConfig.SERVICE_NAME}`, + externalDocs: { + description: "Auth API", + url: `${authConfig.BETTER_AUTH_URL}/docs`, + }, + }, +}) + .all("/auth/*", betterAuthView) + .use(router) + .get( + "", + () => { + return { + message: `Server is running`, + success: true, + name: baseConfig.SERVICE_NAME, + status: "active", + docs: { + default: "/api/docs", + auth: "/api/auth/docs", + }, + }; + }, + { + response: { + 200: t.Object( + { + message: t.String({ default: `Server is running` }), + success: t.Boolean({ default: true }), + name: t.String({ default: baseConfig.SERVICE_NAME }), + status: t.String({ default: `active` }), + docs: t.Object({ + default: t.String({ default: "/api/docs" }), + auth: t.String({ default: "/api/auth/docs" }), + }), + }, + { + description: "Success", + } + ), + 404: t.Object( + { + message: t.String({ default: `Not found` }), + success: t.Boolean({ default: false }), + name: t.String({ default: baseConfig.SERVICE_NAME }), + status: t.String({ default: `active` }), + docs: t.Object({ + default: t.String({ default: "/api/docs" }), + auth: t.String({ default: "/api/auth/docs" }), + }), + }, + { + description: "Not found", + } + ), + }, + } + ); diff --git a/src/api/routes/index.ts b/src/api/routes/index.ts new file mode 100644 index 0000000..6d3d1e2 --- /dev/null +++ b/src/api/routes/index.ts @@ -0,0 +1,6 @@ + +import { Elysia, t } from "elysia"; +import { noteRouter } from "./note/note.route"; + + +export const router = new Elysia().use(noteRouter) \ No newline at end of file diff --git a/src/api/note/note.controller.ts b/src/api/routes/note/note.controller.ts similarity index 97% rename from src/api/note/note.controller.ts rename to src/api/routes/note/note.controller.ts index f916bdb..2bb08a5 100644 --- a/src/api/note/note.controller.ts +++ b/src/api/routes/note/note.controller.ts @@ -1,6 +1,6 @@ import { and, eq, notExists } from "drizzle-orm"; -import { db } from "../../db"; -import { note } from "../../db/schema/note"; +import { db } from "../../../db"; +import { note } from "../../../db/schema/note"; import { CreateNote } from "./note.model"; export class NoteController { diff --git a/src/api/note/note.model.ts b/src/api/routes/note/note.model.ts similarity index 95% rename from src/api/note/note.model.ts rename to src/api/routes/note/note.model.ts index 472a915..4a253bc 100644 --- a/src/api/note/note.model.ts +++ b/src/api/routes/note/note.model.ts @@ -1,6 +1,6 @@ import { createSelectSchema } from "drizzle-typebox"; import { t } from "elysia"; -import { note } from "../../db/schema/note"; +import { note } from "../../../db/schema/note"; import { InferInsertModel, InferSelectModel } from "drizzle-orm"; diff --git a/src/api/note/note.route.ts b/src/api/routes/note/note.route.ts similarity index 89% rename from src/api/note/note.route.ts rename to src/api/routes/note/note.route.ts index 4ce9366..56975ee 100644 --- a/src/api/note/note.route.ts +++ b/src/api/routes/note/note.route.ts @@ -1,8 +1,8 @@ import { Elysia, error, t } from "elysia"; import { createNoteSchema, NoteSchema, successDeleteNoteResponse, successGetNoteResponse } from "./note.model"; import { NoteController } from "./note.controller"; -import { userMiddleware } from "../../middlewares/auth-middleware"; -import { commonResponses } from "../../lib/utils/common"; +import { userMiddleware } from "../../../middlewares/auth-middleware"; +import { commonResponses } from "../../../lib/utils/common"; export const noteRouter = new Elysia({ prefix: "/note", @@ -18,6 +18,15 @@ export const noteRouter = new Elysia({ note: NoteSchema, }) .derive(({ request }) => userMiddleware(request)) + .onError(({ error, code, }) => { + console.error(error); + return { + message: "", + success: false, + data: null, + error: code.toString() + }; + }) .get( "", async ({ note, user, query}) => { diff --git a/src/index.ts b/src/index.ts index 78d18e2..9c3cb33 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,30 +2,47 @@ import { Elysia } from "elysia"; import { swagger } from "@elysiajs/swagger"; import { opentelemetry } from "@elysiajs/opentelemetry"; import { serverTiming } from "@elysiajs/server-timing"; -import { cors } from '@elysiajs/cors' -import { noteRouter } from "./api/note/note.route"; -import { betterAuthView } from "./lib/auth/auth-view"; +import { cors } from "@elysiajs/cors"; import { getBaseConfig, validateEnv } from "./lib/utils/env"; +import { api } from "./api"; -const baseConfig = getBaseConfig() - -const app = new Elysia() - .use(cors()) - .use(opentelemetry({ - "serviceName": baseConfig.SERVICE_NAME - })) - .use(swagger({ - path: "/docs", - })) - .use(serverTiming()) - .onError(({ error, code }) => { - if (code === "NOT_FOUND") return "Not Found :("; - console.error(error); - }) - .all("/api/auth/*", betterAuthView) - .use(noteRouter) - .get("/", () => `${baseConfig.SERVICE_NAME} Server is Running`) +const baseConfig = getBaseConfig(); validateEnv(); +const app = new Elysia() + .use(cors()) + .use( + opentelemetry({ + serviceName: baseConfig.SERVICE_NAME, + }) + ) + .use(serverTiming()) + .use( + swagger({ + path: "/api/docs", + documentation: { + info: { + title: baseConfig.SERVICE_NAME, + version: "0.0.1", + description: `API docs for ${baseConfig.SERVICE_NAME}`, + }, + }, + }) + ) + .onError(({ error, code }) => { + if (code === "NOT_FOUND") + return { + message: `Not Found`, + success: false, + name: baseConfig.SERVICE_NAME, + status: "active", + docs: { + default: "/api/docs", + auth: "/api/auth/docs", + }, + }; + console.error(error); + }) + .use(api); app.listen(baseConfig.PORT); -console.log(`Server is running on: http://127.0.0.1:${baseConfig.PORT}`) +console.log(`Server is running on: http://127.0.0.1:${baseConfig.PORT}`); diff --git a/src/lib/utils/common.ts b/src/lib/utils/common.ts index 083efe1..3d5bf4c 100644 --- a/src/lib/utils/common.ts +++ b/src/lib/utils/common.ts @@ -5,10 +5,8 @@ export const commonResponses = { { data: t.Null(), success: t.Boolean({ default: false }), - message: t.String({ default: "Bad Request" }), - error: t.String({ - default: "Missing parameters, or invalid parameters.", - }), + message: t.String({ default: "" }), + error: t.Number({ default: 400 }), }, { description: @@ -19,10 +17,8 @@ export const commonResponses = { { data: t.Null(), success: t.Boolean({ default: false }), - message: t.String({ default: "Unauthorized" }), - error: t.String({ - default: "User needs to sign in to access this resource", - }), + message: t.String({ default: "" }), + error: t.Number({ default: 401 }), }, { description: "Unauthorized. Due to missing or invalid authentication.", @@ -32,10 +28,8 @@ export const commonResponses = { { data: t.Null(), success: t.Boolean({ default: false }), - message: t.String({ default: "Forbidden" }), - error: t.String({ - default: "User does not have permission to access this resource", - }), + message: t.String({ default: "" }), + error: t.Number({ default: 403 }), }, { description: @@ -46,8 +40,8 @@ export const commonResponses = { { data: t.Null(), success: t.Boolean({ default: false }), - message: t.String({ default: "Not Found" }), - error: t.String({ default: "Requested resource has not found" }), + message: t.String({ default: "" }), + error: t.Number({ default: 404 }), }, { description: "Not Found. The requested resource was not found.", @@ -57,10 +51,8 @@ export const commonResponses = { { data: t.Null(), success: t.Boolean({ default: false }), - message: t.String({ default: "Too Many Requests" }), - error: t.String({ - default: "RUser has exceeded the rate limit. Try again later.", - }), + message: t.String({ default: "" }), + error: t.Number({ default: 429 }), }, { description: @@ -71,8 +63,8 @@ export const commonResponses = { { data: t.Null(), success: t.Boolean({ default: false }), - message: t.String({ default: "Internal Server Error" }), - error: t.String({ default: "Server faced an error" }), + message: t.String({ default: "" }), + error: t.Number({ default: 500 }), }, { description: