Read a JSON from AWS S3 Using JavaScript - javascript

I have this link to an AWS S3 bucket, which automatically downloads the JSON I need. Just to clarify, the JSON isn't displayed on the web page itself. I want to load the data into JavaScript from the link I currently have. I've tried using the following function below, but it hasn't worked. The URL is from AWS-transcribe.
function httpGetAsync(theUrl, callback)
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
callback(xmlHttp.responseText);
}
xmlHttp.open("GET", theUrl, true); // true for asynchronous
xmlHttp.send(null);
}
Does anyone know how to get a JavaScript object from this URL?

You can use the new ES6 fetch API to send a HTTP request and parse the stringified JSON response.
1. Using ES2017 async-await
const url = `https://s3.us-west-2.amazonaws.com/aws-transcribe-us-west-2-prod/165208660162/16/asrOutput.json?X-Amz-Security-Token=FQoDYXdzEBkaDNEU%2BEwhAVoss9PKYyK3A2qPjQJuSJOukAWY%2BTcHUY8vJoq9xQdb2%2FwEYalKy2uDvgEo03cgqeGAp%2Bjg7WGLNi4nr%2Bv5K2yOYMNG1WNmjbC8pWWArkrgGwCr8%2FXLZCxgziieoi1nV9BToNYEaSXI%2BpUR2w50o1T7a%2FY%2FQkL6hBO%2BIr3%2Fr9KYtWk%2BvC5dJryzW%2BxuHjXVv3SP%2F3SsYrqMuFLgqWct3Msvo37or4S7IxGDg6wcFzutLLQ2RrNXXa77oZJ3C%2BLn7t%2FTmthj3IJXT%2F8%2FlNEYMGc6WUG6aEqC%2F3iQmq6Pg6HDNRYQytIg0OelRhBJ7PzF0spwssUo2ZnuuRQKu%2B%2BuFbnp1Ne2B9PNDDIRRQF1bHKydwRiI%2BfIBH%2FRk3SnFH6dzppvdQjjOlZQzaVYsEE4aWJZ1UA%2FGtZlwID%2FU301m3XjdNebnH%2FgeCCrRKs1U51obmXyXeNP0veCXzgFexrf6JApN7bRrBOpWNp%2BlBXXeHI0YPa07zL62JerTwbLmSXzxbqbMSjso0t2LygCWhvsKXry5gig06%2FtyuLf%2Fxi0GRKKrDlpR2Kg%2BHGE%2B1cCbxFT3jPaIZPy1ktScZpxMw89g0kojO7W1wU%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20180511T164920Z&X-Amz-SignedHeaders=host&X-Amz-Expires=900&X-Amz-Credential=ASIAJHSTNMRIX5LPMVVQ%2F20180511%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Signature=586c9c3f4a1a755757e8cd20e77fa1318cf769fce71d3167a885b209d56e537f`;
async function downloadObject(url) {
try {
const fetchResponse = await fetch(url);
return await fetchResponse.json();
} catch (err) {
console.error('Error - ', err);
}
}
downloadObject(url);
2. Using chained then and catch blocks
const url = `https://s3.us-west-2.amazonaws.com/aws-transcribe-us-west-2-prod/165208660162/16/asrOutput.json?X-Amz-Security-Token=FQoDYXdzEBkaDNEU%2BEwhAVoss9PKYyK3A2qPjQJuSJOukAWY%2BTcHUY8vJoq9xQdb2%2FwEYalKy2uDvgEo03cgqeGAp%2Bjg7WGLNi4nr%2Bv5K2yOYMNG1WNmjbC8pWWArkrgGwCr8%2FXLZCxgziieoi1nV9BToNYEaSXI%2BpUR2w50o1T7a%2FY%2FQkL6hBO%2BIr3%2Fr9KYtWk%2BvC5dJryzW%2BxuHjXVv3SP%2F3SsYrqMuFLgqWct3Msvo37or4S7IxGDg6wcFzutLLQ2RrNXXa77oZJ3C%2BLn7t%2FTmthj3IJXT%2F8%2FlNEYMGc6WUG6aEqC%2F3iQmq6Pg6HDNRYQytIg0OelRhBJ7PzF0spwssUo2ZnuuRQKu%2B%2BuFbnp1Ne2B9PNDDIRRQF1bHKydwRiI%2BfIBH%2FRk3SnFH6dzppvdQjjOlZQzaVYsEE4aWJZ1UA%2FGtZlwID%2FU301m3XjdNebnH%2FgeCCrRKs1U51obmXyXeNP0veCXzgFexrf6JApN7bRrBOpWNp%2BlBXXeHI0YPa07zL62JerTwbLmSXzxbqbMSjso0t2LygCWhvsKXry5gig06%2FtyuLf%2Fxi0GRKKrDlpR2Kg%2BHGE%2B1cCbxFT3jPaIZPy1ktScZpxMw89g0kojO7W1wU%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20180511T164920Z&X-Amz-SignedHeaders=host&X-Amz-Expires=900&X-Amz-Credential=ASIAJHSTNMRIX5LPMVVQ%2F20180511%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Signature=586c9c3f4a1a755757e8cd20e77fa1318cf769fce71d3167a885b209d56e537f`;
const successCb = (resp) => {
console.log(resp);
};
const errorCb = (err) => {
console.error('Error - ', err);
};
function downloadObject(url, successCb, errorCb) {
fetch(url)
.then(response => response.json())
.then(successCb)
.catch(errorCb);
}
downloadObject(url, successCb, errorCb);

Related

How to return response from async function correctly & push it into another object

I have an Angular 11.x app that performs a http request to a backend system that reads data from a video file (e.g mp4/mov) using FFMPEG, due to the processing it takes 10 seconds to complete this async request.
I've hard coded some of the values for greater clarity
// video-component.ts
let fileUrl = 'https://abc.s3.eu-west-2.amazonaws.com/video.mp4';
let fileSize = '56117299';
this.videoMetadata = this.videoService.getVideoMediaData(fileUrl, fileSize);
// if any errors found from the async response loop through them and push them into the following error which displays this on the frontend
/* I need to push the errors from the request above into this `errorMessages` variable
self.errorMessages['Instagram'].push({
"message": "Video must be between 3-60 seconds in duration",
});
*/
// video.service.ts (downloads the file & gets metadata using FFMPEG in the endpoint)
public getMetadata(file: string, size: string): Observable<any> {
let params = new HttpParams();
params = params.append('file', file);
params = params.append('size', size);
return this.http.get('post/media-check', { params })
.pipe(map(response => {
return response;
}));
}
public getVideoMediaData(file, size) {
return new Promise((resolve, reject) => {
this.getMetadata(file, size).subscribe(
data => {
resolve(data);
},
errorResponse => {
}
);
});
}
The post/media-check in the getMetadata function hits an PHP endpoint and returns the following response similar to the following.
{
"status":"200",
"data":{
"video":{
"container":"mov",
"bitrate":338,
"stream":0,
"codec":"h264",
"fps":3
}
},
"errors":["Video must be at least 25 frames per second (fps)"],
"responseType":"json",
"response":"success"
}
How do I get the errors array from the backend response from the async request push directly into the self.errorMessages variable?
First you need to make sure that your video-service is handling errors properly.
public getVideoMediaData(file, size) {
return new Promise((resolve, reject) => {
this.getMetadata(file, size).subscribe(
data => {
resolve(data);
},
errorResponse => {
// Reject the Promise and pass the error response in the rejection
reject(errorResponse);
}
);
});
}
Then in your video-component you can handle this scenario like this:
let fileUrl = 'https://abc.s3.eu-west-2.amazonaws.com/video.mp4';
let fileSize = '56117299';
try {
this.videoMetadata = await this.videoService.getVideoMediaData(fileUrl, fileSize);
// happy path - do something with this.videoMetadata
} catch(e) {
// unhappy path - e = errorResponse
const messages = errorResponse.errors.map(message => ({ message }));
self.errorMessages['Instagram'].push(...messages);
}

Prevent a client from waiting indefinitely for server response

I have a scenario where a file is uploaded in the web application and is sent to a back end server to upload in storage. Till a response is received from the server a loading spinner is shown. In case the server is down after receiving the request, no response is received by the client and the web page still shows that the file upload is still in progress. Is there a way to check if the server is not responding and then show an error message to the user ?
export const upload = async (file) => {
let result = null;
try {
const formData = new FormData();
formData.append("file", file, file.name);
result = await API.post(
"/fileupload",
formData,
{}
);
if (result.status === 200) {
return result.data;
} else {
return "Upload file failed.";
}
} catch (ex) {
console.log("parsing failed", ex);
}
};
You can do this with a timeout. Ideally the library you're using allows you to set a timeout, but if not you can manually create a timeout using Promise.race
function timeout(ms) {
return new Promise(reject => setTimeout(() => reject(new Error('timeout'), ms));
}
export const upload = async (file) => {
let result = null;
try {
const formData = new FormData();
formData.append("file", file, file.name);
result = await Promise.race([
timeout(30000), // 30 seconds
API.post(
"/fileupload",
formData,
{}
),
]);
if (result.status === 200) {
return result.data;
} else {
return "Upload file failed.";
}
} catch (ex) {
if (ex.message === 'timeout') {
// timeout handling
}
console.log("parsing failed", ex);
}
};
Note that this can be pretty fragile and ideally you would use a library to handle uploads.
Ideally the timeout handling should be added at the API.post module level

Firebase Cloud Storage Error Loading Preview Uploaded Image

I uploaded an image using react-native-image-picker's base64 generated data. It shows up on Firebase console fine, but when I try to look at it on my browser, it says "Error Loading Preview" and when I click on it, it is just a black box. See screenshots below
Here is my code for the uploading:
const uploadImage = async ({data, filename, uri}) => {
const ext = uri.split('.').pop();
const name = uri.split('/').pop();
const path = `${user.uid}_${name}`;
const storageRef = firebase.storage().ref(`profiles/${path}`);
storageRef
.putString(data, 'base64', {contentType: `image/${ext}`})
.then(function (snapshot) {
console.log('SUCCESSSSS');
});
};
useEffect(() => {
ImagePicker.showImagePicker((response) => {
//console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
console.log(response.uri);
uploadImage(response);
setAvatar({uri: response.uri});
}
});
}, []);
Edit: I copied the base64 string into an online converter, looks good, it gave back the correct image. So there's nothing wrong with the data, it looks like. Something's wrong with how firebase is handling it.
Edit: I tried explicitly setting the type to image/jpeg instead of image/jpg as noted here: Proper way to show image when Firestorage is down or Error loading preview in Firestorage for iOS but no difference.
Looks like there's more than a few bugs involved with firebase's base64 putString method and react-native: see this thread: https://github.com/firebase/firebase-js-sdk/issues/576. I followed yonahforst's answer and ended up using a blob instead. Worked perfectly.
Copied here in case the thread goes away:
function urlToBlob(url) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.onerror = reject;
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
resolve(xhr.response);
}
};
xhr.open('GET', url);
xhr.responseType = 'blob'; // convert type
xhr.send();
})
}
Make sure to add the "data:image/jpeg;base64,9asdf92349..." if it's not there. I was using react-native-image-picker, so it didn't have that out of the box.
const dataURL = 'data:image/jpeg;base64,' + data;
urlToBlob(dataURL).then((blob) => {
storageRef
.put(blob)
.then(function (snapshot) {
const downloadURL = snapshot.ref.getDownloadURL().then((link) => {
console.log('link: ', link);
user.updateProfile({photoURL: link});
});
})
.then(() => console.log('SUCCESS'));
});

Receive and process JSON using fetch API in Javascript

In my Project when conditions are insufficient my Django app send JSON response with message.
I use for this JsonResponse() directive,
Code:
data = {
'is_taken_email': email
}
return JsonResponse(data)
Now I want using Javascript fetch API receive this JSON response and for example show alert.
I don't know how to use fetch API to do this. I want to write a listener who will be waiting for my JSON response from Django App.
I try:
function reqListener() {
var stack = JSON.parse(data);
console.log(stack);
}
var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
I want to compare JSON from my Django app with hardcoded JSON:
For example:
fetch( 'is_taken_email': email) - > then make something
OR
receive JSON from my Django app and as AJAX make it:
success: function(data) { if (data.is_taken_email) { make something; }
Thanks in advance!
A fetch API is provided in the global window scope in javascript, with the first argument being the URL of your API, it's Promise-based mechanism.
Simple Example
// url (required)
fetch('URL_OF_YOUR_API', {//options => (optional)
method: 'get' //Get / POST / ...
}).then(function(response) {
//response
}).catch(function(err) {
// Called if the server returns any errors
console.log("Error:"+err);
});
In your case, If you want to receive the JSON response
fetch('YOUR_URL')
.then(function(response){
// response is a json string
return response.json();// convert it to a pure JavaScript object
})
.then(function(data){
//Process Your data
if (data.is_taken_email)
alert(data);
})
.catch(function(err) {
console.log(err);
});
Example using listener based on XMLHttpRequest
function successListener() {
var data = JSON.parse(this.responseText);
alert("Name is: "+data[0].name);
}
function failureListener(err) {
console.log('Request failed', err);
}
var request = new XMLHttpRequest();
request.onload = successListener;
request.onerror = failureListener;
request.open('get', 'https://jsonplaceholder.typicode.com/users',true);
request.send();
Example of Using Listener as setInterval (I'm not sure that you want to do something like this, it's just to share with you)
var listen = setInterval(function() {
fetch('https://jsonplaceholder.typicode.com/users')
.then(function(response) {
return response.json();
})
.then(function(data) {
if (data[0].name)
console.log(data[0].name);
})
.catch(function(err) {
console.log(err);
});
}, 2000);//2 second
I am not familier with Django, but I hope this could help you.

Redirect after posting form using XMLHttpRequest

Following scenario. I have a simple login-form for username and password.
Wher the user clicks the login-button the form is posted to the server which is checking the credentials. When they are okay, a redirect is made to the default landing-page.
For sending the form-data I have written the following:
static async postData<TResult>(options: { method: string, url: string, data?: any }): Promise<TResult> {
return new Promise<TResult>((resolve, reject) => {
try {
const xhr = new XMLHttpRequest();
xhr.onload = (): void => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
};
xhr.withCredentials = true;
xhr.open(options.method, options.url, true);
xhr.send(options.data);
} catch (e) {
console.error(e);
}
});
}
which is called like:
const response = await postData({ method: theForm.method, url: theForm.action, data: formData })
.then(response => {
console.log(response);
})
.catch(reason => {
console.error(reason);
});
In Chrome and Firefox the response has an responseURL-property which I could use for setting window.location.url = xhr.responseURL; to redirect the page. But this wont work in IE as the response-type is something completely other.
On the other hand I have the complete HTML (which is the content of the redirect aka the landing-page) in xhr.responseText but I have no idea how I can use this?
I tried to replace the page-content as described here But this is throwing a bunch of errors in Chrome and IE it's not working at all showing
SCRIPT70: Permission denied
Some additional notes. I am using TypeScript to write the client-code which is targeted to es6 and afterwards transpiled using babel-loader to es5 via webpack.
I think you need try next code:
location.href = 'http://www.example.com' or
location.assign("http://www.mozilla.org"); // or
location = "http://www.mozilla.org";

Categories

Resources