How to send data from React to Node? - javascript

I am really new to node and wanted to know how to send some data from my frontend using react to my backend (Node JS).I want to send some string to my backend,is this the process or is it a completely different thing?
useEffect(() => {
fetch("/api")
.then((res) => res.json())
.then((data) => setData(data.message));
}, []);
index.js file
// server/index.js
const express = require("express");
const PORT = process.env.PORT || 3001;
const app = express();
app.get("/api", (req, res) => {
const tmp=req.body;
res.json({ message: tmp });
});
app.listen(PORT, () => {
console.log(`Server listening on ${PORT}`);
});

Your /api route is listening to GET requests. GET requests can't contain body, therefore you won't be receiving anything inside the body.
If you want to pass data with get request, you can either use query parameters or URL parameters. Passing query params would be something like,
fetch('/api?' + new URLSearchParams({
message: 'message',
}))
To receive this from backend and use it as a response, you can access the query parameters like below using req.query,
app.get('/api', function(req, res) {
res.json({
message: req.query.message
});
});
You can also send data using URL parameters with GET request, instead of using query parameters.
I suggest taking a deeper look at HTTP requests.

you need to use post method, here is the client side using fetch api(from mdn docs):
// Example POST method implementation:
async function postData(url = '', data = {}) {
// Default options are marked with *
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
return response.json(); // parses JSON response into native JavaScript objects
}
postData('https://example.com/answer', { answer: 42 })
.then(data => {
console.log(data); // JSON data parsed by `data.json()` call
});
and for backend, you can handle it this way (from express docs):
const express = require("express");
const bodyParser = require("body-parser");
const router = express.Router();
const app = express();
//Here we are configuring express to use body-parser as middle-ware.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
router.post(‘/handle’,(request,response) => {
//code to perform particular action.
//To access POST variable use req.body()methods.
const {answer} = request.body;
res.json({answer});
});
// add router in the Express app.
app.use("/", router);

Related

Etsy API authetication - Cannot GET error

I'm very rusty in javascript and haven't touched it in a decade so I was following an Etsy tutorial on how to request an API access token.
I'm running a node.js node on my localhost and ngrok to get a proper URL for it (seems like localhost doesn't work for etsy). The authentication seems to work (I can log in in etsy with it), until the part in the tutorial where I need to send the API information onto the next page (to actually start pulling the etsy store data).
As soon as the etsy authentication page get redirected to the next page I alway get the error "Cannot GET views/index.hbs"
The page is in the views folder in the project folder.
I'm really not sure what the problem is, maybe the way the files are structured in the folder?
Thanks a lot for the help.
This is how the code looks like:
// Import the express library
const express = require('express')
const fetch = require("node-fetch");
const hbs = require("hbs");
// Create a new express application
const app = express();
app.set("view engine", "hbs");
app.set("views", `${process.cwd()}/views`);
// Send a JSON response to a default get request
app.get('/ping', async (req, res) => {
const requestOptions = {
'method': 'GET',
'headers': {
'x-api-key': 'xxxxxxxxxxxxxxx',
},
};
const response = await fetch(
'https://api.etsy.com/v3/application/openapi-ping',
requestOptions
);
if (response.ok) {
const data = await response.json();
res.send(data);
} else {
res.send("oops");
}
});
// This renders our `index.hbs` file.
app.get('/', async (req, res) => {
res.render("index");
});
/**
These variables contain your API Key, the state sent
in the initial authorization request, and the client verifier compliment
to the code_challenge sent with the initial authorization request
*/
const clientID = 'xxxxxxxxxxxxxxxx';
const clientVerifier = 'xxxxxxxxxxxxxxxxxxxxxx';
const redirectUri = 'https://xxxxxxx/views/index.hbs';
app.get("/oauth/redirect", async (req, res) => {
// The req.query object has the query params that Etsy authentication sends
// to this route. The authorization code is in the `code` param
const authCode = req.query.code;
const tokenUrl = 'https://api.etsy.com/v3/public/oauth/token';
const requestOptions = {
method: 'POST',
body: JSON.stringify({
grant_type: 'authorization_code',
client_id: clientID,
redirect_uri: redirectUri,
code: authCode,
code_verifier: clientVerifier,
}),
headers: {
'Content-Type': 'application/json'
}
};
const response = await fetch(tokenUrl, requestOptions);
// Extract the access token from the response access_token data field
if (response.ok) {
const tokenData = await response.json();
res.send(tokenData);
} else {
res.send("oops");
}
});
app.get("/welcome", async (req, res) => {
// We passed the access token in via the querystring
const { access_token } = req.query;
// An Etsy access token includes your shop/user ID
// as a token prefix, so we can extract that too
const user_id = access_token.split('.')[0];
const requestOptions = {
headers: {
'x-api-key': clientID,
// Scoped endpoints require a bearer token
Authorization: `Bearer ${access_token}`,
}
};
const response = await fetch(
`https://api.etsy.com/v3/application/users/${user_id}`,
requestOptions
);
if (response.ok) {
const userData = await response.json();
// Load the template with the first name as a template variable.
res.render("welcome", {
first_name: userData.first_name
});
} else {
res.send("oops");
}
});
// Start the server on port 3003
const port = 3003;
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});

Send data from JavaScript to node.js

Below is the JavaScript code. How can I send the players array to node.js?
let players = [];
for(var i=0; i<22; i++){
players.push($(".card > button").eq(i).attr("value"));
}
Below is the node.js code.
const express = require("express");
const bodyParser = require("body-parser");
const mySql = require("mySql");
const app = express();
app.use(express.static("public"));
app.use(bodyParser.urlencoded({extended: true}));
app.set('view engine', 'ejs');
app.get("/play", function(req, res){
res.render("PlayGame");
});
app.post("/play", function(req, res){
res.render("PlayGame");
});
I need to catch the players array at /play route in node.js. How can I do that?
Yes, you can send data from the browser Javascript to your node.js app. You would use an Ajax call and use either the XMLHttpRequest API or the more modern fetch() API to send the data. You would create a route in your nodejs server such as /play and then send the data with the request. Your server will then need to parse the incoming data (depending upon how it was sent) and can then act on it.
You will also have to decide if you're sending a GET, POST or PUT request (picking what is appropriate based on typical REST design and architecture). If this is starting a game and you're sending a bunch of data with it, then you would probably use a POST request and send the data as JSON in the body of the request.
In Express, here's how you'd receive that type of data:
app.use(express.json());
app.post("/play", (req, res) => {
console.log(req.body); // this would be the data sent with the request
res.send("game started");
});
In the browser, here's how you could send an array of players to your server.
fetch("/play", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(players)
}).then(response => {
// this line of code depends upon what type of response you're expecting
return response.text();
}).then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});
See the "Using Fetch" page on MDN for more info.
On the client side you would need something like this:
const postData = data => {
const body = JSON.stringify(data);
return fetch('https://your.url/play', {
method: 'POST', // GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, cors, same-origin
cache: 'no-cache', // default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, same-origin, omit
headers: {
'Content-Type': 'application/json',
},
redirect: 'follow', // manual, follow, error
referrer: 'no-referrer', // no-referrer, client
body
})
.then(response => response.json()) // parses JSON response into native JavaScript objects
}
const players = ['a', 'b', 'c'];
postData({data: players})
.then(json => {
console.log(json);
})
.catch(e => console.log(e));
On the server side you would need something like this:
app.use(express.json());
app.post("/play", (req, res) => {
const players = req.body.data;
...
...
});

The req.body is empty in node.js sent from react

I create an app in react. I am trying to use fetch with a post to a different port of localhost. I received the req on the server, but my body is empty. Why my body is empty? I don't understand.
Code in React function:
export default function Sending() {
async function handleSubmit(e) {
e.preventDefault()
try{
let result = await fetch('http://localhost:5000',{
method: 'post',
mode: 'no-cors',
headers: {
'Accept': 'application/json',
'Content-type': 'application/json',
},
body: JSON.stringify({ email: 'example#gmail.com' })
})
console.log(result)
} catch (error){
console.log(error)
}
}
return (
<>
Have a Form here
</>
)
}
the console log of browser:
Response {type: "opaque", url: "", redirected: false, status: 0, ok: false, …}
body: null
bodyUsed: false
headers:
Headers {}
ok: false
redirected: false
status: 0
statusText: ""
type: "opaque"
url: ""
__proto__: Response
my simple server hold on node.js:
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const port = process.env.PORT || 5000
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.post('/', (req, res) => {
console.log(req.body)
res.send("Hello")
})
app.get('/hello', (req, res) => {
res.send("Hello, Benny")
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
You are trying to post JSON
To do that you need to set a 'Content-type': 'application/json' request header
This is only allowed on a cross-origin request when you have permission from CORS (from a preflight request).
You said mode: 'no-cors', a declaration that you do not have or want permission to do anything from CORS, so the browser will silently ignore anything that needs CORS permission
The request arrives at the server without 'Content-type': 'application/json' so the body-parser doesn't know that it needs to decode the JSON
You need to:
Remove mode: 'no-cors'
Configure the server to support CORS including for preflight requests
This is most easily done with the cors module
const cors = require('cors')
const app = express()
const corsOptions = {
origin: 'http://example.com',
}
const configuredCors = cors(corsOptions);
app.options('*', configuredCors)
app.post('/', configuredCors, (req, res) => {
console.log(req.body)
res.send("Hello")
})
Consider installing cors and add it to your code such as shown bellow
const cors = require('cors')
app.use(cors())
Then with the help of morgan
const morgan = require('morgan');
Consider reading a previous similar case as shown here
Express JS is receiving an empty req.body from ReactJS
From the first glacne; you are sending over a string with the stringify. Node body-parser trys to parse the json. Try removing the stringify and just sending the object over.

GraphQL API works with Postman, but failed with Javascript fetch

I built a GraphQL server as follows,
import express from 'express';
import graphqlHTTP from 'express-graphql';
import { schema } from './data/schema';
const app = express();
app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res) {
res.sendFile('index.html');
});
app.use('/graphql', graphqlHTTP({
schema: schema,
graphiql: true
}));
app.listen(8081, () => {
console.log('Running server on port localhost:8081/graphql');
});
And I can make a POST call from Postman like below,
However, when I try to call the API with fetch in the app.js file which is loaded in the index.html as follows,
function fetchQuery(query) {
return fetch('/graphql', {
method: 'POST',
header: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ query })
}).then(response => {
return response.json();
});
}
const query = `{
friend {
firstName
}
}`;
fetchQuery(query).then((data) => {
console.log(data);
});
It says the following errors,
app.js:2 POST http://localhost:8081/graphql 400 (Bad Request)
and response error message: "Must provide query string."
Headers should be passed in by providing a headers property in the options object, not header.
headers: {
'Content-Type': 'application/json',
},
The content type for the request is necessary for body-parser to know how to correctly parse the body. Without the header, body ends up an empty object and therefore req.body.query is undefined, which is why you see that error.

Getting invalid JSON on API call

I'm trying to use GoToMeeting's API and making a POST request to create a meeting. At the moment, I'm just trying to hardcode the body of the meeting and send headers but I'm receiving and I'm invalid JSON error and not sure why. Here's the code for that route:
app.post('/new-meeting', (req, res) => {
const headers = {
'Content-Type': 'application/json',
Accept: 'application / json',
Authorization: 'OAuth oauth_token=' + originalToken
};
console.log('-----------------------------------------------------------')
console.log('Acess Token:');
console.log('OAuth oauth_token=' + originalToken);
console.log('-----------------------------------------------------------')
const meetingBody = {
subject: 'string',
starttime: '2018-03-20T08:15:30-05:00',
endtime: '2018-03-20T09:15:30-05:00',
passwordrequired: true,
conferencecallinfo: 'string',
timezonekey: 'string',
meetingtype: 'immediate'
};
return fetch('https://api.getgo.com/G2M/rest/meetings', {
method: 'POST',
body: meetingBody,
headers: headers
}).then(response => {
console.log('response:');
console.log(response);
response
.json()
.then(json => {
res.send(json);
console.log(req.headers);
})
.catch(err => {
console.log(err);
});
});
});
When I hit that router, I get the following error:
{
"error": {
"resource": "/rest/meetings",
"message": "invalid json"
}
}
Any advice would be appreciated!
tl;dr
You are passing fetch a value for the body represented by a JavaScript object. It is converting it to a string by (implicitly) calling its .toString() method. This doesn't give you JSON. The API you are calling then complains and tells you that it isn't JSON.
You need to convert your object to JSON using:
body: JSON.stringify(meetingBody),
Test case
This demonstrates the problem and the solution.
Server
This is designed to be a very primitive and incomplete mock of GoToMeeting's API. It just echos back the request body.
const express = require("express");
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.text({ type: "*/*" }));
app.post("/", (req, res) => {
console.log(req.body);
res.send(req.body)
});
app.listen(7070, () => console.log('Example app listening on port 7070!'))
Client
This represents your code, but with the Express server stripped out. Only the code relevant for sending the request to GoToMeeting's API is preserved.
const url = "http://localhost:7070/";
const fetch = require("node-fetch");
const headers = {
'Content-Type': 'application/json',
Accept: 'application / json',
Authorization: 'OAuth oauth_token=foobarbaz'
};
const meetingBody = {
subject: 'string',
starttime: '2018-03-20T08:15:30-05:00',
endtime: '2018-03-20T09:15:30-05:00',
passwordrequired: true,
conferencecallinfo: 'string',
timezonekey: 'string',
meetingtype: 'immediate'
};
fetch(url, {
method: 'POST',
body: meetingBody,
headers: headers
})
.then(res => res.text())
.then(body => console.log(body));
Results of running the test case
The logs of both server and client show:
[object Object]
This is what you get when you call meetingBody.toString().
If you change the code as described at the top of this answer, you get:
{"subject":"string","starttime":"2018-03-20T08:15:30-05:00","endtime":"2018-03-20T09:15:30-05:00","passwordrequired":true,"conferencecallinfo":"string","timezonekey":"string","meetingtype":"immediate"}
This is JSON, which is what the API is expecting.
Aside
MIME types do not have spaces in them. Accept: 'application / json', should be Accept: 'application/json',. This probably isn't causing you any problems though.
I believe the header is incorrect.
You need 'Accept: application/json' without space.

Categories