Response is undefined via ajax client but proper tru url - javascript

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);
});

Related

Unable to receive response inspite of giving right API key in node js post request

Please help me with the below POST request that I'm trying to make. Below is the code snippet.
const express = require("express");
const bodyParser = require("body-parser");
//const request = require("request");
const https = require("https");
const request = require('request-promise');
const app = express();
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(express.static("public"));
app.get("/", function(req, res){
res.sendFile(__dirname + "/test.html");
});
const data = {
"some_header":{
"name":"xxxxx"
}
};
const jsonData = JSON.stringify(data);
console.log(jsonData);
app.post("/post", function(req, res){
const url = "xxxxxxxxxxxx";
const options = {
method: "POST",
body: data,
json: true,
headers: {
ContentType: "application/json",
Authorization: "nhgjgjhgjghjghj"
}
}
const request = https.request(url, options, function(response) {
if (response.statusCode === 200) {
// res.send("success");
console.log("success");
} else {
//res.send("Failed");
console.log("failure");
}
response.on("data", function(data) {
console.log(JSON.parse(data));
})
})
request.write(jsonData);
request.end();
});
app.listen(process.env.PORT || 3000, function() {
console.log("The app is up and running on Port 3000");
});
I'm getting 200OK response from the external server, but unable to post the data. When I logged the response data from the server, I received this success
{ require_login: true }
"Success" is the console log message. require_login: true is the response I'm getting from the server. where am I going wrong?
Try to add Basic before you api key. Also, if you are using base64, then check that original string is right one and should be something like: login:password
headers: {
ContentType: "application/json",
Authorization: "Basic BAsE64Format or api:key or login:password"
}
headers: { "Content-type": "application/json", Authorization: 'Basic ' + Buffer.from('CtB2HZwaRdGggr1g4K').toString('base64') }
enclosing the content-type with quotes and converting the API key to base 64 did the trick

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))

post with whatwg-fetch is working but no data being posted

Im having issues with a POST with "whatwg-fetch" the response is returnin as 200 but no data is passing.
this is the code on the server...
app.post('/promo', function(request, response) {
response.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
var promo = new PromoItem();
promo.imgUrl = request.body.imgUrl;
promo.name = request.body.name;
promo.description = request.body.description;
promo.category = request.body.category;
console.log('----------');
console.log(promo.name);
console.log(request.body.name);
console.log('----------');
promo.save(function(err, savedPromo) {
if (err) {
responde.status(500).send({
error: "Something happened, promo not saved !"
});
} else {
response.status(200).send("Success !");
}
});
});
both promo.name and request.body.name are returning as undefined.
The code on the client..
setPromo = () => {
const options = {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "POST",
mode: 'no-cors',
body: JSON.stringify({
"imgUrl": "http://via.placeholder.com/900x200",
"name": "MI POST",
"description": "MI PRIMER POST",
"category": "Salud"
})
};
fetch('http://localhost:3010/promo', options).then(function(response) {
console.log('Status', response.status);
})
}
have manipulated the options with different values but still the same result.
any ideas?
thanks
It's possible that the data is not being parsed. In Express, POST bodies can be parsed by body-parser. There are usage examples on the Express website. Essentially, you can use the body-parser middleware like this:
var bodyParser = require('body-parser');
app.use(bodyParser.json());
It can also be used on a per-route basis:
app.post('/promo', bodyParser.json(), function(request, response) { //...
If you are using a version of Express >= 4.16.0, bodyParser.json is available as express.json. (source)

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.

Hapi.js Proxy - change the response before reply

I'm trying to test Hapi.js for a new project I'm working on
My goal is to trigger a request on my Hapi server and this request will trigger another request on a remote server using Hapi proxy, and the response will be only specific properties from the remote response
To test this a request to /api/type3/name must be made which will invoke an API call to GitHub's API to get the user object
Code:
server.route({
method: 'GET',
path: '/api/type3/{name}',
handler: {
proxy: {
mapUri: function(request,callback){
callback(null,'https://api.github.com/users/'+request.params.name);
},
onResponse: function(err, res, request, reply, settings, ttl){
console.log(res);
reply(res);
},
passThrough: true,
xforward: true
}
}
});
The response from the above code is the response object from GitHub
Now I need to save this response so I can manipulate it and return only what I need
But when I debug the response object it contains a lot of data and I can't find the response payload inside of it
So how to extract only the response from GitHub from the response object ?
Thanks a lot
The res object is an http.IncomingMessage. If you want to work with the body of the response you need to read all the data off it first.
You have 2 choices for doing this.
1) Vanilla Node
onResponse: function(err, res, request, reply, settings, ttl){
var body = '';
res.on('data', function (chunk) {
body += chunk;
});
res.on('end', function () {
console.log(body);
reply(body);
});
}
2) Using Wreck (a module for working with HTTP in Node made by the Hapi folks)
var Wreck = require('wreck');
onResponse: function(err, res, request, reply, settings, ttl){
Wreck.read(res, null, function (err, payload) {
console.log(payload);
reply(payload);
});
}
In the wreck case above, you could do
payload = payload.toString();
To convert the buffer to actual data.
I want to load xml data from remote server and convert the response to json.
This thread helped me lot to find a solution that worked for me. But in my case the code above doesn't worked too, because the response from the remote server was gzipped. In my console there were only unreadable data.
I tried to enable automatic payload parsing for the proxy but it was not successful. Finally i had to unzip the response by myself with 'zlib'.
This code is working for me:
'use strict'
const url = require('url')
const h2o2 = require('h2o2')
const Hapi = require('hapi')
const parseString = require('xml2js').parseString
var zlib = require('zlib')
const _ = require('lodash')
var remoteServerUrl = 'http://some-url.com:2434'
var originUrl = 'http://localhost:3000'
// Create a server with a host and port
const server = new Hapi.Server()
server.connection({
host: 'localhost',
port: 3001,
routes: {
cors: {
origin: [originUrl],
},
},
})
server.register({
register: h2o2,
}, function (err) {
server.start(function (err) {
console.log('Proxy Server started at: ' + server.info.uri)
})
})
server.route({
method: '*',
path: '/proxy/{path*}',
config: {
payload: {
// parse: true, // didn't worked for me
// parse: 'gzip', // didn't worked for me
output: 'stream',
},
},
handler: {
proxy: {
passThrough: true,
timeout: 15000,
acceptEncoding: false,
mapUri (request, callback) {
callback(null, url.format({
protocol: url.parse(remoteServerUrl).protocol,
host: url.parse(remoteServerUrl).host,
port: url.parse(remoteServerUrl).port,
pathname: request.params.path,
query: request.query,
}))
},
onResponse (err, res, request, reply, settings, ttl) {
if (err) {
console.error('Hapi server error: ', err)
}
// let's unzip the response
var gunzip = zlib.createGunzip()
var xmlStr = ''
gunzip.on('data', function (data) {
xmlStr += data.toString()
})
gunzip.on('end', function () {
// do something with the string
// in this case convert xml to json string
parseString(xmlStr, {}, function (err, result) {
// send result back
reply(result)
})
})
res.pipe(gunzip)
},
},
},
})
Maybe this helps someone else ;)

Categories