I am new to APIs and I want to add the USDA Nutrients database api to my website. I want the user to be able to search for the food,select one of the appeared results and see its' nutrition information.
How can I do this in plain JS? I've created a search bar in my website and JS takes the input and requests the data from the USDA api.
var apiKey = '';
var q = "eggs";
var url = "http://api.nal.usda.gov/ndb/search/?format=json&q=" + q + "&sort=n" + "&max=25" + "&offset=0" + "&api_key=" + apiKey;
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
var data = JSON.parse(this.responseText);
document.querySelector("#usdaResults").innerHTML = data.body;
}
};
xhr.send();
I want first to present to the user a list of the results of what they searched. Then after they click the food, I want to present its' nutritional information(protein etc).
EDIT: When a user searches a food, I want to display the "group" , "name"and "manu" of all available results. At the same time,when a user wants to see the nutrition information for a specific food of those listed, I want to get its' "ndbno" number and look into the USDA database for it so I can display the data after. Same way as displayed in the official website: https://ndb.nal.usda.gov/ndb/search/list?SYNCHRONIZER_TOKEN=c91f87b5-59c8-47e0-b7dc-65b3c067b7ff&SYNCHRONIZER_URI=%2Fndb%2Fsearch%2Flist&qt=&qlookup=egg+potato&ds=&manu=
EDIT2: I'm getting this error now.
var apiKey = '';
var q = document.getElementById('search').value;
var url = "http://api.nal.usda.gov/ndb/search/?format=json&q=" + q + "&sort=n" + "&max=25" + "&offset=0" + "&api_key=" + apiKey;
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
function getData() {
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText)
var data = JSON.parse(this.responseText);
if (data && data.list && data.list.item) {
var html = "";
data.list.item.map(item => {
let string = "<p>Name: " + item.name + " Manu: " + item.manu + " Group: " + item.group + "<p>";
html += string;
})
}
document.querySelector("#usdaResults").innerHTML = html;
}
else {
console.log("Error", xhr.statusText);
}
}
xhr.send();
}
HTML:
<section class="usda">
<h1>USDA Nutrients Database</h1>
<form id="search">
<input type="text" placeholder="Search.." name="search">
<button type="button" onclick="getData();">Search</button>
</form>
<div id="usdaResults"></div>
</section>
So, it may be that there are errors with your XHR call - however we can catch and log those errors. You want to open your developer tools in your browser (usually right click > developer tools) to look at the JS logs.
I'm getting: VM131:20 GET http://api.nal.usda.gov/ndb/search/?format=json&q=eggs&sort=n&max=25&offset=0&api_key= 403 (Forbidden)
But that's because I have no API Key. If you do not, you'll need to get an API key from them.
I have grabbed some code from another SO post, here:
var apiKey = '';
var q = "eggs";
var url = "http://api.nal.usda.gov/ndb/search/?format=json&q=" + q + "&sort=n" + "&max=25" + "&offset=0" + "&api_key=" + apiKey;
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function (oEvent) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log(xhr.responseText)
} else {
console.log("Error", xhr.statusText);
}
}
};
xhr.send();
Reference:
XMLHttpRequest (Ajax) Error
EDIT:
For the response, once you have parsed the JSON - you can get all the available name, group and manu of the data as so - I've output the details in tags, and this is untested - so maybe incorrect, but this is more for pseudo code.
var data = JSON.parse(this.responseText);
//Assuming data is valid!
if (data && data.list && data.list.item) {
var html = "";
data.list.item.map(item => {
let string = "<p>Name: " + item.name + " Manu: " + item.manu + " Group: " + item.group + "<p>";
html += string;
})
}
document.querySelector("#usdaResults").innerHTML = html;
Related
I cannot seem to console.log each HTTP POST request's responseText when batching my HTTP POST's using a for loop.
As briefly as I can possibly explain. I am using the for loop to take individual user information and batch users in groups of 99. Once that criteria is met, I build the POST request in JSON, and send it. Then repeat in batches of 99 until all users have been accounted for.
My issue is that I am ONLY getting responseText from the last batch, that is, from the last POST request made. I have tried a number of things, including adding/appending the responseText to a global variable (E.g. var responseString ="";, but am still ONLY getting the last POST's response information...
I'd like to get each batch's responseText and am happy to have them logged individually, or all in the same string... I just need access to this information, in some way. Any help would be appreciated. Here is the code i have going right now:
var responseString = "";
function sendPushNotification(tokens) {
var pageSelecterRadioButton = document.querySelector(
'input[name="page_selecter"]:checked'
);
var pageSelected = pageSelecterRadioButton.value;
var listComplete = tokens.length;
var batchCounter = 0;
var batchMaker = 0;
var batchRecipients;
var batchNumber = 0;
var recipientsProcessed = 0;
for (batchMaker = 0; batchMaker < 99; batchMaker++) {
batchRecipients =
tokens[recipientsProcessed] + `","` + batchRecipients;
console.log(
"Building Batch #" + (batchNumber + 1));
batchCounter++;
recipientsProcessed++;
if (batchCounter == 99 || listComplete == recipientsProcessed) {
// console.log(`"` + batchRecipients.slice(0, -11));
batchNumber++;
var subjectLineRaw = document.getElementById("subject").value;
var messageBodyRaw = document.getElementById("body").value;
const subjectLine = subjectLineRaw.replace(/(\r\n|\n|\r)/gm, " ").replace(/ "/gm, ' “').replace(/" /gm, '” ').replace(/^"/gm, "“")
.replace(/"$/gm, "”");
const messageBody = messageBodyRaw.replace(/(\r\n|\n|\r)/gm, " ").replace(/ "/gm, ' “').replace(/" /gm, '” ').replace(/^"/gm, "“")
.replace(/"$/gm, "”");;
var data =
`{
"to": ["` +
batchRecipients.slice(0, -11) +
`],
"title": "` +
subjectLine +
`",
"body": "` +
messageBody +
`",
"sound": "default",
"data": {"event": "` +
pageSelected +
`"}
}`;
var xhr = new XMLHttpRequest();
var url =
"https://api_server_for_sending_push_notifications.com";
xhr.open("POST", url);
xhr.setRequestHeader("accept", "application/json");
xhr.setRequestHeader("content-type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status == 200 ) {
responseString += xhr.responseText;
}
};
console.log(data);
console.log(xhr);
xhr.send(data);
console.log(
"Push Notification POST batch #" + batchNumber + "complete!"
);
batchCounter = 2;
batchMaker = 0;
var batchRecipients = " ";
}
if (listComplete + 1 == recipientsProcessed) {
console.log("Awaiting Server Response...");
setTimeout(function () {
btn.classList.remove("button--loading");
}, 3000);
setTimeout(function () {
alert(recipientsProcessed - 1 + " Push Notifications Sent!");
console.log("Complete! Here is the Server Response...");
}, 3500);
submitButton.disabled = false;
console.log(responseString);
break;
}
}
}
I'm trying to write an function that collects information from a contact form, makes a XMLHttpRequest to postmail.invotes.com/send, which forwards an email. The weird thing is, this code works in Firefox but it doesn't work in Chrome.
In the Network tab, the send request is (failed) with net::ERR_CERT_DATE_INVALID ; is that something I can fix, or the postmail.invotes.com website needs to fix?
function js_send() { // User has clicked send email button.
let request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
js_onSuccess(); //Return sent message alert.
} else
if(request.readyState == 4) {
js_onError(request.response); //Return failed message alert.
}
};
let fname = document.querySelector("#" + form_id_js + " [name='fname']").value;
let reply_to = document.querySelector("#" + form_id_js + " [name='reply_to']").value;
let subject = document.querySelector("#" + form_id_js + " [name='subject']").value;
let text = document.querySelector("#" + form_id_js + " [name='text']").value;
if (fname && reply_to && subject && text) { // Only try to send a message if user has entered all 4 values.
data_js['subject'] = `You have a new message from your Portfolio: ${subject}`;
data_js['text'] = `You have a new message from your Portfolio! \n\n Subject: ${subject} \n Email: ${reply_to} \n Text: ${text} \n Sender: ${fname}`;
let params = toParams(data_js);
request.open("POST", "https://postmail.invotes.com/send", true);
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.send(params);
} else { // User has not entered all 4 values.
alertMessage.innerHTML = "Please fill out form completely.";
}
}
I am writing a small Cordova (PhoneGap) app. that is sending an image from a file input - using a post method. It works fine in my Android device, but fails in both broswer and Ripple emulator. Here is the code:
function queryImageByData(dataURL) {
var imgType = dataURL.substring(5, dataURL.indexOf(";"));
var imgExt = imgType.split("/")[1];
var imgData = atob(dataURL.substring(dataURL.indexOf(",") + 1));
var filenameTimestamp = (new Date().getTime());
var separator = "----------12345-multipart-boundary-" + filenameTimestamp;
var formData = "--" + separator + "\r\n" +
"Content-Disposition: file; name=\"file\"; filename=\"snapshot_" + filenameTimestamp + "." + imgExt + "\"\r\n" +
"Content-Type: " + imgType + "\r\nContent-Transfer-Encoding: base64" + "\r\n\r\n" + imgData + "\r\n--" + separator + "\r\n";
var xhr = new XMLHttpRequest();
xhr.sendAsBinary = function (data) {
var arrb = new ArrayBuffer(data.length);
var ui8a = new Uint8Array(arrb, 0);
for (var i = 0; i < data.length; i++) {
ui8a[i] = (data.charCodeAt(i) & 0xff);
}
var blob = new Blob([arrb]);
this.send(blob);
};
xhr.open("POST", "https:/my_endpoint_here", true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
parseResult(xhr.responseText);
}
else {
onFailedResponse(xhr.responseText);
}
}
};
xhr.setRequestHeader("Content-type", "multipart/form-data; boundary=" + separator);
xhr.sendAsBinary(formData);
}
The error I get is:
Error: MultipartParser.end(): stream ended unexpectedly: state = HEADER_FIELD_START
at MultipartParser.end
EDIT:
I have a problem also with a get method. It fails on Ripple/Browser but runs OK on the device. here is some sample code:
var url = document.getElementById("urlInput").value;
var query = "my_url_here";
var jqxhr = $.ajax(query)
.done(function (data) {
alert("success" + data);
})
.fail(function (data) {
alert("error" + data);
})
Well I found the core issue, which cross domain calls.
The browsers do not allow it, and apperently so does Ripple emulator,
but mobile devices do allow it.
Now I just need to figure out how to make it work using CORS.
I'm sending an xmlhttprequest to youtube to get some videos. I have gone to the google developer's console and set up an api key with WORK URL I'm requesting from connected to it. When I try to run the script from WORK URL, I get an 'ipreferrer not allowed' error, even though I specified that url on my api key.
But when I connect the api key to MY OWN PERSONAL URL and run the same script from that url, it works fine. So when it's run from WORK URL it must be sending the wrong referral url to youtube.
The question is, how can I tell what referral url my xmlhttprequest is telling youtube it is coming from?
My code is below:
function createCORSRequest(myurl, cb)
{
var xmlhttp;
if (window.XMLHttpRequest){
xmlhttp=new XMLHttpRequest();}
else{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
if( typeof cb === 'function' )
cb(xmlhttp.responseText);
}
}
xmlhttp.open("GET",myurl,true);
xmlhttp.send();
}
function buildVideoMenu()
{
openDiv = true;
mainVideoTarget = 'main_video';
playlistID = 'PLAg45-Ox3WR4gODmcAmIYHVvCpngXcCTZ';
menuDiv = 'video_menu_images';
thumbnailDiv = 'thumb';
APIKey = 'AIzaSy...';
url = 'https://www.googleapis.com/youtube/v3/playlistItems?' +
'&part=snippet' +
'&maxResults=25' +
'&playlistId=' + playlistID +
'&key=' + APIKey;
//alert(url);
createCORSRequest(url, function(srchJSON) //Get JSON for search
{
myDivHTML = '';
myDiv = document.getElementById("video_menu_images"); //get div in variable
console.log("YouTube returned the json code: " + srchJSON);
srchObj = JSON.parse(srchJSON); //parse JSON for playlistItems
for(i=0;i<srchObj.items.length;i++) //For items in srchObj.items:
{
console.log("item number " + i);
if(srchObj.items[i].snippet.thumbnails!=undefined)
{
if(openDiv)
{
myDivHTML += '<div id = "tnvertblock">';
}
myDivHTML += ' <div class = "' + thumbnailDiv + '">';
//console.log(srchObj.items[i].snippet.title);
vidFrameURL = 'https://www.youtube.com/embed/' + srchObj.items[i].snippet.resourceId.videoId;
//console.log("url = " + vidFrameURL);
imgUrl = srchObj.items[i].snippet.thumbnails.default.url; //get thumbnail image url
myDivHTML += ' <a href = "' + vidFrameURL + '" target = "' + mainVideoTarget +'">';
myDivHTML += ' <img width = "120" height = "90" class = "thumbnail" src = "' + imgUrl + '" />';
myDivHTML += ' </a>';// Put in the item.snippet.thumbnails.default.url (its own div)
myDivHTML += ' </div>'; //close thumbnail div
if(!openDiv)
{
myDivHTML += '</div>';
}
openDiv = !openDiv;
}
}
//alert(myDivHTML);
myDiv.innerHTML = myDivHTML;
});
}
buildVideoMenu();
UPDATE: To clarify my question, here's a screenshot of the console developer's page with an explanation:
Receiving http 403 response error when trying to get a
request token.
I've checked my base string's singing process, and that's proper. If
I use the default keys on the Twitter dev site, it generates the same
result as they list on the site, so i'm pretty sure that's okay.
Any insight would be much appreciated!
var reqURL = 'https://api.twitter.com/oauth/request_token';
var reqNonce = getNonce();
var reqTimeStamp = getTimeStamp();
var reqSignatureMethod = 'HMAC-SHA1';
var reqOauthVersion = '1.0';
var reqConsumerKey = 'ySBPkqxaRlheQKFwejMpqg';
var reqConsumerSecret = '______________&' // note the & at the end..
var reqCallback = 'http%3A%2F%2Flocalhost%3A3005%2Fthe_dance%2Fprocess_callback%3Fservice_provider_id%3D11'
var reqQuery = 'oauth_callback=' + reqCallback + '&oauth_consumer_key=' + reqConsumerKey + '&oauth_nonce=' + reqNonce + '&oauth_signature_method=' + reqSignatureMethod + '&oauth_timestamp=' + reqTimeStamp + '&oauth_version=' + reqOauthVersion;
var reqBaseString = 'POST&' + reqURL + '&' + encodeURIComponent(reqQuery);
var reqSignature = b64_hmac_sha1(reqConsumerSecret, reqBaseString);
var reqSignature = reqSignature + '=';
var request = new XMLHttpRequest();
request.onreadystatechange = function(data) {
if (request.readyState == 4) {
// Good response, got the xml file
if (request.status == 200) {
alert ('good response');
}
}
};
// alert (reqURL);
// alert (reqBaseString);
var oauthParams = encodeURIComponent("OAuth oauth_callback=\"" + reqCallback + "\",oauth_consumer_key=\"" + reqConsumerKey + "\",oauth_nonce=\"" + reqNonce + "\",oauth_signature_method=\"" + reqSignatureMethod + "\",oauth_timestamp=\"" + reqTimeStamp + "\",oauth_version=\"1.0\",oauth_signature=\"" + reqSignature + "\"");
request.open("POST", reqURL, true);
request.setRequestHeader("Accept", "text/plain, */*");
request.setRequestHeader("Connection", "Keep-Alive");
request.setRequestHeader("Authorization", oauthParams);
request.send();
What I have found to be immensely helpful is to just get the raw HTTP request that does work with the Netflix OAuth Test that cnauroth suggested and then compare it to what you are sending with this code snippet here. OAuth is tricky and not fun so if you can just diff the two requests you should be able to find some improper encoding or a misplaced &.