-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'thombergs:master' into beginner-guide-to-creating-apach…
…e-http-client
- Loading branch information
Showing
6 changed files
with
955 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,17 @@ | ||
# Optimizing Node.js Application Performance with Caching | ||
|
||
This README provides a quick guide to start a simple Node.js server project. | ||
|
||
Install Dependencies | ||
|
||
```bash | ||
npm install | ||
``` | ||
|
||
Start your Node.js server: | ||
|
||
```bash | ||
node index.js | ||
``` | ||
|
||
To check Node Server is Working RUN `http://localhost:7000/api/v1/products` |
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,23 @@ | ||
const productController = { | ||
getproducts: async (req, res) => { | ||
// emulating data store delay time to retrieve product data | ||
await new Promise(resolve => setTimeout(resolve, 750)); | ||
|
||
const products = [ | ||
{ id: 1, name: "Desk Bed", price: 854.44 }, | ||
{ id: 2, name: "Shelf Table", price: 357.08 }, | ||
{ id: 3, name: "Couch Lamp", price: 594.53 }, | ||
{ id: 4, name: "Bed Couch", price: 309.62 }, | ||
{ id: 5, name: "Desk Shelf", price: 116.39 }, | ||
{ id: 6, name: "Couch Lamp", price: 405.03 }, | ||
{ id: 7, name: "Rug Chair", price: 47.77 }, | ||
{ id: 8, name: "Sofa Shelf", price: 359.85 }, | ||
{ id: 9, name: "Desk Table", price: 823.21 }, | ||
{ id: 10, name: "Table Shelf", price: 758.91 }, | ||
]; | ||
|
||
res.json({ products }); | ||
}, | ||
}; | ||
|
||
module.exports = { productController }; |
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,33 @@ | ||
const express = require("express"); | ||
const { | ||
initializeRedisClient, | ||
cacheMiddleware, | ||
invalidateCacheMiddleware, | ||
} = require("./middlewares/redis"); | ||
const { productController } = require("./controllers/product"); | ||
|
||
const app = express(); | ||
app.use(express.json()); | ||
|
||
// connect to Redis | ||
initializeRedisClient(); | ||
|
||
// register an endpoint | ||
app.get( | ||
"/api/v1/products", | ||
cacheMiddleware({ | ||
EX: 3600, // 1h | ||
}), | ||
productController.getproducts | ||
); | ||
|
||
app.post("/api/v1/product", invalidateCacheMiddleware, (req, res) => { | ||
// Implement your logic to update data in Application data store | ||
res.json({ message: "Product data updated successfully" }); | ||
}); | ||
|
||
// start the server | ||
const port = 7000; | ||
app.listen(port, () => { | ||
console.log(`Server is running on port: http://localhost:${port}`); | ||
}); |
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,74 @@ | ||
const { createClient } = require("redis"); | ||
const hash = require("object-hash"); | ||
let redisClient; | ||
|
||
async function initializeRedisClient() { | ||
try { | ||
redisClient = createClient(); | ||
await redisClient.connect(); | ||
console.log("Redis Connected Successfully"); | ||
} catch (e) { | ||
console.error(`Redis connection failed with error:`); | ||
console.error(e); | ||
} | ||
} | ||
|
||
function generateCacheKey(req, method = "GET") { | ||
let type = method.toUpperCase(); | ||
// build a custom object to use as a part of our Redis key | ||
const reqDataToHash = { | ||
query: req.query, | ||
}; | ||
return `${type}-${req.path}/${hash.sha1(reqDataToHash)}`; | ||
} | ||
|
||
function cacheMiddleware( | ||
options = { | ||
EX: 10800, // 3h | ||
} | ||
) { | ||
return async (req, res, next) => { | ||
if (redisClient?.isOpen) { | ||
const key = generateCacheKey(req, req.method); | ||
|
||
//if cached data is found retrieve it | ||
const cachedValue = await redisClient.get(key); | ||
|
||
if (cachedValue) { | ||
return res.json(JSON.parse(cachedValue)); | ||
} else { | ||
const oldSend = res.send; | ||
|
||
// When the middleware function redisCachingMiddleware is executed, it replaces the res.send function with a custom function. | ||
res.send = async function saveCache(data) { | ||
res.send = oldSend; | ||
|
||
// cache the response only if it is successful | ||
if (res.statusCode >= 200 && res.statusCode < 300) { | ||
await redisClient.set(key, data, options); | ||
} | ||
|
||
return res.send(data); | ||
}; | ||
|
||
// continue to the controller function | ||
next(); | ||
} | ||
} else { | ||
next(); | ||
} | ||
}; | ||
} | ||
|
||
function invalidateCacheMiddleware(req, res, next) { | ||
// Invalidate the cache for the cache key | ||
const key = generateCacheKey(req); | ||
redisClient.del(key); | ||
next(); | ||
} | ||
|
||
module.exports = { | ||
initializeRedisClient, | ||
cacheMiddleware, | ||
invalidateCacheMiddleware, | ||
}; |
Oops, something went wrong.