-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ea8bc19
commit 3cacb30
Showing
13 changed files
with
718 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
MONGO_URI=YOUR_MONGO_URI | ||
PORT=5000 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/node_modules | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
73
Existing_API_Collection/ProductStoreAPI/controllers/products.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
6 changes: 6 additions & 0 deletions
6
Existing_API_Collection/ProductStoreAPI/middleware/error-handler.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
3 changes: 3 additions & 0 deletions
3
Existing_API_Collection/ProductStoreAPI/middleware/not-found.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
Oops, something went wrong.