I have this function that reads a csv file that contains a list of url.
For every line I do a get request to the current url to read the response header.
function readCSV(csv) {
var lines = csv.split("\n");
var table = lines.map((line) => line.split(","));
var requests = table.map((row) =>
request({
method: "GET",
uri: "https://www." + row[1],
resolveWithFullResponse: true,
})
.catch((err) => null) // Errors are ignored and resolved as `null`
);
return Promise.all(requests)
.then((responses) => {
responses.forEach((response) => {
if(response === null) return; // If the response is null, skip it
// ... handle successful responses here
var hrds = response.headers;
//console.log(hrds.url)
console.log(hrds['content-security-policy'])
console.log(hrds['x-frame-options'])
});
})
.catch((err) => console.log(err));
}
I would like to do something like: console.log(hrds.url) to see the url that sent me the response. If I try to print hrds.url it gives me undefined.
EDIT:
I tried response.url but it prints blank line
According to MDN docs you can get the URL from the response it self.
response.url
Related
I am trying to make an API call from my JavaScript app to an endpoint in another application.
When I call the endpoint I get the status code and the message, but I cannot access the response body in any way. I have tried different ways to get the data, but nothing seems to work for me.
In the method "someAction", I want to use the data in the response/result from the API call. I added the outputs that the single log-lines print in the code.
How can "result" be undefined while "result.status/message" are defined?
What do I have to do in order to get the data/body as JSON or String?
The API itself is tested and returns data when tested in postman.
Thanks for your help!
const request = require('request')
let callEndpoint = () => {
return new Promise((resolve, reject) => {
const url = `https://my.api.com/endpoint`
const requestOptions = {
url: url,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
'My-API-Authorization': '123456789'
},
json: true,
strictSSL: false
}
request.get(requestOptions, (err, response) => {
if(err)
{
return reject(err);
}
return resolve(response);
});
});
}
let someAction = () => {
callEndpoint()
.then(result => {
logger.logInfo(result.statusCode) // => 200
logger.logInfo(result.statusMessage) // => OK
logger.logInfo(result) // => undefined
logger.logInfo(result.toString()) // => [object Object]
logger.logInfo(result.body) // => undefined
logger.logInfo(result.data) // => undefined
JSON.parse(result.toString()) // => Unexpected token o in JSON at position 1
JSON.parse(result) // => Unexpected token o in JSON at position 1
// DO SOME STUFF WITH THE RESULT
})
}
I'm kind of new to JS and can't figure out how to make the following work:
I'd like to run functions (for test reasons console) in the different stages of the fetch API. Like run console when fetch started because of click –> then when fetch received a response (text) -> then when the fetch response has been parsed -> and finally when the parsed response text has replaced the HTML of an existing DOM-element.
var doFetch = (url) => {
fetch(url, {
method: "GET",
headers: new Headers({
'X-Requested-With': 'fetch'
})
}){
console.log("fetch request started because of click on element");
}
.then(response => response.text();
console.log("fetch request has received the response text");
)
.then(response => {
let content = new DOMParser().parseFromString(text, "text/html");
console.log("the received request response text was DOMparsed");
})
.then(response => {
let main = content.querySelector('main').innerHTML;
console.log("the parsed response content replaced current HTML");
}
};
Any tips on how to correct the code would be gladly welcomed!
each then block will execute if previous then block return.
Your first console.log statement should be at the start of the doFetch function. It cannot be written where it is currently written in your code.
You should also chain a catch block at the end to catch any errors that might occur in the promise chain.
As a side note, you should use const or let keywords to declare variables instead of var.
const doFetch = (url) => {
console.log("fetch request started because of click on element");
fetch(url, {
method: "GET",
headers: 'X-Requested-With': 'fetch'
})
.then(response => {
console.log("fetch request has received the response text");
return response.text();
})
.then(response => {
console.log("the received request response text was DOMparsed");
return new DOMParser().parseFromString(text, "text/html");
})
.then(response => {
let main = content.querySelector('main').innerHTML;
console.log("the parsed response content replaced current HTML");
})
.catch(error => console.log(error));
};
In order to do chaining you need to return from each .then block. Aslo your first console.log() post the fetch function had incorrect syntax
var doFetch = (url) => {
fetch(url, {
method: "GET",
headers: 'X-Requested-With': 'fetch'
})
.then(response => {
console.log("fetch request has received the response text");
return response.text();
})
.then(response => {
let content = new DOMParser().parseFromString(text, "text/html");
console.log("the received request response text was DOMparsed");
return content
})
.then(content => {
let main = content.querySelector('main').innerHTML;
console.log("the parsed response content replaced current HTML");
});
console.log("fetch request started because of click on element"); // This will be executed first
};
I have written the following HTTP firebase JS function which is returning the incorrect status 500 error response using Postman even though the axios GET call response from the API service has returned the correct 200 status response (confirmed by the console output screenshot below)
exports.doshiiMenuUpdatedWebhook = functions.https.onRequest((req, res) => {
if (req.method === 'PUT') {
return res.status(403).send('Forbidden!');
}
return cors(req, res, () => {
let verify = req.query.verify;
if (!verify) {
verify = req.body.verify;
}
let locationId = req.body.data.locationId
let posId = req.body.data.posId
let type = req.body.data.type
let uri = req.body.data.uri
let itemUri = req.body.data.itemUri
console.log('locationId', locationId);
console.log('posId', posId);
console.log('type', type);
console.log('uri', uri);
console.log('itemUri', itemUri);
const options = {
headers: {'authorization': 'Bearer ' + req.query.verify}
};
return axios.get(uri, options)
.then(response => {
console.log('response data: ', response.data);
console.log('response status: ', response.status);
console.log('response statusText: ', response.statusText);
console.log('response headers: ', response.headers);
console.log('response config: ', response.config);
return res.status(200).json({
message: response
})
})
.catch(err => {
return res.status(500).json({
error: err
})
});
});
});
In Postman I'm expecting to see "Status: 200" response, but I get this:
There is no error report in the Firebase console other than this:
As explained in the Express documentation:
res.json([body])
Sends a JSON response. This method sends a response (with the correct
content-type) that is the parameter converted to a JSON string using
JSON.stringify().
The parameter can be any JSON type, including object, array, string,
Boolean, number, or null, and you can also use it to convert other
values to JSON.
Following the "debugging" we did through the comments/chat, it seems that the
{message: response}
object that you pass to json() generates the error.
Following the HTTP Cloud Functions documentation, which states:
Important: Make sure that all HTTP functions terminate properly. By
terminating functions correctly, you can avoid excessive charges from
functions that run for too long. Terminate HTTP functions with
res.redirect(), res.send(), or res.end().
and since you explained in the chat that you "only need to return the status code" and that you "want to save the json data to: admin.database().ref(/venue-menus/${locationId}/menu)",
I would advise you do as follows:
exports.doshiiMenuUpdatedWebhook = functions.https.onRequest((req, res) => {
if (req.method === 'PUT') {
return res.status(403).send('Forbidden!');
}
cors(req, res, () => {
let verify = req.query.verify;
if (!verify) {
verify = req.body.verify;
}
let locationId = req.body.data.locationId
let posId = req.body.data.posId
let type = req.body.data.type
let uri = req.body.data.uri
let itemUri = req.body.data.itemUri
const options = {
headers: { 'authorization': 'Bearer ' + req.query.verify }
};
axios.get(uri, options)
.then(response => {
console.log('response data: ', response.data);
return admin.database().ref(`/venue-menus/${locationId}/menu`).set(response.data)
})
.then(response => {
return res.status(200).end()
})
.catch(err => {
return res.status(500).send({
error: err
})
})
})
});
I'm trying to return a JSON result to my client using IHttpActionResult.
My .Net code, looks like this:
[AllowAnonymous, HttpPost, Route("")]
public IHttpActionResult Login(LoginRequest login)
{
if (login == null)
return BadRequest("No Data Provided");
var loginResponse = CheckUser(login.Username, login.Password);
if(loginResponse != null)
{
return Ok(new
{
message = "Login Success",
token = JwtManager.GenerateToken(login.Username, loginResponse.Roles),
success = true
});
}
return Ok( new
{
message = "Invalid Username/Password",
success = false
});
}
This doesn't work though, as I never seem to see the JSON on the response after my JavaScript fetch:
const fetchData = ( {method="GET", URL, data={}} ) => {
console.log("Calling FetchData with URL " + URL);
var header = {
'Content-Type': "application/json",
}
// If we have a bearer token, add it to the header.
if(typeof window.sessionStorage.accessToken != 'undefined')
{
header['Authorization'] = 'Bearer ' + window.sessionStorage.accessToken
}
var config = {
method: method,
headers: header
};
// I think this adds the data payload to the body, unless it's a get. Not sure what happens with a get.
if(method !== "GET") {
config = Object.assign({}, config, {body: JSON.stringify(data)});
}
// Use the browser api, fetch, to make the call.
return fetch(URL, config)
.then(response => {
console.log(response.body);
return response;
})
.catch(function (e) {
console.log("An error has occured while calling the API. " + e);
});
}
There is no JSON available in the body.
How do I get aresult back to my client to parse? response.body doesn't have the json object.
The console.log shows:
While the request/response shows:
Using striped's advice: console.log(response.json())
I see the message there. It seems to be in the wrong place. Shouldn't it be in the body?
Fetch works like this
Body methods
Each of the methods to access the response body returns a Promise that
will be resolved when the associated data type is ready.
text() - yields the response text as String
json() - yields the result of JSON.parse(responseText)
blob() - yields a Blob
arrayBuffer() - yields an ArrayBuffer
formData() - yields FormData that can be forwarded to another request
I think you need to
return fetch(URL, config)
.then(response => response.json())
.catch(e => console.log("An error has occured while calling the API. " + e));
doc here: https://github.github.io/fetch/
Your are making a GET request but your controller method is expecting a POST request.
I have the following code for making POST Requests.
I'm not 100% sure about error handling here, but it was important for me that I get body text when request is not successful.
One issue that I still do have is - if server responds with 200 OK but invalid json - can I log that payload?
What would be the correct way of logging for Fetch?
Fetch(data.notificationUrl, {
method: 'POST',
body: post_data,
headers: {
'Content-Type': 'application/json'
}
}).then((res) => {
if (!res.ok) {
// Could reject the promise here but than response text wouldn't be available
//return Promise.reject(`Response was not OK. Status code: ${res.status} text: ${res.statusText}`);
return res.text().then((txt) => `Response was not OK. Status code: ${res.status} text: ${res.statusText}.\nResponse: ${txt}`);
}
// response ok so we should return json, could follow https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch and determine the payload type by content-type header...
return res.json();
}).then((response) => {
if (response) {
// set result
// ...
// redirect
return reply.redirect(data.redirectUrlDirectory);
}
return reply(Boom.preconditionFailed(`Did not reply with correct payload! json:'${JSON.stringify(response)}'`));
}).catch((err) => {
return reply(Boom.badData(`Could not notify on url ${data.notificationUrl} about the payment ${id}.\nError: "${err}"`));
});
I would use something like this.
This fist option asumes your service response always the header "application/json" and a the pay load simple text which I mock it like this.
var app = new express();
app.get('/valid', function(req, res){
res.json({ok: "ok"});
});
app.get('/invalid', function(req, res){
res.json("bad json body");
});
and the fetch json handling should looks like this. The other part of your code looks like good for me.
var response2 = res.clone();
return res.json().then((json) => {
// log your good payload
try {
// here we check json is not an object
return typeof json === 'object' ? json : JSON.parse(json);
} catch(error) {
// this drives you the Promise catch
throw error;
}
}).catch(function(error) {
return response2.text().then((txt) => `Response was not OK. Status code: ${response2.status} text: ${response2.statusText}.\nResponse: ${txt}`);
//this error will be capture by your last .catch()
});
xxx.clone() allows you to resolve multiple times the same response and create your own combinations like the previous one.