Skip to content

Commit

Permalink
ProductStore API
Browse files Browse the repository at this point in the history
  • Loading branch information
thesohailjafri committed Oct 11, 2023
1 parent ea8bc19 commit 3cacb30
Show file tree
Hide file tree
Showing 13 changed files with 718 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Existing_API_Collection/ProductStoreAPI/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
MONGO_URI=YOUR_MONGO_URI
PORT=5000
2 changes: 2 additions & 0 deletions Existing_API_Collection/ProductStoreAPI/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/node_modules
.env
75 changes: 75 additions & 0 deletions Existing_API_Collection/ProductStoreAPI/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Lets build a Product Store API using NodeJS, ExpressJS, MongoDB and Mongoose

## Table of contents

- [What is an API?](#what-is-an-api)
- [What is a REST API?](#what-is-a-rest-api)
- [Getting Started](#getting-started)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Built With](#built-with)
- [Author](#author)

## What is an API?

An API is an application programming interface. It is a set of rules that allow programs to talk to each other. The developer creates the API on the server and allows the client to talk to it.

## What is a REST API?

A REST API is an API that conforms to the design principles of the REST, or representational state transfer architectural style. REST APIs are stateless, meaning that calls can be made independently of one another, and contain all of the information necessary to complete itself successfully.

## Getting Started

### Prerequisites

- NodeJS
- MongoDB
- Postman

### Installation

- Clone the repository
- Type in the following command in the terminal

```bash
cd ProductStoreAPI
npm install
```

- Create a .env file in the root directory and add the following
- Add your MongoDB connection string and desired port number

```bash
MONGO_URI = <YOUR_MONGODB_CONNECTION_STRING>
PORT = <YOUR_DESIRED_PORT_NUMBER>
```

- Run the following command in the terminal

```bash
npm start
```

- Open Postman and test the API by sending requests to the following endpoints

```bash
GET http://localhost:3000/api/v1/products
GET http://localhost:3000/api/v1/products?name=Chair
GET http://localhost:3000/api/v1/products?name=Chair&featured=true&company=ikea&sort=price&fields=name,price&numericFilters[price]=<100
```

## Built With

- [NodeJS](https://nodejs.org/en/)
- [ExpressJS](https://expressjs.com/)
- [MongoDB](https://www.mongodb.com/)
- [Mongoose](https://mongoosejs.com/)
- [Postman](https://www.postman.com/)
- [VS Code](https://code.visualstudio.com/)
- [Git](https://git-scm.com/)

## Author

- Github - [thesohailjafri](https://github.com/thesohailjafri)
- LinkedIn - [thesohailjafri](https://www.linkedin.com/in/thesohailjafri/)
- Twitter - [@thesohailjafri](https://twitter.com/thesohailjafri)
41 changes: 41 additions & 0 deletions Existing_API_Collection/ProductStoreAPI/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require('dotenv').config();
require('express-async-errors');

const express = require('express');
const app = express();

const connectDB = require('./db/connect');
const productsRouter = require('./routes/products');

const notFoundMiddleware = require('./middleware/not-found');
const errorMiddleware = require('./middleware/error-handler');

// middleware
app.use(express.json());

// routes

app.get('/', (req, res) => {
res.send('<h1>Store API</h1><a href="/api/v1/products">products route</a>');
});

app.use('/api/v1/products', productsRouter);

// products route

app.use(notFoundMiddleware);
app.use(errorMiddleware);

const port = process.env.PORT || 3000;

const start = async () => {
try {
// connectDB
await connectDB(process.env.MONGO_URI);
app.listen(port, () => console.log(`Server is listening port ${port}...`));
} catch (error) {
console.log(error);
}
};

start();
73 changes: 73 additions & 0 deletions Existing_API_Collection/ProductStoreAPI/controllers/products.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
const Product = require('../models/product');

const getAllProductsStatic = async (req, res) => {
const products = await Product.find({ price: { $gt: 30 } })
.sort('price')
.select('name price');

res.status(200).json({ products, nbHits: products.length });
};
const getAllProducts = async (req, res) => {
const { featured, company, name, sort, fields, numericFilters } = req.query;
const queryObject = {};

if (featured) {
queryObject.featured = featured === 'true' ? true : false;
}
if (company) {
queryObject.company = company;
}
if (name) {
queryObject.name = { $regex: name, $options: 'i' };
}
if (numericFilters) {
const operatorMap = {
'>': '$gt',
'>=': '$gte',
'=': '$eq',
'<': '$lt',
'<=': '$lte',
};
const regEx = /\b(<|>|>=|=|<|<=)\b/g;
let filters = numericFilters.replace(
regEx,
(match) => `-${operatorMap[match]}-`
);
const options = ['price', 'rating'];
filters = filters.split(',').forEach((item) => {
const [field, operator, value] = item.split('-');
if (options.includes(field)) {
queryObject[field] = { [operator]: Number(value) };
}
});
}

let result = Product.find(queryObject);
// sort
if (sort) {
const sortList = sort.split(',').join(' ');
result = result.sort(sortList);
} else {
result = result.sort('createdAt');
}

if (fields) {
const fieldsList = fields.split(',').join(' ');
result = result.select(fieldsList);
}
const page = Number(req.query.page) || 1;
const limit = Number(req.query.limit) || 10;
const skip = (page - 1) * limit;

result = result.skip(skip).limit(limit);
// 23
// 4 7 7 7 2

const products = await result;
res.status(200).json({ products, nbHits: products.length });
};

module.exports = {
getAllProducts,
getAllProductsStatic,
};
12 changes: 12 additions & 0 deletions Existing_API_Collection/ProductStoreAPI/db/connect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const mongoose = require('mongoose')

const connectDB = (url) => {
return mongoose.connect(url, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
useUnifiedTopology: true,
})
}

module.exports = connectDB
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const errorHandlerMiddleware = async (err, req, res, next) => {
console.log(err)
return res.status(500).json({ msg: 'Something went wrong, please try again' })
}

module.exports = errorHandlerMiddleware
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const notFound = (req, res) => res.status(404).send('Route does not exist')

module.exports = notFound
48 changes: 48 additions & 0 deletions Existing_API_Collection/ProductStoreAPI/models/product.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const mongoose = require('mongoose')
// use https://json-generator.com/ to generate fake data
// use below code to generate fake data for product collection
// [
// '{{repeat(50)}}',
// {
// name: '{{company()}} {{random("Bed", "Sofa", "Table", "Desk", "Wardrobe", "Chair")}}',
// price: '{{floating(300, 1000, 2, "$0,0.00")}}',
// featured: '{{bool()}}',
// rating: '{{floating(1, 5, 1, "0.0")}}',
// createdAt: '{{date(new Date(2020, 0, 1), new Date(), "YYYY-MM-ddThh:mm:ss Z")}}',
// company: '{{random("ikea", "liddy", "caressa", "marcos")}}',
// }
// ]
// paste the data in products.json file if want to use different data

const productSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'product name must be provided'],
},
price: {
type: Number,
required: [true, 'product price must be provided'],
},
featured: {
type: Boolean,
default: false,
},
rating: {
type: Number,
default: 4.5,
},
createdAt: {
type: Date,
default: Date.now(),
},
company: {
type: String,
enum: {
values: ['ikea', 'liddy', 'caressa', 'marcos'],
message: '{VALUE} is not supported',
},
// enum: ['ikea', 'liddy', 'caressa', 'marcos'],
},
})

module.exports = mongoose.model('Product', productSchema)
21 changes: 21 additions & 0 deletions Existing_API_Collection/ProductStoreAPI/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "jobs",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "nodemon app.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-async-errors": "^3.1.1",
"mongoose": "^5.11.10"
},
"devDependencies": {
"nodemon": "^2.0.7"
}
}
21 changes: 21 additions & 0 deletions Existing_API_Collection/ProductStoreAPI/populate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require('dotenv').config()

const connectDB = require('./db/connect')
const Product = require('./models/product')

const jsonProducts = require('./products.json')

const start = async () => {
try {
await connectDB(process.env.MONGO_URI)
await Product.deleteMany()
await Product.create(jsonProducts)
console.log('Success!!!!')
process.exit(0)
} catch (error) {
console.log(error)
process.exit(1)
}
}

start()
Loading

0 comments on commit 3cacb30

Please sign in to comment.