IBM - Creating a VPC using API with Node.js - node.js

I have a Node.js application which currently allows the user to provision a Digital Ocean Droplet. However, I'm now trying to migrate over to IBM Cloud and instead want to provision a Virtual Server.
The issue I'm having is I have no experience working with APIs. Digital Ocean has its own NPM package acting as a wrapper over the Digital Ocean API bit I can't find an equivalent for IBM Cloud. I've been looking through the VPC API documentation and I have gone through the entire process of creating a Virtual Server using the terminal and I've successfully provisioned a Virtual Server.
Now, I'm trying to get these cURL requests to work in Node.js. I'm starting with just the simple GET images API to try and print the available images. The command looks like this:
curl -X GET "https://eu-gb.iaas.cloud.ibm.com/v1/images?version=2019-10-08&generation=1" \
-H "Authorization: *IAM TOKEN HERE*"
I've read over the Node HTTP documentation and so far I've converted this command to look like this:
const http = require('http')
const options = {
hostname: 'https://eu-gb.iaas.cloud.ibm.com',
port: 80,
path: '/v1/images?version=2019-10-08&generation=1',
method: 'GET',
headers: {
'Authorization': '*IAM TOKEN HERE*'
}
};
const req = http.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.on('end', () => {
console.log('No more data in response.');
});
});
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});
req.end();
However, when I run the JS file, I get the following error:
problem with request: getaddrinfo ENOTFOUND https://eu-gb.iaas.cloud.ibm.com https://eu-gb.iaas.cloud.ibm.com:80
Can someone please explain to me the error, where I'm going wrong, and how I can fix this issue?
Many thanks in advance,
G

try as below:
const https = require('https');
const options = {
hostname: 'eu-gb.iaas.cloud.ibm.com',
port: 443,
path: '/v1/images?version=2019-10-08&generation=1',
method: 'GET',
headers: {
'Authorization': 'Bearer <IAM TOKEN HERE>'
}
};
const 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.end();
The protocol http:// shouldn't be included in the host field, also, it is recommended the use of https.

Related

How to make HTTP request to Discord API?

I am trying to make an HTTP request to the Discord API, and I keep getting ECONNREFUSED as an error back. I am trying to access this route provided in the Discord API Documentation:
Get Global Application Commands GET/applications/{application.id}/commands
Fetch all of the global commands for your application. Returns an array of ApplicationCommand objects.
Using NodeJS, here is the relevant section of code:
const https = require('https')
const options = {
hostname: 'https://discord.com',
path: '/api/v8/applications/<myapplicationID>/commands', //with my actual appID
port: 443,
method: 'GET',
headers: {
Authorization: `Bot ${process.env.TOKEN}`
}
}
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`)
res.on('data', d => {
process.stdout.write(d)
})
})
req.on('error', error => {
console.error(error)
})
req.end()
I know this is a relatively simple question, but looking at the related questions didn't provide much insight, and as far as I can tell, I am adhering to the API's documentation. Any advice would be very helpful.
Thanks,
Dylan
So it was pretty stupid... The hostname field can't have 'https://'

How to make an https version of a Unirest example

I would like to use the https library in node.js to send a request to this api:
https://rapidapi.com/dimas/api/NasaAPI?endpoint=apiendpoint_b4e69440-f966-11e7-809f-87f99bda0814getPictureOfTheDay
The given example on the RapidAPI website uses Unirest, and I would like to only use the https library. I've tried to write it like this:
const https = require('https');
var link = "https://NasaAPIdimasV1.p.rapidapi.com/getPictureOfTheDay";
var options = {host: "https://NasaAPIdimasV1.p.rapidapi.com/getPictureOfTheDay",
path: "/", headers: {"X-RapidAPI-Key": "---MY KEY(Yes, I've replaced it)---", "Content-Type": "application/x-www-form-urlencoded"}}
https.get(link, options, (resp) => {
let data = '';
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end', () => {
console.log(data);
});
}).on("error", (err) => {
console.log("https error 4: " + err.message);
});
But that returns the following response:
{"message":"Endpoint\/ does not exist"}
Thanks for any help
There are several mistakes.
First, you essentially pass URL in https twice - first as link param, second as combination of host and path properties for options param.
Second, your host is actually the full path - but it shouldn't be. In the end, looks like the library got confused and sent request to https://NasaAPIdimasV1.p.rapidapi.com/ instead.
Finally, this particular API requires using 'POST', not 'GET' method. That's actually mentioned in the documentation. That's why you have 'endpoint does not exist' error even on correctly formed request.
One possible approach is dropping link altogether, sending URL as part of options:
var options = {
host: 'NasaAPIdimasV1.p.rapidapi.com',
method: 'POST',
path: '/getPictureOfTheDay',
headers: {/* the same */}
};
https.request(options, (resp) => { /* the same */ }).end();

Proxy to get a url feed with AWS Lambda

I am trying to include a news feed area in an Ionic app I am developing, consulting feeds from other websites. But for some feed urls, the app complains about the absence of Access-Control-Allow-Origin parameter. So I created a lambda function, which get the content from the url feed parameter and returns it to the client, adding Access-Control-Allow-Origin in the response header. You can see the code below:
const https = require('https');
exports.handler = (event, context, callback) => {
var url = event.queryStringParameters.url;
https.get(url, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => {
rawData += chunk;
});
res.on('end', () => {
try {
const response = {
statusCode: 200,
headers: {
'Content-Type': 'text/xml, application/xml',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*'
},
body: rawData,
};
// callback is sending HTML back
callback(null, response);
} catch (e) {
console.error(e.message);
callback(e);
}
});
}).on('error', (e) => {
console.error(e);
callback(e);
});
};
This works for most urls, but for one specifically (https://www.passblue.com/feed/) I get blocked by their firewall. It sends me back the following message:
Access Denied - Sucuri Website Firewall - If you are the site owner (or you manage this site), please whitelist your IP or if you think this block is an error please open a support ticket and make sure to include the block details (displayed in the box below), so we can assist you in troubleshooting the issue.
I tested it also from my local browser and it works correctly. I also created a local script in my computer to mimic the aws lambda function and it also gets blocked by the firewall. I am guessing that there are some header information I should be sending in the request.
Did anybody see this behaviour before?
I was able to solve the issue by replacing https node module with node-fetch npm package. I am guessing that a newer approach is setting better headers in the request (resembling less of a DDOS attack).
const fetch = require('node-fetch');
exports.handler = (event, context, callback) => {
var url = event.queryStringParameters.url;
fetch(url).then((res) => {
return res.text();
}).then((body) => {
const response = {
statusCode: 200,
headers: {
'Content-Type': 'text/xml, application/xml',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*'
},
body,
};
callback(null, response);
}).catch('error', (e) => {
console.error(e);
callback(e);
});
};

Remove port number from Node HTTP request to external API

I am writing a React app using Node, Express, and Webpack. My problem is that my API calls' URLs always have a port number between the host and the path. It seems like most of the questions on this topic have more to do with routing than with external API calls.
I am much more comfortable with Request, but I got very frustrated trying to get it to play nicely with Webpack, so I turned to Node's http which I know less about.
Here is the method responsible for the API call:
getData() {
const self = this;
const url = "api.civicapps.org";
const options = {
"method": "GET",
"mode": "no-cors",
"host": url,
"path": "/restaurant-inspections/?restaurant_name=" + this.state.nameQuery,
"port": 8080,
"headers": {
"Access-Control-Allow-Origin": "http://localhost:3000"
}
}
const p1 = new Promise(function(resolve, reject) {
resolve(
http.request(options, function(res) {
res.setEncoding('utf8');
const body = {};
//This is clearly not ideal, but all I need right now is to get a response from the API
res.on('data', function(chunk) {
body.push(chunk);
});
return body;
}).end()
)
});
p1.then(function(data) {
console.log(data);
self.setState({
name: data.body
});
});
p1.catch(function(err) {
...
});
}
All I want to do is a simple test GET request to this API. Once that's working, I will be fine.
Thanks in advance.
It turns out setting the port to 80 and running with sudo solved the problem.
I know this topic is old, but I think it's good to share my experience with a similar issue in a Docker environment.
Since I was calling a service as hostname in my Node container, I didn't want the port to be set after the service name (e.g.: http://my-api-service/v1/users was called as http://my-api-service/v1/users:80).
I didn't reach to figure it out so I used Axios. It has its own definition types and can be used like that:
import Axios, { AxiosRequestConfig } from 'axios';
...
const options: AxiosRequestConfig = {
headers: { 'Authorization': 'Bearer ' + token, 'Accept': 'application/ld+json' }
};
Axios.get('http://my-api-service/v1/users', options)
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.error("Error: " + error.message);
})
.then(() => {
// always executed
// ...
});
This is the only way I found to solve that kind of errors with a Dockerized environment.

Node.js proxy to return exact response from the external website

I'm trying to create the express.js proxy to an external website to obtaining audio data from there. I know about modules like http-proxy, but think they are excessive for the case when only one url-bound request goes through proxy. I'm using the code below:
express.get('/proxy', function (req, res) {
var options ={
host: "website.com",
port: 80,
path: "/audio/test.mp3",
method: 'GET'
};
http.get(options, function (audioRes) {
var data = [], dataLen = 0;
audioRes.on('data', function(chunk) {
data.push(chunk);
dataLen += chunk.length;
})
.on('end', function() {
var buf = new Buffer(dataLen);
res.set(audioRes.headers);
res.send(buf);
});
})
.on('error', function (error) {
console.log(error.message);
});
});
I get response, but it cannot be decoded as a valid audio. While debugging with the Fiddler, I found out that the number of bites sent by a server mismatches the number specified in the Content-Length header (which indicates fewer bytes being retrieved).
I cannot figure out how to properly return the exact response that's been retrieved from the remote server. Would be grateful for any help.
To send request via proxy, you can set the proxy url in Host header. Also you have to specify the full URL of the external resource you are trying to access via proxy.
var http = require("http");
var options = {
host: "proxy",
port: 8080,
path: "http://www.google.com", //full URL
headers: {
Host: "10.1.2.3" //your proxy location
}
};
http.get(options, function(res) {
console.log(res);
});
I am not sure why it is not returning full response. Can you post your options.
Update
Try this inside /proxy after putting the options
http.get(options, function (audioRes) {
audioRes.pipe(res);
})
.on('error', function (error) {
console.log(error.message);
});

Resources