Change Fetch URL from event listener? - javascript

I'm trying to change a global variable from inside a click event listener. However the variable fails to change once button is clicked. The objective here is to change a URL for a fetch request.
// Default URL
var url = 'https://newsapi.org/v2/top-headlines?sources=bbc-news&Apikey123';
var req = new Request(url);
// Event Listener - Change URL
document.getElementById('btn').addEventListener('click', function() {
var url = 'https://newsapi.org/v2/top-headlines?sources=cnn&apiKey=Apikey123';
var req = new Request(url);
sendRequest();
})
// Fetch Data from API
function sendRequest() {
fetch(req)
.then(r => r.json())
.then(r => {
const container = document.getElementsByClassName('post-container')[0];
for(i = 0; i < 5 ; i++) {
// Create post elements
const post = document.createElement('div');
const postHeader = document.createElement('div');
const postBody = document.createElement('div');
// Set ID
post.id = 'post';
postHeader.id = 'post-header';
postBody.id = 'post-body';
// Append Elements
container.appendChild(post);
post.appendChild(postHeader);
post.appendChild(postBody);
// Post title data from array into div
let article = r.articles[i];
let title = article.title;
let content = article.description;
postHeader.innerHTML = title;
postBody.innerHTML = content;
}
console.log(container);
});
}
sendRequest();

To solve the problem:
...
document.getElementById('btn').addEventListener('click', function() {
var url = 'https://newsapi.org/v2/top-headlines?sources=cnn&apiKey=Apikey123';
// Don't use var, becouse it's variable have scope in current function
// var req = new Request(url);
req = new Request(url);
sendRequest();
})
...
But better send param to sendRequest:
...
// Event Listener - Change URL
document.getElementById('btn').addEventListener('click', function() {
var url = 'https://newsapi.org/v2/top-headlines?sources=cnn&apiKey=Apikey123';
var req = new Request(url);
sendRequest(req); // <--- set param
})
// Fetch Data from API
function sendRequest(req) { // <--- get param
...
});
...

Remove the var from inside the Event Listener
document.getElementById('btn').addEventListener('click', function()
{
url = 'https://newsapi.org/v2/top-headlines?sources=cnn&apiKey=Apikey123';
var req = new Request(url);
sendRequest();
})

The thing is you are declaring the var url twice , and var req twice
the first one at the begining of your code and the second one in your event listner ,
try this
var url = 'https://newsapi.org/v2/top-headlines?sources=bbc-news&Apikey123';
var req = new Request(url);
// Event Listener - Change URL
document.getElementById('btn').addEventListener('click', function() {
url = 'https://newsapi.org/v2/top-headlines?sources=cnn&apiKey=Apikey123';
req = new Request(url);
sendRequest();
})
// Fetch Data from API
function sendRequest() {
fetch(req)
.then(r => r.json())
.then(r => {
const container = document.getElementsByClassName('post-container')[0];
for(i = 0; i < 5 ; i++) {
// Create post elements
const post = document.createElement('div');
const postHeader = document.createElement('div');
const postBody = document.createElement('div');
// Set ID
post.id = 'post';
postHeader.id = 'post-header';
postBody.id = 'post-body';
// Append Elements
container.appendChild(post);
post.appendChild(postHeader);
post.appendChild(postBody);
// Post title data from array into div
let article = r.articles[i];
let title = article.title;
let content = article.description;
postHeader.innerHTML = title;
postBody.innerHTML = content;
}
console.log(container);
});
}
sendRequest();

Related

fetch image from URL Javascript

How I can make this
var imageurl = 'https://tr.wikipedia.org/wiki/'
let queryimage = `${imageurl}Dosya:${cityName}.jpg`
console.log(queryimage)
When ı look console ı see this ;
https://tr.wikipedia.org/wiki/Dosya:england.jpg
thats ok but now
How ı can download image on this page https://tr.wikipedia.org/wiki/Dosya:england.jpg
This is your way :
// Your url must be like this : 'https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/England.jpg/800px-England.jpg'
let cityName = 'England';
let imageurl = 'https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/'
let queryimage = `${imageurl}${cityName}.jpg/800px-${cityName}.jpg`
let img = document.getElementById('image');
img.setAttribute('src',queryimage)
You can use MediaWiki's Action API to retrieve information about the images in these pages and grab the source of this image.
async function grabImageInfo(pageTitle) {
const resp = await fetch(`https://tr.wikipedia.org/w/api.php?action=query&prop=pageimages&titles=${pageTitle}&piprop=original&format=json&origin=*`);
if (!resp.ok) {
throw new Error("Network Error");
}
return resp.json();
}
async function grabImageSource(pageTitle) {
const imageInfo = await grabImageInfo(pageTitle);
return Object.values(imageInfo.query.pages)[0].original.source;
}
const select = document.querySelector("select");
const img = document.querySelector("img");
const a = document.querySelector("a");
async function handleChange() {
try {
const pageTitle = `Dosya:${select.value}.jpg`;
const imgUrl = await grabImageSource(pageTitle);
img.src = imgUrl;
a.href = `https://tr.wikipedia.org/wiki/${pageTitle}`
}
catch(err) {
console.error(err);
}
}
select.onchange = handleChange;
handleChange();
<select>
<option>England</option>
<option>Italy</option>
<option>Germany</option>
<option>Flower</option>
<option>Cat</option>
</select><br>
<a>Go to Wikipedia's page</a><br>
<img>

add async await to fetch javascript

I'm new to async and await. I'm working on a recipe website using an api and fetch. need help to add async await to the fetch. I'm using spoonacular api.
there are no errors just want to add async await.
function retrieve(e) {
newsList.innerHTML = "";
e.preventDefault();
const apiKey = "my api key";
let topic = input.value;
let url = `https://api.spoonacular.com/recipes/complexSearch?query=${topic}&apiKey=${apiKey}&cuisine=&fillIngredients=false&addRecipeInformation=true&maxReadyTime=120&ignorePantry=flase&number=20&intolerances=gluten&sourceUrl=http://www.foodista.com`;
fetch(url)
.then((res) => {
return res.json();
})
.then((data) => {
console.log(data);
data.results.forEach((results) => {
let li = document.createElement("li");
let a = document.createElement("a");
let div = document.createElement("div");
let img = document.createElement("img");
let btn = document.createElement("button");
// styling
div.className = "newsdiv";
img.className = "newsimg";
btn.className = "btns";
li.style.width = "300px";
a.setAttribute("href", results.sourceUrl);
a.setAttribute("target", "_blank");
img.setAttribute("src", results.image);
div.textContent = results.title;
// btn.prepend(br);
div.appendChild(a);
div.prepend(img);
li.prepend(div);
btn.textContent = "Get Recipe";
div.appendChild(btn);
a.appendChild(btn);
newsList.appendChild(li);
});
})
.catch((error) => {
console.log(error);
});
}
Look at below snippet. This will be useful to your solution. In the function you may do whatever operations you want.
const retrieve = async (e) => {
newsList.innerHTML = "";
e.preventDefault();
const apiKey = "my api key";
let topic = input.value;
let url = `https://api.spoonacular.com/recipes/complexSearch?query=${topic}&apiKey=${apiKey}&cuisine=&fillIngredients=false&addRecipeInformation=true&maxReadyTime=120&ignorePantry=flase&number=20&intolerances=gluten&sourceUrl=http://www.foodista.com`;
const response = await fetch(url);
const myJson = await response.json(); //extract JSON from the http response
console.log(myjson);
}
retrieve(null);

How fetch data from Django REST in JavaScript

Im totaly new in Javascript so help me figure out
I have simple Rest with data:
[
{
"id": 1,
"content": "Hello Tweet"
}
]
Im trying to get this info in my <script>
<script>
const tweetsElement = document.getElementById('tweets')
const xhr = new XMLHttpRequest();
const method = 'GET'
const url = '/tweets'
const responseType ='json'
xhr.responseType = responseType
xhr.open(method,url)
xhr.onload = function(){
const serverResponse = xhr.response
const listedItems = serverResponse.response
console.log(listedItems)
var finalTweetStr = ""
var i;
for(i=0;i<listedItems.length;i++){
console.log(i)
console.log(listedItems[i])
var currentItem = "<div class='mb-4'><h1>"+listedItems[i].id + "</h1>"+"<p>"+ listedItems[i].content+"</p></div>"
finalTweetStr += currentItem
}
tweetsElement.innerHTML = finalTweetStr;
}
xhr.send();
</script>
But it doesnt work , where is the problem?
Your main issue appears to be here:
const serverResponse = xhr.response
const listedItems = serverResponse.response
Change it to:
const listedItems = xhr.response
and you can remove the redundant serverResponse variable.

AWS IOT GetThingShadow API request sends response "Signature expired"

const https = require('https');
const crypto = require('crypto');
const utf8 = require('utf8');
const awsIoT = require('aws-iot-device-sdk');
const {AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY} = require('../../config');
const endpointFile = require('../../endpoint.json');
function sign(key, msg){
// since we are deriving key, refer getSignatureKey function
// we use binary format hash => digest() and not digest('hex')
return crypto.createHmac("sha256", key).update(utf8.encode(msg)).digest();
}
function getSignatureKey(key, date, region, service){
// deriving the key as follows:
// HMAC(HMAC(HMAC(HMAC("AWS4" + kSecret,"20150830"),"us-east-1"),"iam"),"aws4_request")
let kDate = sign(utf8.encode(`AWS4${key}`), date);
let kRegion = sign(kDate, region);
let kService = sign(kRegion, service);
let kSigning = sign(kService, 'aws4_request');
return kSigning;
}
function getTime(){
let timeObj = new Date().toISOString();
let arr = timeObj.split(':');
let len = arr[0].length;
let hh = arr[0].slice(len-2,len);
let mm = arr[1];
let ss = arr[2].slice(0,2);
return `${hh}${mm}${ss}`;
}
function getDate(){
let timeObj = new Date().toISOString();
let arr = timeObj.split('-');
let year = arr[0];
let month = arr[1];
let day = arr[2].slice(0,2);
return `${year}${month}${day}`;
}
const ENDPOINT = endpointFile.endpointAddress;
const THING_NAME = __dirname.split('/').pop();
const URI = `https://${ENDPOINT}/things/${THING_NAME}/shadow`;
console.log(URI);
// access key = access key ID + secret access key
// SigV4
// Signing Key derived from credential scope
// Step1
// Create a canonical request (CR)
// CanonicalRequest =
// HTTPRequestMethod + '\n' +
// CanonicalURI + '\n' +
// CanonicalQueryString + '\n' +
// CanonicalHeaders + '\n' +
// SignedHeaders + '\n' +
// HexEncode(Hash(RequestPayload))
const CONTENT_TYPE = "application/json; charset=utf-8";
const HTTP_REQUEST_METHOD = "GET";
// remove the protocol part from URI and query parameters (none in this case)
const CANONICAL_URI = URI.slice(URI.indexOf('/')+2, URI.length);
// console.log(`CANONICAL_URI: ${CANONICAL_URI}`);
const CANONICAL_QUERY_STRING = "";
const HOST = `${ENDPOINT}`;
const DATE = getDate();
const TIME = getTime();
const X_AMZ_DATE = `${DATE}T${TIME}Z`;
console.log(`X_AMZ_DATE: ${X_AMZ_DATE}`);
// note the trailing \n is present
const CANONICAL_HEADER = `content-type:${CONTENT_TYPE}\n`+
`host:${HOST}\n`+
`x-amz-date:${X_AMZ_DATE}\n`;
const SIGNED_HEADER = "content-type;host;x-amz-date";
// payload is the contents of request body
const PAYLOAD = "";
const PAYLOAD_HEX_HASH_ENCODED = crypto.createHash("sha256").update(utf8.encode(PAYLOAD)).digest("hex");
// string for signing CR_STRING = canonical request + metadata
const CANONICAL_REQUEST = `${HTTP_REQUEST_METHOD}\n`+
`${CANONICAL_URI}\n`+
`${CANONICAL_QUERY_STRING}\n`+
`${CANONICAL_HEADER}\n`+
`${SIGNED_HEADER}\n`+
`${PAYLOAD_HEX_HASH_ENCODED}`;
// Step2
// signing key STR_TO_SIGN
const HASH_ALGO = "AWS4-HMAC-SHA256";
const REGION = "us-east-2";
const SERVICE = "iot";
const CREDENTIAL_SCOPE = `${DATE}/`+
`${REGION}/`+
`${SERVICE}/`+
`aws4_request`;
const STRING_TO_SIGN = `${HASH_ALGO}\n`+
`${X_AMZ_DATE}\n`+
`${CREDENTIAL_SCOPE}\n`+
crypto.createHash("sha256")
.update(CANONICAL_REQUEST)
.digest("hex");
// Step3
const SECRET_KEY = AWS_SECRET_ACCESS_KEY;
const SIGNING_KEY = getSignatureKey(SECRET_KEY, DATE, REGION, SERVICE);
const SIGNATURE = crypto.createHmac("sha256", SIGNING_KEY).update(utf8.encode(STRING_TO_SIGN)).digest("hex");
// Step4
// Add SIGNATURE to HTTP request in a header or as a query string parameter
const ACCESS_KEY_ID = AWS_ACCESS_KEY_ID;
const AUTHORIZATION_HEADER = `${HASH_ALGO}`+
` Credential=`+
`${ACCESS_KEY_ID}`+
`/`+
`${CREDENTIAL_SCOPE}`+
`, SignedHeaders=`+
`${SIGNED_HEADER}`+
`, Signature=`+
`${SIGNATURE}`;
const HEADERS = {
'host':HOST,
'content-type':CONTENT_TYPE,
'Authorization':AUTHORIZATION_HEADER,
'x-amz-date':X_AMZ_DATE
};
const OPTIONS = {
hostname: HOST,
path: `/things/${THING_NAME}/shadow`,
headers: HEADERS
};
// send request
https.get(OPTIONS, res=>{
res.setEncoding("utf-8");
let body = "";
res.on("data", data=>{
body += data;
});
res.on("end", ()=>{
body = JSON.parse(body);
console.log(body);
});
});
On running this code the typical response I'm getting is
{ message: 'Signature expired: 20201017T000000Z is now earlier than 20201017T073249Z (20201017T073749Z - 5 min.)', traceId: 'b8f04573-2afd-d26a-5f2a-a13dd2dade3' }
I don't know what is going wrong or what to do to remove this error.
The ISO format is used here with this structure YYYYMMDDTHHMMSSZ
Signature expired: YYYYMMDDT000000Z is now earlier than YYYYMMDDT073249Z (YYYYMMDDT073749Z - 5 min.)
Why is HHMMSS always zero in the reported message?
What I'm trying to do is get "thing" shadow document by sending a request to the API referring to this (AWS_IOT_GetThingShadow API)
However, for authenticating my request I have to do a lot of other stuff which is stated here Signing AWS requests. I have simply performed the 4 tasks / steps mentioned in order to sign the request.
They have provided an example script (sigv4-signed-request-examples) in python which I followed to write my code.
I have been stuck on this for quite a while now. If anyone has any idea about this please help.
EDIT: The above problem was solved by using X_AMZ_DATE in STRING_TO_SIGN and HEADERS. I was wrongly using DATE. I have updated the above code accordingly.
New error I am gettiing is
{ message: 'Credential should be scoped to correct service. ', traceId: 'e711927a-11f4-ae75-c4fe-8cdc5a120c0d' }
I am not sure what is wrong with the credentials. I have set the REGION correctly. I am using SERVICE as iot which should be correct as well for requesting shadow API.
EDIT: It turns out iot is wrong. Changed SERVICE = "iotdata" and now I can successfully request shadow data. Solution found here. It is strange that I couldn't find it anywhere in the AWS docs. Another thing wrong was CANONICAL_URI = path in URI after domain and before query strings
So in my case it will be CANONICAL_URI = /things/${THING_NAME}/shadow
I am posting the correct final version of my code in case anyone is facing similar issue.
Three things were wrong in my original code.
X_AMZ_DATE (YYYYMMDDTHHMMSSZ) didn't use it in HEADERS and STRING_TO_SIGN. Hence, was getting Signature expired error.
SERVICE I thought would be iot but it is iotdata. Credential should be scoped to correct service error was resolved.
CANONICAL_URI should only contain part after the domain and before query parameters. Eg. If request URI is https://foo.bar.baz.com/foo1/foo2/foo3?bar1=baz1&bar2=baz2 then CANONICAL_URI = "/foo1/foo2/foo3"
const https = require('https');
const crypto = require('crypto');
const utf8 = require('utf8');
const {AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY} = require('../../config');
const endpointFile = require('../../endpoint.json');
function sign(key, msg){
// since we are deriving key, refer getSignatureKey function
// we use binary format hash => digest() and not digest('hex')
return crypto.createHmac("sha256", key).update(utf8.encode(msg)).digest();
}
function getSignatureKey(key, date, region, service){
// deriving the key as follows:
// HMAC(HMAC(HMAC(HMAC("AWS4" + kSecret,"20150830"),"us-east-1"),"iam"),"aws4_request")
let kDate = sign(utf8.encode(`AWS4${key}`), date);
let kRegion = sign(kDate, region);
let kService = sign(kRegion, service);
let kSigning = sign(kService, 'aws4_request');
return kSigning;
}
function getTime(){
let timeObj = new Date().toISOString();
let arr = timeObj.split(':');
let len = arr[0].length;
let hh = arr[0].slice(len-2,len);
let mm = arr[1];
let ss = arr[2].slice(0,2);
return `${hh}${mm}${ss}`;
}
function getDate(){
let timeObj = new Date().toISOString();
let arr = timeObj.split('-');
let year = arr[0];
let month = arr[1];
let day = arr[2].slice(0,2);
return `${year}${month}${day}`;
}
const ENDPOINT = endpointFile.endpointAddress;
const THING_NAME = __dirname.split('/').pop();
const URI = `https://${ENDPOINT}/things/${THING_NAME}/shadow`;
console.log(URI);
// access key = access key ID + secret access key
// SigV4
// Signing Key derived from credential scope
// Step1
// Create a canonical request (CR)
// CanonicalRequest =
// HTTPRequestMethod + '\n' +
// CanonicalURI + '\n' +
// CanonicalQueryString + '\n' +
// CanonicalHeaders + '\n' +
// SignedHeaders + '\n' +
// HexEncode(Hash(RequestPayload))
const CONTENT_TYPE = "application/json; charset=utf-8";
const HTTP_REQUEST_METHOD = "GET";
const CANONICAL_URI = `/things/${THING_NAME}/shadow`;
const CANONICAL_QUERY_STRING = "";
const HOST = `${ENDPOINT}`;
const DATE = getDate();
const TIME = getTime();
const X_AMZ_DATE = `${DATE}T${TIME}Z`;
// note the trailing \n is present
const CANONICAL_HEADER = `content-type:${CONTENT_TYPE}\n`+
`host:${HOST}\n`+
`x-amz-date:${X_AMZ_DATE}\n`;
const SIGNED_HEADER = "content-type;host;x-amz-date";
// payload is the contents of request body
const PAYLOAD = "";
const PAYLOAD_HEX_HASH_ENCODED = crypto.createHash("sha256").update(utf8.encode(PAYLOAD)).digest("hex");
// console.log(`Payload: ${PAYLOAD_HEX_HASH_ENCODED}`);
// string for signing CR_STRING = canonical request + metadata
const CANONICAL_REQUEST = `${HTTP_REQUEST_METHOD}\n`+
`${CANONICAL_URI}\n`+
`${CANONICAL_QUERY_STRING}\n`+
`${CANONICAL_HEADER}\n`+
`${SIGNED_HEADER}\n`+
`${PAYLOAD_HEX_HASH_ENCODED}`;
// Step2
// signing key STR_TO_SIGN
const HASH_ALGO = "AWS4-HMAC-SHA256";
const REGION = "us-east-2";
const SERVICE = "iotdata";
const CREDENTIAL_SCOPE = `${DATE}/`+
`${REGION}/`+
`${SERVICE}/`+
`aws4_request`;
const STRING_TO_SIGN = `${HASH_ALGO}\n`+
`${X_AMZ_DATE}\n`+
`${CREDENTIAL_SCOPE}\n`+
crypto.createHash("sha256")
.update(CANONICAL_REQUEST)
.digest("hex");
// Step3
const SECRET_KEY = AWS_SECRET_ACCESS_KEY;
const SIGNING_KEY = getSignatureKey(SECRET_KEY, DATE, REGION, SERVICE);
const SIGNATURE = crypto.createHmac("sha256", SIGNING_KEY).update(utf8.encode(STRING_TO_SIGN)).digest("hex");
// Step4
// Add SIGNATURE to HTTP request in a header or as a query string parameter
const ACCESS_KEY_ID = AWS_ACCESS_KEY_ID;
const AUTHORIZATION_HEADER = `${HASH_ALGO}`+
` Credential=`+
`${ACCESS_KEY_ID}`+
`/`+
`${CREDENTIAL_SCOPE}`+
`, SignedHeaders=`+
`${SIGNED_HEADER}`+
`, Signature=`+
`${SIGNATURE}`;
const HEADERS = {
'host':HOST,
'content-type':CONTENT_TYPE,
'Authorization':AUTHORIZATION_HEADER,
'x-amz-date':X_AMZ_DATE
};
const OPTIONS = {
hostname: HOST,
path: `/things/${THING_NAME}/shadow`,
headers: HEADERS
};
https.get(OPTIONS, res=>{
res.setEncoding("utf-8");
let body = "";
res.on("data", data=>{
body += data;
});
res.on("end", ()=>{
body = JSON.parse(body);
console.log(body);
});
});

How to write a callback for FileReader?

I'm trying to upload multiple attachments.
First I'm getting attachments from user interface, then I'm converting them into JSON , then I need to make a server call.
In this I'm using FileReader.
//showing ajax loader
component.set("v.showLoadingSpinner", true);
//getting attached files
var files = component.find("fileId").get("v.files");
var details = {}; //JS Object need to send server
details.files = [];
for (var i = 0; i < files.length; i++)
{
(function(file) {
var name = file.name;
var reader = new FileReader();
reader.fName = files[i]['name'];
reader.fType = files[i]['type'];
reader.i = i;
reader.onload = function(e) {
var fileContents = reader.result;
var base64 = 'base64,';
var dataStart = fileContents.indexOf(base64) + base64.length;
fileContents = fileContents.substring(dataStart);
var startPosition = 0;
var endPosition = Math.min(fileContents.length, startPosition + 750000);
var getchunk = fileContents.substring(startPosition, endPosition);
var fDetails = {};
fDetails.fileName = reader.fName;
fDetails.base64Data = encodeURIComponent(getchunk);
fDetails.contentType = reader.fType;
details.files.push(fDetails);
}
reader.readAsDataURL(file);
})(files[i]);
// I want to make a server call here with data in "details" object.
console.log(details);
But I'm not getting data in above console log.
Please help me to achieve this.
You can use promises :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://davidwalsh.name/promises
https://developers.google.com/web/fundamentals/primers/promises
Also jQuery provide $.when() function :
https://api.jquery.com/jquery.when/
And with promisejs you can do something like this :
function readJSON(filename){
return new Promise(function (fulfill, reject){
readFile(filename, 'utf8').done(function (res){
try {
fulfill(JSON.parse(res));
} catch (ex) {
reject(ex);
}
}, reject);
});
}

Categories