A simple Node-Express REST API with fully functional CRUD operations and a frontend UI/UX implementation following a MVC design pattern. Developed, tested and deployed in less than 30 hours during the GUC final exams.
Postman
supported release, check the other branch named postman
This project was created for Vekelz.com as part of an ongoing status. It was a personal challenge for me to encounter, as this project was assigned to me during a very critical period which is the final exams' period.
It was assigned to me throughout my preperations for the Analysis & Design of Algorithms
final exam, hence I challenged myself to finish both of those assignments on time and effeciently.
- This project is currently a work-in-progress.
- Unit tests using
jest
will be added in the next roll-out.
- The code style is enforced using
prettier
. - camelCase in variable names was used.
- Standard development naming conventions were used.
You can then run Prettier on your code by using the prettier command in your terminal. For example:
prettier --write "src/**/*.js"
and using the formatting command:
Alt + Shift + F
The system serves all different types of CRUD operations synchronously with a provided MySQL database.
- Create, Read, Update and Delete specific users by ID.
- Create, Read, Update and Delete all users.
- Create, Read, Update and Delete specific cars by ID.
- Create, Read, Update and Delete all users.
// UPDATE (PUT) a single Car with a given id
exports.updateCar = async (req, res) => {
// Validate request
if (!req.body) {
res.status(400).send({
message: "Content can not be empty!",
});
}
// Save Car in the database
await Car.update(
{
carMake: req.body.carMake,
carModel: req.body.carModel,
color: req.body.color,
userId: req.body.userId,
},
{
where: {
id: req.params.id,
},
}
)
.then((car) => {
CarImage.findAll({
where: {
carId: req.params.id,
},
}).then((carimages) => {
let index = 0;
carimages.forEach(async (carimage) => {
if (req.files[index]) {
carimage.update({
image: db.Sequelize.fn(
"concat",
`http://localhost:${process.env.port}/Media/`,
req.files[index].filename
),
});
index++;
}
});
});
req.session.message = {
type: "info",
message: `Car with ID ${req.params.id} was updated successfully`,
};
res.redirect("/api/cars");
})
.catch((err) => {
if (err.kind === "not_found") {
res.status(404).send({
message: `Not found Car with id ${req.params.id}.`,
});
} else {
console.log(err);
res.status(500).send({
message: "Error updating Car with id " + req.params.id,
});
}
});
};
<!-- Render Users Table -->
<div class="table-responsive">
<table class="table table-dark text-center">
<thead>
<tr>
<th>ID</th>
<th>Image</th>
<th>First Name</th>
<th>Last Name</th>
<th>E-Mail</th>
<th>Phone</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<% users.forEach(function(user){ %>
<tr class="align-middle">
<td>
<%= user.id %>
</td>
<td>
<img src="<%= user.image.substr(21) %>" width="70" />
</td>
<td>
<%= user.firstName %>
</td>
<td>
<%= user.lastName %>
</td>
<td>
<%= user.email %>
</td>
<td>
<%= user.phone %>
</td>
<td>
<a href="user/<%= user.id %>" class="btn btn-dark btn-sm"
style="background-color: #649094;">View</a>
<a href="user/update/<%= user.id %>" class="btn btn-dark btn-sm"
style="background-color: #649094;">Update</a>
<a href="user/delete/<%= user.id %>" class="btn btn-light btn-sm"
style="background-color: #f4cc0c;">Delete</a>
</td>
</tr>
<% }); %>
</tbody>
</table>
</div>
- First of all, you will need to import the provided database to your local MySQL environment using the following command:
> mysql -u your_username -p vekelz < vekelz.sql
or through any GUI like MySQL Workbench or phpMyAdmin.
- Then, install all the needed dependencies with
npm
:
> git clone /~https://github.com/ahmillect/Vekelz
> cd Vekelz/
> cd npm i
To start the server type in the following command:
cd nodemon app
and then the backend server will be running on the specified port in your .env
file.
To run this project, you must add the following environment variables to your .env
file:
PORT
HOST
USERNAME
PASSWORD
- The
PORT
refers to the port you want to run and test the server on. - The
HOST
refers to your MySQL host. - The
USERNAME
refers to your MySQL username. - The
PASSWORD
refers to your MySQL password, if any.
- Testing was done using
Postman
on every API end-point. - For a
Postman
test-driven version of this project, clone the branch namedpostman
instead ofmaster
.
- Asynchronous programming was used.
- Indexes were used on the database to optimize search.
- To get a better understanding for how the models are related to each other, check the schema diagram from here!
POST /user
Body | Type | Description |
---|---|---|
firstName |
varchar |
Required. firstName of the user |
lastName |
varchar |
Required. lastName of the user |
email |
varchar |
Required. email of the user |
phone |
varchar |
Required. password of the user |
image |
text |
Required. link for the user's image |
Response
{
"id": 10,
"firstName": "John",
"lastName": "James",
"email": "john@email.com",
"phone": "12345",
"image": "http://localhost:3500/Media/ggwywwzocuyofvkkdukwmlncvgfxoewzaeimbbgemm.jpg"
}
GET /user
Response
[
{
"id": 5,
"firstName": "John",
"lastName": "James",
"email": "john@email.com",
"phone": "12345",
"image": "http://localhost:3500/Media/nlbrqwlqvuirrkovcjgqfmrjcmptelsfzbtabgtvf.jpg"
},
{
"id": 6,
"firstName": "John",
"lastName": "James",
"email": "john@email.com",
"phone": "12345",
"image": "http://localhost:3500/Media/skldthjgpneixoatshqhkitkpsmflrrdazfgaoeop.jpg"
},
{
"id": 7,
"firstName": "John",
"lastName": "James",
"email": "john@email.com",
"phone": "12345",
"image": "http://localhost:3500/Media/hzinynnrwoqigvhrbjiuxhbbzifxxivnutfyfqibg.jpg"
}
]
PUT /user
Body | Type | Description |
---|---|---|
firstName |
varchar |
Required. firstName of the user |
lastName |
varchar |
Required. lastName of the user |
email |
varchar |
Required. email of the user |
phone |
varchar |
Required. password of the user |
image |
text |
Required. link for the user's image |
Response
{
"message": "All Users were updated successfully"
}
DELETE /user
Response
{
"message": "All Users were deleted successfully"
}
GET /user/:id
Response
{
"id": 5,
"firstName": "John",
"lastName": "James",
"email": "john@email.com",
"phone": "12345",
"image": "http://localhost:3500/Media/nlbrqwlqvuirrkovcjgqfmrjcmptelsfzbtabgtvf.jpg"
}
PUT /user/:id
Body | Type | Description |
---|---|---|
firstName |
varchar |
Required. firstName of the user |
lastName |
varchar |
Required. lastName of the user |
email |
varchar |
Required. email of the user |
phone |
varchar |
Required. password of the user |
image |
text |
Required. link for the user's image |
Response
{
"message": "User with ID 5 was updated successfully"
}
DELETE /user/:id
Response
{
"message": "User with ID 5 was deleted successfully"
}
POST /cars
Body | Type | Description |
---|---|---|
carMake |
varchar |
Required. carMake of the car |
carModel |
varchar |
Required. carModel of the car |
color |
varchar |
Required. color of the car |
userId |
varchar |
Required. id of the user who owns the car |
images |
file |
Required. multiple images for the car |
Response
{
"id": 5,
"carMake": "Skoda",
"carModel": "Octavia",
"color": "Grey",
"userId": "5"
}
GET /cars
Response
[
{
"id": 4,
"carMake": "Honda",
"carModel": "Accord",
"color": "Red",
"images": [
{
"id": 10,
"image": "http://localhost:3500/Media/xaqirajzzdwsqhoroenrsybornccxifoilestwinc.jpg"
}
],
"user": {
"id": 5,
"firstName": "John",
"lastName": "James",
"email": "john@email.com",
"phone": "12345",
"image": "http://localhost:3500/Media/ezladcknyvartlejsranvrzuntebmqxgdczumjfcv.jpg"
}
},
{
"id": 5,
"carMake": "Skoda",
"carModel": "Octavia",
"color": "Grey",
"images": [
{
"id": 11,
"image": "http://localhost:3500/Media/kzeujkjtwriwqexugnbxuizhxqvcnkebwvjrnplum.jpg"
},
{
"id": 12,
"image": "http://localhost:3500/Media/lgatchpwzcvgcvzrgckfijezncifhbjraxoznapjc.jpg"
},
{
"id": 13,
"image": "http://localhost:3500/Media/qaovtcbjoqkkupnkwfkwpcioqrmkwkfnynjbkamij.jpg"
},
{
"id": 14,
"image": "http://localhost:3500/Media/msbbtpgvxrlrndcffixsbseqmufdedppokxecrmju.jpg"
}
],
"user": {
"id": 5,
"firstName": "John",
"lastName": "James",
"email": "john@email.com",
"phone": "12345",
"image": "http://localhost:3500/Media/ezladcknyvartlejsranvrzuntebmqxgdczumjfcv.jpg"
}
}
]
PUT /cars
Body | Type | Description |
---|---|---|
carMake |
varchar |
Required. carMake of the car |
carModel |
varchar |
Required. carModel of the car |
color |
varchar |
Required. color of the car |
userId |
varchar |
Required. id of the user who owns the car |
image |
file |
Required. one single image for all the cars |
Response
{
"message": "All Cars were updated successfully"
}
DELETE /cars
Response
{
"message": "All Cars were deleted successfully"
}
GET /cars/:id
Response
{
"id": 5,
"carMake": "Skoda",
"carModel": "Octavia",
"color": "Grey",
"images": [
{
"id": 11,
"image": "http://localhost:3500/Media/kzeujkjtwriwqexugnbxuizhxqvcnkebwvjrnplum.jpg"
},
{
"id": 12,
"image": "http://localhost:3500/Media/lgatchpwzcvgcvzrgckfijezncifhbjraxoznapjc.jpg"
},
{
"id": 13,
"image": "http://localhost:3500/Media/qaovtcbjoqkkupnkwfkwpcioqrmkwkfnynjbkamij.jpg"
},
{
"id": 14,
"image": "http://localhost:3500/Media/msbbtpgvxrlrndcffixsbseqmufdedppokxecrmju.jpg"
}
],
"user": {
"id": 5,
"firstName": "John",
"lastName": "James",
"email": "john@email.com",
"phone": "12345",
"image": "http://localhost:3500/Media/ezladcknyvartlejsranvrzuntebmqxgdczumjfcv.jpg"
}
}
PUT /cars/:id
Body | Type | Description |
---|---|---|
carMake |
varchar |
Required. carMake of the car |
carModel |
varchar |
Required. carModel of the car |
color |
varchar |
Required. color of the car |
userId |
varchar |
Required. id of the user who owns the car |
images |
file |
Required. multiple images for the car |
Response
{
"message": "Car with ID 5 was updated successfully"
}
DELETE /cars/:id
Response
{
"message": "Car with ID 5 was deleted successfully"
}
Refer to the LICENSE.md file for more information
© Copyright 2023 [Ahmed Khaled] [Vekelz]