PUT request crashes the server - javascript

I'm getting this error when trying to update an entry (in this case, checking a todo and setting it to true/false)
It seems like i'm getting the proper object (seen in the data console log) which makes me wonder why i'm getting [object Object].
Would appreciate any kind of help!
Here's the action :
export function onSaveTodo(todo) {
return async (dispatch) => {
try {
const savedTodo = await todosService.saveTodo(todo);
const action = {
type: 'UPDATE_TODO',
todo: savedTodo,
};
dispatch(action);
} catch (err) {
console.log('cant save todo');
}
};
}
the service :
const BASE_URL = 'todo';
async function saveTodo(todo) {
try {
if (todo._id) {
return httpService.put(BASE_URL, todo);
} else {
return httpService.post(BASE_URL, todo);
}
} catch (err) {
console.log(`could not save todo `, err);
throw err;
}
}
Http service :
export const httpService = {
get(endpoint, data) {
return ajax(endpoint, 'GET', data);
},
post(endpoint, data) {
return ajax(endpoint, 'POST', data);
},
put(endpoint, data) {
console.log('endpoint:', endpoint);
console.log('data:', data);
return ajax(endpoint, 'PUT', data);
},
delete(endpoint, data) {
return ajax(endpoint, 'DELETE', data);
},
};
The backend controller :
async function updateTodo(req, res) {
try {
const { todo } = req.body;
// console.log('todo:', todo);
const savedTodo = await todoService.update(todo);
res.json(savedTodo);
} catch (err) {
logger.error('Failed to update todo', err);
res.status(500).send({ err: 'Failed to update todo' });
}
}
and the backend service :
async function update(todo) {
try {
const newTodo = {
...todo,
_id: ObjectId(todo._id),
};
console.log('newTodo:', newTodo);
const collection = await dbService.getCollection('todo');
await collection.updateOne({ _id: newTodo._id }, { $set: newTodo });
return todo;
} catch (err) {
logger.error(`Can not update toy ${todo._id}`, err);
throw err;
}
}

Related

How to make the program wait for the if statement to finish before continuing in javascript?

I'm new to Javascript. I want to make this block run after the if statement is finished (asynchronous). The reason I want that is that I want to make some changes to update them if it falls into the if statement
let params = {
TableName: "storepedia-test",
Item: updatedItem
};
docClient.put(params, function (err, data) {
if (err) {
console.log(err);
} else {
res.redirect('/devices');
}
});
Here is my whole code
const { id } = req.params;
const file = req.file;
let updatedItem = { ...req.body};
updatedItem.id = id;
if (file !== undefined){
const deleteParams = {
Key: updatedItem.image,
Bucket: bucketName
}
s3.deleteObject(deleteParams, async (err, data) => {
if (err) {
console.log(err)
} else {
const result = await uploadFile(file);
console.log('result', result);
await unlinkFile(file.path);
updatedItem.image = result.Key;
let params = {
TableName: "storepedia-test",
Item: updatedItem
};
docClient.put(params, function (err, data) {
if (err) {
console.log(err);
} else {
res.redirect('/devices');
}
});
}
})
}
let params = {
TableName: "storepedia-test",
Item: updatedItem
};
docClient.put(params, function (err, data) {
if (err) {
console.log(err);
} else {
res.redirect('/devices');
}
});
Just to run something after the if? I think this is the best spot:
docClient.put(params, function(err, data) {
if (err) {
console.log(err);
} else {
// run async code here.
// when done do the redirect.
// for example:
s3.do_something(function(err, data) {
if (err) {
console.log(err)
} else {
console.log(data)
res.redirect('/devices');
}
})
}
});

unable to catch any form of error or response from firebase notification callback function in Node js

I am using the package "fcm-node" in order to send notifications to certain device id.
the sendNotification function is as follows:
const FCM = require('fcm-node');
const serverKey = process.env.SERVER_KEY;
const fcm = new FCM(serverKey);
function sendNotification(registrationToken, title, body, type, key) {
const message = {
to: registrationToken,
collapse_key: key,
notification: {
title: title,
body: body,
delivery_receipt_requested: true,
sound: `ping.aiff`
},
data: {
type: type,
my_key: key,
}
};
fcm.send(message, function (err, value) {
if (err) {
console.log(err);
return false;
} else {
console.log(value);
return value;
}
});
};
module.exports = {
sendNotification
};
The api function I use to call this function is as follows:
router.get('/test', async (req, res, next) => {
const promise = new Promise((resolve, reject) => {
let data = sendNotification('', 'dfsa', 'asds', 'dfas', 'afsdf');
console.log(data)
if (data == false) reject(data);
else resolve(data);
});
promise
.then((data) => { return res.status(200).send(data); })
.catch((data) => { return res.status(500).send(data) })
});
When I console.log the "err" and "value" from the sendNotification, I get either of the followings:
{"multicast_id":4488027446433525506,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1652082785265643%557c6f39557c6f39"}]};
{"multicast_id":8241007545302148303,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}
In case it is successful, I made sure that the device is receiving the notification.
The problem is in the api's data. It is always "undefined" and weither send notification is successful or not I get the 200 Ok status.
What seems to be the problem?
You can't return anything from the function (err, value) {} callback of a node-style asynchrnous function.
Your sendNotification() function needs to return a promise. util.promisify() makes the conversion from a node-style asynchronous function to a promise-returning asynchronous function convenient. Note the return, it's important:
const FCM = require('fcm-node');
const serverKey = process.env.SERVER_KEY;
const fcm = new FCM(serverKey);
const { promisify } = require('util');
fcm.sendAsync = promisify(fcm.send);
function sendNotification(registrationToken, title, body, type, key) {
return fcm.sendAsync({
to: registrationToken,
collapse_key: key,
notification: {
title: title,
body: body,
delivery_receipt_requested: true,
sound: `ping.aiff`
},
data: {
type: type,
my_key: key,
}
});
}
module.exports = {
sendNotification
};
Now you can do what you had in mind
router.get('/test', async (req, res, next) => {
try {
const data = await sendNotification('', 'dfsa', 'asds', 'dfas', 'afsdf');
return res.status(200).send(data);
} catch (err) {
return res.status(500).send(err);
}
});
Maybe it will help, at first try to return your response (the promise) in sendNotification, as actually you have a void function, that's why it's always undefined and after in your route
router.get('/test', async (req, res, next) => {
try {
const data = sendNotification('', 'dfsa', 'asds', 'dfas', 'afsdf');
if (data) {
return res.status(200).send(data);
}
} catch(err) {
return res.status(500).send(err);
}
});

Unsubscribe email using Fetch api Javascript

I have a form where i enter an email and it gets ''subscribed'' in a user.json file using a fetch api on node server.My task is to :
upon clicking on the "Unsubscribe" button, implement the functionality for unsubscribing from the community list. For that, make POST Ajax request using http://localhost:3000/unsubscribe endpoint.
I tried to make the function but it wasnt succeseful so i deleted it. Also,i need to do the following :
While the requests to http://localhost:3000/subscribe and
http://localhost:3000/unsubscribe endpoints are in progress, prevent
additional requests upon clicking on "Subscribe" and "Unsubscribe".
Also, disable them (use the disabled attribute) and style them using
opacity: 0.5.
For me ajax requests,fetch and javascript is something new,so i dont know really well how to do this task,if you could help me i'll be happy,thanks in advance.
fetch code for subscribing:
import { validateEmail } from './email-validator.js'
export const sendSubscribe = (emailInput) => {
const isValidEmail = validateEmail(emailInput)
if (isValidEmail === true) {
sendData(emailInput);
}
}
export const sendHttpRequest = (method, url, data) => {
return fetch(url, {
method: method,
body: JSON.stringify(data),
headers: data ? {
'Content-Type': 'application/json'
} : {}
}).then(response => {
if (response.status >= 400) {
return response.json().then(errResData => {
const error = new Error('Something went wrong!');
error.data = errResData;
throw error;
});
}
return response.json();
});
};
const sendData = (emailInput) => {
sendHttpRequest('POST', 'http://localhost:8080/subscribe', {
email: emailInput
}).then(responseData => {
return responseData
}).catch(err => {
console.log(err, err.data);
window.alert(err.data.error)
});
}
index.js from route node server:
const express = require('express');
const router = express.Router();
const FileStorage = require('../services/FileStorage');
/* POST /subscribe */
router.post('/subscribe', async function (req, res) {
try {
if (!req.body || !req.body.email) {
return res.status(400).json({ error: "Wrong payload" });
}
if (req.body.email === 'forbidden#gmail.com') {
return res.status(422).json({ error: "Email is already in use" });
}
const data = {email: req.body.email};
await FileStorage.writeFile('user.json', data);
await res.json({success: true})
} catch (e) {
console.log(e);
res.status(500).send('Internal error');
}
});
/* GET /unsubscribe */
router.post('/unsubscribe ', async function (req, res) {
try {
await FileStorage.deleteFile('user.json');
await FileStorage.writeFile('user-analytics.json', []);
await FileStorage.writeFile('performance-analytics.json', []);
await res.json({success: true})
} catch (e) {
console.log(e);
res.status(500).send('Internal error');
}
});
module.exports = router;
And user.json file looks like this :
{"email":"Email#gmail.com"}
This is my attempt for unsubscribing :
export const unsubscribeUser = () => {
try {
const response = fetch('http://localhost:8080/unsubscribe', {
method: "POST"
});
if (!response.ok) {
const message = 'Error with Status Code: ' + response.status;
throw new Error(message);
}
const data = response.json();
console.log(data);
} catch (error) {
console.log('Error: ' + error);
}
}
It gives the following errors:
Error: Error: Error with Status Code: undefined
main.js:2
main.js:2 POST http://localhost:8080/unsubscribe 404 (Not Found)
FileStorage.js:
const fs = require('fs');
const fsp = fs.promises;
class FileStorage {
static getRealPath(path) {
return `${global.appRoot}/storage/${path}`
}
static async checkFileExist(path, mode = fs.constants.F_OK) {
try {
await fsp.access(FileStorage.getRealPath(path), mode);
return true
} catch (e) {
return false
}
}
static async readFile(path) {
if (await FileStorage.checkFileExist(path)) {
return await fsp.readFile(FileStorage.getRealPath(path), 'utf-8');
} else {
throw new Error('File read error');
}
}
static async readJsonFile(path) {
const rawJson = await FileStorage.readFile(path);
try {
return JSON.parse(rawJson);
} catch (e) {
return {error: 'Non valid JSON in file content'};
}
}
static async writeFile(path, content) {
const preparedContent = typeof content !== 'string' && typeof content === 'object' ? JSON.stringify(content) : content;
return await fsp.writeFile(FileStorage.getRealPath(path), preparedContent);
}
static async deleteFile(path) {
if (!await FileStorage.checkFileExist(path, fs.constants.F_OK | fs.constants.W_OK)) {
return await fsp.unlink(FileStorage.getRealPath(path));
}
return true;
}
}
module.exports = FileStorage;
You should consider using a database for handling CRUD operations on your persisted data. If you must use filestorage, theres a flat file DB library called lowdb that can make working the files easier.
As for preventing duplicate requests, you can track if user has already made a request.
let fetchBtn = document.getElementById('fetch')
let isFetching = false
fetchBtn.addEventListener('click', handleClick)
async function handleClick(){
if (isFetching) return // do nothing if request already made
isFetching = true
disableBtn()
const response = await fetchMock()
isFetching = false
enableBtn()
}
function fetchMock(){
// const response = await fetch("https://example.com");
return new Promise(resolve => setTimeout (() => resolve('hello'), 2000))
}
function disableBtn(){
fetchBtn.setAttribute('disabled', 'disabled');
fetchBtn.style.opacity = "0.5"
}
function enableBtn(){
fetchBtn.removeAttribute('disabled');
fetchBtn.style.opacity = "1"
}
<button type="button" id="fetch">Fetch</button>

callback does not invoke

MongoClient.connect's callback does not invoke
I try to invoke the callback in aws lambda but it doesn't work, however if I remove exports.lambdaHandler and just invoke it by node app.js it works just fine.
exports.lambdaHandler = async (event, context) => {
try {
MongoClient.connect(url, {
useNewUrlParser: true
}, (err, client) => {
console.log("Connected successfully to server");
});
response = {
'statusCode': 200,
'body': JSON.stringify({
message: 'test'
})
}
return response
} catch (err) {
console.log(err);
return err;
}
};
should return
Connected successfully to server
edit
I changed it to await instead. now it's good
exports.lambdaHandler = async (event, context) => {
try {
const client = await MongoClient.connect(url, {
useNewUrlParser: true
})
const db = client.db(dbName)
await db.createCollection(collectionName)
client.close()
return {
'statusCode': 200,
'body': JSON.stringify({
message: 'test'
})
}
} catch (err) {
console.log(err);
return err;
}
};
Try this, it would return the results else throw an error which will be caught below and returned by Lambda
exports.lambdaHandler = async (event, context) => {
try {
MongoClient.connect(url, {useNewUrlParser: true}, (err, client) => {
if (err) { console.log(err); throw(err); }
else {
console.log("Connected successfully to server");
console.log(client);
response = {
'statusCode': 200,
'body': JSON.stringify({message: client})
};
return response;
};
});
} catch (err) {
console.log(err);
return err;
}
};

Serverless querying NodeJS MSSQL and cannot get result back to callback

I'm writing a small Serverless function to query a MSSQL db using the node mssql library (https://www.npmjs.com/package/mssql#callbacks)
I've read the documentation and I think I'm doing everything right but getting confused - I can see the result in my logs, but the main function callback is not being called and therefore data not being outputted by the API (basically the whole thing times out)
Heres my Lambda function:
import {success, error} from './libs/response-lib';
import {EPDBConfig} from "./libs/Database-lib";
import sql from "mssql";
import config from "./config";
export function main(event, context, callback) {
console.log("start");
EPDBConfig().then(dbConfig => {
if(config.debug) console.log("Hello!");
let EPDBconfig = {
user: dbConfig.dbuser,
password: dbConfig.dbpassword,
server: dbConfig.dbhost,
database: dbConfig.dbname
};
sql.connect(EPDBconfig)
.then(pool => {
return pool.request()
.input('student_no', sql.Int, 129546)
.query('select * from Student where StudentNo = #student_no')
}).then(result => {
console.log("success!");
if(config.debug) console.log('result', result);
return result;
}).catch(err => {
if(config.debug) console.log('err1', err);
return err;
});
sql.on('error', err => {
if(config.debug) console.log('err2', err);
return callback(null, error(err));
});
sql.on('done', result => {
if(config.debug) console.log('done', result);
return callback(null, success(result));
});
}).catch(err => {
if(config.debug) console.log('err3', err);
return callback(null, error(err));
})
}
DB Config is pulled from AWS KMS for secure vars
import AWS from "aws-sdk";
import config from "../config";
const kms = new AWS.KMS({
region: AWS.config.region
});
export function EPDBConfig() {
//DECRYPT THE DATABASE CONNECTION DETAILS
return new Promise((resolve, reject) => {
let params = {
CiphertextBlob: Buffer(process.env.epdb, 'base64')
};
kms.decrypt(params, function(err, data) {
if (err) {
reject(err);
} // an error occurred
else {
let dbParams = JSON.parse(String(data.Plaintext));
resolve(dbParams);
}
});
});
}
and response lib:
export function success(data, message) {
return buildResponse(200, true, data, message);
}
export function error(data, message) {
return buildResponse(400, false, data, message);
}
export function unauthorized(data, message) {
return buildResponse(401, false, data, message);
}
export function forbidden(data, message) {
return buildResponse(403, false, data, message);
}
export function exception(data, message) {
return buildResponse(500, false, data, message);
}
function buildResponse(statusCode, successState, data, message) {
var body = {
success: successState,
message: message
};
if (successState) {
body.data = data;
}
return {
statusCode: statusCode,
headers: {
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Credentials': true
},
body: JSON.stringify(body)
};
}
Can anyone point out where I'm going wrong here? I think I have a whole pile of promises going on. The sql.on('done', result => { ... doesn't appear to work, and I tried adding 'return callback(null, success(result));' in the area where I have 'success'
Please help me!
So, I endded up resolving this with a bit of refactoring:
import sql from "mssql";
import _ from "lodash";
import {success, error} from './libs/response-lib';
import {DB} from "./libs/Database-lib";
import {Student} from "./models/ep.student";
export function main(event, context, callback) {
DB().then(pool => {
return new Promise((resolve, reject) => {
pool.connect(err => {
if(err) reject(err);
pool.request()
.input('StudentNo', sql.Int, 129546)
.execute('StoredProcedure')
.then(result => {
if(process.env.debug) console.log('result', result);
let student = new Student();
_.assign(student, result.recordset[0]);
resolve(student);
pool.close();
}).catch(err => {
reject(err);
pool.close();
});
});
});
}).then(result => {
if(process.env.debug) console.log('result', result);
callback(null, success(result));
}).catch(err => {
if(process.env.debug) console.log('err', err);
callback(null, error(err));
});
}
The first issue was that I wasn't terminating my connection - just a note that I switched to using a stored procedure as this was always going to be the case.
The second issue was that I wasn't really using promises correctly (i think) I wrapped up my connection in a promise and only when I had the response did I resolve or reject it.

Categories

Resources