404 error with POST request using express server - javascript

I am running this function that should post data to my express server. The function is called when a button is clicked.
const fetchData = async () => {
const response = await fetch('http://localhost:1337/api/test', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
message: 'hello world'
}),
})
// const data = await response.json()
const data = await response
console.log(data)
}
Here is my express configuration
const express = require('express')
const cors = require('cors')
const app = express()
app.use(cors())
app.use(express.json())
app.get('/api/test', (req: any, res: any) => {
console.log(req.body)
res.json({ status: 'ok' })
})
app.listen(1337, () => {
console.log('Server started on 1337')
})
The problem is that when I click the button I receive a 404 error for the POST request and my console.log(response) results in the following.
Response { type: "cors", url: "http://localhost:1337/api/test", redirected: false, status: 404, ok: false, statusText: "Not Found", headers: Headers, body: ReadableStream, bodyUsed: false }
​
body: ReadableStream { locked: false }
​
bodyUsed: false
​
headers: Headers { }
​
ok: false
​
redirected: false
​
status: 404
​
statusText: "Not Found"
​
type: "cors"
​
url: "http://localhost:1337/api/test"
​
<prototype>: ResponsePrototype { clone: clone(), arrayBuffer: arrayBuffer(), blob: blob(), … }

You are issuing a POST request from the client end but do not have a POST request handler configured on the server-side. You instead have a GET request handler. The solution is to either add a handler for POST request or turn your POST request method to GET.

You are not returning response from the fetchData function.
You should simply return the response as below.
-Also there is no post request handler at server side.
You can add post request handler as you have written for get request.
const fetchData = async () => {
const response = await fetch('http://localhost:1337/api/test', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
message: 'hello world'
}),
})
// const data = await response.json()
const data = await response
//need to return response as below
return data.json();
}

In the backend change app.get to app.post
const express = require('express')
const cors = require('cors')
const app = express()
app.use(cors())
app.use(express.json())
// here
app.post('/api/test', (req: any, res: any) => {
console.log(req.body)
res.json({ status: 'ok' })
})
app.listen(1337, () => {
console.log('Server started on 1337')
})

in the server you have not implemented POST endpoint, You have implemented GET endpoint only

Related

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.

Express server not sending response to client (using fetch)

I'm using express for my server side, and i'm making a post request to the server from the client, using fetch.
The data that i'm posting to the server are being sent and displayed. The data from the server's response can't be seen anywhere in the client.
Here's my code in the server side:
app.post('/info',
ensureAuthenticated, function(req,res){
console.log(req.body)
var tryFetch = {myString: 'I am working fetch'};
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(tryFetch));
})
The client side is as follows:
fetch("/info", {
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name : e.target.parentElement.username,
socketID : e.target.parentElement.socketID,
id : e.target.parentElement.id,
})
})
.then( (response) => {
console.log(response)
});
When i console.log() the response, the console displays:
Response {type: "basic", url: "http://localhost:4000/info", redirected: false, status: 200, ok: true, …}
type: "basic"
url: "http://localhost:4000/info"
redirected: false
status: 200
ok: truestatusText: "OK"
headers: Headers
__proto__: Headersbody: (...)
bodyUsed: false
__proto__: Response
I don't know what i'm missing here, and cannot send data from the server to the client. Can anyone help me with this please? It will be much appreciated. Thank you for your time
So, i finally found out what's wrong with this case.
The problem is not on the server, but on the client and the fetch promise. Actually, what made me think that the problem was on fetch, was when i console.log(res.body) and got
ReadableStream {locked: false}
locked: false
__proto__: ReadableStream
Here's what worked for me. I replaced
.then( (response) => {
console.log(response)
});
with
.then(response => response.json())
.then((body) => {
console.log(body);
});
So in conclusion the fetch must look like this:
fetch("/info", {
method: "post",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
//make sure to serialize your JSON body
body: JSON.stringify({
name : e.target.parentElement.username,
socketID : e.target.parentElement.socketID,
id : e.target.parentElement.id,
})
})
.then(response => response.json())
.then((body) => {
console.log(body);
});
Now the response from the server is displayed when i console.log()
You are supposed to res.send or res.json not res.end.
res.end() is used to quickly end the response without any data.
app.post('/info',
ensureAuthenticated, function(req,res){
console.log(req.body)
var tryFetch = {myString: 'I am working fetch'};
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(tryFetch));
})
UPDATE
To return json
app.post('/info',
ensureAuthenticated, function(req,res){
console.log(req.body)
var tryFetch = {myString: 'I am working fetch'};
res.json(tryFetch);
})
Had this exact same issue using axios due to the argument I was using for .then(). The following update worked for me...
axios.post(url, userInfo)
.then((req, res) => {
console.log('Response:', res)
})
.catch(error => console.log("client Error:", error))
Instead of .then((req, res)=>{})
Updated to .then((res) => {})
axios.post(url, userInfo)
.then((res) => {
console.log('Response:', res)
})
.catch(error => console.log("client Error:", error))

Proxying an endpoint to avoid CORS issues

I am using an external api that doesn't allow client side POST request. I can make a POST request using node.js and I am getting my desired response on the server. I am stuck trying to figure out how to get the response from the server into my HTML file.
const https = require("https");
const data = JSON.stringify({
key: "value"
});
const options = {
hostname: "url",
port: 443,
path: "/path",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": data.length
}
};
const req = https.request(options, res => {
console.log(
`statusCode: ${res.statusCode} statusMessage: ${res.statusMessage}`
);
res.setEncoding("utf8");
res.on("data", chunk => {
console.log(chunk);
});
});
req.on("error", error => {
console.error(error);
});
req.write(data)
req.end();
This is my server.js file, I'm not sure what the next step is to get in a file.

Response is undefined via ajax client but proper tru url

I'm setting up an ajax client with a dummy server (just to test). I've managed to resolve the cors issue it seems, but the response as seen from the ajax client is undefined. When I get at the same URL using just a browser thought, it displays the object properly.
// server-side
var express = require('express');
var router = express.Router();
var cors = require('cors');
router.use(cors());
var data = [
{"id": 1, "message": 'first object'},
{"id": 2, "message": 'second object'},
{"id": 3, "message": 'third object'}
];
router.get('/', (req, res, next) => {
console.log("building response body");
res.json(data);
});
// client-side
function fetcher() {
console.log("fetch from:" + rootUrl + arrayEndpoint);
fetch(rootUrl + arrayEndpoint, {
mode: "cors",
method: "GET",
headers: {
"Content-Type": "application/json"
}
})
.then((response) => {
console.log(response);
console.log("response: " + response.body);
})
.catch((error) => {
console.log("error: " + error);
});
}
The response printed to the console of the client:
Response { type: "cors", url: "https://angry-badger-63.localtunnel.me/getArray/", redirected: false, status: 200, ok: true, statusText: "OK", headers: Headers, bodyUsed: false }
undefined
And on the browser:
[{"id":1,"message":"first object"},{"id":2,"message":"second object"},{"id":3,"message":"third object"}]
So I'm pretty sure my server-side is fine (it does send what I expect to the browser and how complicated can resp.json(object) really be?), but apparently something about the ajax client I'm not seein. What's wrong with it?
Taking into account SLak's comment, fetch doesn't have resp.body, which I sort just had assumed. Huge blind spot there.
That revealed another issue - which was that resp.json() (which would be the actual way to handle it) returns a promise, which I wasn't handling. Actually it seems the parsing of the response (whether with .json() or with .text()) returns a promise in general. I'm still not really getting the array proper, but to keep things on topic here's a corrected snippet to parse a generic json object:
//client.js
function fetcher() {
console.log("fetch from:" + rootUrl + arrayEndpoint);
fetch(rootUrl + arrayEndpoint,{
mode: "cors",
method: "GET",
headers: {"Content-Type": "application/json"}
})
.then(function(response) {
response.json()
.then(function (data) {
console.log(data);
});
})
.catch(error => console.log("error:" + error));
}
//server.js
var express = require('express');
var router = express.Router();
var cors = require('cors');
/* GET users listing. */
router.use(cors());
var data = {"1":{"id":1, "message": 'first object'},
"2":{"id":2, "message": 'second object'},
"3":{"id":3, "message": 'third object'}};
router.get('/', function(req, res, next) {
console.log("building response body")
console.log(data)
res.json(data);
});

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