trying to call api but its giving me connection refuse - javascript

this is my code where am using http module to call the api inside the promise but not able make
any api call its just giving 500 err
const dataString = JSON.stringify(consentDetail)
console.log("dataString",dataString)
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': dataString.length
}
}
const response = await new Promise((resolve, reject) => {
const req = https.get("URL", options, (res) => {
let finalData = "";
res.on("data", function(data){
finalData += data.toString();
})
res.on("end", () => {
var data = JSON.parse(finalData);
resolve({
statusCode: 200,
body: JSON.stringify(data, null, 2)
})
})
})
req.on('error', (err) => {
reject({
statusCode: 500,
body: err
});
})
})
return response;
and I want call the api using only http or https without having to install any npm package

There are a few things you will need to change in your code. First, the API you are calling is expecting a GET request, so you have to change that in your 'options' object. And since you're going to send a GET request, the headers 'Content-Type' and 'Content-Length' need to be removed.
Also, there is no 'url' option for the 'options' in the http module. This is why you are receiving a 500 response. Since no url/host were provided to the http module, it is attempting to connect to http://127.0.0.1:80. The correct way is to use the parameters 'host' and 'path', like this:
const options = {
host: 'catfact.ninja',
path: '/fact',
method: 'GET'
}
or include the url as the first parameter in the get method, like this:
const req = http.get('http://catfact.ninja/fact', options, (res) => {
...
}
By doing so, you will see that we now receive a new error:
undefined:1
<html>
^
SyntaxError: Unexpected token < in JSON at position 0
at JSON.parse (<anonymous>)
at IncomingMessage.<anonymous> (C:\...\index.js:18:33)
at IncomingMessage.emit (events.js:327:22)
at endReadableNT (internal/streams/readable.js:1327:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
The reason for this is that we are receiving a html response instead of a JSON. Looking further into the response, we can see that we actually received a 301 response:
HTTP/1.1 301 Moved Permanently
Server: nginx/1.20.1
Date: Wed, 29 Dec 2021 19:24:33 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://catfact.ninja/fact
The 301 redirects to the https protocol, meaning the API doesn't support http requests anymore. So let's use https instead. Just use the https built-in module instead of the http one, and change the URL to https://catfact.ninja/fact. No other changes to the code are necessary.
So, the final code should be:
const options = {
method: 'GET'
}
const response = await new Promise((resolve, reject) => {
const req = https.get('https://catfact.ninja/fact', options, (res) => {
let finalData = "";
res.on("data", function(data){
finalData += data.toString();
})
res.on("end", () => {
var data = JSON.parse(finalData);
resolve({
statusCode: 200,
body: JSON.stringify(data, null, 2)
})
})
})
req.on('error', (err) => {
reject({
statusCode: 500,
body: err
});
})
})
return response;

I think you should use https.request and options pass host and path.
check here:
https://nodejs.org/api/https.html#httpsrequestoptions-callback
const dataString = JSON.stringify(consentDetail);
console.log("dataString", dataString);
const options = {
// Update here
hostname: "hostname",
path: "/path",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": dataString.length,
},
};
const response = await new Promise((resolve, reject) => {
// update here
const req = https.request(options, (res) => {
let finalData = "";
res.on("data", function (data) {
finalData += data.toString();
});
res.on("end", () => {
var data = JSON.parse(finalData);
resolve({
statusCode: 200,
body: JSON.stringify(data),
});
});
});
req.on("error", (err) => {
reject({
statusCode: 500,
body: err,
});
});
});
return response;

Related

How to get multiple values out of resolve() and reject()?

I would like both resolve() to return {valid_to: cert.valid_to, statusCode, statusMessage} and reject() should return {error: -1, statusCode, statusMessage}.
Question
How can I do that, when statusCode, statusMessage are in a different scope?
const https = require('https');
(async () => {
const options = {
hostname: "github.com",
port: 443,
path: '/',
method: 'GET',
timeout: 1000
};
options.agent = new https.Agent(options);
let valid_to = await new Promise((resolve, reject) => {
const req = https.request({
...options, checkServerIdentity: function (host, cert) {
resolve(cert.valid_to);
}
}).on('error', error => {
reject(-2);
});
req.on("timeout", chunk => {
reject(-1);
});
req.on('response', response => {
console.log(response.statusCode);
console.log(response.statusMessage);
});
req.end();
}).catch(error => {
console.log(error);
return -3;
});
})();
I will do something like this.
Edit: You need to specify res.on('data') in the https.request Object. Otherwise, timeout will always emit because there is no activity from the stream.
You can resolve in res.on("data") or res.on("end") and it is up to your use case.
res is an IncomingMessage object is created by http.ClientRequest and passed as the first argument to the 'request' and 'response' event respectively.
req is A reference to the original http.ClientRequest.
Both streams can emit events and you may handle them separately.
Also, when you reject the Promise, you actually cannot get the statusCode and StatusMessage from the req because there is an error in the req and the .on("response") will not be emitted. So, you need to customize the statusCode and statusMessage yourself.
const https = require("https");
// {valid_to: cert.valid_to, statusCode, statusMessage}
// {error: -1, statusCode, statusMessage}.
(async () => {
const options = {
hostname: "githubasdfa.com",
port: 443,
path: "/",
method: "GET",
timeout: 1000,
};
options.agent = new https.Agent(options);
try {
const response = await new Promise((resolve, reject) => {
let valid_to;
let statusCode;
let statusMessage;
const req = https
.request(
{
...options,
checkServerIdentity: function (host, cert) {
valid_to = cert.valid_to;
},
},
res => {
res.on("data", chunk => {
resolve({
valid_to,
statusCode,
statusMessage,
});
});
res.on("end", () => {
console.log("No more data in response.");
});
}
)
.on("error", err => {
console.log(err);
reject({
error: -2,
statusCode: "custom code",
statusMessage: "unhandled error",
});
})
.on("timeout", chunk => {
reject({
error: -1,
statusCode: "custom code",
statusMessage: "unhandled error",
});
})
.on("response", response => {
statusCode = response.statusCode;
statusMessage = response.statusMessage;
})
.end();
});
console.log(response);
} catch (error) {
console.log(error);
}
})();

How do I add parameters to https get request?

I am working on a little project to learn how to work with APIs by making GET requests to the Twitter API v2 via a node server.
For the get requests I am using Node's built in https package.
I made a basic GET request that returns a list of the last 10 tweets from a user.
I think in order to increase the amount of tweets I can get I have to make a separate parameter object, which I then implement in the get request.
Right now my function looks like this:
function getTweets() {
const options = {
host: "api.twitter.com",
path: `/2/users/${userId}/tweets`,
headers: {
authorization:
`Bearer ${bearerToken}`,
},
};
https
.get(options, (response) => {
let data = "";
response.on("data", (chunk) => {
data += chunk;
});
response.on("end", () => {
let jsonObject = JSON.parse(data);
tweetObjects = jsonObject.data;
tweetObjects.map((item) => {
let tweetWords = "";
tweetWords += item.text;
userTweets.push(tweetWords);
});
const result = userTweets.flatMap((str) => str.split(" "));
console.log(result);
});
})
.on("error", (error) => {
console.log(error);
});
}
Right now I only have the options object with host, path, and headers in the request.
This is what I am trying to do:
function getTweets() {
const options = {
host: "api.twitter.com",
path: `/2/users/${userId}/tweets`,
headers: {
authorization:
`Bearer ${bearerToken}`,
},
};
let params = {
max_results: 100,
};
https
.get(params, options, (response) => {
let data = "";
response.on("data", (chunk) => {
data += chunk;
});
response.on("end", () => {
let jsonObject = JSON.parse(data);
tweetObjects = jsonObject.data;
tweetObjects.map((item) => {
let tweetWords = "";
tweetWords += item.text;
userTweets.push(tweetWords);
});
const result = userTweets.flatMap((str) => str.split(" "));
console.log(result);
});
})
.on("error", (error) => {
console.log(error);
});
}
But I get
throw new ERR_INVALID_ARG_TYPE('listener', 'Function', listener);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "listener" argument must be of type function. Received an instance of Object
at checkListener (events.js:131:11)
at ClientRequest.once (events.js:496:3)
at new ClientRequest (_http_client.js:215:10)
at request (https.js:326:10)
at Object.get (https.js:330:15)
at IncomingMessage.emit (events.js:388:22)
at endReadableNT (internal/streams/readable.js:1336:12)
at processTicksAndRejections (internal/process/task_queues.js:82:21) {
code: 'ERR_INVALID_ARG_TYPE'
You can either only pass the URL or an object containing options as stated in the docs:
https://nodejs.org/api/https.html#https_https_get_url_options_callback
So you might want to try something like this:
function getTweets() {
let params = {
max_results: 100,
};
const options = {
host: "api.twitter.com",
path: `/2/users/${userId}/tweets?max_results=${params.max_results}`,
headers: {
authorization:
`Bearer ${bearerToken}`,
},
};
https
.get(options, (response) => {
let data = "";
...
}
I am not sure to understand what you are calling parameters that you want to give to the get request.
Anyway a get request does not take some body or parameter. If you want to add some data to the core of your request you have to use the post method and not the get one.
Can you show us the import of https library just to check the functions that it propose?
Best Regards,
Hugo Delatte

Create new product by calliing shopify api

I am trying to create a new product by calling the shopify product api (/admin/api/2020-01/products.json). I am trying to achieve this using the "https" module. Below is the sample code
const url1 = 'https://{api_token}#tuscstore.myshopify.com/admin/api/2020-01/products.json';
var obj = {
"product":[
{
"title": "Saturn",
"body_html": "<p>The epitome of elegance</p>",
"vendor": "Soltions inc",
"product_type": "Planets",
"handle": "saturn",
"tags": "",
"images": [
{
"src": "https://solarsystem.nasa.gov/system/stellar_items/image_files/38_saturn_1600x900.jpg"
}
]
}
]
};
const https = require('https');
var data = JSON.stringify(obj)
const options = new URL(url1);
var req = https.request(options, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
/* res.on('data', (d) => {
process.stdout.write(d);
}); */
});
req.on('error', (e) => {
console.error(e);
});
req.write(data);
req.end();
const Index = () => (
<div>
<p>Sample app using React and Next.js</p>
</div>
);
export default Index;
I am facing 2 problems,
when I do "process.stdout.write(d)", I receive cannot readproperty "write" undefined.
If I comment it out as I have done in
the code above, I don't get the error.
In either case I get the statuscode as 200, and not 201 which is what I shoudl receive according to shopify's docs.
Can someone please help me with what is going wrong?
Edit: Using Post,I get a type error
const https = require('https');
var data = JSON.stringify(obj)
var options = {
hostname: 'https://{apikey:password}#tuscstore.myshopify.com/admin/api/2020-01',
path: '/products.json',
method: 'POST',
headers: {
'Content-Type': 'application/json',
/*'Content-Length': data.length*/
'Authorization' : 'API_TOKEN'
}
};
var req = https.request(options, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
});
req.on('error', (e) => {
console.error(e);
});
req.write(data);
req.end();
TypeError: Failed to execute 'fetch' on 'Window': Failed to parse URL from https://[https://{APIKEY:PWD}#tuscstore.myshopify.com/admin/api/2020-01]/products.json
you creating a new product you have to make http POST request , and now your making http GET request you should update your options like so :
const options = {
hostname: 'https://apikey:password#<#store_url>/admin/api/2020-01', // your host name
path: '/shop.json', // your end point
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization' : 'YOUR_API_TOKEN'
}
}
OR you can use this package to solve all your problems https://www.npmjs.com/package/shopify-api-node

How to convert a CURL request into an axios request?

I just successfully curled here:
curl -X POST https://jenkins-url/job/MyJob/job/some-job/job/master/build --user myemail:mypassword -H 'Jenkins-Crumb: mycrumb'
now I want to use axios inside my lambda
so I have this:
const axios = require('axios')
exports.handler = async (event) => {
const url = "my-url";
try {
const res = await axios.post(url, {}, {
auth: {
username: 'user',
password: 'passowrd'
},
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Jenkins-Crumb": "my-crumb"
},
}).then(function(response) {
console.log('Authenticated');
}).catch(function(error) {
console.log('Error on Authentication');
});
console.log(res)
return {
statusCode: 200,
body: JSON.stringify(res)
}
} catch (e) {
console.log(e)
return {
statusCode: 400,
body: JSON.stringify(e)
}
}
};
but when I trigger the lambda it returns with: failed with the error "Request completed but is not OK"
not sure if I'm doing something wrong somewhere but seems to be everything is correctly mapped from CURL to axios
You have a few issues:
In your .then(...) handler, you are doing a console log, but you aren't returning anything from that function. Therefore, res is going to be undefined.
You're doing a JSON.stringify on res. res would be an axios response, not the response body. Stringifying the axios response is a bad idea, because it contains hefty object references and also circular references. You want res.data to give you the response data.
The error returned from Axios may also contain these heavy objects and circular references. In my experience, you can actually crash node when trying to serialize responses and errors from axios.
Here's how I'd modify your function:
const axios = require('axios')
exports.handler = async (event) => {
const url = "my-url";
try {
const res = await axios.post(url, {}, {
auth: {
username: 'user',
password: 'passowrd'
},
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Jenkins-Crumb": "my-crumb"
},
});
return {
statusCode: 200,
body: JSON.stringify(res.data)
}
} catch (e) {
console.log(e)
return {
statusCode: 400,
// Don't do JSON.stringify(e).
// e.response.data will be the axios response body,
// but e.response may be undefined if the error isn't an HTTP error
body: e.stack
}
}
};

Adding Authorization header to GET request

I'm building an alexa skill using the new SDK 2.0 and I'm now having trouble implementing a simple http get request. How would I add an authorization header to the getRemoteData url request? The code below isn't working.
I'm trying to call Airtable API to get some remote data
const UserReplyIntent_Handler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' && request.intent.name === 'UserReplyIntent' ;
},
async handle(handlerInput) {
const response = await httpGet();
console.log(response);
return handlerInput.responseBuilder
.speak("Okay. Here is what I got back." + response.records.fields.Indication)
.reprompt("Would you like to learn more?")
.getResponse();
},
};
function httpGet() {
return new Promise(((resolve, reject) => {
const headers = {
Authorization: 'Bearer key12345678'
};
var options = {
host: 'api.airtable.com',
port: 443,
path: '/v0/appYqfJ3Rt2F0sRGn/Database?filterByFormula=(DrugName=%27azatadine%27)',
method: 'GET',
};
const request = https.request(options, {headers}, (response) => {
response.setEncoding('utf8');
let returnData = '';
response.on('data', (chunk) => {
returnData += chunk;
});
response.on('end', () => {
resolve(JSON.parse(returnData));
});
response.on('error', (error) => {
reject(error);
});
});
request.end();
}));
}
header go into the options object, not as a separate parameter:
var options = {
host: 'api.airtable.com',
port: 443,
path: '/v0/appYqfJ3Rt2F0sRGn/Database?filterByFormula=(DrugName=%27azatadine%27)',
method: 'GET',
headers: {
Authorization: 'Bearer key12345678'
}
};
https.request accepts the same options fields as http.reqest.
http.request options object allows headers to be defined.

Categories

Resources