AJAX Post request - sending json object to node.js server - node.js

I am making an Ajax Post request:
$.ajax({
type:"POST",
dataType:"json",
contentType: "application/json",
data:newWorkLog,
url:"/add",
})
.done(function(response){
console.log("Response of update: ",response)
})
.fail(function(xhr, textStatus, errorThrown){
console.log("ERROR: ",xhr.responseText)
return xhr.responseText;
});
and was expecting to pass that newWorkLog object to an API method through my node.js server:
var bodyParser = require('body-parser');
app.use(bodyParser.json())
app.post('/add', function(req, res){
console.log(req.body) //This doesnt output anything
res.send(JSON.stringify(req.body));
});
After trying some approaches, I decided to only check what is being sent to my server.
Doing this, the message I get is:
SyntaxError: Unexpected token # in JSON at position 0
at JSON.parse (<anonymous>)
at createStrictSyntaxError (C:\working\app\node_modules\body-parser\lib\types\json.js:157:10)
at parse (C:\working\app\node_modules\body-parser\lib\types\json.js:83:15)
at C:\working\app\node_modules\body-parser\lib\read.js:121:18
at invokeCallback (C:\working\app\node_modules\raw-body\index.js:224:16)
at done (C:\working\app\node_modules\raw-body\index.js:213:7)
at IncomingMessage.onEnd (C:\working\app\node_modules\raw-body\index.js:273:7)
at emitNone (events.js:106:13)
at IncomingMessage.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1055:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
When I console.log my newWorkLog object, I can see from my client side, the correct json object.
when I check the param on the console I see the request payload and it looks like:
user%5Bid%5D=109&user%5BuserName%5D=myname
What could be causing that error?

You say newWorkLog is an object so you need to convert it to json to send it in your request.
$.ajax({
type:"POST",
dataType:"json",
contentType: "application/json",
data:JSON.stringify(newWorkLog),
url:"/add",
})
.done(function(response){
console.log("Response of update: ",response)
})
.fail(function(xhr, textStatus, errorThrown){
console.log("ERROR: ",xhr.responseText)
return xhr.responseText;
});

Related

NodeJS axios request self signed works in browser but not in jest supertest case

I am building a NodeJS app that makes calls to an external API. The external API uses a self-signed certificate. I tried setting the environment variable process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'. This works to ignore the certificate verification when using the app normally. However, a request to the same endpoint does NOT work when calling the NodeJS route with the Jest Supertest agent.
There is a certificate verification error when running the Jest Supertest case. Is there a way to accept self-signed certificates when sending requests using the Supertest agent?
npm test
Error: Error: SSL Error: DEPTH_ZERO_SELF_SIGNED_CERT
at Object.dispatchError (/home/node/app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:54:19)
at EventEmitter.<anonymous> (/home/node/app/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:675:20)
at EventEmitter.emit (events.js:323:22)
at Request.<anonymous> (/home/node/app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:384:47)
at Request.emit (events.js:311:20)
at Request.onRequestResponse (/home/node/app/node_modules/request/request.js:948:10)
at ClientRequest.emit (events.js:311:20)
at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:603:27)
at HTTPParser.parserOnHeadersComplete (_http_common.js:119:17)
at TLSSocket.socketOnData (_http_client.js:476:22) undefined
NodeJS internal route
Works when accessing route via the browser, but not when running Jest Supertest. The internal route is /internal and that works, but when that code subsequently sends a request to the external API that has a self-signed certificate, the self-signed certificate causes a 500 error message.
router.get('/internal', (req, res, next) => {
// Set request values that are specific to this route
const requestOptionsData = { method: `GET`, endpoint: `/external` };
try {
httpCtrl.makeRequest(requestOptionsData).then(result => {
if (result.error) {
return res.status(result.status).json(result.error.message || result.error);
}
return res.status(result.status).json(result);
}).catch((error) => {
console.error(error);
return res.status(500).send(error);
});
} catch (e) {
console.error(e);
return res.status(500).send(e);
}
});
NodeJS controller
A wrapper function to make axios requests to external API
httpCtrl.makeRequest = async (requestOptionsData) => {
let result = {};
// Set request options
const requestOptions = httpCtrl.setApiRequestOptions(requestOptionsData);
let response;
try {
response = await axios(requestOptions);
} catch(e) {
result.error = e.toJSON() || e;
console.error(result.error);
result.status = 500;
return result;
}
result.status = response && response.status || 500;
result.data = response && response.data || {};
return result;
}
JEST Supertest
Test that causes certificate error
const app = require('../app.js');
const supertest = require('supertest');
describe('API routes', () => {
it('GET internal NodeJS route', async done => {
agent
.get('/internal')
.set('Accept', 'application/json')
.send()
.expect(200)
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.status).toBe(200);
return done();
});
});
});
UPDATE:
I tried removing NODE_TLS_REJECT_UNAUTHORIZED and setting rejectUnauthorized to false in the axios agent config but still having the same problem. The connection works when using the app via the browser but does work with supertest.
const agent = new https.Agent({
rejectUnauthorized: false
});
const options = {
url: url,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${requestOptionsData.jwt}`,
'Host': process.env.ADMIN_API_BASE_URL
},
method: requestOptionsData.method || `GET`,
httpsAgent: agent
}
Here is the error with this agent configuration:
Error: Error: self signed certificate
at Object.dispatchError (/home/node/app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:54:19)
at EventEmitter.<anonymous> (/home/node/app/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:675:20)
at EventEmitter.emit (events.js:323:22)
at Request.<anonymous> (/home/node/app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:384:47)
at Request.emit (events.js:311:20)
at Request.onRequestError (/home/node/app/node_modules/request/request.js:877:8)
at ClientRequest.emit (events.js:311:20)
at TLSSocket.socketErrorListener (_http_client.js:426:9)
at TLSSocket.emit (events.js:311:20)
at emitErrorNT (internal/streams/destroy.js:92:8) undefined
console.error controllers/http.ctrl.js:50
I was able to solve this with the solution in this github issue.
I solved it by adding testEnvironment: 'node', to jest.config.js file.
https://github.com/axios/axios/issues/1180

Some error occures after send request to the function url

I set up a one firebase function to send messages to my bot. But when firebase gets request I can see that some error occurred.
FetchError: request to https://api.telegram.org/bot<BOT-TOKEN>/getMe failed, reason: getaddrinfo EAI_AGAIN api.telegram.org:443
at ClientRequest.<anonymous> (/srv/node_modules/node-fetch/lib/index.js:1453:11)
at emitOne (events.js:116:13)
at ClientRequest.emit (events.js:211:7)
at TLSSocket.socketErrorListener (_http_client.js:401:9)
at emitOne (events.js:116:13)
at TLSSocket.emit (events.js:211:7)
at emitErrorNT (internal/streams/destroy.js:66:8)
at _combinedTickCallback (internal/process/next_tick.js:139:11)
at process._tickDomainCallback (internal/process/next_tick.js:219:9)
and
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:3)
at ServerResponse.header (/worker/node_modules/express/lib/response.js:767:10)
at ServerResponse.contentType (/worker/node_modules/express/lib/response.js:595:15)
at ServerResponse.sendStatus (/worker/node_modules/express/lib/response.js:357:8)
at /srv/index.js:30:13
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
But secound one I suppose does not influence on the result.
As a result, I don't get any message to my to Bot.
The next script that i use:
const functions = require('firebase-functions');
const telegraf = require('telegraf');
const axios = require('axios');
const bot = new telegraf('<BOT-TOKEN>')
bot.start((ctx) => ctx.reply('Welcome!'))
bot.help((ctx) => ctx.reply('Send me a sticker'))
bot.on('sticker', (ctx) => ctx.reply('👍'))
bot.hears('hi', (ctx) => ctx.reply('Hey there'))
bot.launch()
exports.helloWorld = functions.https.onRequest((request, res) => {
const token = '<BOT-TOKEN>';
const url = `https://api.telegram.org/bot${token}/sendMessage`;
axios.post(url, {
chat_id: '154866113',
text: "just do it!"
})
.then(function (response) {
console.log(response);
res.send({ status: "O"});
return 'ok';
})
.catch(function (error) {
console.log(error);
res.sendStatus(500);
});
res.send("Hello from Firebase!");
});
The getaddrinfo EAI_AGAIN error means that you need to switch to the "Flame" or "Blaze" pricing plan.
As a matter of fact, the free "Spark" plan "allows outbound network requests only to Google-owned services". See https://firebase.google.com/pricing/ (hover your mouse on the question mark situated after the "Cloud Functions" title)
The telegram API is not a Google-owned service, so you need to switch to the "Flame" or "Blaze" plan.
I'm guessing the answer to the EAI_AGAIN error is due to a malformed URI. Are you sure https://api.telegram.org/bot<BOT-TOKEN>/getMe is the correct URI and is accessible from where ever this script is being run from?
The second error is due to you calling the res.send() method more than once. Express res objects wrap Node's ServerResponse object, and once the connection is closed via write or end, it cannot be sent again. Try removing the res.send("Hello from Firebase!"); section of your code and coming back.

How to fix grant_type error is NULL - unsupported grant type with Pay Pal's REST API for access token

I'm calling Paypal's REST API to get an access token https://developer.paypal.com/docs/api/overview/#get-an-access-token
I'm using node with superagent to make the AJAX call.
Here is my code:
const basicAuth = Buffer.from(`${PAYPAL_CLIENT}:${PAYPAL_SECRET}`).toString('base64')
request
.post(PAYPAL_OAUTH_API)
.set('Accept', 'application/json')
.set('grant_type', 'client_credentials')
.set('Authorization', `Basic ${basicAuth}`)
.send()
.end((result) => {
console.log(result.response.error)
})
And here is the logs with the errors I'm getting
{ Error: cannot POST /v1/oauth2/token/ (400)
at Response.toError (C:\Users\shlomo\projects\tribewise-backend-v1\node_modules\superagent\lib\node\response.js:94:15)
at ResponseBase._setStatusProperties (C:\Users\shlomo\projects\tribewise-backend-v1\node_modules\superagent\lib\response-base.js:123:16)
at new Response (C:\Users\shlomo\projects\tribewise-backend-v1\node_modules\superagent\lib\node\response.js:41:8)
at Request._emitResponse (C:\Users\shlomo\projects\tribewise-backend-v1\node_modules\superagent\lib\node\index.js:850:20)
at parser (C:\Users\shlomo\projects\tribewise-backend-v1\node_modules\superagent\lib\node\index.js:1036:38)
at IncomingMessage.res.on (C:\Users\shlomo\projects\tribewise-backend-v1\node_modules\superagent\lib\node\parsers\json.js:19:7)
at emitNone (events.js:111:20)
at IncomingMessage.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1064:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickDomainCallback (internal/process/next_tick.js:218:9)
status: 400,
text: '{"error":"unsupported_grant_type","error_description":"Grant Type is NULL"}',
method: 'POST',
path: '/v1/oauth2/token/' }
Why am I getting an error unssuported grant type - the grant type is NULL?
In postman it works but I can't get it to work with superagent and node. Paypal gives two examples here with postman and curl. Why is it not working with superagent?
From paypal docs which you've linked to:
If you use a command-line tool other than cURL, set the Accept header to application/x-www-form-urlencoded
From superget docs which you've linked to:
By default sending strings will set the Content-Type to application/x-www-form-urlencoded
So change your request to:
// PAYPAL_LINK = "https://api.sandbox.paypal.com"
// PAYPAL_OAUTH_API = "/v1/oauth2/token"
request(PAYPAL_LINK)
.post(PAYPAL_OAUTH_API)
.send('grant_type=client_credentials')
.auth(PAYPAL_CLIENT, PAYPAL_SECRET)
.then(response => console.log(response))
.catch(error => console.error(error))
Optionally set Accept: application/json if you want response as json

Proxy Post Request to another server is failing

I am new to node.js. I have a requirement to proxy a POST request (with payload) to another server from node.js and process its response back to the browser client.
my scenario (browser <-> node.js <-> final destination server).
This is how my code looks, before i explain my issue.
app.post('^*$', function(req, res) {
delete req.headers.host; // i read somewhere to delete the old host
req.headers.host = 'ipadress:port';
request({ url: 'http://ipaddress:port' + req.path, headers: req.headers, body: req.body }, function(err, remoteResponse, remoteBody) {
if (err) { return res.status(500).end('Error no response'); }
res.writeHead(200,{
'Content-Length': remoteBody.length,
'Content-Type': 'text/xml' }); // copy all headers from Response
res.end(remoteBody);
});
});
I keep on getting "500 internal server error" "Error no response".
I strongly suspect (although not sure!) , the reason for this error is my payload from initial request is not being copied to the proxied request and the complete url which my final server expects is not there.
Can someone advise me, how i can copy the url and payload to the forwarding request ?
Also, how do i handle the response back from the forwarding serer ?
My payload is a xml object and final url is
http://ipaddress:port/XISOAPAdapter/MessageServlet?senderParty=&senderService=BS_WSAPPS_Q&receiverParty=&receiverService=&interface=SI_OrderStatusRequest_Out&interfaceNamespace=http://xyz/IF027/EC/OrderStatus/I_WS_APPS
#Krzysztof Sztompka.
Here is the information you asked me to put. miine is a dev environment.
_http_outgoing.js:512
throw new TypeError('first argument must be a string or Buffer');
^
TypeError: first argument must be a string or Buffer
at ServerResponse.OutgoingMessage.end (_http_outgoing.js:512:11)
at Request._callback (D:\MyNode.js\serverproxy.js:18:43)
at self.callback (D:\MyNode.js\node_modules\request\request.js:198:22)
at Request.emit (events.js:107:17)
at Request.onRequestError (D:\MyNode.js\node_modules\request\request.js:867:8)
at ClientRequest.emit (events.js:107:17)
at Socket.socketOnEnd (_http_client.js:300:9)
at Socket.emit (events.js:129:20)
at _stream_readable.js:908:16
at process._tickCallback (node.js:355:11)

Twitter stream api

I am trying to learn and understand nodejs. While trying to connect to api of Twitter stream and track tweets, I get following error :
undefined:1
<html>\n<head>\n<meta http-equiv="Content-Type" content="text/html; charset=ut
^
SyntaxError: Unexpected token <
at Object.parse (native)
at IncomingMessage.<anonymous> (/home/ytsejam/public_html/nodejs/11/twitter.js:15:20)
at IncomingMessage.emit (events.js:95:17)
at IncomingMessage.<anonymous> (_stream_readable.js:764:14)
at IncomingMessage.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:426:10)
at emitReadable (_stream_readable.js:422:5)
at readableAddChunk (_stream_readable.js:165:9)
at IncomingMessage.Readable.push (_stream_readable.js:127:10)
at HTTPParser.parserOnBody [as onBody] (http.js:142:22)
here is my code which I try to connect :
var https = require("https");
var options = {
host: 'stream.twitter.com',
path: '/1.1/statuses/filter.json?track=bieber',
method: 'GET',
headers: {
"Authorization": "Basic " + new Buffer("username:password").toString("base64")
}
};
var request = https.request('https://stream.twitter.com/1.1/statuses/filter.json?track=query', function(response){
var body = '';
response.on("data", function(chunk){
var chunk = chunk.toString();
try {
var tweet = JSON.parse(chunk);
} catch (err) {
console.log("JSON parse error:" + err);
}
console.log(tweet.text);
});
response.on("end",function(){
console.log("Disconnected");
});
});
request.end();
I did a research and tried to debug. my best guess is var tweet = JSON.parse(chunk); may cause problems. second option, I am missing oauth parameters.
Can you help me ? Thanks.
Edit :
I solved this using answer here Node.js and Twitter API 1.1
JSON.parse() is throwing a SyntaxError because the data it is trying to parse is HTML and not JSON.
In general, it's a good idea to wrap JSON.parse() in a try/catch block so you can handle those sorts of things gracefully.
(It is possible that there is a problem in your oauth stuff and it is failing to authenticate. So instead of getting JSON, you are getting an HTML page telling you that authentication has failed. But that is just a guess.)

Resources