GraphqQL Cannot set headers after they are sent to the client - node.js

I have tried looking at other articles on SO related to this question, but I am unable to resolve this issue.
I have a graphql api and in my component on the UI side, I am calling it as such
useEffect(()=>{
const leaders = graphQLClient.request(GetLeadersQuery)
if(leaders && leaders.leaders) {
let leadersList = JSON.parse(leaders.leaders)
setLeaders(leadersList)
}
}, [leaders])
On the server side, this looks like this
leaders: (_parent, args, _context) => {
return (JSON.stringify({
name:"Jane Dooe"
}))
This is the query that I am using
query {
leaders
}
Now everytime, my client side code is hit, I see the following error in my terminal.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
My use case is very simple and yet , I am unable to see why I am encountering this error.
Update
On my client side, I tried doing the following, just to make sure that I am resolving the promises, but I am still getting the same result.
useEffect(()=>{
async function getLeaders(){
const leaders = await graphQLClient.request(GetLeadersQuery)
console.log({ leaders })
if (leaders && leaders.leaders) {
let leadersList = JSON.parse(leaders.leaders)
setLeaders(leadersList)
}
}
getLeaders()
}, [])
On the server side I am using
NextJS
apollo-server-micro
On the client side I am using
React
graphql-request
Can you please help ?
Thanks

Related

How can I fix IPC error "Error invoking remote method, an object could not be cloned" in Electron?

The whole error message is the following:
Error: Error invoking remote method 'MY-IPC-CHANNEL': Error: An object
could not be cloned. at EventEmitter.o.invoke
(electron/js2c/renderer_init.js:71)
The electron/js2c/renderer_init.js:71 line is not my original line of code, but a compiled one.
I'm trying to send a POST request in order to get my Google access token, so that I can work with Google Drive's API. Currently I'm stuck trying to communicate between the renderer process and the main process by giving the main process the code I got from Google and making it send a POST request to the auth server. I have no problem establishing the connection but when I try to do it while sending an HTTP request I get the error above.
// ******* MAIN *******
function exchangeCodeForAccessToken(code: string) {
const clientID = "My Google client ID";
const clientSecret = "My Google client secret";
const body = {
code: code,
client_id: clientID,
client_secret: clientSecret,
redirect_uri: "http://localhost:4000",
grant_type: "authorization_code",
};
const body2 = `code=${code}&
client_id=${clientID}&
client_secret=${clientSecret}&
grant_type=authorization_code`;
// return fetch("https://oauth2.googleapis.com/token", {
// method: "POST",
// body: body
// });
return axios.post("https://oauth2.googleapis.com/token", body);
}
Here's the main handle:
// ******* MAIN *******
ipcMain.handle(
OAUTH2_ACCESS_TOKEN_REQUEST_CHANNEL,
async (event, code: string) => await exchangeCodeForAccessToken(code)
);
And the renderer invoke function:
// ******* RENDERER *******
function exchangeCodeForAccessToken(code: string) {
ipcRenderer.invoke(OAUTH2_ACCESS_TOKEN_REQUEST_CHANNEL, code).then((response) => {
console.log(response);
}).catch((error) => {
//TODO Improve error handling
console.log(error);
});
}
I tried sending the request through the net module from Electron. I also tried with the electron-fetch module, which is supposed to be an Electron integrated version of Node's fetch module. And finally I tried with the axios module, but it kept throwing the same error. I thought it had something to do with object serialization through IPC but then I tried just using the function without returning its promise and the same error kept popping up. Which means that the error is not only appearing when the promise is being returned but whenever the HTTP request function is being called. I also tried sending the request with both the object version of the request and its string version, hence the body and body2.
I don't know what I'm missing, and I'm so close to integrating Google login into my desktop app.
I thought it had something to do with object serialization through IPC but then I tried just using the function without returning its promise and the same error kept popping up.
It is an IPC error. You're returning the full response object, which presumably contains some properties with methods and/or other non-cloneable values. You need to make sure that the returned value can be cloned and sent to the renderer, for example:
ipcMain.handle(
OAUTH2_ACCESS_TOKEN_REQUEST_CHANNEL,
async (event, code) => {
const response = await exchangeCodeForAccessToken(code);
const {status, data} = response;
return {status, data};
}
);
I'm not sure how you called the function in your attempt to fix this, but I just ran this in Electron and it works without issues.
EDIT: Assuming response is coming from a fetch call (use response.json() if the data is JSON):
ipcMain.handle(
OAUTH2_ACCESS_TOKEN_REQUEST_CHANNEL,
async (event, code) => {
const response = await exchangeCodeForAccessToken(code);
const data = await response.text();
return data;
}
);

Socket.IO: "UnhandledPromiseRejectionWarning: Error: Callbacks are not supported when broadcasting"

im trying to create a login system with Node.js, Socket.IO and MongoDB.
At one point i have to get a certain cookie of the client.
So i "send" an event to the client which should return the cookie so i can work with that data within the same function.
My code is as follows:
Server:
async function checklogin(user) {
user = user;
console.log("user:", user);
await User.find({username:user}).then(function(docs) {
servercookieid = docs[0].cookieid;
servercookiedate = docs[0].cookiedate;
});
io.emit('getCookie', function(responseData) {
console.log(responseData)
}).catch(error)
}
Client:
socket.on('getCookie', function(callback) {
console.log('getting cookie...');
var Cookie = document.cookie;
callback(Cookie)
});
I really dont know why i get this error, because as you can see i am not even broadcasting, sooo...
/shrug
If you need more information, please dont hesitate to ask.
The error message says:
Socket.IO: “UnhandledPromiseRejectionWarning: Error: Callbacks are not
supported when broadcasting”
But in fact when you do io.emit you're broadcasting.
Currently you're broadcasting when you do the command:
io.emit('getCookie', function(responseData) {
console.log(responseData)
}).catch(error)
But for broadcasting you just need set a parameter, it's not a function.
Just fix your code to fix the error.
Changing to:
io.emit('getCookie', responseData);//must set the cookie
by the code you provided responseData is not defined. But by the name it should be a cookie.

How to handle server side error during authentication in react-native

So I was making an app and in that app I have say login with facebook
For login, I am using expo-web-browser
Here is my relevant code,
loginWithFacebook = async () => {
const redirectUrl = await Linking.getInitialURL()
const authUrl = config.backendUrl + '/auth/facebook'
Linking.addEventListener('url', this.handleRedirect)
try {
const authResult = await WebBrowser.openAuthSessionAsync(authUrl, redirectUrl)
console.log(authResult)
Linking.removeEventListener('url', this.handleRedirect)
} catch (err) {
console.warn('ERROR:', err)
}
}
While this works, my problem is on error handling, I am using passport Js on the backend (NodeJS). On successful authentication, I am re-directing to my deep link url
return res.redirect(myapplink://)
and currently, on error (say there is an sql connection error), I am throwing a 500 internal error
return res.status(error.status).send(error.message)
Since typically auth related events are done using href and not using ajaxy request, How would you typically handle the error in this situation? I think the answer for the app and web should be identical but if not can you please suggest the way I can handle error in the app and web.

How to make a shipping request to chronopost using soap and nodejs

I've had trouble getting to make a simple request with node-soap and chronopost (shipping platform) soap api.
the first thing I did was to follow the basic node-soap example but it just fails miserably without any real USEFUL error from chronopost.
Here's what I have:
const soap = require('soap')
const client = await soap.createClientAsync(
'https://ws.chronopost.fr/shipping-cxf/ShippingServiceWS?wsdl'
)
client.shippingV6(...somedata, (err, result) => {
if (err) {
return handleErr(); // it always fails
}
handleResult();
})
After multiple attempt it seems like chronopost api uses special root attributes (who knows why) and you need to craft the options on node-soap that actually fit their needs (yay..)
Here's what works for me
const createClientShippingServiceWS = async () => {
const wsdlOptions = {
envelopeKey: 'soapenv',
overrideRootElement: {
namespace: 'cxf',
xmlnsAttributes: [
{
name: 'xmlns:cxf',
value: 'http://cxf.shipping.soap.chronopost.fr/'
}
]
}
}
return await soap.createClientAsync(
'https://ws.chronopost.fr/shipping-cxf/ShippingServiceWS?wsdl',
wsdlOptions
)
}
Also what's the point of getting the wsdl if node-soap can't event figure how to make the response??
Thanks chronopost for being stuck in 2008

Can fetch website in CURL but not in Nodejs Request

I'm trying to fetch a page from IMDB, but for some odd reason it gives me error 400 when I'm using request-promise
But the same query works fine if I'm using CURL:
curl "https://www.imdb.com/title/tt6306064/mediaviewer/rm3146075904"
My nodejs code:
async function getMoviePosterImage(mediaViewerUrl) {
const options = {
uri: mediaViewerUrl
};
try {
const mediaViewerHtml = await request.get(options);
return mediaViewerHtml;
} catch (error) {
console.error(error.statusCode);
}
}
await getMoviePosterImage(
"https://www.imdb.com/title/tt6306064/mediaviewer/rm3146075904"
);
Things I have tried so far:
Setting a user agent
Setting keep-alive
Having cookie jar enabled
On my end, I just tried locally and the same error happened for me. Not a definitive answer, but I have a feeling that IMDB protects against web scrapers.

Resources