Can send post request with curl but cannot from a node server - node.js

I can make a post request to a REST api endpoint of a web service with curl successfully but couldnt do so with request module in node.js. Instead, I always get error CONNECTION ETIMEDOUT.What is the problem?
curl command:
curl -i --header "Content-Type: application/json" -XPOST 'http://<endpoint_url>/urls' -d '{
"callback": "http://www.example.com/callback",
"total": 3,
"urls": [ {
"url": "http://www.domain.com/index1.html"
}, {
"url": "http://www.domain.com/index2.html"
}, {
"url": "http://www.domain.com/index3.html"
}
]
}'
code:
function sendRequestToEndPoint() {
const sample = {
"callback": "http://www.example.com/callback",
"total": 3,
"urls": [ {
"url": "http://www.domain.com/index1.html"
}, {
"url": "http://www.domain.com/index2.html"
}, {
"url": "http://www.domain.com/index3.html"
}
]
}
const options = {
method: 'post',
//headers: {
// 'Content-Type': 'application/json',
// 'Accept': 'application/json',
//},
url: 'http://<endpoint_url>/urls',
json: sample
//body: JSON.stringify(sample) // also tried this with headers on
};
console.log(sample);
request(options, (error, response, body) => {
console.log(response)
});
}
Update: Turned out that it was because the api url I used is not correct.

use querystring to stringify your json data,
var querystring = require('querystring');
...
sample = querystring.stringify(sample);
look at this answer How to make an HTTP POST request in node.js

this code works,
you need to Stringify your json object using JSON.stringify , and use the methode write of the object request to send the sample json object
, http = require('http')
, bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
var sample = JSON.stringify({
"callback": "http://www.example.com/callback"
, "total": 3
, "urls": [{
"url": "http://www.domain.com/index1.html"
}, {
"url": "http://www.domain.com/index2.html"
}, {
"url": "http://www.domain.com/index3.html"
}
]
});
var options = {
hostname: 'localhost'
, port: 80
, path: '/test/a'
, method: 'POST'
, headers: {
'Content-Type': 'application/json'
, 'Content-Length': sample.length
}
};
app.get('/', function (req, res) {
var r = http.request(options, (response) => {
console.log(`STATUS: ${response.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(response.headers)}`);
response.setEncoding('utf8');
response.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
});
response.on('end', () => {
console.log('No more data in response.');
});
});
r.on('error', (e) => {
console.log(`problem with request: ${e.message}`);
});
r.write(sample);
r.end();
res.send('ok');
});
a link for more details about http.request nodejs.org http.request(options[, callback])

Related

Postman works but not react redux action (axios.post request)

Something really weird is going on.
I am building an API using Cloud Functions. Basically the Cloud Function makes a request to the server and retrieves a token.
This is the code
exports.Klarna = functions.https.onRequest((req, res) => {
// const app = express();
// app.use(cors({ origin: true }));
res.set('Access-Control-Allow-Origin', '*');
const url = "https://someLink.com";
const creds = req.body;
const token = `Basic ${Buffer.from(
`${"Pxxx"}:${"xxx"}`
).toString("base64")}`;
request(
"https://somelink.com",
{
method: "POST",
url: url,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
Authorization: token,
},
Authorization: token,
body: creds,
json: true,
},
function (error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body);
res.json(response.body.client_token);
}
}
);
});
Then I am calling it from the frontend (reactJS) like this using redux-thunk and axios:
export function Klarna() {
return async (dispatch) => {
try {
let response = await axios('https://google.cloud.function', {
method: 'POST',
redirect: 'follow',
headers: { 'Content-Type': 'application/json', "Access-Control-Allow-Origin": "*",Authorization: "Basic XXX" },
body: JSON.stringify({
"purchase_country": "SE",
"purchase_currency": "SEK",
"locale": "sv-SE",
"order_amount": 10,
"order_tax_amount": 0,
"order_lines": [
{
"type": "physical",
"reference": "19-402",
"name": "Battery Power Pack",
"quantity": 1,
"unit_price": 10,
"tax_rate": 0,
"total_amount": 10,
"total_discount_amount": 0,
"total_tax_amount": 0
}
]
}),
json: true
})
console.log(response);
} finally {
console.log("yea!")
}
}
}
however while in postman succeeds, here I get
[Error] Failed to load resource: The request timed out. (Klarna, line 0)
[Error] Unhandled Promise Rejection: Error: timeout of 0ms exceeded
(anonymous function) (main.chunk.js:7307)
asyncFunctionResume
(anonymous function)
promiseReactionJobWithoutPromise
promiseReactionJob
Any suggestions that could help me moving forward with this? Have been 2 days around this bug and I am not seeing a way to solve it.
UPDATE:
I went around and found how to do it. Here is the code:
const functions = require("firebase-functions");
const express = require("express");
var rp = require("request-promise");
const cors = require("cors")({
origin: true,
allowedHeaders: [
"Access-Control-Allow-Origin",
"Access-Control-Allow-Methods",
"Content-Type",
"Origin",
"X-Requested-With",
"Accept",
"Authorization"
],
methods: ["POST", "OPTIONS"],
credentials: true,
});
const admin = require("firebase-admin");
const serviceAccount = require("./serviceAccountKey.json");
var request = require("request");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
exports.Klarnas = functions.https.onRequest((req, res) => {
// Google Cloud Function res.methods
res.set("Access-Control-Allow-Headers", "Content-Type");
res.set("Content-Type", "Application/JSON");
// CORS-enabled req.methods, res.methods
return cors(req, res, async () => {
res.set("Content-Type", "Application/JSON");
var origin = req.get("Origin");
var allowedOrigins = [
"https://yourLink.com",
"http://localhost:3000",
"http://localhost:5001/xxx/xxx",
];
if (allowedOrigins.indexOf(origin) > -1) {
// Origin Allowed!!
res.set("Access-Control-Allow-Origin", origin);
if (req.method === "OPTIONS") {
// Method accepted for next request
res.set("Access-Control-Allow-Methods", "POST");
//SEND or end
return res.status(200).send({});
} else {
// After req.method === 'OPTIONS' set ["Access-Control-Allow-Methods": "POST"]
// req.method === 'POST' with req.body.{name} => res.body.{name}
// req.method === 'PUT' with req.body.{name}, no res.body.{name}
const url = "https://someLink.com";
const creds = req.body;
const token = `Basic ${Buffer.from(
`${"XXXX"}:${"XXX"}`
).toString("base64")}`;
request(
"https://someLink.com",
{
method: "POST",
url: url,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
Authorization: token,
},
Authorization: token,
body: creds,
json: true,
},
function (error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body);
res.json(response.body.client_token);
}
}
);
}
} else {
//Origin Bad!!
//SEND or end
return res.status(400).send("no access for this origin");
}
});
});
Please try to use then/catch to catch the error orhandle the promise rejection.
You can use the following code:
export function Klarna() {
return async (dispatch) => {
let response = await axios('https://[REGION]-[PROJECT-ID].cloudfunctions.net/Klarna', {
method: 'POST',
redirect: 'follow',
headers: { 'Content-Type': 'application/json', "Access-Control-Allow-Origin": "*",Authorization: "Basic [Token]==" },
body: JSON.stringify({
"purchase_country": "SE",
"purchase_currency": "SEK",
"locale": "sv-SE",
"order_amount": 10,
"order_tax_amount": 0,
"order_lines": [
{
"type": "physical",
"reference": "19-402",
"name": "Battery Power Pack",
"quantity": 1,
"unit_price": 10,
"tax_rate": 0,
"total_amount": 10,
"total_discount_amount": 0,
"total_tax_amount": 0
}
]
}),
json: true
}).then(data => console.log(data))
.catch(err => console.log(err);
}
}
Please let me know if it works.

Using CSRF Token from GET and Uses that in POST | 403 Forbidden | AWS Lambda

I am creating node.js function through aws lambda which makes a GET request to Hybris Market Place and gets a CSRF Token. Then I am using that token to make another POST request to post some data to Hybris Market place but I am getting an error of 403 Forbidden. Same thing works in Postman which I believe due to POSTMAN keeps GET session alive and hence CSRF token is still valid. How May I achieve that in AWS Lambda function. Below is my code. I am using promise to make two requests.
const https = require('https');
exports.handler = async (event, context, callback) => {
const tokenOptions = {
"host": "*******.s4hana.ondemand.com",
"path": "/sap/opu/odata/sap/***********/",
"port": null,
"headers":{
"authorization": "Basic ************=",
"cache-control": "no-cache",
"x-csrf-token": "fetch"
},
"method": "GET"
};
var getToken = (tokenOptions) => {
return new Promise((resolve,reject)=>{
const req = https.request(tokenOptions, (res) => {
var xToken = res.headers["x-csrf-token"];
var sCookies = res.headers["set-cookie"];
var response = [xToken,sCookies]
res.on('data', () => {
console.log('Successfully processed HTTPS response');
resolve(response);
});
res.on('end', () => {
});
});
req.on('error', function(){
reject('Request to get token failed.');
});
req.end();
});
};
var postContent = (response) => {
return new Promise((resolve,reject)=>{
var options = {
"method": "POST",
"host": "*********-***.s4hana.ondemand.com",
"path": "/sap/opu/odata/sap/*********/*******",
"port":null,
"headers":
{ "authorization": "Basic *******==",
"x-csrf-token": response[0],
"accept": "application/json",
"content-type": "application/json",
"cache-control": "no-cache",
},
"cookie":response[1],
"body":
{
/* Data I want to POST */
},
"json": true
};
const req = https.request(options, (res,data) => {
console.log(res.statusCode);
res.on('data', () => {
resolve('Successfully submitted.');
});
res.on('end', () => {
});
});
req.on('error', function(err,res){
reject('Request to get Post failed.');
});
req.end();
});
};
getToken(tokenOptions).then((response) =>{
console.log('Result: ' +response[0]);
return postContent(response);
}).then((successMsg) =>{
callback(null,successMsg);
}).catch((errMsg)=>{
callback();
});
};

Query ElasticSearch on Node.js with HTTP module Ignores Request Body

StackOverflow community. I've started to play with ES and Node.js, and right now I'm trying to query my ES instance using the HTTP module.
I'm trying to mimic the following curl GET request:
curl -XGET 'localhost:9200/_search?pretty' -H 'Content-Type: application/json' -d'
{
"query": {
"multi_match" : {
"query": "this is a test",
"fields": [ "subject", "message" ]
}
}
}
'
like this:
var options = {
hostname: '127.0.0.1',
port: 9200,
method: 'GET',
path: '/twitter/tweet/_search?pretty',
headers: {
'Content-Type': 'application/json',
'accept': 'application/json'
},
json: query
body: {
"query": {
"multi_match" : {
"query": "this is a test",
"fields": [ "subject", "message" ]
}
}
}
};
var req = http.request(options, function (response) {
var responseBody = "";
response.setEncoding("UTF-8");
response.on('data', function (chunk) {
responseBody += chunk;
});
response.on("end", function() {
fs.writeFile("responseBody.json", responseBody, function(err) {
if (err) {
throw err;
}
});
});
});
req.on("error", function(err) {
console.log(`problem with request: ${err.message}`);
});
req.end();
But ES is returning ALL the records (like if I was hitting the _all field), not just the hits for the query I'm passing. It's like if the request body is being ignored.
I've also tried to pass it by saving the query in a variable, and the simply put in in the json key:
json: query
But the result is the same. If I enclose the json with single quotes, I get the "unexpected token" error when trying to run the app, so I'm lost on what to do to succesfully pass a query to Node.js with the HTTP module :S.
EDIT:
The solution is to pass the query (JSON stringified) in the request.write method:
req.write(query);
The whole request should look like this:
var query = JSON.stringify({
"query": {
"multi_match" : {
"query": "this is a test",
"fields": [ "subject", "message" ]
}
}
});
var options = {
hostname: '127.0.0.1',
port: 9200,
method: 'GET',
path: '/twitter/tweet/_search?pretty',
headers: {
'content-length': Buffer.byteLength(query),
'Content-Type': 'application/json'
}
};
var req = http.request(options, function (response) {
var responseBody = "";
response.setEncoding("UTF-8");
response.on('data', function (chunk) {
responseBody += chunk;
});
response.on("end", function() {
fs.writeFile("responseBody.json", responseBody, function(err) {
if (err) {
throw err;
}
});
});
});
req.on("error", function(err) {
console.log(`problem with request: ${err.message}`);
});
req.write(query);
req.end();
So the GET request of the http.request won't respect the body, it will always ignore the request body. So, you should send a POST request if you want to send body to the elasticsearch.
The elasticsearch handles both POST and GET call in the same manner.

can't make this specific http patch request in node.js

Here is how I do the request in curl:
curl -v --request PATCH -H "Authorization: token TOKEN-VALUE-FROM-PREVIOUS-CALL" -d '{"description": "updated gist","public": true,"files": {"file1.txt": {"content": "String file contents are now updated"}}}' https://api.github.com/gists/GIST-ID-FORM-PREVIOUS-CALL
I have tried a few node libraries to make that "patch" request but no success. I can also do the same thing in client side with jQuery.ajax but can't get it working on the server side. Thanks in advance.
Using the native HTTP request function in Node.js, you can make your requests as follows -
var qs = require("querystring");
var http = require("https");
var options = {
"method": "PATCH",
"hostname": "api.github.com",
"port": null,
"path": "/gists/GIST-ID-FORM-PREVIOUS-CALL",
"headers": {
"authorization": "token TOKEN-VALUE-FROM-PREVIOUS-CALL",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded"
}
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.write(qs.stringify(
{
"description": "updated gist",
"public": "true",
"files": {
"file1.txt": {
"content": "String file contents are now updated"
}
}
}));
req.end();

cURL call to API in NodeJS Request

it's me again with another lame question. I have the following call to a Rattic password database API which works properly:
curl -s -H 'Authorization: ApiKey myUser:verySecretAPIKey' -H 'Accept: text/json' https://example.com/passdb/api/v1/cred/\?format\=json
I tried to replicate this call in NodeJS, however the following returns blank:
var request = require('request');
url='https://example.com/passdb/api/v1/cred/?format=json';
request({
url: url,
method: 'POST',
headers: [
{ 'Authorization': 'ApiKey myUser:verySecretAPIKey' }
],
},
function (error, response, body) {
if (error) throw error;
console.log(body);
}
);
Any help is appreciated.
As pointed out in the comments already, use GET, not POST;
headers should be an object, not an array;
You're not adding the Accept header.
All combined, try this:
request({
url : url,
method : 'GET',
headers : {
Authorization : 'ApiKey myUser:verySecretAPIKey',
Accept : 'text/json'
}, function (error, response, body) {
if (error) throw error;
console.log(body);
}
});
One thing you can do is import a curl request into Postman and then export it into different forms. for example, nodejs:
var http = require("https");
var options = {
"method": "GET",
"hostname": "example.com",
"port": null,
"path": "/passdb/api/v1/cred/%5C?format%5C=json",
"headers": {
"authorization": "ApiKey myUser:verySecretAPIKey",
"accept": "text/json",
"cache-control": "no-cache",
"postman-token": "c3c32eb5-ac9e-a847-aa23-91b2cbe771c9"
}
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.end();
Headers should be an object.
var request = require('request');
url='https://example.com/passdb/api/v1/cred/?format=json';
request({
url: url,
method: 'POST',
headers: {
'Authorization': 'ApiKey myUser:verySecretAPIKey'
}
}, function (error, response, body) {
if (error) throw error;
console.log(body);
});

Resources