How to send a post request to mailchimp on express through react - javascript

I am trying to send a new membership from a form in react to my express server to add to the mailchimp memberlist I am getting a cors error and I don't know if I am missing any proxys. I want a user to be able to sign up in react and then it sends it to the mailchimp database
I have been able to get the members list but I am not allowed to post to it :
This is my express backend :
const express = require('express');
const Mailchimp = require('mailchimp-api-v3');
require('dotenv').config();
var request = require('superagent');
var mc_api_key = process.env.REACT_APP_MAILCHIMP_API;
var list_id = process.env.REACT_APP_LIST_ID;
const app = express();
const mailchimp = new Mailchimp(mc_api_key);
const port = process.env.PORT || 5000;
// console.log that your server is up and running
app.listen(port, () => console.log(`Listening on port ${port}`));
app.use((request, response, next) => {
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Headers", "Content-Type");
next();
});
// Routes
app.post('/signup', function (req, res) {
request
.post('https://' + 'us20' + '.api.mailchimp.com/3.0/lists/' + list_id + '/members/')
.set('Content-Type', 'application/json;charset=utf-8')
.set('Authorization', 'Basic ' + new Buffer('any:' + mc_api_key ).toString('base64'))
.send({
'email_address': req.body.email,
'status': 'subscribed',
'merge_fields': {
'FNAME': req.body.firstName,
'LNAME': req.body.lastName
}
})
.end(function(err, response) {
if (response.status < 300 || (response.status === 400 && response.body.title === "Member Exists")) {
res.send('Signed Up!');
} else {
res.send('Sign Up Failed :(');
}
});
});
This is where I am trying to fetch in react in my app.js file :
onSubmit = (e,email) => {
e.preventDefault()
this.setState({user:email})
fetch('http://localhost:5000/signup',{
method: 'POST',
headers: {
'Accept':'application/json',
'Content-type':'application/json'
},
body: JSON.stringify({email_address: email, status: 'subscribed'})
}).then(console.log)
};
when clicking submit I expect the members email address to be sent over to the mailchimp API instead I am getting this error :
Access to fetch at 'http://localhost:5000/signup' from origin
'http://localhost:3000' has been blocked by CORS policy: Response to
preflight request doesn't pass access control check: 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.

Try this.
app.use((request, response, next) => {
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Headers", "Content-Type");
next();
});
to
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:5000");
next();
});

Just enable CORS on your server.
Install cors
$ npm install --save cors
Enable cors in express:
const cors = require('cors');
const express = require('express');
const app = express();
app.use(cors());
More about cors here.

Related

CORS error despite changing Access-Control-Allow-Methods with CORS middleware when deployed in Heroku

I'm running one client local server with "VSC's Live servers" on localhost:5500, and I'm running a remote server using heroku.
Here is the relevant code regarding the AJAX call client-side when submitting a form:
const xhr = new XMLHttpRequest();
xhr.open("POST", "https://git.heroku.com/morning-falls-52888.git");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(JContactRequest);
xhr.onload = () => {
const status = xhr.status;
if (status >= 200 && status < 300 ) {
$("form").append("<p id='submit-message' style='text-align:center;'>Thank you for your submission!</p>");
} else if (status == 418 ) {
window.alert(`Error: ${xhr.status}\nCannot brew coffee, I am a teapot.`);
} else {
console.log(`Before append ${status} ready state: ${xhr.readystate}`);
$("form").append("<p id='submit-message' style='text-align:center;'>Submission Failed</p>");
console.log(`After append ${status} ready state: ${xhr.readystate}`);
}
}
And here is the code server side:
require('dotenv').config();
const express = require('express');
const app = express();
app.use(express.json());
const PORT = process.env.PORT ||4500;
const cors = require("cors");
app.use(cors());
app.listen(PORT, () => { console.log(`Listening on PORT: ${PORT}`) });
// app.use((req,res,next)=>{
// res.status(404).send('this is working');
// })
app.get('/', (req, res) => {
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS");
res.status(201).send();
console.log("received get request");
})
app.post('/', (req, res) => {
var body=req.body;
console.log(body);
for(let [key,value] of Object.entries(body)){
if(value==""){
res.status(400).send(`Empty Field in ${key}`);
res.end();
break;
}
}
var email = body.emailfield;
if (body.comment == "Can you brew coffee?") {
res.status(418).send();
} else {
res.status(200).send('message sent');
}
// calling the api
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
to: email,
from: 'd#gmail.com', // Use the email address or domain you verified above
templateId:'*************************************',
dynamic_template_data:body,
}
//ES6
sgMail
.send(msg)
.then(() => {}, error => {
console.error(error);
if (error.response) {
console.error(error.response.body)
console.log(process.env.SENDGRID_API_KEY)
}
});
});
The message I'm getting on my console is the following:
Access to XMLHttpRequest at 'https://git.heroku.com/morning-falls-52888.git' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I'm kind of stumped because I would have thought that app.use(cors()) would have access-control-allow-origin=*.
I'm still very new to this, so any help is mighty appreciated. Thanks!
EDIT I just wanted to add that this code was running fine when I was running the server locally on port 4500
xhr.open("POST", "https://git.heroku.com/morning-falls-52888.git");
You're making an HTTP request to Heroku's Git repo, not to your application running on Heroku (which will have a URL like https://APPLICATION_NAME.herokuapp.com/something)
The CORS permissions have to be granted for the URL you are making the request to, not one that is loosely adjacent to it.

Have an error with cors, if my cors is enable?

I want to do a request get or post to my firebase backend api
this is my request
const verify = async (address) => {
const params = { address }
const { data } = await client.get('test', { params })
}
and my backend i am using cors
const app = require('express')()
const cors = require('cors')
const options = {
origin: true,
methods: 'GET,POST,PUT,DELETE,OPTIONS,HEAD,PATCH',
preflightContinue: false,
optionsSuccessStatus: 204,
}
app.use(cors(options))
app.get('/test', (req, res) => {
console.log('console.log', req.body)
res.status(200).send('hello world!')
})
module.exports = {
Module: () => app,
}
I don't know what happened, but I am getting an error in cors:
Access to XMLHttpRequest at 'https://...functions.net/test?address=AABB' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I suspect you need to insert the URL, on which your Vue App is running into options.origin
Or does options.origin: true set headers to '"Access-Control-Allow-Origin": *'?
EDIT: First, you need req.query.address in order to access the address query param, that you sent from Vue.
EDIT: Without setting your options to cors() I get the Access-Control-Allow-Origin: * Response Header from Express. Might not want to do this in production, but set origin to some URL that use the API.
const app = require('express')()
const cors = require('cors')
app.use(cors())
app.get('/test', (req, res) => {
console.log('console.log', req.query.address)
res.status(200).send(`The address is ${req.query.address || "not existing"}`)
})
app.listen(3000, () => console.log("Express running..."))
I use this. Find this solution on Stackoverflow :
//#region CORS - Area...
var whitelist = [
"http://127.0.0.1:3000",
"https://127.0.0.1:3000",
"https://localhost:3000",
"http://localhost:3000",
];
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true);
} else {
console.log("Blocked-Origin:", origin);
callback(new Error("Not in CORS-Origin-List"));
}
},
methods: ["POST, DELETE, GET"],
optionsSuccessStatus: 200,
};
app.use(cors(corsOptions));
//#endregion CORS - Area...
And this solution is not recommended, but for Test ok...
app.use(
cors({
optionsSuccessStatus: 200,
credentials: true,
origin: "*",
methods: ["GET", "POST", "DELETE"],
})
);
Note: origin: "*", not true

Serving NodeJS Server in a ReactJS project seperately

I am making an API request inside of a redux action. That API request is blocked due to a CORS issue. To solve this I made a proxy Express NodeJS server on the same project, that listens to a different port.
This works great in development, on my local host. But in production(deployed on Heroku), I'm not able to serve the proxy server.
Part of the problem is I'm not sure what port to serve the proxy server in production, and how to serve it differently from the React App
My API call:
axios.get(`/api/item-info`, {
params: {
productId: productId,
variantId: variantId
}
})
.then(response => response.data)
.then(data =>
dispatch(checkItemInventoryQuantity(parseInt(data.variant.inventory_quantity)))
)
.catch(error => console.log(error));
My Express NodeJS Server:
const express = require('express');
const request = require('request');
const app = express();
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
);
next();
});
app.get('/api/item-info', (req, res) => {
const {productId, variantId } = req.query
const username = process.env.REACT_APP_SHOPIFY_API_KEY;
const password = process.env.REACT_APP_SHOPIFY_API_PASSWORD;
request(
{ url: `https://${username}:${password}#semi-aquatics.myshopify.com/admin/api/2020-04/products/${productId}/variants/${variantId}.json` },
(error, response, body) => {
if (error || response.statusCode !== 200) {
return res.status(500).json({ type: 'error', message: error.message });
}
res.json(JSON.parse(body));
}
)
});
app.listen(3001, () =>
console.log('Express server is running on localhost:3001')
);

Redirect 302 does not work when I pass it from express to react

I have an Express Application and in my API, I send a 302 status to the client. The client uses React and AXIOS. It throws this error:
Access to XMLHttpRequest at 'https://sandbox.zarinpal.com/pg/StartPay/000000000000000000000000000000012807' (redirected from 'http://localhost:5000/api/payment/x/handle/accepted')
from origin 'null' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource
Here is my API
router.post('/x/handle/accepted', (req, res) => {
const uuidv4 = require('uuid/v4');
zarinpalLib.request(req.body.acamount, req.body.acemail, req.body.acphone, req.body.acdescription, uuidv4(), function (data) {
if (data.status) {
console.log('here ', data.url)
res.writeHeader(302, { 'Location': data.url });
res.end();
} else {
console.log('here2 ', data.code)
// res.render('error', {zpTitle: appConfig.appTitle, zpError: data.code});
res.status(500).send(data.code)
}
});
});
Here is the React part
if (inputValue === 'RLS') {
var data = {
acfirstname: 'xx',
aclastname: 'xx',
acemail: 'xx',
acphone: phoneNumber,
acamount: inputAmount,
acdescription: 'xx'
};
const res = await;
axios({ method: 'POST', url: `${END_POINT_URL}/api/payment/x/handle/accepted`, data });
console.log(res)
}
I use this middleware in my Express app for CORS:
var allowCrossDomain = function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Headers', 'Content-Type,x-phone-token,Location');
next();
}

cors error within a cloud function

I've copied exactly what's written in the sample code here: https://github.com/firebase/functions-samples/blob/master/authorized-https-endpoint/functions/index.js
but I keep getting this error when trying to make a normal get request to the /savedProfiles endpoint
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://us-central1-my-app.cloudfunctions.net/savedProfiles. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
This is my code:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const express = require('express');
const cookieParser = require('cookie-parser')();
const cors = require('cors')({origin: true});
const app = express();
// Express middleware that validates Firebase ID Tokens passed in the Authorization HTTP header.
// The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this:
// `Authorization: Bearer <Firebase ID Token>`.
// when decoded successfully, the ID Token content will be added as `req.user`.
const validateFirebaseIdToken = (req, res, next) => {
console.log('Check if request is authorized with Firebase ID token');
if ((!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) &&
!req.cookies.__session) {
console.error('No Firebase ID token was passed as a Bearer token in the Authorization header.',
'Make sure you authorize your request by providing the following HTTP header:',
'Authorization: Bearer <Firebase ID Token>',
'or by passing a "__session" cookie.');
res.status(403).send('Unauthorized');
return;
}
let idToken;
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
console.log('Found "Authorization" header');
// Read the ID Token from the Authorization header.
idToken = req.headers.authorization.split('Bearer ')[1];
} else {
console.log('Found "__session" cookie');
// Read the ID Token from cookie.
idToken = req.cookies.__session;
}
admin.auth().verifyIdToken(idToken).then((decodedIdToken) => {
console.log('ID Token correctly decoded', decodedIdToken);
req.user = decodedIdToken;
return next();
}).catch((error) => {
console.error('Error while verifying Firebase ID token:', error);
res.status(403).send('Unauthorized');
});
};
app.use(cors);
app.use(cookieParser);
app.use(validateFirebaseIdToken);
app.get('/savedProfiles', (req, res) => {
res.send(`Hello ${req.user.name}`);
});
// This HTTPS endpoint can only be accessed by your Firebase Users.
// Requests need to be authorized by providing an `Authorization` HTTP header
// with value `Bearer <Firebase ID Token>`.
exports.savedProfiles = functions.https.onRequest(app);
Shouldn't app.use(cors); prevent these sorts of errors?
So I managed to get this to work without even using express. Here's what I came up with:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const cookieParser = require('cookie-parser')();
const cors = require('cors')({
origin: 'http://localhost:8100'
});
exports.savedProfiles = functions.https.onRequest((req, res) => {
cors(req, res, () => {
console.log('Check if request is authorized with Firebase ID token');
if ((!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) &&
!req.cookies.__session) {
console.error('No Firebase ID token was passed as a Bearer token in the Authorization header.');
res.status(403).send('Unauthorized');
return;
}
let idToken;
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
// Read the ID Token from the Authorization header.
idToken = req.headers.authorization.split('Bearer ')[1];
} else {
// Read the ID Token from cookie.
idToken = req.cookies.__session;
}
admin.auth().verifyIdToken(idToken).then((decodedIdToken) => {
req.user = decodedIdToken;
res.status(200).send("SUCCESS");
return;
}).catch((error) => {
console.error('Error while verifying Firebase ID token:', error);
res.status(403).send('Unauthorized');
});
});
});
I did some test and on my PC the above cors setup works as expected.
Check the http response status: if I reproduce an error status (for example a 403) in my setup the Access-Control-Allow-Origin header is not present.
In validateFirebaseIdToken try to add:
res.set('Access-Control-Allow-Origin', '*');
just before res.status(403).send('Unauthorized'); expression to enable CORS also when errors happens.

Categories