caching query with redis - node.js

i need to cache a query with redis and node js , the database is aws s3 ,the problem here as a noob ,i will recive the query as a string, i need to encode the keys in the body request so when i will later try to fetsch the data i will use one of those keys(they need to be seperated with '/') can anyone help me with that and bunch of thanks.
here is what i' tried to do:
const { default: axios } = require('axios');
const express = require('express');
const redisClient = require('./helper/Client')
const app = express();
const port = process.env.PORT || 3000
app.use(express.json());
async function fetchApi(species){
const apiResponse = await axios.get(`https://www.fishwatch.gov/api/species/${species}`)
console.log('request sent successfully');
return apiResponse.data
}
async function getSpeciesData(req, res) {
const species = req.body;
const keys = Object.keys(species);
const encodedParams = {};
for (const key of keys) {
const encodedKey = Buffer.from(key).toString('base64');
encodedParams[encodedKey] = species[key];
}
const key = JSON.stringify(encodedParams);
let resultat;
let isCached = false;
const cachedResponse = await redisClient.get(key);
if (cachedResponse) {
isCached = true;
const decodedResponse = Buffer.from(cachedResponse, 'base64').toString('utf-8');
resultat = JSON.parse(decodedResponse);
res.send({
fromCache: isCached,
data: resultat
});
console.log(cachedResponse);
} else {
const responseData = await fetchApi(keys.join('/'));
const encodedResponseData = Buffer.from(JSON.stringify(responseData)).toString('base64');
redisClient.SETEX(key, 3600, encodedResponseData);
res.send(responseData);
}
}
app.post("/fish", getSpeciesData);
app.listen(port, () => {
console.log(`Listening on ${port}`);
});

Related

node js rest api for crud application

I have started off with a REST API creation using Node.js. I have designed create and read functions and tested functionality using postman. Can you suggest how to add update and delete functions to it?
My dboperations.js file
var config = require('./dbconfig');
const sql = require('mssql/msnodesqlv8');
async function getFilms(){
try{
let pool = await sql.connect(config);
let films = await pool.request().query("SELECT * from Film8node");
return films.recordsets;
}
catch (error){
console.log(error);
}
}
async function getFilm(Film_id){
try{
let pool = await sql.connect(config);
let films = await pool.request()
.input('input_parameter',sql.Int,Film_id)
.query("SELECT * from Film8node where Film_id = #input_parameter"); ;
return films.recordsets;
}
catch (error){
console.log(error);
}
}
async function addFilm(Film8node){
try{
let pool = await sql.connect(config);
let insertFilm = await pool.request()
.input('film_name',sql.VarChar,Film8node.film_name)
.input('actor',sql.VarChar,Film8node.actor)
.input('actress',sql.VarChar,Film8node.actress)
.input('pub_date',sql.VarChar,Film8node.pub_date)
.input('director',sql.VarChar,Film8node.director)
.input('producer',sql.VarChar,Film8node.producer)
.input('prod_cost',sql.VarChar,Film8node.prod_cost)
.input('dist_cost',sql.VarChar,Film8node.dist_cost)
.input('category',sql.VarChar,Film8node.category)
.input('cert_category',sql.VarChar,Film8node.cert_category)
.input('poster',sql.VarBinary,Film8node.poster)
.query("INSERT into Film8node(film_name,actor,actress,pub_date,director,producer,prod_cost,dist_cost,category,cert_category,poster) values(#film_name,#actor,#actress,#pub_date,#director,#producer,#prod_cost,#dist_cost,#category,#cert_category,#poster)");
return insertFilm.recordsets;
}
catch (error){
console.log(error);
}
}
async function updateFilm(Film8node,Film_id){
try{
let pool = await sql.connect(config);
let updFilm = await pool.request()
.input('Film_id',sql.Int,Film_id)
.input('film_name',sql.VarChar,Film8node.film_name)
.input('actor',sql.VarChar,Film8node.actor)
.input('actress',sql.VarChar,Film8node.actress)
.input('pub_date',sql.VarChar,Film8node.pub_date)
.input('director',sql.VarChar,Film8node.director)
.input('producer',sql.VarChar,Film8node.producer)
.input('prod_cost',sql.VarChar,Film8node.prod_cost)
.input('dist_cost',sql.VarChar,Film8node.dist_cost)
.input('category',sql.VarChar,Film8node.category)
.input('cert_category',sql.VarChar,Film8node.cert_category)
.input('poster',sql.VarBinary,Film8node.poster)
.query("UPDATE Film8node set film_name=#film_name,actor=#actor,actress=#actress,pub_date=#pub_date,director=#director,producer=#producer,prod_cost=#prod_cost,dist_cost=#dist_cost,category=#category,cert_category=#cert_category,poster=#poster where Film_id=#Film_id");
return updFilm.recordsets;
}
catch (error){
console.log(error);
}
}
module.exports = {
getFilms : getFilms,
getFilm : getFilm,
addFilm : addFilm,
updateFilm : updateFilm
}
My api.js file
var Db = require('./dboperations');
var Filmnode = require('./Film8node');
const dboperations = require('./dboperations');
var express = require('express');
var bodyParser = require('body-parser');
var cors = require('cors');
var app = express();
var router = express.Router();
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(cors());
app.use('/api',router);
router.use((request,response,next) => {
console.log('middleware');
next();
})
router.route('/Films').get((request,response) => {
dboperations.getFilms().then(result => {
response.json(result[0]);
})
})
router.route('/Films/:Film_id').get((request,response)=>{
dboperations.getFilm(request.params.Film_id).then(result => {
response.json(result[0]);
})
})
router.route('/Films').post((request,response) => {
let Film8node = {...request.body}
dboperations.addFilm(Film8node).then(result => {
response.status(201).json(result);
})
})
router.route('/Films/:Film_id').put((request,response)=>{
let Film8node = {...request.body}
dboperations.updateFilm(Film8node,request.params.Film_id).then(result => {
response.status(201).json(result);
})
})
var port = process.env.PORT || 8090;
app.listen(port);
console.log('Film API is running at ' + port);
dboperations.getFilms().then(result => {
console.log(result);
})
My Film8node.js file
class Filmnode{
constructor(Film_id,film_name,actor,actress,pub_date,director,producer,prod_cost,dist_cost,category,cert_category,poster){
this.Film_id=Film_id;
this.film_name=film_name;
this.actor=actor;
this.actress=actress;
this.pub_date=pub_date;
this.director=director;
this.producer=producer;
this.prod_cost=prod_cost;
this.dist_cost=dist_cost;
this.category=category;
this.cert_category=cert_category;
this.poster=poster;
}
}
module.exports = Filmnode;
Can anyone help me in adding a update and delete functions to this?
Is my ..[updateFilm].. method correct in "dboperations.js" file?
Also about the ...[ router.route('/Films/:Film_id').put((request,response)]... part in "api.js" file?

Force MicroService to await until RabbitMQ publishes a message , using Cote

I have a an API-GATEWAY MicroService that manages the entire show , and one of the services is called QueueService.
Here is the API-Gateway
const express = require('express')
const bodyParser = require('body-parser')
const cote = require('cote')
const cors = require('cors');
const app = express()
app.use(bodyParser.json())
app.use(cors());
app.post('/queue-msg', async (req, res, next) => {
let { from, to } = req.body;
const payload = {
from, to
}
const queue = await queueRequester.send({ type: 'create-queue-message', payload })
res.status(200).send({ "message-sent": true, queue });
});
This is thq QueueService :
const cote = require('cote')
const queueProducer = require('./utils/queueProducer');
const queueName = 'pathfinderqueue';
const queueResponder = new cote.Responder({ name: 'queue responder', key: 'deliveries' })
queueResponder.on('*', req => req.type && console.log(req))
const deliveries = []
let idCounter = 0
queueResponder.on('create-queue-message', req => {
async function makeRequest() {
console.log('Got a message from API-GATEWAY!');
let { payload } = req; // get From & To
queueProducer.publishToQueue(queueName, payload); // Publish to Rabbit
const queue = { id: idCounter++, status: 'pending' } // Set the ID
deliveries.push(queue)
return Promise.resolve(queue)
}
const response = makeRequest();
return response;
})
However every time that API-Gateway publishes a message from the React client to the QueueService , the QueueService doesn't awaits in the on event , and sends back a
"message-sent": true
to the client.
How can we force QueueService to await ?

How should I parse URL parameters using Node JS express?

I would like to pass the lat lon from this URL http://localhost:8080/fp?lon=103.742463567216646&lat=1.336711421273283. Where should I place the "req.query.lon" and "req.query.lat" in the following code?
I am hoping to parse the users input in the URL link so that I can dynamically retrieve from the database.
const {Client} = require("pg")
const express = require ("express")
const url=require('url')
const fs= require('')
const app = express();
app.use(express.json())
const client = new Client({
"user": "xxx",
"password" : "xxx",
"host" : "xxx",
"port" : xxx,
"database" : "xxx"
})
//app.get("/", (req, res) => res.sendFile(`${__dirname}/index.html`))
app.get("/fp", async (req, res) => {
//const lon = 103.742463567216646;
//const lat = 1.336711421273283;
//const lon = req.query.lon;
//const lat = req.query.lat;
const rows = await readTodos ();
res.send(JSON.stringify(rows))
})
app.listen(8080, () => console.log("Web server is listening.. on port 8080"))
start()
async function start() {
await connect();
}
async function connect() {
try {
await client.connect();
}
catch(e) {
console.error(`Failed to connect ${e}`)
}
}
async function readTodos() {
try {
const results = await client.query("SELECT ST_AsText(ST_Force2D(geom)) FROM fp ORDER BY geom <-> ST_SetSRID(ST_MakePoint("+lon+ ","+lat+ "), 3993) LIMIT 1;");
return results.rows;
}
catch(e){
return [];
}
}
Express parses it by default and store them in req.query.
Accessing req.query.<key> will give you the value you are looking for.
For instance, in your example, express will store it inside req.query.lon and req.query.lat.
So, actually you access them right in the request handler of /fp, just comment out the access to these variables and pass them as parameters to readTodos():
app.get("/fp", async (req, res) => {
const lon = req.query.lon;
const lat = req.query.lat;
const rows = await readTodos(lon, lat);
res.send(JSON.stringify(rows))
})
async function readTodos(lon, lat) {
try {
const results = await client.query("SELECT ST_AsText(ST_Force2D(geom)) FROM fp ORDER BY geom <-> ST_SetSRID(ST_MakePoint("+lon+ ","+lat+ "), 3993) LIMIT 1;");
return results.rows;
}
catch(e){
return [];
}
}

async and await function Node.js

I have followed this tutorial to upload files into IPFS using Node.js, but I had a problem which doesn't appear in the tutorial!
It is related to with Async and await function, I can't make this statement
const fileHash = fileAdded[0].hash;
I tried with await
const fileAdded = await ipfs.add({path: Name, content: file});
but unfortunately, I got an error which is (hash undefined).
I tried with a callback function, but I'm not sure about my way because (fileAdded) variable didn't give me any answer and also it was undefined,
this is a full code:
const ipfsClient = require('ipfs-http-client');
const express = require('express');
const bodyParser = require('body-parser');
const fileUpload = require('express-fileupload');
const fs= require('fs');
const ipfs = new ipfsClient({host: 'localhost', port: '5001', protocol: 'http'});
const app= express();
var hash = require('hash');
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended:true}));
app.use(fileUpload());
app.get('/',(req,res)=>{
res.render('home');
});
app.post('/upload',(req,res)=>{
const f= req.files.file;
const Name = req.files.file.name;
const filePath ="files/"+ Name;
f.mv(filePath,async(err)=>{
if(err){
console.log("error failed to download a file");
return res.status(500).send(err);
}
const fileh = await addFile(Name,filePath);
fs.unlink(filePath, (err)=>{
if(err) console.log("error");
});
res.render('upload',{Name,fileh});
});
});
const addFile= async(Name,filePath)=> {
const file=fs.readFileSync(filePath);
const fileAdded = await ipfs.add({path: Name, content: file});
const fileHash = fileAdded[0].hash;
return fileHash;
};
app.listen(3000,()=>{
console.log("server is listen");
});
this is the error appears:
i write a callback function like that :
const addFile= async(Name,filePath)=> {
const file=fs.readFileSync(filePath);
const fileAdded = await ipfs.add({path: Name, content: file},(err,res)=>{
if(err)
console.log(err);
const fileHash = fileAdded[0].hash;
return fileHash;});};
but the value of fileAdded and fileHash was undefined.
after i use this code from #Always Learning :
const addFile= async(Name,filePath)=> {
const file=fs.readFileSync(filePath);
const hashes = [];
const filesAdded = ipfs.add({path: Name, content: file});
for await (const result of filesAdded) {
hashes.push(result.hash);
console.log(result.hash);
console.log(result);
}
return hashes; // if you know it's just one for example
};
It gave me an information of a file, but hash does not work as it gave me undefined, I want extract just a hash like this "QmRndAYkvH3D2qhmYfaAZvWT6MDi4NiJPbzJor3EL87rrb"
Since ipfs.add() returns an async-iterable object, you need to use for async to go through it like this:
const addFile= async(Name,filePath)=> {
const file=fs.readFileSync(filePath);
const hashes = [];
const filesAdded = ipfs.add({path: Name, content: file});
for await (const result of filesAdded) {
if (result.hash) {
hashes.push(result.hash);
} else if (result.cid) {
hashes.push(result.cid.multihash); // guessing here - might be another part of the cid object
} else {
console.log("No hash found in",result);
}
}
return hashes[0]; // if you know it's just one for example
};
You have to change this:
const fileHash = fileAdded[0].hash;
into this:
const fileHash = fileAdded.hash;
(so remove [0]).
This worked for me: it has to do with the libraries.

App refused to connect (NodeJs & Express)

I've created an app in the Partners panel, and I followed this documentation (using Nodejs and Express).
I can get the JSON format for the products' object without any problem. However, when I add to the scopes variable "read_price_rules" I get this error message: "express-example-app refused to connect."
Is this issue caused by the app's permissions?
My app can: Read products, variants, and collections.
Here is the index.js file:
const dotenv = require('dotenv').config();
const express = require('express');
const app = express();
const crypto = require('crypto');
const cookie = require('cookie');
const nonce = require('nonce')();
const querystring = require('querystring');
const request = require('request-promise');
const apiKey = process.env.SHOPIFY_API_KEY;
const apiSecret = process.env.SHOPIFY_API_SECRET;
const scopes = 'read_products,read_price_rules';
const forwardingAddress = "https://53b16008.ngrok.io";
app.listen(3000, () => {
console.log('Example app listening on port 3000!');
});
app.get('/shopify', (req, res) => {
const shop = req.query.shop;
if (shop) {
const state = nonce();
const redirectUri = forwardingAddress + '/shopify/callback';
const installUrl = 'https://' + shop + '/admin/oauth/authorize?client_id=' + apiKey + '&scope=' + scopes + '&state=' + state + '&redirect_uri=' + redirectUri;
res.cookie('state', state);
res.redirect(installUrl);
}
else { return res.status(400).send('Missing shop parameter. Please add ?shop=your-development-shop.myshopify.com to your request'); }
});
app.get('/shopify/callback', (req, res) => {
const { shop, hmac, code, state } = req.query;
const stateCookie = cookie.parse(req.headers.cookie).state;
if (state !== stateCookie) { return res.status(403).send('Request origin cannot be verified'); }
if (shop && hmac && code) {
// DONE: Validate request is from Shopify
const map = Object.assign({}, req.query);
delete map['signature'];
delete map['hmac'];
const message = querystring.stringify(map);
const providedHmac = Buffer.from(hmac, 'utf-8');
const generatedHash = Buffer.from(crypto.createHmac('sha256', apiSecret).update(message).digest('hex'), 'utf-8');
let hashEquals = false;
try { hashEquals = crypto.timingSafeEqual(generatedHash, providedHmac) }
catch (e) { hashEquals = false; };
if (!hashEquals) { return res.status(400).send('HMAC validation failed'); }
// DONE: Exchange temporary code for a permanent access token
const accessTokenRequestUrl = 'https://' + shop + '/admin/oauth/access_token';
const accessTokenPayload = {
client_id: apiKey,
client_secret: apiSecret,
code,
};
request.post(accessTokenRequestUrl, { json: accessTokenPayload })
.then((accessTokenResponse) => {
const accessToken = accessTokenResponse.access_token;
// DONE: Use access token to make API call to 'shop' endpoint
const shopRequestUrl = 'https://' + shop + '/admin/api/2019-04/discount_codes/lookup.json?code=20OFF';
const shopRequestHeaders = { 'X-Shopify-Access-Token': accessToken, };
request.get(shopRequestUrl, { headers: shopRequestHeaders })
.then((shopResponse) => {
res.status(200).end(shopResponse);
})
.catch((error) => {
res.status(error.statusCode).send(error.error.error_description);
});
})
.catch((error) => {
res.status(error.statusCode).send(error.error.error_description);
});
} else {
res.status(400).send('Required parameters missing');
}
});
I Just had to reinstall the app after adding an extra scope in the index.js file.

Resources