From 17eb272b1d9a1668abac765c8b792310c0788ebf Mon Sep 17 00:00:00 2001 From: Rafi Arrafif Date: Wed, 1 Apr 2026 23:28:22 +0700 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20endpoint=20to=20fetch?= =?UTF-8?q?=20media=20by=20slug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/getEpisodeDetails.service.ts | 11 +++---- .../http/bulkInsertEpisode.service.ts | 15 +++------- .../controllers/getMediaBySlug.controller.ts | 18 ++++++++++++ src/modules/media/index.ts | 9 +++--- .../selectAllMedia.repository.ts} | 2 +- .../selectMediaByMalId.repository.ts} | 2 +- .../selectMediaIdFromSlug.repository.ts} | 2 +- .../media/schemas/getMediaBySlug.schema.ts | 29 +++++++++++++++++++ .../services/http/getAllMedia.service.ts | 9 ++---- 9 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 src/modules/media/controllers/getMediaBySlug.controller.ts rename src/modules/media/repositories/{GET/getAllMedia.repository.ts => SELECT/selectAllMedia.repository.ts} (85%) rename src/modules/media/repositories/{GET/getMediaByMalId.repository.ts => SELECT/selectMediaByMalId.repository.ts} (80%) rename src/modules/media/repositories/{GET/getMediaIdFromSlug.repository.ts => SELECT/selectMediaIdFromSlug.repository.ts} (82%) create mode 100644 src/modules/media/schemas/getMediaBySlug.schema.ts diff --git a/src/modules/episode/services/http/getEpisodeDetails.service.ts b/src/modules/episode/services/http/getEpisodeDetails.service.ts index fa7d1b3..71f55e0 100644 --- a/src/modules/episode/services/http/getEpisodeDetails.service.ts +++ b/src/modules/episode/services/http/getEpisodeDetails.service.ts @@ -1,17 +1,14 @@ import { AppError } from "../../../../helpers/error/instances/app"; import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder"; -import { getMediaIdFromSlugRepository } from "../../../media/repositories/GET/getMediaIdFromSlug.repository"; +import { selectMediaIdFromSlugRepository } from "../../../media/repositories/SELECT/selectMediaIdFromSlug.repository"; import { GetEpisodeDetailsParams } from "../../controllers/getEpisodeDetails.controller"; import { getEpisodeDetailsRepository } from "../../repositories/GET/getEpisodeDetails.repository"; -export const getEpisodeDetailsService = async ( - params: GetEpisodeDetailsParams, -) => { +export const getEpisodeDetailsService = async (params: GetEpisodeDetailsParams) => { try { - if (!params.mediaSlug || !params.episode) - throw new AppError(400, "Media slug and episode are required."); + if (!params.mediaSlug || !params.episode) throw new AppError(400, "Media slug and episode are required."); - const mediaId = await getMediaIdFromSlugRepository(params.mediaSlug); + const mediaId = await selectMediaIdFromSlugRepository(params.mediaSlug); if (!mediaId?.id) throw new AppError(404, "Media not found."); const result = await getEpisodeDetailsRepository({ diff --git a/src/modules/internal/services/http/bulkInsertEpisode.service.ts b/src/modules/internal/services/http/bulkInsertEpisode.service.ts index 326304e..ed8d820 100644 --- a/src/modules/internal/services/http/bulkInsertEpisode.service.ts +++ b/src/modules/internal/services/http/bulkInsertEpisode.service.ts @@ -1,27 +1,20 @@ import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder"; import { MediaEpisodeInfoResponse } from "../../types/mediaEpisodeInfo.type"; -import { getMediaByMalIdRepository } from "../../../media/repositories/GET/getMediaByMalId.repository"; import { AppError } from "../../../../helpers/error/instances/app"; import { SystemAccountId } from "../../../../config/account/system"; import { bulkInsertEpisodesRepository } from "../../repositories/bulkInsertEpisodes.repository"; import { getEpisodeReferenceAPI } from "../../../../config/apis/jikan/episode.reference"; +import { selectMediaByMalIdRepository } from "../../../media/repositories/SELECT/selectMediaByMalId.repository"; -export const bulkInsertEpisodeService = async ( - mal_id: number, - page: number = 1, -) => { +export const bulkInsertEpisodeService = async (mal_id: number, page: number = 1) => { try { const episodeAPI = getEpisodeReferenceAPI(mal_id); const episodeData: MediaEpisodeInfoResponse = await fetch( `${episodeAPI.baseURL}${episodeAPI.getEpisodeList}?page=${page}`, ).then((res) => res.json()); - const mediaData = await getMediaByMalIdRepository(mal_id); - if (!mediaData) - throw new AppError( - 404, - `Media with Mal ID ${mal_id} not found in database`, - ); + const mediaData = await selectMediaByMalIdRepository(mal_id); + if (!mediaData) throw new AppError(404, `Media with Mal ID ${mal_id} not found in database`); const insertedEpisodeData = []; episodeData.data.forEach(async (episode) => { diff --git a/src/modules/media/controllers/getMediaBySlug.controller.ts b/src/modules/media/controllers/getMediaBySlug.controller.ts new file mode 100644 index 0000000..f51a450 --- /dev/null +++ b/src/modules/media/controllers/getMediaBySlug.controller.ts @@ -0,0 +1,18 @@ +import { Context, Static } from "elysia"; +import { mainErrorHandler } from "../../../helpers/error/handler"; +import { getMediaBySlugSchema } from "../schemas/getMediaBySlug.schema"; + +export const getMediaBySlugController = async (ctx: { + set: Context["set"]; + params: Static; +}) => { + try { + return { + success: true, + status: 200, + message: `Media with slug '${ctx.params.slug}' fetched successfully`, + }; + } catch (error) { + return mainErrorHandler(ctx.set, error); + } +}; diff --git a/src/modules/media/index.ts b/src/modules/media/index.ts index 106d7de..d1cc726 100644 --- a/src/modules/media/index.ts +++ b/src/modules/media/index.ts @@ -1,7 +1,8 @@ import Elysia from "elysia"; import { getAllMediaController } from "./controllers/getAllMedia.controller"; +import { getMediaBySlugController } from "./controllers/getMediaBySlug.controller"; +import { getMediaBySlugSchema } from "./schemas/getMediaBySlug.schema"; -export const mediaModule = new Elysia({ prefix: "/media" }).get( - "/", - getAllMediaController, -); +export const mediaModule = new Elysia({ prefix: "/media" }) + .get("/", getAllMediaController) + .get("/:slug", getMediaBySlugController, getMediaBySlugSchema); diff --git a/src/modules/media/repositories/GET/getAllMedia.repository.ts b/src/modules/media/repositories/SELECT/selectAllMedia.repository.ts similarity index 85% rename from src/modules/media/repositories/GET/getAllMedia.repository.ts rename to src/modules/media/repositories/SELECT/selectAllMedia.repository.ts index 30a5ca8..63ad138 100644 --- a/src/modules/media/repositories/GET/getAllMedia.repository.ts +++ b/src/modules/media/repositories/SELECT/selectAllMedia.repository.ts @@ -1,7 +1,7 @@ import { AppError } from "../../../../helpers/error/instances/app"; import { mediaModel } from "../../model"; -export const getAllMediaRepository = async (page: number) => { +export const selectAllMediaRepository = async (page: number) => { try { const limit = 10; return await mediaModel.findMany({ diff --git a/src/modules/media/repositories/GET/getMediaByMalId.repository.ts b/src/modules/media/repositories/SELECT/selectMediaByMalId.repository.ts similarity index 80% rename from src/modules/media/repositories/GET/getMediaByMalId.repository.ts rename to src/modules/media/repositories/SELECT/selectMediaByMalId.repository.ts index 6d17559..ef3cb08 100644 --- a/src/modules/media/repositories/GET/getMediaByMalId.repository.ts +++ b/src/modules/media/repositories/SELECT/selectMediaByMalId.repository.ts @@ -1,7 +1,7 @@ import { AppError } from "../../../../helpers/error/instances/app"; import { mediaModel } from "../../model"; -export const getMediaByMalIdRepository = async (mal_id: number) => { +export const selectMediaByMalIdRepository = async (mal_id: number) => { try { return await mediaModel.findUnique({ where: { malId: mal_id }, diff --git a/src/modules/media/repositories/GET/getMediaIdFromSlug.repository.ts b/src/modules/media/repositories/SELECT/selectMediaIdFromSlug.repository.ts similarity index 82% rename from src/modules/media/repositories/GET/getMediaIdFromSlug.repository.ts rename to src/modules/media/repositories/SELECT/selectMediaIdFromSlug.repository.ts index b29064e..56b2399 100644 --- a/src/modules/media/repositories/GET/getMediaIdFromSlug.repository.ts +++ b/src/modules/media/repositories/SELECT/selectMediaIdFromSlug.repository.ts @@ -1,7 +1,7 @@ import { AppError } from "../../../../helpers/error/instances/app"; import { mediaModel } from "../../model"; -export const getMediaIdFromSlugRepository = async (slug: string) => { +export const selectMediaIdFromSlugRepository = async (slug: string) => { try { return await mediaModel.findUnique({ where: { slug }, diff --git a/src/modules/media/schemas/getMediaBySlug.schema.ts b/src/modules/media/schemas/getMediaBySlug.schema.ts new file mode 100644 index 0000000..5bbb2b7 --- /dev/null +++ b/src/modules/media/schemas/getMediaBySlug.schema.ts @@ -0,0 +1,29 @@ +import { t } from "elysia"; +import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema"; + +export const getMediaBySlugSchema = { + params: t.Object({ + slug: t.String({ description: "The slug of the media to fetch" }), + }), + detail: { + summary: "Fetch a media item by its slug", + description: "Fetch the specified media item using its slug. This endpoint returns the media details if found.", + responses: { + 200: { + description: "Media item fetched successfully", + content: { + "application/json": { + schema: { + type: "object", + properties: { + success: { type: "boolean", example: true }, + status: { type: "number", example: 200 }, + message: { type: "string", example: "Media fetched successfully" }, + }, + }, + }, + }, + }, + }, + }, +} satisfies AppRouteSchema; diff --git a/src/modules/media/services/http/getAllMedia.service.ts b/src/modules/media/services/http/getAllMedia.service.ts index 88316f4..89c85d0 100644 --- a/src/modules/media/services/http/getAllMedia.service.ts +++ b/src/modules/media/services/http/getAllMedia.service.ts @@ -1,14 +1,11 @@ import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder"; -import { getAllMediaRepository } from "../../repositories/GET/getAllMedia.repository"; +import { selectAllMediaRepository } from "../../repositories/SELECT/selectAllMedia.repository"; export const getAllMediaService = async (pagination: string) => { try { - const page = - /^\d+$/.test(pagination) && Number(pagination) > 0 - ? Number(pagination) - : 1; + const page = /^\d+$/.test(pagination) && Number(pagination) > 0 ? Number(pagination) : 1; - return getAllMediaRepository(page); + return selectAllMediaRepository(page); } catch (error) { ErrorForwarder(error); }