ExpressJS response middleware - javascript

I've made an HttpInterceptor for the front-end that send every request with some default headers and automatically encrypt body/url for every request and a middleware for the back-end that check the headers and decrypt the packet if needed.. Now I have a problem with the response middleware, because I want to send the response with encrypted body only for some requests.
app.use((req,res,next)=>{
if(req.headers['x-data-encoded'] && (req.headers['x-server'] == "HP")){
res.append('X-Encoded-Data', true);
var nsp = res.send;
res.send = function(data){
var body = Crypto.encodeData(data); // Result a string of letters and numbers
nsp.apply(this, body);
}
}
next();
});
Caught exception: TypeError: CreateListFromArrayLike called on non-object

I think that error appears because send method waits an object and it is receiving a String. If you assign manually body an object this error should dissapear or change to another one.
Besides, second parameter of apply should be an array.
Hope it helps

Related

Handling POST request on a GET route (express.js)

I am new to express and node together and seem to be stuck, with what seems to be, a simple issue. I have an API route that uses GET. Route:
app.get('/api/v1/all', getAllWords);
Then inside of the getAllWords callback function, I want to check if the request that was sent was of GET or POST. This is the code I have to check the request method:
function getAllWords(request, response) {
let reply;
if (request.method === 'GET') {
console.log('This was a GET request');
// handle GET here...
}
if (request.method === 'POST') {
console.log('This was a POST request');
reply = {
"msg": "HTTP Method not allowed"
};
response.send(reply)
}
}
When I use Postman to send off a GET request it works just fine. But when sending a POST request I get the generic express.js "Cannot POST /api/v1/all".
Why did it the response.send(reply) not work for the POST method?
app.get(...) define endpoint that only matches with GET method. If you want to handle POST method you must supply seperate middleware in app.post(...)
You can make use of app.all(...) to handle both GET and POST requests but it also accepts other kind of requests such as PUT and DELETE. I prefer separating the GETand POST request though.

Uncaught (in promise) SyntaxError: Unexpected end of JSON input

I am trying to send a new push subscription to my server but am encountering an error "Uncaught (in promise) SyntaxError: Unexpected end of JSON input" and the console says it's in my index page at line 1, which obviously is not the case.
The function where I suspect the problem occurring (because error is not thrown when I comment it out) is sendSubscriptionToBackEnd(subscription) which is called in the following:
function updateSubscriptionOnServer(subscription) {
const subscriptionJson = document.querySelector('.js-subscription-json');
const subscriptionDetails = document.querySelector('.js-subscription-details');
if (subscription) {
subscriptionJson.textContent = JSON.stringify(subscription);
sendSubscriptionToBackEnd(subscription);
subscriptionDetails.classList.remove('is-invisible');
} else {
subscriptionDetails.classList.add('is-invisible');
}
}
The function itself (which precedes the above function):
function sendSubscriptionToBackEnd(subscription) {
return fetch('/path/to/app/savesub.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(subscription)
})
.then(function(response) {
if (!response.ok) {
throw new Error('Bad status code from server.');
}
return response.json();
})
.then(function(responseData) {
if (!(responseData.data && responseData.data.success)) {
throw new Error('Bad response from server.');
}
});
}
I have tried replacing single quotes with double quotes in the fetch call but that yields the same results.
I know that the JSON should be populated because it prints to the screen in the updateSubscriptionOnServer() function with subscriptionJson.textContent = JSON.stringify(subscription);, and I used that output in the google codelab's example server to receive a push successfully.
EDIT: Here is the JSON as a string, but I don't see a mistake in syntax:
{"endpoint":"https://fcm.googleapis.com/fcm/send/dLmthm1wZuc:APA91bGULRezL7SzZKywF2wiS50hXNaLqjJxJ869y8wiWLA3Y_1pHqTI458VIhJZkyOsRMO2xBS77erpmKUp-Tg0sMkYHkuUJCI8wEid1jMESeO2ExjNhNC9OS1DQT2j05BaRgckFbCN","keys":{"p256dh":"BBz2c7S5uiKR-SE2fYJrjPaxuAiFiLogxsJbl8S1A_fQrOEH4_LQjp8qocIxOFEicpcf4PHZksAtA8zKJG9pMzs=","auth":"VOHh5P-1ZTupRXTMs4VhlQ=="}}
Any ideas??
This might be a problem with the endpoint not passing the appropriate parameters in the response's header.
In Chrome's console, inside the Network tab, check the headers sent by the endpoint and it should contain this:
Example of proper response to allow requests from localhost and cross domains requests
Ask the API developer to include this in the headers:
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Credentials" : true
This happened to me also when I was running a server with Express.js and using Brave browser. In my case it was the CORs problem. I did the following and it solved the problem in my case:
(since this is an Express framework, I am using app.get)
-on the server side:
res.set({
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
});
-on client side I used Fetch to get data but disabled the CORS option
// mode: "no-cors" //disabled this in Fetch
That took care of my issues with fetching data with Express
This can be because you're not sending any JSON from the server
OR
This can be because you're sending invalid JSON.
Your code might look like
res.end();
One of the pitfalls is that returned data that is not a JSON but just a plain text payload regardless of headers set. I.e. sending out in Express via something like
res.send({a: "b"});
rather than
res.json({a: "b"});
would return this confusing error. Not easy to detect in network activity as it looks quite legit.
For someone looking here later. I received this error not because of my headers but because I was not recursively appending the response body to a string to JSON.parse later.
As per the MDN example (I've taken out some parts of their example not immediately relevant):
reader.read().then(function processText({ done, value }) {
if (done) {
console.log("Stream complete");
return;
}
result += chunk;
return reader.read().then(processText);
});
For my issue I had to
Use a named function (not an anonymous ()=>{}) inside the .then
Append the result together recursively.
Once done is true execute something else on the total appended result
Just in case this is helpful for you in the future and your issue is not header related, but related to the done value not being true with the initial JSON stream response.
I know this question has already been answered but just thought I add my thoughts.
This will happen when your response body is empty and response.json() is expecting a JSON string. Make sure that your API is returning a response body in JSON format if must be.

callback function req. and res

I'm having trouble to understand why my callback function needs 2 parameters, i.e. one for the request and one for the response?
For instance i bind a callback function to my server:
server.on("request", doThis(req, resp));
In my opinion he needs only one parameter (req for example here) to store the req information (GET, POST, url, etc.). Why does he need a second for response? I write the information in resp. (i.e. the server, so my other scripts) and not the client.
Every time a request is coming in, the callback function is invoked and so the req parameter is set. Am i wrong? But why do I need the response parameter? My server needs it when he is responding but not when I'm reading/saving the request informations?
The Response parameter is what's generally used to send back a response.
A request comes in, you get the request's data in the req (first) param and you then use the res (second) param to send back a response like:
server.on('message', function(req, res){
res.send('hello your ip is: ' + req.client.ip);
})
This is all dependant on your framework but in expressjs this is how it works (more or less).
To answer your question, you don't need it - you can simply not issue it as a parameter (although it will still be accessible) if you don't plan on responding (which is weird and quite uncommon)
server.on('message', function(req){
console.log('someone requested "message"')
})
Generally speaking, you would always send back a response although the end user might never visually see it, it's just to confirm that the action has been completed successfully.
server.on('save', function(req, res){
saveFile(req.file)
res.sendStatus(200)
})
Additionally, you could check if the process completed successfully - if it did you'd send back a success message, otherwise send back an error message.
server.on('save', function(req, res){
saveFile(req.file, function(error){
if(error) res.sendStatus(500)
res.sendStatus(200)
})
})

Twilio response object undefined but no errors?

I am working on an implementation of Twilio in a basic meteor app. I have set up client-side code to call the server-side method below (in this case, on login).
The method is called without issue and no error is produced in the server logs. However if I log out my response data, it is undefined. Is this a timing issue? My impression was that the function containing the response or error is called when a response is received.
Any input would be appreciated, thanks in advance!
Meteor.methods({
twilioTest:function () {
console.log("Twilio Test Called!");
ACCOUNT_SID = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
AUTH_TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
twilio = Twilio(ACCOUNT_SID, AUTH_TOKEN);
twilio.sendSms({
to:'+xxx-xxx-xxxx', // Any number Twilio can deliver to
from: '+xxx-xxx-xxxx', // A number you bought from Twilio and can use for outbound communication
body: 'Greetings!' // body of the SMS message
},function(err, responseData) { //this function is executed when a response is received from Twilio
console.log(responseData); // log out response object
if (!err) { // "err" is an error received during the request, if any
// "responseData" is a JavaScript object containing data received from Twilio.
// A sample response from sending an SMS message is here (click "JSON" to see how the data appears in JavaScript):
// http://www.twilio.com/docs/api/rest/sending-sms#example-1
console.log(responseData.from); // outputs outbound number
console.log(responseData.body); // outputs message body
}
});
}
As John Hascall pointed out, I should have been logging out the error object instead of the response object. This revealed that my target phone number was invalid and allowed me to correct the issue.

Node JS app only display the first JSON object. Why?

I am trying to write a json object in my node application, integrating the Twilio API. When console logging the object all objects are returned properly but when I write it to the document only the first object is written. Why? How should I change the code to see the same written response as in my console log.
var express = require('express');
var app = express();
app.use(express.bodyParser());
app.get('/', function(req, res) {
var accountSid = 'xxx';
var authToken = 'xxx';
var client = require('twilio')(accountSid, authToken);
client.messages.list({
from: "xxx",
to: "xxx"
}, function(err, data) {
data.messages.forEach(function(message) {
console.log(message.body); // THIS WILL DISPLAY ALL OBJECTS
res.json(message.body); // THIS WILL ONLY DISPLAY THE FIRST OBJECT
});
});
});
app.listen(1337);
I am new to Node JS and think this is easy to solve, but I still can’t find the solution.
res.json(...); sends back the response. You are doing that in the first iteration over the array, hence the client only gets the first message.
If you want to extract body from all messages and send all of them back, then do that. Create an array with the data you want and send it back. Example:
res.json(data.messages.map(function(message) {
return message.body;
}));
You can only call res.json once per request. You're calling it multiple times in a loop. The first time you call it, the browser receives the response, and you'll get a headers already sent exceptions (or something like that) for all other res.json calls.
res.json actually does a data conversion to JSON. I'd be willing to bet there is something it is not dealing with, or it's simply screwing it up. If the response from Twilio is already json, you probably don't need to do that. Try res.send, instead, which just returns whatever you got back.

Categories