diff --git a/src/index.ts b/src/index.ts index 703444f..9228a11 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,19 +3,24 @@ import { swagger } from "@elysiajs/swagger"; import { swaggerConfig, welcomeMessage } from "./utils/app.config"; import { commentRoutes } from "./routes/comment.routes"; import { ShutdownHandler } from "./utils/shutdown-handler"; +import { blogImageRoutes } from "./routes/blogImage.routes"; import { reactionRoutes } from './routes/reaction.routes'; +const PORT = Number(process.env.PORT) || 5454; + const app = new Elysia() .use(swagger(swaggerConfig)) .get("/", () => welcomeMessage) .use(commentRoutes) + .use(blogImageRoutes) .use(reactionRoutes) - .listen(5454); + .listen(PORT); console.log( `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}` ); -console.log('Comments API: http://localhost:5454/comments - Done by JuanBap'); -console.log('Reactions API: http://localhost:5454/reactions - Done by Ivan140826'); +console.log(`Comments API: http://localhost:${PORT}/comments - Done by JuanBap`); +console.log(`Reactions API: http://localhost:${PORT}/reactions - Done by Ivan140826`); +console.log(`Blog Images API: http://localhost:${PORT}/blog-image - Done by Arkan56`); //Shutdown of the server in a appropiate way ShutdownHandler.setupSignalHandlers(app); \ No newline at end of file diff --git a/src/routes/blogImage.routes.ts b/src/routes/blogImage.routes.ts new file mode 100644 index 0000000..f1fce37 --- /dev/null +++ b/src/routes/blogImage.routes.ts @@ -0,0 +1,136 @@ +import { Elysia } from 'elysia'; +import { CreateBlogImageSchema, UpdateBlogImageSchema, BlogImageParamsSchema } from '../schemas/blogImage.schemas'; +import { ResponseHelpers } from '../utils/response.helpers'; +import { SupabaseAdaapter } from '../repositories/supabase.adapter'; +import { IDatabase } from '../repositories/database.interface'; + +const TABLE = 'blog-image'; +const db: IDatabase = SupabaseAdaapter.getInstance(); + +export const blogImageRoutes = new Elysia({ prefix: '/blog-image' }) + + // GET /blog-image - Get all blog images + .get('/', async () => { + try { + const response = await db.getAll(TABLE, { column: 'id', asc: true }); + if (response.error) { + return ResponseHelpers.serverError(response.error); + } + const blogImages = response.data; + return ResponseHelpers.ok( + blogImages, + "Blog Images retrieved successfully", + blogImages.length + ); + } catch (error) { + return ResponseHelpers.serverError("Failed to retrieve blog images"); + } + }) + + // GET /blog-image/:id - Get a specific blog image + .get('/:id', async ({ params: { id } }) => { + try { + const blogImageId = parseInt(id); + const response = await db.getBy(TABLE, { id: blogImageId }); + if (response.error) { + return ResponseHelpers.serverError(response.error); + } + const blogImages = response.data?.[0] || null; + + if (!blogImages) { + return ResponseHelpers.notFound('Blog Image not found'); + } + + return ResponseHelpers.ok(blogImages, "Blog Image retrieved successfully"); + } catch (error) { + return ResponseHelpers.serverError("Failed to retrieve blog image"); + } + }, { + params: BlogImageParamsSchema + }) + + // GET /blog-image/blog/:blog_id - Get blog images for a specific blog + .get('/blog/:blog_id', async ({ params: { blog_id } }) => { + try { + const blogId = parseInt(blog_id); + const response = await db.getBy(TABLE, { blog_id: blogId }, { column: 'id', asc: true }); + if (response.error) { + return ResponseHelpers.serverError(response.error); + } + const blogImages = response.data?.[0] || null; + + if (!blogImages) { + return ResponseHelpers.notFound('Blog images not found'); + } + + return ResponseHelpers.ok( + blogImages, + `blog images for blog ${blogId} retrieved successfully`, + blogImages.length + ); + } catch (error) { + return ResponseHelpers.serverError("Failed to retrieve blog images"); + } + }) + + // POST /blog-image - Create a new blog image + .post('/', async ({ body }) => { + try { + const response = await db.insert(TABLE, body); + if (response.error) { + return ResponseHelpers.serverError(response.error); + } + const newBlogImage = response.data; + return ResponseHelpers.created(newBlogImage, "Blog Image created successfully"); + } catch (error) { + return ResponseHelpers.serverError("Failed to create blog image"); + } + }, { + body: CreateBlogImageSchema + }) + + // PUT /blog-image/:id - Update a blog image + .put('/:id', async ({ params: { id }, body }) => { + try { + const blogImageId = parseInt(id); + const response = await db.updateBy(TABLE, { id: blogImageId }, body); + if (response.error) { + return ResponseHelpers.serverError(response.error); + } + + const updatedBlogImage = response.data?.[0] || null;; + + if (!updatedBlogImage) { + return ResponseHelpers.notFound('Blog Image not found'); + } + + return ResponseHelpers.ok(updatedBlogImage, "Blog Image updated successfully"); + } catch (error) { + return ResponseHelpers.serverError("Failed to update comment"); + } + }, { + params: BlogImageParamsSchema, + body: UpdateBlogImageSchema + }) + + // DELETE /blog-image/:id - Delete a blog image + .delete('/:id', async ({ params: { id } }) => { + try { + const blogImageId = parseInt(id); + const response = await db.delete(TABLE, { id: blogImageId }); + if (response.error) { + return ResponseHelpers.serverError(response.error); + } + const deletedBlogImage = response.data?.[0] || null; + + if (!deletedBlogImage) { + return ResponseHelpers.notFound('Blog Image not found'); + } + + return ResponseHelpers.ok(deletedBlogImage, "Blog Image deleted successfully"); + } catch (error) { + return ResponseHelpers.serverError("Failed to delete blog image"); + } + }, { + params: BlogImageParamsSchema + }); \ No newline at end of file diff --git a/src/schemas/blogImage.schemas.ts b/src/schemas/blogImage.schemas.ts new file mode 100644 index 0000000..21935d6 --- /dev/null +++ b/src/schemas/blogImage.schemas.ts @@ -0,0 +1,37 @@ +import {t} from "elysia"; + +// Schema for creating a new blog image +export const CreateBlogImageSchema = t.Object({ + blog_id: t.Number({ minimum: 1 }), + url: t.String({ + format: "uri", + description: "URL must be a valid URI" + }), + alt: t.Optional(t.String({ + minLength: 1, + maxLength: 255, + description: "Alt text must be between 1-255 characters long" + })) +}); + +// Schema for updating a blog image +export const UpdateBlogImageSchema = t.Object({ + url: t.Optional(t.String({ + format: "uri", + description: "URL must be a valid URI" + })), + alt: t.Optional(t.String({ + minLength: 1, + maxLength: 255, + description: "Alt text must be between 1-255 characters long" + })) +}); + +// Schema for deleting and retrieving a blog image (GET, DELETE http methods) +export const BlogImageParamsSchema = t.Object({ + id: t.String({ + // Regular expression for validating only numeric types + pattern: "^[0-9]+$", + description: "Blog Image ID must be numeric" + }) +}); \ No newline at end of file diff --git a/src/types/blogImage.ts b/src/types/blogImage.ts new file mode 100644 index 0000000..2134591 --- /dev/null +++ b/src/types/blogImage.ts @@ -0,0 +1,17 @@ +export interface BlogImage { + id: number; + blog_id: number; + url: string; + alt: string; +} + +export interface CreateBlogImageRequest { + blog_id: number; + url: string; + alt?: string; +} + +export interface UpdateBlogImageRequest { + url?: string; + alt?: string; +} \ No newline at end of file