From 7462fdb8128a53909570421dcded87bb8d26ef70 Mon Sep 17 00:00:00 2001 From: Haris Shah Date: Sun, 25 Feb 2024 19:22:45 +0500 Subject: [PATCH] feat: add user routes, controllers and model --- apps/api/config/db.ts | 3 +- apps/api/src/controllers/user_controller.ts | 115 ++++++++++++++++++ apps/api/src/index.ts | 16 ++- ...middleware.ts => validation_middleware.ts} | 2 +- apps/api/src/models/user_model.ts | 14 +++ apps/api/src/routes/index.ts | 2 + apps/api/src/routes/job_route.ts | 11 +- apps/api/src/routes/user_route.ts | 28 +++++ apps/api/src/server.ts | 2 - apps/api/src/validations/user_validation.ts | 7 ++ apps/api/types/index.ts | 12 -- apps/api/types/package.json | 16 --- 12 files changed, 185 insertions(+), 43 deletions(-) create mode 100644 apps/api/src/controllers/user_controller.ts rename apps/api/src/middleware/{job_validation_middleware.ts => validation_middleware.ts} (89%) create mode 100644 apps/api/src/models/user_model.ts create mode 100644 apps/api/src/routes/index.ts create mode 100644 apps/api/src/routes/user_route.ts create mode 100644 apps/api/src/validations/user_validation.ts delete mode 100644 apps/api/types/index.ts delete mode 100644 apps/api/types/package.json diff --git a/apps/api/config/db.ts b/apps/api/config/db.ts index d4b7240..c1c4a55 100644 --- a/apps/api/config/db.ts +++ b/apps/api/config/db.ts @@ -3,8 +3,7 @@ import { log } from '@repo/logger' export const connect_db = async () => { try { - const conn = await mongoose.connect(process.env.MONGO_URI as string) - log(`MongoDB Connected: ${conn.connection.name}`) + await mongoose.connect(process.env.MONGO_URI as string) } catch (error) { log(`Error: ${error}`) process.exit(1) diff --git a/apps/api/src/controllers/user_controller.ts b/apps/api/src/controllers/user_controller.ts new file mode 100644 index 0000000..8cd189b --- /dev/null +++ b/apps/api/src/controllers/user_controller.ts @@ -0,0 +1,115 @@ +import { Request, Response } from 'express' +import { USER_SCHEMA } from '@/models/user_model' +import { isValidObjectId } from 'mongoose' +import { log } from 'console' + +//* @desc Post user +//* route POST /api/user +//? @access Public +export async function post_user(req: Request, res: Response): Promise { + try { + const user_data = req.body + + // check if user email already exists + const { email } = req.body + const existing_user = await USER_SCHEMA.findOne({ email }) + if (existing_user) { + res.status(409).json({ error: 'User email already exists' }) + return + } + + //* post user + const new_job = await USER_SCHEMA.create(user_data) + res.status(201).json(new_job) + } catch (error) { + log('Error posting user:', error) + res.status(500).json({ error: 'Internal server error' }) + } +} + +//* @desc Get user +//* route GET /api/user/:id +//! @access Private +export async function get_user(req: Request, res: Response): Promise { + try { + const { id } = req.params + //* check if id is valid + if (!isValidObjectId(id)) { + res.status(400).json({ error: 'Invalid id' }) + return + } + //* check if user exists + const user = await USER_SCHEMA.findById(id) + if (!user) { + res.status(404).json({ error: 'user not found' }) + return + } + res.status(200).json(user) + } catch (error) { + log('Error fetching user:', error) + res.status(500).json({ error: 'Internal server error' }) + } +} + +//* @desc Delete job +//* route DELETE /api/user/:id +//! @access Private +export async function delete_user(req: Request, res: Response): Promise { + try { + const { id } = req.params + //* check if id is valid + if (!isValidObjectId(id)) { + res.status(400).json({ error: 'Invalid id' }) + return + } + //* check if user exists + const user = await USER_SCHEMA.findById(id) + if (!user) { + res.status(404).json({ error: 'user not found' }) + return + } + //* delete user + await USER_SCHEMA.findByIdAndDelete(id) + res.status(200).json({ message: 'user deleted successfully' }) + } catch (error) { + log('Error deleting user:', error) + res.status(500).json({ error: 'Internal server error' }) + } +} + +//* @desc Update user +//* route PATCH /api/user/:id +//! @access Private +export async function update_user(req: Request, res: Response): Promise { + try { + const { id } = req.params + //* check if id is valid + if (!isValidObjectId(id)) { + res.status(400).json({ error: 'Invalid id' }) + return + } + //* check if user exists + const user = await USER_SCHEMA.findById(id) + if (!user) { + res.status(404).json({ error: 'user not found' }) + return + } + + // check if user email already exists + const { email } = req.body + const existing_user = await USER_SCHEMA.findOne({ email }) + if (existing_user && existing_user._id.toString() !== id) { + res.status(400).json({ error: 'Email already exists' }) + return + } + + //* update user + const updated_user = await USER_SCHEMA.findByIdAndUpdate(id, req.body, { + new: true, + }) + res.status(200).json(updated_user) + } catch (error) { + log('Error updating user:', error) + res.status(500).json({ error: 'Internal server error' }) + } +} diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index a7cf113..762ceb0 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -1,12 +1,20 @@ import { log } from '@repo/logger' import { createServer } from './server' -import job_route from '@/routes/job_route' +import { job_route, user_route } from '@/routes' +import { connect_db } from 'config/db' const port = process.env.PORT || 5001 const server = createServer() server.use('/api/v1/jobs', job_route) +server.use('/api/v1/user', user_route) -server.listen(port, () => { - log(`api running on ${port}`) -}) +connect_db() + .then(() => { + server.listen(port, () => { + log(`db connected & api running on ${port}`) + }) + }) + .catch((error) => { + log('Error connecting to db:', error) + }) diff --git a/apps/api/src/middleware/job_validation_middleware.ts b/apps/api/src/middleware/validation_middleware.ts similarity index 89% rename from apps/api/src/middleware/job_validation_middleware.ts rename to apps/api/src/middleware/validation_middleware.ts index c97bec7..e82651f 100644 --- a/apps/api/src/middleware/job_validation_middleware.ts +++ b/apps/api/src/middleware/validation_middleware.ts @@ -1,7 +1,7 @@ import { Request, Response, NextFunction } from 'express' import { z } from 'zod' -export function validate_job_data(schema: z.AnyZodObject) { +export function validate_schema(schema: z.AnyZodObject) { return (req: Request, res: Response, next: NextFunction) => { try { schema.parse(req.body) diff --git a/apps/api/src/models/user_model.ts b/apps/api/src/models/user_model.ts new file mode 100644 index 0000000..9d9d77b --- /dev/null +++ b/apps/api/src/models/user_model.ts @@ -0,0 +1,14 @@ +import mongoose, { Schema } from 'mongoose' + +const user_schema = new Schema( + { + name: { type: String, required: true }, + email: { type: String, required: true, unique: true }, + password: { type: String, required: true }, + }, + { + timestamps: true, + } +) + +export const USER_SCHEMA = mongoose.model('User', user_schema) diff --git a/apps/api/src/routes/index.ts b/apps/api/src/routes/index.ts new file mode 100644 index 0000000..3d9245c --- /dev/null +++ b/apps/api/src/routes/index.ts @@ -0,0 +1,2 @@ +export { default as job_route } from './job_route' +export { default as user_route } from './user_route' diff --git a/apps/api/src/routes/job_route.ts b/apps/api/src/routes/job_route.ts index 942f972..607fafe 100644 --- a/apps/api/src/routes/job_route.ts +++ b/apps/api/src/routes/job_route.ts @@ -1,4 +1,7 @@ import express from 'express' +const router = express.Router() +import { validate_schema } from '@/middleware/validation_middleware' +import { JOB_VALIDATION_SCHEMA } from '@/validations/job_validation' import { delete_job, get_job, @@ -6,10 +9,6 @@ import { post_job, update_job, } from '@/controllers/job_controller' -import { validate_job_data } from '@/middleware/job_validation_middleware' -import { JOB_VALIDATION_SCHEMA } from '@/validations/job_validation' - -const router = express.Router() //* @desc Get all jobs //? @access Public @@ -21,7 +20,7 @@ router.get('/:id', get_job) //* @desc Post job //! @access Private -router.post('/', validate_job_data(JOB_VALIDATION_SCHEMA), post_job) +router.post('/', validate_schema(JOB_VALIDATION_SCHEMA), post_job) //* @desc Delete job //! @access Private @@ -29,6 +28,6 @@ router.delete('/:id', delete_job) //* @desc Update job //! @access Private -router.patch('/:id', validate_job_data(JOB_VALIDATION_SCHEMA), update_job) +router.patch('/:id', validate_schema(JOB_VALIDATION_SCHEMA), update_job) export default router diff --git a/apps/api/src/routes/user_route.ts b/apps/api/src/routes/user_route.ts new file mode 100644 index 0000000..f9e4d86 --- /dev/null +++ b/apps/api/src/routes/user_route.ts @@ -0,0 +1,28 @@ +import express from 'express' +const router = express.Router() +import { validate_schema } from '@/middleware/validation_middleware' +import { USER_VALIDATION_SCHEMA } from '@/validations/user_validation' +import { + delete_user, + get_user, + post_user, + update_user, +} from '@/controllers/user_controller' + +//* @desc Post user +//? @access Public +router.post('/', validate_schema(USER_VALIDATION_SCHEMA), post_user) + +//* @desc Get user +//! @access Private +router.get('/:id', get_user) + +//* @desc Delete user +//! @access Private +router.delete('/:id', delete_user) + +//* @desc Update user +//! @access Private +router.patch('/:id', validate_schema(USER_VALIDATION_SCHEMA), update_user) + +export default router diff --git a/apps/api/src/server.ts b/apps/api/src/server.ts index d805a66..8ab8cff 100644 --- a/apps/api/src/server.ts +++ b/apps/api/src/server.ts @@ -3,10 +3,8 @@ import express, { type Express } from 'express' import morgan from 'morgan' import cors from 'cors' import { config } from 'dotenv' -import { connect_db } from 'config/db' config() -connect_db() export const createServer = (): Express => { const app = express() diff --git a/apps/api/src/validations/user_validation.ts b/apps/api/src/validations/user_validation.ts new file mode 100644 index 0000000..15b960f --- /dev/null +++ b/apps/api/src/validations/user_validation.ts @@ -0,0 +1,7 @@ +import { z } from 'zod' + +export const USER_VALIDATION_SCHEMA = z.object({ + name: z.string(), + email: z.string().email(), + password: z.string().min(6), +}) diff --git a/apps/api/types/index.ts b/apps/api/types/index.ts deleted file mode 100644 index 6515841..0000000 --- a/apps/api/types/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -export type Job = { - company: string - logo?: string - featured?: boolean - position: string - role: string - level: string - contract: string - location: string - languages: string[] - tools: string[] -} diff --git a/apps/api/types/package.json b/apps/api/types/package.json deleted file mode 100644 index ae7e391..0000000 --- a/apps/api/types/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "@repo/types", - "version": "1.0.0", - "description": "", - "main": "./src/index.ts", - "types": "./src/index.ts", - "exports": { - ".": "./src/index.ts" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [], - "author": "", - "license": "MIT" -}