Express/axios don't set cookies and headers for response - javascript

I have very complicated problem. My project has 2 API's. 1 API is for front-end of my application and 1 is for back-end. How it works, is just I send request from front-end API to back-end API.
Front-end API has URL http://localhost:8080/api/ and back-end API has URL http://localhost:3000.
The problem is front-end API can't get cookies from back-end API.
Here is example, function of front-end API just send request to back-end:
router.get('/test-front-api', async (req, res) => {
const data = await api.get('/test-back-api')
return res.json(data.data)
})
Back-and just sends cookie and some random text:
router.get("/test-back-api", (req, res) => {
res.cookie("test", "cookie")
res.send("Hi from back-end")
})
A here is where I have problem:
router.get('/test-front-api', async (req, res) => {
const data = await api.get('/test-back-api')
console.log(data.headers) // If you do console.log here you will this cookie test
return res.json(data.data)
})
But this cookie is not set in browser.
Let me show one more example. In browser I can just type http://localhost:8080/api/test-front-api and here is result, no cookie:
But, if I type not front-end API endpoint, but back-end, everything works perfect:
I was trying literally everything I found about cors options, axios {withCredentials: true} etc. Nothing works.
I have found one solution, but I don't like it:
router.get('/test-front-api', async (req, res) => {
const data = await api.get('/test-back-api')
// Something like this
res.cookie("test", JSON.stringify(data.headers['set-cookie']))
return res.json(data.data)
})
So, my question is why cookie is no set by front-end endpoint?

I have found not reason of the problem, but solution that seems to be ok. As I said, there are 2 API's - front-end and back-end.
From back-end API I get this cookie, but actually, it makes no sense to send it in header. Why? Because the front-end API will send it back on front.
So, using example above, you can do this, first, just send this cookies in body:
router.get("/test-back-api", (req, res) => {
res.json({cookie: "cookie"})
res.send("Hi from back-end")
})
And then, in front-end API, handle it:
router.get('/test-front-api', async (req, res) => {
const data = await api.get('/test-back-api')
res.cookie("test", data.cookie)
return res.json(data.data)
})
But I still have no idea, why I can send the same headers twice, through back-end API, then front-end API and finally on front.

Related

How we can intergrate Qr code monkey api to an express.js backend

Intergrate this for https://rapidapi.com/qrcode-monkey/api/custom-qr-code-with-logo
For this code
const express = require('express');
const http = require("https");
const router = express.Router();
router.post('/',async (req,res)=>{
console.log("req",req.body);
return res.sendStatus(200);
});
module.exports = router;
I'm not sure the question you're asking here.
My guess is that you're trying to interact with the qrcode-monkey API using express.js?
If that's true, following the qrcode-monkey API documentation you'll have to invoke (in this case) express to issue either a GET or POST request to the correct end point /qr/transparent with the required data both in the request body and head. this is documented in the link you provided
since you're doing this via express it's I assume you're going to be passing the URL that the qr code points to via your endpoint then to the 3rd party API. This might looking something like this.
router.get('/:url', async (req, res, next) => {
if (!req.params.url) next(new Error('400 missing url param'))
try {
res.body.qr = await fetch('https://qrcode-monkey.p.rapidapi.com/qr/transparent',
{
method: 'GET',
headers: { ... },
body: { ... }
}
).json()
} catch (error) {
next(error)
}
res.json(req.body.qr)
})
note: this is pesudo code and shouldn't just be copy/pasted.
I suggest refering to the express.js documentation
This question seems to go into more detail about 3rd party API interation with express.

Can't send POST request from React front-end to Node.js back-end

I have a simple node.js portfolio page built with which includes a contact page that I use a third-party API to send emails with (sendgrid). The information for the sendgrid API query is saved to sendgridObjand I make a POST request with it to my server at server.js upon submitting the contact form.
//CONTACT.JS PAGE
emailApi = () => {
let sendgridObj = {
to: 'caseyclinga#gmail.com',
from: this.state.from,
subject: this.state.subject,
text: this.state.text
}
this.resetState();
axios.post('/contact', sendgridObj)
.then(res => console.log(`CONTACT.JS RESPONSE: ${res}`))
.catch(err => console.log(`CONTACT.JS ERROR: ${err}`));
}
On the backend, I set up my route for /contact and make a POST request with the sendgridObj to sendgrid mail.
//SERVER.JS FILE
const express = require('express');
var app = express();
const SgMail = require('#sendgrid/mail');
const path = require('path');
SgMail.setApiKey(process.env.REACT_APP_SENDGRID_API_KEY);
//Middleware stuff
app.post('/contact', (req, res) => {
console.log(req.body)
SgMail.send(req.body)
.then(res => console.log(JSON.stringify(res, null, 2)))
.catch(err => console.log(`SERVER.JS ERROR: ${err}`));
});
app.listen(PORT, () => console.log(`Server running on port ${PORT}`))
All relatively straight forward stuff. This was all working well until a few days ago when it inexplicably stopped funcitoning. When I run console.log(req.body) on my back-end, it shows the object I sent so it's not an issue with the req.body. It's also not an issue with my API key and I receive a 202 in the response object from Sendgrid (catches no errors).
However, about 45 seconds or so after submitting the contact form, the front end catches a 500 error POST http://localhost:3000/contact 500 (Internal Server Error).
Then I noticed if I reset my server, I get a proxy error on my backend Proxy error: Could not proxy request /contact from localhost:3000 to http://localhost:5000/.
So it seems like I have an issue with my routes or somehow with sending the request to Sendgrid but I'm completely confused as to why. I can console log the query object to show it's being sent to the backend and then I get a 202 response but still I am getting an error? If it could not proxy my request, then why was the object still sent?
Here is my whole code: https://github.com/caseycling/portfolio
You should create baseURL for both on backend and frontend. Example:
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
Then, you should use the created instance to get or post for integrating with backend.
Seem like your react server and your node js server is running in different port.
2 thing you need to handle is:
Specify full baseURL to node js backend
Add cors config for node js and run
npm install cors
Then add this in your node.js code
var cors = require('cors')
var app = express()
app.use(cors())

How do I fetch on an update to a url containing JSON?

I am running a couple of arduino mini's who send JSON data to a url-path on my website. Currently I have managed to fetch the data just fine, but would like to fetch upon JSON changes to the url, instead of fetching every x seconds.
Code for the fetch part:
async function getMini4 () {
let response = await fetch('/api/sensor/mini4')
let data = await response.json()
return data
}
And the Express that posts the formatted json:
app.get('/api/sensor/mini1', (req, resp, next) => {
resp.send(gyroData1)
})
app.post('/api/sensor/mini1', (req, resp, next) => {
gyroData1 = req.body
resp.send()
})
The fetch works just fine, but I can't seem to find anything on fetching when the url changes.
Are you familiar with websockets ? This protocol allow you to push update from the server to the client and it seems to exactly fit your need.

Node server to send image to cloud to be hosted

I send an image file to my node server via my react app -
I want to host these images on google cloud or similar so they have an accessible URL.
I have tried using cloudinary and google cloud but to no avail thus far!
My react-side code (shortened):
imageFile = this.state.files[0])
const formData = new FormData()
formData.append('file', imageFile);
sendImage(formData)
sendImage(image) {
axios.post("https://137a6167.ngrok.io/image-upload", image, {
})
.then(res => { // then print response status
console.log(res.statusText)
})
}
The file is successfully sent to my server and consoled:
app.post('/image-upload', (req, res) => {
console.log('consoling the req.body!!!!' + JSON.stringify(req.body))
})
THE CONSOLE: consoling the req.body!!!!{"1":"[object File]"}
I did try use this following cloudinary method, yet it threw errors:
cloudinary.config({
cloud_name: process.env.CLOUD_NAME,
api_key: process.env.API_KEY,
api_secret: process.env.API_SECRET
})
app.use(formData.parse())
app.post('/image-upload', (req, res) => {
const values = Object.values(req.files)
const promises = values.map(image => cloudinary.uploader.upload(image.path))
Promise
.all(promises)
.then(results => res.json(results))
})
this gave me the error that an unhandled error in the promise wasnt handled and i got a bit lost with where to go beyond that!
I looked at google cloud storage too but couldn't get it working! Any advice?
What I really want to do is return back to my react app the URL of the hosted image - so it can be stored in DB for the user!
If you can help at all that would be greatly appreciated, thank you.
There are couple of things you need to fix on the front end before you try to upload to any cloud.
First you need to set 'Content-Type': 'multipart/form-data' header in axios to send the file data properly.
Check this thread for more details: How do I set multipart in axios with react?
Then on the express side you need multer or some other similar library to receive the data. You can't access it from req.body. multer adds req.files for example.
https://github.com/expressjs/multer
Try there steps and then post the exact error message you are receiving from google cloud.

Protect API routes in Node.js

I have some routes in my Node.js API sending data from a MongoDB database to an Angular 4 frontend.
Example:
Node.js route:
router.get('/api/articles', (req, res) => {
Article.find({}, (err, articles) => {
if(err) return res.status(500).send("Something went wrong");
res.status(200).send(articles);
});
});
Angular 4 service function:
getArticles() {
return this.http.get('http://localhost:3000/api/articles')
.map(res => res.json()).subscribe(res => this.articles = res);
}
The question is, how do I protect my Node.js API routes from browser access? When I go to http://localhost:3000/api/articles I can see all my articles in json format.
This is not a security measure, just a way to filter the request. For security use other mechanisms like JWT or similar.
If the angular app is controlled by you then send a special header like X-Requested-With:XMLHttpRequest (chrome sends it by default for AJAX calls) and before responding check for the presence of this header.
If you are really particular about exposing the endpoint to a special case use a unique header may be X-Request-App: MyNgApp and filter for it.
You can't really unless you are willing to implement some sort of authentication — i.e your angular user will need to sign into the api.
You can make it less convenient. For example, simply switching your route to accept POST request instead of GET requests will stop browsers from seeing it easily. It will still be visible in dev tool or curl.
Alternatively you can set a header with your angular request that you look for in your express handler, but that seems like a lot of work for only the appearance of security.
Best method is to implement an authentication token system. You can start with a static token(Later you can implement dynamic token with authorisation).
Token is just a string to ensure the request is authenticated.
Node.js route:
router.get('/api/articles', (req, res) => {
let token = url.parse(req.url,true).query.token; //Parse GET param from URL
if("mytoken" == token){ // Validate Token
Article.find({}, (err, articles) => {
if(err) return res.status(500).send("Something went wrong");
res.status(200).send(articles);
});
}else {
res.status(401).send("Error:Invalid Token"); //Send Error message
}
});
Angular 4 service function:
getArticles() {
return this.http.get('http://localhost:3000/api/articles?token=mytoken') // Add token when making call
.map(res => res.json()).subscribe(res => this.articles = res);
}
With Express, you can use route handlers to allow or deny access to your endpoints. This method is used by Passport authentication middleware (which you can use for this, by the way).
function isAccessGranted (req, res, next) {
// Here your authorization logic (jwt, OAuth, custom connection logic...)
if (!isGranted) return res.status(401).end()
next()
}
router.get('/api/articles', isAccessGranted, (req, res) => {
//...
})
Or make it more generic for all your routes:
app.use('*', isAccessGranted)

Categories