❄ Express.js Middleware Documentation
❄ Building a Simple CRUD app with Node, Express, and MongoDB
❄ Postman API testing by example
❄ Connecting to a MongoDB database using Node.js
❄ How to use CORS in Node.js with Express
❄ React Query - Hooks for fetching, caching and updating asynchronous data in React
- create folder structure (backend/frontend)
npm init -y
npm i express cors mongodb dotenv jsonwebtoken
npm i -g nodemon
- create
.gitignore
insertnode_modules
and.env
- go to
package.json
"scripts": {
"start": "node index.js",
"start-dev": "nodemon index.js",
}
- create
index.js
// Basic
const express = require("express");
const app = express();
const port = 5000;
app.get("/users", async (req, res) => {
res.send({message: "Hello Users"})
})
app.listen(port, () => {
console.log("Listening to port", port);
});
// Standard
const express = require("express");
const app = express(); // create app by calling express()
const cors = require("cors");
const jwt = require('jsonwebtoken');
const { MongoClient, ServerApiVersion } = require("mongodb");
const ObjectId = require('mongodb').ObjectId;
const port = process.env.PORT || 5000;
require('dotenv').config();
// use middleware
app.use(cors()); // Allow access for two different port and server
app.use(express.json()); // For parsing body of POST and PUT Method
// for testing
app.get("/", (req, res) => {
res.send({ message: "Success" });
});
app.listen(port, () => {
console.log("Listening to port", port);
});
nodemon index.js
(run backend server)
- go to > dotenv guide - https://northflank.com/guides/connecting-to-a-mongo-db-database-using-node-js
require('dotenv').config();
- create
.env
variable MONGO_URI=mongo+srv://<user>:<pass>@<host>:<port>/<database>?<connection options>
- doesn't matter, using :-
- whitespace between (=)
- string
- not using string
- const uri = process.env.MONGO_URI;
- sign up using google
- create user/pass (copy)
- network access > ip address: allow access from anywhere
- database > connect > connect your application > copy from include all
- paste in
index.js
(Server) - replace with
<password>
- comment
// client.close()
✔
- paste async run function
- copy from mongodb initial setup connection
const uri = `mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASS}@cluster0.iukjo.mongodb.net/myFirstDatabase?retryWrites=true&w=majority`;
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
serverApi: ServerApiVersion.v1,
});
async function run() {
try {
await client.connect();
// Collections
/*
const myCollection = client.db(Database Name).collection(Collection Name [plural]);
const productCollection = client.db("dewalt_DB").collection("products");
const reviewCollection = client.db("dewalt_DB").collection("reviews");
const orderCollection = client.db("dewalt_DB").collection("orders");
const userCollection = client.db("dewalt_DB").collection("users");
const paymentCollection = client.db("dewalt_DB").collection("payments");
*/
app.get("/inventory", async (req, res) => { // Endpoint name must be singular
const query = req.query;
const cursor = myCollection.find(query);
const result = await cursor.toArray();
console.log("mongodb connected");
res.send(result);
});
} finally {
// await client.close(); // do not forget to comment ✔
}
}
run().catch(console.dir); // do not forget to call run ✔
// for testing
/*
app.get("/", (req, res) => {
res.send({ message: "Success" });
});
*/
app.listen(port, () => {
console.log("Listening to port", port);
});
Find Multiple Documents - https://www.mongodb.com/docs/drivers/node/current/usage-examples/find/#find-multiple-documents
app.get("/products", async (req, res) => {
const query = req.query;
const products = await productCollection.find(query).toArray();
res.send(products);
});
- using fetch
const [products, setProducts] = useState([]);
const [isReload, setIsReload] = useState(false); ✔
useEffect(() => {
fetch("http://localhost:5000/products")
.then((res) => res.json())
.then((data) => setProducts(data));
}, [isReload]);
- using Axios
useEffect(() => {
const getItems = async () => {
const url = "http://localhost:5000/products";
const { data } = await axios.get(url);
setIsLoading(false);
setData(data);
};
getItems();
}, []);
- using React Query
const {
isLoading,
error,
data: products,
refetch,
} = useQuery("products", () =>
fetch("http://localhost:5000/products").then((res) =>
res.json()
)
);
if (isLoading) {
return <Loading />;
}
app.get("/products/:id", async (req, res) => {
const id = req.params.id;
const query = {_id: ObjectId(id)}
const product = await productCollection.findOne(query);
res.send(product);
});
- using fetch
- using Axios
- using React Query
- jwt authorization
- Implement 401 and 403
const {
isLoading,
error,
data: product,
} = useQuery("product", () =>
fetch(`http:localhost:5000/products/${_id}`, {
method: "GET",
headers: {
authorization: `Bearer ${localStorage.getItem("accessToken")}`,
},
}).then((res) => {
if (res.status === 401 || res.status === 403) {
signOut(auth);
localStorage.removeItem("accessToken");
navigate("/login");
}
return res.json();
})
);
if (isLoading) {
return <Loading />;
}
app.post("/note", async (req, res) => {
const data = req.body;
console.log(data); // testing
const result = await notesCollection.insertOne(data);
res.send(result)
});
- go to > Insert a Document - https://www.mongodb.com/docs/drivers/node/current/usage-examples/insertOne/#insert-a-document
- we will create a single data so endpoint should be single example: ("/note")
- get receive body data from req.body
- send post request from postman Body > raw > JSON
- console.log(data) for testing post data
- pass data into collection
- send result as a response
- copy and comment endpoint from postman to index.js
app.put("/note/:id", async (req, res) => {
const id = req.params.id;
const data = req.body;
const filter = { _id: ObjectId(id) };
const options = { upsert: true };
const updateNote = {
$set: {
userName: data.userName,
textData: data.textData
},
/* modify object using spread operator
$set: {
...data
},
*/
};
const result = await notesCollection.updateOne(filter, updateNote, options);
res.send(result)
});
- go to Update a Document
- use params in endpoint example ("/note/:id")
- get id from
req.params.id
- here parameter need to be same
- example:
("/note/:same_parameter" && req.params.same_parameter)
- example:
- console.log(id) // testing
- passing id from url using Postman
http://localhost:5000/note/62659010b03fcf637b79ebdd
- get receive body data from req.body
- console.log(data) // testing
- create a filter for update
- require ObjectId and pass id parameter
- set option upsert: true:
- if not exist add new value or if exist update
- set update object manually or using spread operator example ...data
- updateOne(filter, updateNote, options), parameters need to be placed serially
- send result as a response
- copy and comment endpoint from postman to index.js
- test GET, POST, PUT methods using Postman
app.delete("/note/:id" , async(req, res) =>{
const id = req.params.id;
const filter = { _id: ObjectId(id) };
const result = await notesCollection.deleteOne(filter);
res.send(result);
})
- go to Delete a Document - https://www.mongodb.com/docs/drivers/node/current/usage-examples/deleteOne/#delete-a-document
- get id from req.params.id
- create a filter for delete
- set ObjectId and pass id parameter
- send result as a response
- test GET, POST, PUT, DELETE methods using Postman
- copy and comment endpoint from postman to index.js
const [notes, setNotes] = useState([]);
const [isReload, setIsReload] = useState(false); ✔
useEffect(() => {
// GET Method 🐼
fetch("http://localhost:5000/notes")
.then((res) => res.json())
.then((data) => setNotes(data));
}, [isReload]);
- declare state for notes (all data)
- set isReload as a dependency for reload data after changes
const handleSearch = (e) => {
e.preventDefault();
const searchText = e.target.searchText.value;
// clear input
e.target.searchText.value = "";
if(searchText === ""){ // load all data when empty
fetch("http://localhost:5000/notes")
.then((res) => res.json())
.then((data) => setNotes(data));
} else{
fetch(`http://localhost:5000/notes?userName=${searchText}`)
.then((res) => res.json())
.then((data) => setNotes(data)); ✔
}
};
- search by query parameter from MongoDB
- display result by setNotes(data) ✔
const handlePost = (e) => {
e.preventDefault();
const userName = e.target.userName.value;
const textData = e.target.textData.value;
// clear input
e.target.userName.value = "";
e.target.textData.value = "";
fetch("http://localhost:5000/note", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({ userName, textData }),
/* body:JSON.stringify({
"userName": userName,
"textData": textData
}) */
}).then((res) => res.json());
// .then((data) => console.log(data));
setIsReload(!isReload); ✔
};
- insert new data by POST Method
- body set by manually or object literal also using spread operator at backend
- reload by setIsReload(!isReload) ✔
- here isReload fetch all data after changes
const handleDelete = (id) => {
fetch(`http://localhost:5000/note/${id}`, {
method: "DELETE",
});
setIsReload(!isReload);
};
- delete data from MongoDB using DELETE Method
- reload by setIsReload(!isReload) ✔
- here isReload fetch all data after changes
const handleUpdate = (e) => {
e.preventDefault();
const userName = e.target.userName.value;
const textData = e.target.textData.value;
// clear input
e.target.userName.value = "";
e.target.textData.value = "";
fetch(`http://localhost:5000/note/${id}`, {
method: "PUT",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({ userName, textData }),
/* body:JSON.stringify({
"userName": userName,
"textData": textData
}) */
}).then((res) => res.json());
// .then((data) => console.log(data));
setIsReload(!isReload); ✔
};
- Update data using PUT Method
- reload by setIsReload(!isReload) ✔
- here isReload fetch all data after changes
- create custom hook is optional for [isReload, setIsReload]
- (req, res)
- req
- client থেকে request receive করে।
- req.body
- req.body is actually key value pair json data from POST method
body: JSON.stringify({ title: 'foo', body: 'bar', userId: 1, })
- req.query
- query strings from URL
- key value form
- start after (?) mark
- req.params.id
- receive dynamic parameter from URL
- endpoint using with /:id
- endpoint parameter and req.params.parameter need to be same
- require ObjectId and pass idParameter if update based on _id
- res
- request receive করার পর process করে client কে data send করে।
- res.send(result)
- req
🔥 API Naming Convention
app.get("/booking") // get all bookings in this collection, or get more than one by filter/query
app.get("/booking/:id") // get a specific booking(id)
app.post("/booking") // add new booking
app.patch("/booking/:id") // update specific booking(id)
app.delete("/booking/:id") // delete specific booking(id)