Why is node.js fetch giving a 'Bad Request' error? - node.js

I am getting a 400 error (bad request) from this POST:
siteData.myPost = async function (url, data) {
let options = {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(data)
}
try {
const response = await fetch(quilkinUrlBase() + url,options);
return response.json();
}
catch (error) {
qPopup.Alert("Error with web request: " + error);
}
};
(the fetch address computes to "http://localhost:1337/UpdateSiteVisits").
This can't, of course, convert 'response' to json because the response is a DOC containing the 400 error message.
in server.js I have the following callback definition for the URL specified in the fetch:
app.post("/UpdateSiteVisits", sites.updateVisits);
in the debugger, the code never reaches updateVisits().
I have a very similar construct with a GET:
app.get("/GetSitesForType/:type", sites.findByType);
which works fine, so I assume the problem is with the 'options' object (which the GET doesn't use). In the POST case the data is just an integer ID, and if I change the data format to plain text (instead of json), the post works fine.
If leave the format as json, and send an object, rather than a simple integer, the post also works fine. So it looks like the system just doesn't like converting a single integer to json.

I needed to send the integer as json, so instead of using the method like this:
siteData.myPost("UpdateSiteVisits", siteID)
I needed to use
siteData.myPost("UpdateSiteVisits", { siteId: siteID })
[ later ]
Please ignore my question and answer, I was just getting mixed up with types. Such is the result from me converting from strongly-typed C# to untyped javascript!

Related

How to change text encoding and pass it to axios?

The API host wants me to send euc-kr encoded parameters.
But I'm not sure how to do it.
My Node.Js doesn't seem to support euc-kr.
I succeeded in getting the text written in euc-kr through a module iconv-lite.
const eucKrBuffer = incov.encode("ㅎㅎㅎ", "euc-kr");
But this is a Buffer type.
I need to convert this to String type to use it as a parameter.
I called eucKrBuffer.toString(). However,
I'm not sure what this results in.
eucKrBuffer.toString() => ??? I am not sure what result actually is
So I just send it obviously it failed.
const result = await Axios.post(
url,
stringify({
Name: eucKrBuffer.toString()
}),
{
headers: {
"Content-Type":
"application/x-www-form-urlencoded; charset=euc-kr",
},
}
);

fetch returns empty body, json works, but plain text doesn't

I am trying to create a function which return the latest blocked domain from my pihole server.
I first created a JSON call, since the first call I needed was in JSON format, this is all working and I get the data needed.
However, the second function I need is to fetch plain text data and that one doesn't work, it simply returns an empty body [].
This is the function
socket.on("pihole_last", function() {
setInterval(function() {
let settings = {
method: "Get",
headers: {
"Accept": "text/html"
}
};
fetch('http://domain/admin/api.php?recentBlocked', settings)
.then(res => res.text())
.then((data) => {
console.log(data);
}).catch(error => {
return error;
});;
}, 1000)
});
The JSON function which works looks pretty much the same, the only real different is the header accept and the res.text() which should fetch the data in plain text?
The data returned from the URL is a plain text domain, no tags, no nothing.
According to this issue from the pi-hole GIT, you should provide some form of authentication. The question which you linked in your comment is 5 years old, at that time this was an unintended behaviour.
If I understand correctly the API description one way to authorize should be working with this url:
http://domain/admin/api.php?recentBlocked?auth=YOUR_TOKEN
The YOUR_TOKEN should be in:
Authorization & Token required (see WEBPASSWORD in /etc/pihole/setupVars.conf)

Pass image ArrayBuffer to Azure Face SDK detectWithStream()

I am trying to write a NodeJS app that grabs a image from private URL using Axios and passes it to the Azure Face SDK (documentation) to detect faces in the image and get attributes of those faces - in this case, emotions and head pose.
I have gotten a modified version of the quickstart example code here working, which makes a call to the detectWithUrl() method. However, the image that I have in my code is a ArrayBuffer, so I thought I would try calling detectWithStream() instead. The documentation for this method says it needs to be passed something of type msRest.HttpRequestBody - I found some documentation for this type, which looks like it wants to be a Blob, string, ArrayBuffer, or ArrayBufferView. The problem is, I don't really understand what those are or how I might get from a arraybuffer image to an HttpRequestBody of that type. I have worked with HTTP requests before, but I don't quite understand why one is being passed to this method, or how to make it.
const rqs = {
responseType: 'arraybuffer',
url: `${fileUrl}`,
method: 'GET',
headers: {
'Content-Type': `image/jpeg`,
'Cache-Control': 'no-cache'
},
httpsAgent: agent
};
axios.request(rqs)
.then((ret) => {
// ret.data is a ArrayBuffer type;
let detected_faces = client.face.detectWithStream(ret.data, {
returnFaceAttributes: ["Accessories", "Age", "Blur", "Emotion", "Exposure", "FacialHair", "Glasses", "Hair", "HeadPose", "Makeup", "Noise", "Occlusion", "Smile", "QualityForRecognition"],
detectionModel: "detection_01",
recognitionModel: "recognition_03"
})
.then(ok => {
console.log(ok);
console.log("face(s) detected from image.");
console.log("Face attributes for face(s):");
})
.catch(err => {
console.error(err.message);
});
console.log('ok');
resolve(ret.data);
})
.catch((err) => {
console.error('nok');
console.error(err.message);
reject(false)
});
And I had receive a message error Only absolute URLs are supported
Only absolute URLs are supported -
a. it may be due to passing relative URL to Axios in line 3, try checking the fileUrl.
b. check the face SDK is provided with the proper endpoint
relative URL - "./a/b"
absolute URL - "https://www.x.com/a/b"
how I might get from an array buffer image?
Array buffer is not needed. Looking at face SDK code Ref (hope this is right sdk), we just need streams.
we can get this by changing the responseType value to stream
responseType: 'arraybuffer', // current
responseType: 'stream', // updated - we can update it in rqs and reponse will be stream and you can pass res.data to detectWithStream function
-------------------------------------Hope the code works----------------------------------------
Recommendation:
You are creating a callback hell by using nested .then chains what is call back hell.
Try using async/await syntax to achieve the same functionality in a simplified way - Ref.
Regards,
Muhamed

AWS Lambda return both a base64 encoded data and a text string in body response

I am using an AWS Lambda implementation with Node.js to generate a PDF file. I have the following callback that returns the pdf in an encoded base64 result. This works great for me:
return callback(null, {
statusCode: 200,
body: new Buffer(data).toString('base64'),
isBase64Encoded: true,
headers: {
'Content-Type': 'text',
},
})
However, I would like to add further information with my response - not just the PDF bae64 encoded data, but some string type results that I can use further down my active application connected to this Lambda function. I'd like to return the base64 data and string data, something like this:
return callback(null, {
statusCode: 200,
body: JSON.stringify(
{
message: 'hello world',
report: new Buffer(data).toString('base64')
}
),
isBase64Encoded: true,
headers: {
'Content-Type': 'text',
},
})
But this is failing for me. How would I refactor the above to return both string data and base64 data? I'm also having to force the isBase64Encoded setting to true, which may clash with my new requirement to return both base64 and normal string data.
The Content-Type of your response is not text - since you are returning JSON, a application/json value would make more sense and might alleviate some of the issues you are having. It would be helpful if the post could be updated with some more relevant details of the errors you are encountering.
One other possible work-around would be to add the message (and any other string values) as HTTP headers on the base64 encoded response you already have working. Then your client can decode the HTTP response whose body contains the base64 encoded PDF and HTTP headers x-custom-message (or something similar) set to hello world.

Node.js - Why does my HTTP GET Request return a 404 when I know the data is there # the URL I am using

I'm still new enough with Node that HTTP requests trip me up. I have checked all the answers to similar questions but none seem to address my issue.
I have been dealt a hand in the Wild of having to go after JSON files in an API. I then parse those JSON files to separate them out into rows that populate a SQL database. The API has one JSON file with an ID of 'keys.json' that looks like this:
{
"keys":["5sM5YLnnNMN_1540338527220.json","5sM5YLnnNMN_1540389571029.json","6tN6ZMooONO_1540389269289.json"]
}
Each array element in the keys property holds the value of one of the JSON data files in the API.
I am having problems getting either type of file returned to me, but I figure if I can learn what is wrong with the way I am trying to get 'keys.json', I can leverage that knowledge to get the individual JSON data files represented in the keys array.
I am using the npm modules 'request' and 'request-promise-native' as follows:
const request = require('request');
const rp = require('request-promise-native');
My URL is constructed with the following elements, as follows (I have used the ... to keep my client anonymous, but other than that it is a direct copy:
let baseURL = 'http://localhost:3000/Users/doug5solas/sandbox/.../server/.quizzes/'; // this is the development value only
let keysID = 'keys.json';
Clearly the localhost aspect will have to go away when we deploy but I am just testing now.
Here is my HTTP call:
let options = {
method: 'GET',
uri: baseURL + keysID,
headers: {
'User-Agent': 'Request-Promise'
},
json: true // Automatically parses the JSON string in the response
};
rp(options)
.then(function (res) {
jsonKeysList = res.keys;
console.log('Fetched', jsonKeysList);
})
.catch(function (err) {
// API call failed
let errMessage = err.options.uri + ' ' + err.statusCode + ' Not Found';
console.log(errMessage);
return errMessage;
});
Here is my console output:
http://localhost:3000/Users/doug5solas/sandbox/.../server/.quizzes/keys.json 404 Not Found
It is clear to me that the .catch() clause is being taken and not the .then() clause. But I do not know why that is because the data is there at that spot. I know it is because I placed it there manually.
Thanks to #Kevin B for the tip regarding serving of static files. I revamped the logic using express.static and served the file using that capability and everything worked as expected.

Resources