Skip to content

Commit f845354

Browse files
DafloresdiazDaniel Flores Diaz
and
Daniel Flores Diaz
authored
Feat: CRUD functionality (#11)
Co-authored-by: Daniel Flores Diaz <[email protected]>
1 parent 15339f2 commit f845354

File tree

14 files changed

+876
-46
lines changed

14 files changed

+876
-46
lines changed

.env.example

+5
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
SECRET_KEY = 'foo';
22
EXPIRES_IN = '1h';
3+
POSTGRES_USER = 'postgres';
4+
POSTGRES_PASSWORD = 'changethis';
5+
POSTGRES_HOST ='db';
6+
POSTGRES_DB = 'ca_microservices_nodejs';
7+
POSTGRES_PORT = '5432';

app/internal/core/controllers/users.controller.js

+21-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { constants } from 'http2';
22
import { UserServices } from '../services';
3+
import { UserModel } from '../models';
34

45
/**
56
* Callback function for getting a user by id.
@@ -8,9 +9,9 @@ import { UserServices } from '../services';
89
* @param {import('express').Response} res - Express response object.
910
* @param {import('express').NextFunction} next - Express next middleware function.
1011
*/
11-
const getById = (req, res, next) => {
12+
const getById = async (req, res, next) => {
1213
try {
13-
const message = UserServices.getById();
14+
const message = await UserServices.getById(req.db.client, req.params.id);
1415
res.status(constants.HTTP_STATUS_OK).json(message);
1516
} catch (err) {
1617
next(err);
@@ -26,7 +27,22 @@ const getById = (req, res, next) => {
2627
*/
2728
const create = async (req, res, next) => {
2829
try {
29-
const message = UserServices.create();
30+
const err = UserModel.validate(req.body)
31+
if (err.error) {
32+
throw new Error(`Request is not correct`);
33+
}
34+
const { first_name, last_name, email } = req.body;
35+
const newUser = new UserModel({
36+
email: email,
37+
first_name: first_name,
38+
last_name: last_name,
39+
});
40+
const message = UserServices.create(
41+
req.db.client,
42+
newUser.first_name,
43+
newUser.last_name,
44+
newUser.email,
45+
);
3046
res.status(constants.HTTP_STATUS_OK).json(message);
3147
} catch (err) {
3248
next(err);
@@ -42,7 +58,7 @@ const create = async (req, res, next) => {
4258
*/
4359
const update = async (req, res, next) => {
4460
try {
45-
const message = UserServices.update();
61+
const message = await UserServices.update(req.db.client, req.params.id, req.body);
4662
res.status(constants.HTTP_STATUS_OK).json(message);
4763
} catch (err) {
4864
next(err);
@@ -58,7 +74,7 @@ const update = async (req, res, next) => {
5874
*/
5975
const drop = async (req, res, next) => {
6076
try {
61-
const message = UserServices.deleteByID();
77+
const message = await UserServices.deleteByID(req.db.client, req.params.id);
6278
res.status(constants.HTTP_STATUS_OK).json(message);
6379
} catch (err) {
6480
next(err);

app/internal/core/domain/models/responses.models.js

+33
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,40 @@ const tokenResponse = (token, expiresIn) => ({
3838
tokenType: 'Bearer',
3939
});
4040

41+
/**
42+
* Represents a token response object.
43+
* @typedef {object} UserResponse
44+
* @property {string} id - The user id.
45+
* @property {string} firstName - User first name.
46+
* @property {string} lastName - User last name.
47+
* @property {string} email - User email.
48+
*/
49+
50+
/**
51+
* Creates a token response object.
52+
* @param {string} success - A simple flag.
53+
* @param {string} message - A simple message about the response.
54+
* @param {Map} user - The user information from the database.
55+
* @param {string} id - The id in UUID form of the user.
56+
* @param {string} first_name - The first name of the user.
57+
* @param {string} last_name - The last_name of the user.
58+
* @param {string} email - The email from the user.
59+
* @returns {UserResponse} The user response with the information about the user.
60+
*/
61+
62+
const userResponse = (id, firstName, lastName, email) =>({
63+
success: true,
64+
message: "Success",
65+
user: {
66+
id: id,
67+
first_name: firstName,
68+
last_name: lastName,
69+
email: email,
70+
}
71+
});
72+
4173
export const Responses = {
4274
simple,
4375
tokenResponse,
76+
userResponse,
4477
};

app/internal/core/middlewares/auth.middleware.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const Auth = (req, res, next) => {
2121
req.headers.authorization && req.headers.authorization.split(' ')[1];
2222
if (token !== 'undefined' && tokenPaths.includes(req.path.slice(0, 7))) {
2323
try {
24-
JWT.verifyToken(token, req.defaultConfig.auth.secretKey);
24+
JWT.verifyToken(token, req.config.auth.securityKey);
2525
next();
2626
} catch (err) {
2727
next(err);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Auth middlewares
3+
* @module Middlewares/Database
4+
*/
5+
6+
import {Pool} from "pg";
7+
8+
/**
9+
* Express middleware to create the connection to the database.
10+
* @function
11+
* @param {import('express').Request} req - The Express request object.
12+
* @param {import('express').Response} res - The Express response object.
13+
* @param {import('express').NextFunction} next - The Express next function.
14+
* @throws {Error} If authentication fails.
15+
*/
16+
export const DatabaseConnection = (req, res, next) => {
17+
const { user, password, host, port, database } = req.config.db;
18+
try {
19+
const dbConfig = {
20+
user: user,
21+
password: password,
22+
host: host,
23+
port: port,
24+
database: database
25+
};
26+
const client = new Pool(dbConfig);
27+
client.connect((err, client, release) => {
28+
if (err) {
29+
console.error('Error connecting to PostgreSQL database:', err);
30+
return res.status(500).send('Error connecting to database');
31+
}
32+
console.log('Connected to PostgreSQL database');
33+
req.db = { client, release };
34+
next();
35+
});
36+
} catch (ex) {
37+
console.error('Error connecting to PostgreSQL database:', ex);
38+
res.status(500).send();
39+
}
40+
};

app/internal/core/middlewares/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from './logs.middleware';
22
export * from './error.middleware';
33
export * from './configurations.middleware';
44
export * from './auth.middleware';
5+
export * from './database.middleware';

app/internal/core/models/users.model.js

-7
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@ import { model, Schema } from 'mongoose';
77
*/
88
const createUserSchema = new Schema(
99
{
10-
Id: {
11-
type: Number,
12-
required: true,
13-
},
1410
email: {
1511
type: String,
1612
required: true,
@@ -23,9 +19,6 @@ const createUserSchema = new Schema(
2319
type: String,
2420
required: true,
2521
},
26-
company: String,
27-
url: String,
28-
text: String,
2922
},
3023
{ timestamps: true, versionKey: false },
3124
);

app/internal/core/providers/config.provider.js

+7
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,11 @@ export const defaultConfig = {
2020
securityKey: process.env.SECRET_KEY,
2121
expiresIn: process.env.EXPIRES_IN,
2222
},
23+
db: {
24+
user: process.env.POSTGRES_USER,
25+
password: process.env.POSTGRES_PASSWORD,
26+
host: process.env.POSTGRES_HOST,
27+
port: process.env.POSTGRES_PORT,
28+
database: process.env.POSTGRES_DB
29+
}
2330
};
+64-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/** @module Services/Users */
22

33
import { Domain } from '../domain';
4+
import {v4 as uuidv4} from 'uuid';
45

56
const {
67
Models: { Responses },
@@ -9,31 +10,86 @@ const {
910
/**
1011
* Get user by ID.
1112
* @function
12-
* @returns {import('../domain/models/responses.models.js').SimpleResponse} The response for the get by ID request.
13+
* @param {db} db - DB client for the connection to the database.
14+
* @param {string} id - The UUID for the user in the database.
15+
* @returns {import('../domain/models/responses.models.js').UserResponse} The response for the get by ID request.
1316
*/
14-
const getById = () => Responses.simple('This is a response from a GET request');
17+
const getById = async (db, id) => {
18+
try{
19+
const query = 'SELECT id, first_name, last_name, email FROM users WHERE id=$1';
20+
const result = await db.query(query, [id]);
21+
if (result.rows.length === 0) {
22+
return Responses.simple(`User with ${id} is not in the database.`);
23+
} else {
24+
return Responses.userResponse(id,result.rows[0].first_name, result.rows[0].last_name, result.rows[0].email);
25+
}
26+
} catch (error) {
27+
return error;
28+
}
29+
}
1530

1631
/**
1732
* Create a new user.
1833
* @function
19-
* @returns {import('../domain/models/responses.models.js').SimpleResponse} The response for the create request.
34+
* @param {db} db - DB client for the connection to the database.
35+
* @param {string} firstName - The first name of the user.
36+
* @param {string} lastName - The last name of the user.
37+
* @param {string} email - The email from the user.
38+
* @returns {import('../domain/models/responses.models.js').userResponse} The response for the create request.
2039
*/
21-
const create = () => Responses.simple('This is a response from a POST request');
40+
const create = (db, firstName, lastName, email) => {
41+
const randomUuid = uuidv4();
42+
const query = 'INSERT INTO users (id, first_name, last_name, email) VALUES ($1, $2, $3, $4)';
43+
db.query(query, [randomUuid, firstName, lastName, email]);
44+
return Responses.userResponse(randomUuid, firstName, lastName, email);
45+
};
2246

2347
/**
2448
* Update an existing user.
2549
* @function
50+
* @param {db} db - DB client for the connection to the database.
51+
* @param {string} id - The id of the user.
52+
* @param {Map} body - THe fields to be updated.
2653
* @returns {import('../domain/models/responses.models.js').SimpleResponse} The response for the update request.
2754
*/
28-
const update = () =>
29-
Responses.simple('This is a response from an UPDATE request');
55+
const update = async (db, id, body) =>{
56+
try{
57+
const updates = [];
58+
const values = [id];
59+
let index = 2;
60+
for (const value in body) {
61+
updates.push(`${value} = $${index}`);
62+
values.push(body[value]);
63+
index++;
64+
}
65+
const query = `UPDATE users SET ${updates.join(',')} WHERE id = $1`;
66+
db.query(query, values);
67+
return Responses.simple(`User with ${id} has been updated.`)
68+
} catch (error) {
69+
return error;
70+
}
71+
}
3072

3173
/**
3274
* Delete a user by ID.
3375
* @function
3476
* @returns {import('../domain/models/responses.models.js').SimpleResponse} The response for the delete request.
3577
*/
36-
const deleteByID = () =>
37-
Responses.simple('This is a response from a DELETE request');
78+
const deleteByID = async (db, id) =>{
79+
try{
80+
const query = 'SELECT id FROM users WHERE id=$1';
81+
const result = await db.query(query, [id]);
82+
if (result.rows.length === 0) {
83+
return Responses.simple(`User with ${id} is not in the database.`);
84+
} else{
85+
const query = 'DELETE FROM users WHERE id = $1';
86+
db.query(query, [id]);
87+
return Responses.simple(`User with ${id} has been deleted.`);
88+
}
89+
} catch (error) {
90+
return error;
91+
}
92+
}
93+
3894

3995
export const UserServices = { getById, create, update, deleteByID };

app/server/index.js

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
HandlerError,
88
Configurations,
99
Auth,
10+
DatabaseConnection,
1011
} from '../internal/core/middlewares';
1112

1213
const { Routes } = Adapters;
@@ -25,6 +26,9 @@ App.use(bodyParser.urlencoded({ extended: false }));
2526
// Apply global configurations middleware
2627
App.use(Configurations);
2728

29+
//Apply database middleware
30+
App.use(DatabaseConnection)
31+
2832
// Apply logger middleware
2933
App.use(Logger);
3034

db_migrations/000001.sql

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CREATE TABLE IF NOT EXISTS users (
2+
id TEXT PRIMARY KEY,
3+
first_name TEXT NOT NULL,
4+
last_name TEXT NOT NULL,
5+
email TEXT NOT NULL
6+
);

docker-compose.yml

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
version: "3.4"
22
services:
3+
db:
4+
container_name: ca-microservices-app-db
5+
image: postgres:latest
6+
restart: always
7+
environment:
8+
- POSTGRES_USER=postgres
9+
- POSTGRES_PASSWORD=changethis
10+
- POSTGRES_DB=ca_microservices_nodejs
11+
- POSTGRES_PORT=5432
12+
ports:
13+
- "5432:5432"
14+
volumes:
15+
- postgres_data:/var/lib/postgresql/data
16+
- ./db_migrations/000001.sql:/docker-entrypoint-initdb.d/000001.sql
17+
command: ["docker-entrypoint.sh", "postgres", "-c", "log_statement=all"]
318
express:
419
image: ca-microservices-nodejs:latest
520
container_name: ca-microservices-app
@@ -11,4 +26,12 @@ services:
1126
- NODE_ENV=development
1227
- PORT=3001
1328
- SECRET_KEY=secret_key_value
14-
- EXPIRES_IN=1h
29+
- EXPIRES_IN=1h
30+
- POSTGRES_USER=postgres
31+
- POSTGRES_PASSWORD=changethis
32+
- POSTGRES_HOST=db
33+
- POSTGRES_DB=ca_microservices_nodejs
34+
- POSTGRES_PORT=5432
35+
restart: on-failure
36+
volumes:
37+
postgres_data:

0 commit comments

Comments
 (0)