I am trying to create a covid cases app with react.js, node.js, and puppeteer. With node.js and puppeteer I created an api. This is my code for node.
const puppeteer = require("puppeteer")
var http = require("http")
var fs = require("fs")
let dataExplained = {}
async function getCovidCases(){
const browser = await puppeteer.launch()
const page = await browser.newPage()
const url = "https://www.worldometers.info/coronavirus/#countries"
await page.goto(url, {waitUntil: 'networkidle0'})
const results = await page.$$eval(".even", navBars => {
return navBars.map(navBar => {
const anchors = Array.from(navBar.getElementsByTagName('td'));
return anchors.map(anchor => anchor.innerText);
});
})
browser.close()
dataExplained.country = results[15][1]
dataExplained.totalCases = results[15][2]
dataExplained.newCases = results[15][3]
dataExplained.totalDeaths = results[15][4]
dataExplained.newDeaths = results[15][5]
dataExplained.totalRecovered = results[15][6]
dataExplained.activeCases = results[15][7]
dataExplained.critical = results[15][8]
dataExplained.totalCasesPerMillion = results[15][9]
dataExplained.deathsPerMillion = results[15][10]
dataExplained.totalTests = results[15][11]
dataExplained.totalTestsPerMillion = results[15][12]
dataExplained.population = results[15][13]
var server = http.createServer((req, res) => {
if (req.url === "/api/covid/canada"){
res.writeHead(200, {"Content-Type": "application/json"})
res.end(JSON.stringify(dataExplained))
}
})
server.listen(8080, "127.0.0.1")
console.log("wooh sent")
}
getCovidCases()
This is the json file it outputs to localhost 8080:
{"country":"Canada","totalCases":"582,697","newCases":"+1,302","totalDeaths":"15,606","newDeaths":"","totalRecovered":"489,819","activeCases":"77,272","critical":"711","totalCasesPerMillion":"15,371","deathsPerMillion":"412","totalTests":"13,775,115","totalTestsPerMillion":"363,376","population":"37,908,690"}
Then I tried to access that json api file in my react.js file. This is my code:
fetch("http://localhost:8080/api/covid/canada")
.then(req => req.json())
.then(myJson => console.log(myJson)
But it gave me multiple errors :
Access to fetch at 'http://localhost:8080/api/covid/canada' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
GET http://localhost:8080/api/covid/canada net::ERR_FAILED
How Do I Fix This?
CORS is just a default security mechanism that browsers have. MDN has a good resource about it.
To be able to your Node API send the response, just add:
res.setHeader("Access-Control-Allow-Origin", "http://localhost:3000")
before res.end(JSON.stringify(dataExplained))
I wrote and deployed a Firebase Cloud function with CORS support:
const cors = require('cors')({
origin: true
});
...
exports.test = functions.https.onRequest((req, res) => {
cors(req, res, () => {
const idToken = req.query.idToken;
admin.auth().verifyIdToken(idToken)
.then((decoded) => {
var uid = decoded.uid;
return res.status(200).send(uid);
})
.catch((err) => res.status(401).send(err));
});
});
I call the HTTP Trigger from my React app using the Axios package:
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
// Send token to your backend via HTTPS
// ...
console.log(idToken);
axios.get('https://XXX.cloudfunctions.net/test?idToken='+idToken)
.then(response => console.log(response));
}).catch(function(error) {
// Handle error
});
Unfortunately, when running the app on my local server, I still get an error:
Failed to load...Redirect From..to..
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
PS. I have used the procedure reported here
I found an answer here
exports.test = functions.https.onRequest((req, res) => {
cors(req, res, () => {});
const idToken = req.query.idToken;
admin.auth().verifyIdToken(idToken)
.then((decoded) => {
var uid = decoded.uid;
return res.status(200).send(uid);
})
.catch((err) => res.status(403).send(err));
});
Having an issue with a firebase function that I need to work with cors. Based off the documentation and all the posts I've read it should be working but seem's like no matter what I try I keep getting the same error:
Failed to load <URL>: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 500.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
And here is the corresponding code in my firebase functions index.js file:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const cors = require('cors')({origin: true});
const stripe = require('stripe')('<TEST_KEY>');
const gcs = require('#google-cloud/storage')({keyFilename: '<PATH_TO_KEY>'});
const Easypost = require('#easypost/api');
const api = new Easypost('<TEST_KEY>');
admin.initializeApp(functions.config().firebase);
exports.processOrder = functions.https.onRequest((req, res) => {
cors(req, res, () => {
var body = JSON.parse(req.body);
if (
!body.shipment_id ||
!body.items ||
!body.card
) return res.set('Access-Control-Allow-Origin', '*').send({error: true, message: 'Missing information'});
getPrices(body.items, (err, prices, totalPrice) => {
if (err) return res.set('Access-Control-Allow-Origin', '*').send({error: err, message: "Error"})
// Create a new customer and then a new charge for that customer:
stripe.customers.create({
email: 'test#example.com'
}).then((customer) => {
return stripe.customers.createSource(customer.id, {
source: body.card.token.id
});
}).then((source) => {
return stripe.charges.create({
amount: (totalPrice * 100),
currency: 'usd',
customer: source.customer
});
}).then((charge) => {
return res.set('Access-Control-Allow-Origin', '*').send({error: false, message: "Success"});
}).catch((err) => {
console.log(err);
return res.set('Access-Control-Allow-Origin', '*').send({error: err, message: "Error"});
});
});
});
});
Any help would be greatly appreciated :)
Edit: Just wanted to note: I've tried only setting res.set('Access-Control-Allow-Origin', '*') and not using the cors middleware, and I've tried not setting the header and only using cors. Neither of which worked :(
Solution: As #sideshowbarker said in a comment, my function had an error elsewhere before returning. The Access-Control-Allow-Origin was never even getting set. Once I fixed the error it was all good! Ty!
In node you can use a package to solve this problem. To enable all CORS install the following package:
npm install cors
Then assuming you are using express you can then enable CORS by the following lines of code:
var cors = require('cors');
app.use(cors());
I'm building a React application and I'm trying to make a call to https://itunes.apple.com/search?term=jack+johnson
I have a helper called requestHelper.js which looks like :
import 'whatwg-fetch';
function parseJSON(response) {
return response.json();
}
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(response.statusText);
error.response = response;
throw error;
}
export default function request(url, options) {
return fetch(url, options)
.then(checkStatus)
.then(parseJSON);
}
So I get:
XMLHttpRequest cannot load
https://itunes.apple.com/search?term=jack%20johnson. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access.
My express server looks like this:
const ip = require('ip');
const cors = require('cors');
const path = require('path');
const express = require('express');
const port = process.env.PORT || 3000;
const resolve = require('path').resolve;
const app = express();
app.use(cors());
app.use('/', express.static(resolve(process.cwd(), 'dist')));
app.get('*', function(req, res) {
res.sendFile(path.resolve(resolve(process.cwd(), 'dist'), 'index.html'))
});
// Start app
app.listen(port, (err) => {
if (err) {
console.error(err.message);
return false;
}
const divider = '\n-----------------------------------';
console.log('Server started ✓');
console.log(`Access URLs:${divider}\n
Localhost: http://localhost:${port}
LAN: http://${ip.address()}:${port}
${divider}
`);
});
I have tried using mode: 'no-cors' but is not actually what I need since the response is empty.
Am I doing something wrong with this configuration?
The same origin policy kicks in when code hosted on A makes a request to B.
In this case A is your Express app and B is iTunes.
CORS is used to allow B to grant permission to the code on A to read the response.
You are setting up CORS on A. This does nothing useful since your site cannot grant your client side code permission to read data from a different site.
You need to set it up on B. Since you (presumably) do not work for Apple, you can't do this. Only Apple can grant your client side code permission to read data from its servers.
Read the data with server side code instead.
How can I make an HTTP request from within Node.js or Express.js? I need to connect to another service. I am hoping the call is asynchronous and that the callback contains the remote server's response.
Here is a snippet of some code from a sample of mine. It's asynchronous and returns a JSON object. It can do any form of GET request.
Note that there are more optimal ways (just a sample) - for example, instead of concatenating the chunks you put into an array and join it etc... Hopefully, it gets you started in the right direction:
const http = require('http');
const https = require('https');
/**
* getJSON: RESTful GET request returning JSON object(s)
* #param options: http options object
* #param callback: callback to pass the results JSON object(s) back
*/
module.exports.getJSON = (options, onResult) => {
console.log('rest::getJSON');
const port = options.port == 443 ? https : http;
let output = '';
const req = port.request(options, (res) => {
console.log(`${options.host} : ${res.statusCode}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
output += chunk;
});
res.on('end', () => {
let obj = JSON.parse(output);
onResult(res.statusCode, obj);
});
});
req.on('error', (err) => {
// res.send('error: ' + err.message);
});
req.end();
};
It's called by creating an options object like:
const options = {
host: 'somesite.com',
port: 443,
path: '/some/path',
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
And providing a callback function.
For example, in a service, I require the REST module above and then do this:
rest.getJSON(options, (statusCode, result) => {
// I could work with the resulting HTML/JSON here. I could also just return it
console.log(`onResult: (${statusCode})\n\n${JSON.stringify(result)}`);
res.statusCode = statusCode;
res.send(result);
});
UPDATE
If you're looking for async/await (linear, no callback), promises, compile time support and intellisense, we created a lightweight HTTP and REST client that fits that bill:
Microsoft typed-rest-client
Try using the simple http.get(options, callback) function in node.js:
var http = require('http');
var options = {
host: 'www.google.com',
path: '/index.html'
};
var req = http.get(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
// Buffer the body entirely for processing as a whole.
var bodyChunks = [];
res.on('data', function(chunk) {
// You can process streamed parts here...
bodyChunks.push(chunk);
}).on('end', function() {
var body = Buffer.concat(bodyChunks);
console.log('BODY: ' + body);
// ...and/or process the entire body here.
})
});
req.on('error', function(e) {
console.log('ERROR: ' + e.message);
});
There is also a general http.request(options, callback) function which allows you to specify the request method and other request details.
Request and Superagent are pretty good libraries to use.
note: request is deprecated, use at your risk!
Using request:
var request=require('request');
request.get('https://someplace',options,function(err,res,body){
if(err) //TODO: handle err
if(res.statusCode === 200 ) //etc
//TODO Do something with response
});
You can also use Requestify, a really cool and very simple HTTP client I wrote for nodeJS + it supports caching.
Just do the following for GET method request:
var requestify = require('requestify');
requestify.get('http://example.com/api/resource')
.then(function(response) {
// Get the response body (JSON parsed or jQuery object for XMLs)
response.getBody();
}
);
This version is based on the initially proposed by bryanmac function which uses promises, better error handling, and is rewritten in ES6.
let http = require("http"),
https = require("https");
/**
* getJSON: REST get request returning JSON object(s)
* #param options: http options object
*/
exports.getJSON = function (options) {
console.log('rest::getJSON');
let reqHandler = +options.port === 443 ? https : http;
return new Promise((resolve, reject) => {
let req = reqHandler.request(options, (res) => {
let output = '';
console.log('rest::', options.host + ':' + res.statusCode);
res.setEncoding('utf8');
res.on('data', function (chunk) {
output += chunk;
});
res.on('end', () => {
try {
let obj = JSON.parse(output);
// console.log('rest::', obj);
resolve({
statusCode: res.statusCode,
data: obj
});
}
catch (err) {
console.error('rest::end', err);
reject(err);
}
});
});
req.on('error', (err) => {
console.error('rest::request', err);
reject(err);
});
req.end();
});
};
As a result you don't have to pass in a callback function, instead getJSON() returns a promise. In the following example the function is used inside of an ExpressJS route handler
router.get('/:id', (req, res, next) => {
rest.getJSON({
host: host,
path: `/posts/${req.params.id}`,
method: 'GET'
}).then(({ statusCode, data }) => {
res.json(data);
}, (error) => {
next(error);
});
});
On error it delegates the error to the server error handling middleware.
Unirest is the best library I've come across for making HTTP requests from Node. It's aiming at being a multiplatform framework, so learning how it works on Node will serve you well if you need to use an HTTP client on Ruby, PHP, Java, Python, Objective C, .Net or Windows 8 as well. As far as I can tell the unirest libraries are mostly backed by existing HTTP clients (e.g. on Java, the Apache HTTP client, on Node, Mikeal's Request libary) - Unirest just puts a nicer API on top.
Here are a couple of code examples for Node.js:
var unirest = require('unirest')
// GET a resource
unirest.get('http://httpbin.org/get')
.query({'foo': 'bar'})
.query({'stack': 'overflow'})
.end(function(res) {
if (res.error) {
console.log('GET error', res.error)
} else {
console.log('GET response', res.body)
}
})
// POST a form with an attached file
unirest.post('http://httpbin.org/post')
.field('foo', 'bar')
.field('stack', 'overflow')
.attach('myfile', 'examples.js')
.end(function(res) {
if (res.error) {
console.log('POST error', res.error)
} else {
console.log('POST response', res.body)
}
})
You can jump straight to the Node docs here
Check out shred. It's a node HTTP client created and maintained by spire.io that handles redirects, sessions, and JSON responses. It's great for interacting with rest APIs. See this blog post for more details.
Check out httpreq: it's a node library I created because I was frustrated there was no simple http GET or POST module out there ;-)
For anyone who looking for a library to send HTTP requests in NodeJS, axios is also a good choice. It supports Promises :)
Install (npm): npm install axios
Example GET request:
const axios = require('axios');
axios.get('https://google.com')
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
Github page
Update 10/02/2022
Node.js integrates fetch in v17.5.0 in experimental mode. Now, you can use fetch to send requests just like you do on the client-side. For now, it is an experimental feature so be careful.
If you just need to make simple get requests and don't need support for any other HTTP methods take a look at: simple-get:
var get = require('simple-get');
get('http://example.com', function (err, res) {
if (err) throw err;
console.log(res.statusCode); // 200
res.pipe(process.stdout); // `res` is a stream
});
Use reqclient: not designed for scripting purpose
like request or many other libraries. Reqclient allows in the constructor
specify many configurations useful when you need to reuse the same
configuration again and again: base URL, headers, auth options,
logging options, caching, etc. Also has useful features like
query and URL parsing, automatic query encoding and JSON parsing, etc.
The best way to use the library is create a module to export the object
pointing to the API and the necessary configurations to connect with:
Module client.js:
let RequestClient = require("reqclient").RequestClient
let client = new RequestClient({
baseUrl: "https://myapp.com/api/v1",
cache: true,
auth: {user: "admin", pass: "secret"}
})
module.exports = client
And in the controllers where you need to consume the API use like this:
let client = require('client')
//let router = ...
router.get('/dashboard', (req, res) => {
// Simple GET with Promise handling to https://myapp.com/api/v1/reports/clients
client.get("reports/clients")
.then(response => {
console.log("Report for client", response.userId) // REST responses are parsed as JSON objects
res.render('clients/dashboard', {title: 'Customer Report', report: response})
})
.catch(err => {
console.error("Ups!", err)
res.status(400).render('error', {error: err})
})
})
router.get('/orders', (req, res, next) => {
// GET with query (https://myapp.com/api/v1/orders?state=open&limit=10)
client.get({"uri": "orders", "query": {"state": "open", "limit": 10}})
.then(orders => {
res.render('clients/orders', {title: 'Customer Orders', orders: orders})
})
.catch(err => someErrorHandler(req, res, next))
})
router.delete('/orders', (req, res, next) => {
// DELETE with params (https://myapp.com/api/v1/orders/1234/A987)
client.delete({
"uri": "orders/{client}/{id}",
"params": {"client": "A987", "id": 1234}
})
.then(resp => res.status(204))
.catch(err => someErrorHandler(req, res, next))
})
reqclient supports many features, but it has some that are not supported by other
libraries: OAuth2 integration and logger integration
with cURL syntax, and always returns native Promise objects.
If you ever need to send GET request to an IP as well as a Domain (Other answers did not mention you can specify a port variable), you can make use of this function:
function getCode(host, port, path, queryString) {
console.log("(" + host + ":" + port + path + ")" + "Running httpHelper.getCode()")
// Construct url and query string
const requestUrl = url.parse(url.format({
protocol: 'http',
hostname: host,
pathname: path,
port: port,
query: queryString
}));
console.log("(" + host + path + ")" + "Sending GET request")
// Send request
console.log(url.format(requestUrl))
http.get(url.format(requestUrl), (resp) => {
let data = '';
// A chunk of data has been received.
resp.on('data', (chunk) => {
console.log("GET chunk: " + chunk);
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', () => {
console.log("GET end of response: " + data);
});
}).on("error", (err) => {
console.log("GET Error: " + err);
});
}
Don't miss requiring modules at the top of your file:
http = require("http");
url = require('url')
Also bare in mind that you may use https module for communicating over secured network. so these two lines would change:
https = require("https");
...
https.get(url.format(requestUrl), (resp) => { ......
## you can use request module and promise in express to make any request ##
const promise = require('promise');
const requestModule = require('request');
const curlRequest =(requestOption) =>{
return new Promise((resolve, reject)=> {
requestModule(requestOption, (error, response, body) => {
try {
if (error) {
throw error;
}
if (body) {
try {
body = (body) ? JSON.parse(body) : body;
resolve(body);
}catch(error){
resolve(body);
}
} else {
throw new Error('something wrong');
}
} catch (error) {
reject(error);
}
})
})
};
const option = {
url : uri,
method : "GET",
headers : {
}
};
curlRequest(option).then((data)=>{
}).catch((err)=>{
})