JavaScript: No callback after invoking fetch - javascript

I did write a Javascript code to upload a file via API:
function submitForm(bucket, accessToken) {
console.log("Fetching the file...");
var input = document.getElementsByTagName('input')[0];
var name = input.files[0].name;
var uploadUrl = 'https://www.googleapis.com/upload/storage/v1/b/'+ bucket +'/o?uploadType=media&access_token=' + accessToken +'&name=' + name;
fetch(uploadUrl, {
method: 'POST',
body: input.files[0]
}).then(function(res) {
console.log('Something did happen!'); // <<----- Message never displayed!
});
}
However, I am not able to get the response body from the post request. The upload went well, but without a callback I cannot control the result in a deterministic way. How can I fix it, at least getting the HTTP Status Code?

Solved in a very stupid way, by adding:
event.preventDefault();
Source: What does status=canceled for a resource mean in Chrome Developer Tools?

fetch can generate an error and, if it does, that happens through the .catch.
Like this:
function submitForm(bucket, accessToken) {
console.log("Fetching the file...");
var name = 'testName';
var uploadUrl = 'https://www.googleapis.com/upload/storage/v1/b/'+ bucket +'/o?uploadType=media&access_tokenn=' + accessToken +'&name=' + name;
fetch(uploadUrl, {
method: 'POST',
body: 'body stuff'
}).then(function(res) {
console.log('Something did happen!'); // <<----- Message never displayed!
console.log(res);
}).catch(function(err) {
console.error('Got error:', err);
});
}
submitForm('12345', 'testing');

Related

How to send json data to client side from express nodejs

I have an application, where I need to send the form data through XMLHttpRequest. When I send that information over, I then need to validate the form, then send information back to the client based on if the form validates or not. I'm using nodejs with express.
My client side code is:
editor.save().then((output) => {
let formData = new FormData();
const xhr = new XMLHttpRequest();
formData.append('name', document.getElementById('inputProductName').value);
xhr.open('post', '/items/add', true);
xhr.send(formData);
}).catch((error) => {
console.error('Error: ' + error);
return;
}).finally(() => {
// This is where I need to retrieve the validation code and redirect accordingly.
if (success == false) {
window.location.href = '/items/add/failed';
} else {
window.location.href = '/items/add/success';
}
});
My server side code is this:
router.post('/add', (req, res) => {
let form = new formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
if (fields.name.length < 1) { // If the name is empty
res.status(200).json({
success: false,
message: 'Product name must be specified'
});
} else {
res.status(200).json({
success: true,
message: 'Product added successfully'
});
}
});
});
So if the the validation fails, then I want to be able to get the success and message variable through the client end if possible.
Have a look at using fetch API from MDN docs
fetch data via POST
await response
based on response.success act accordingly
Additionally,looking a the server-side code, it doesn't appear necessary that form encoding be used.
Suggest sending the data in json format and have the server check the request.body for the appropriate field to be populated.
pseudo code
editor.save().then(async (output) => {
let formData = new FormData();
formData.append('name', document.getElementById('inputProductName').value);
const response = await fetch(url, {
method: 'POST',
// ... additional form data here, looks like you can send JSON, no need for form encoding
}
if(response.success) {
window.location.href = '/items/add/success';
} else {
window.location.href = '/items/add/failed';
}
}).catch((error) => {
console.error('Error: ' + error);
return;
})
Note that the anonymous function () => {} is now async () => {} to allow await on the fetch call.
async / await

Google Drive API: 404 when accessing file someone else created

I'm trying to get the contents of a file located a shared drive in which I am a content manager. The scope I'm using is https://www.googleapis.com/auth/drive.file.
I get 404 errors when I try to access files that are created with my app (which I know is required for the drive.file scope), but by someone else. Everything works as it should when I try to access files created by me.
Here is my code:
function getJsonContent(fileId, accessToken) {
let url = "https://www.googleapis.com/drive/v3/files/" + fileId + "?alt=media&supportsAllDrives=true";
console.log("Sending JSON read request.");
return fetch(url, {
'headers': {'Authorization': "Bearer " + accessToken}
})
.then(response => {
if (response.ok) {
console.log("JSON read successful.");
return response.json();
}
else {
throw "JSON read unsuccessful.";
}
});
}
Here is my authorization code:
function handleAuth(onAccept, onDenial) {
let onSignInUpdate = function(isSignedIn) {
if (isSignedIn) {
onAccept();
} else {
onDenial();
}
}
gapi.load('client:auth2', function() {
gapi.client.init({
apiKey: API_KEY,
clientId: CLIENT_ID,
discoveryDocs: DISCOVERY_DOCS,
scope: SCOPES
})
.then(function() {
gapi.auth2.getAuthInstance().isSignedIn.listen(onSignInUpdate);
onSignInUpdate(gapi.auth2.getAuthInstance().isSignedIn.get()); //Initial update
})
.catch(err => {
console.error(err);
});
});
}
//In another module, specific to a webpage:
function onAccept() {
accessToken = gapi.auth.getToken().access_token;
getJsonContent(<ACTUALFILEID>, accessToken)
.catch(err => {
console.error(err);
});
}
function onDenial() {
console.log("Permission rejected; redirecting to index.html.");
location.replace("index.html");
}
window.onload = function() {
handleAuth(onAccept, onDenial);
};
This is the file creation code:
function makeJsonFile(parentId, fileName, accessToken) {
let url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id&keepRevisionForever=true&supportsAllDrives=true";
console.log("Sending JSON creation request.");
let file = new Blob([JSON.stringify([])], {'type': "application/json"}); //The object is an empty array initially
let metadata = {
'name': fileName,
'mimeType': "application/json",
'parents': [parentId],
}
let form = new FormData();
form.append("metadata", new Blob([JSON.stringify(metadata)], {type: "application/json"}));
form.append("file", file);
return fetch(url, { //Returns a promise that resolves with the id of the created file
'method': "POST",
'headers': {
'Authorization': "Bearer " + accessToken
},
'body': form
})
.then(response => {
if (response.ok) {
console.log("JSON created.")
return response.json();
}
else {
throw "JSON creation unsuccessful.";
}
})
.then(val => val.id);
}
Issue:
https://www.googleapis.com/auth/drive.file only gives you access to files that YOU have opened or created with the corresponding app. See this:
View and manage Google Drive files and folders that you have opened or created with this app.
In this case, it is irrelevant that the file is created on a shared drive. I'm thinking you will have to use a wider scope like https://www.googleapis.com/auth/drive, unfortunately.
Feature request:
Also, considering your situation, I think you might be interested in this Feature Request, regarding the possibility to restrict access to a specific folder. I think that could be very useful for you if it got implemented. I'd suggest you to star that issue, both to keep track of its development and to help prioritize its implemenation:
Drive Restrict access to folder when authorizing applications
Reference:
OAuth 2.0 Scopes for Google APIs > Drive API, v3
Authorizing requests with OAuth 2.0

http 401 error when providing an access token the outlook api

I am trying to create a folder for a user, and I have been unsuccessful with api call attempts. My code is able to receive the correct access token, so I believe the be bug would be in createFolderTestFunction below.
async function redirectToDashboard() {
console.log("redirect to dashboard");
// var response = await requestTokenSilent();
var response;
if (!response || !response.status == 200) {
response = await requestTokenPopup();
}
if (response.accessToken) {
console.log(response);
createFolderTest(response.accessToken);
// location.href = hostname;
} else {
console.log("Unable to acquire token");
}
}
function createFolderTest(accessToken) {
var options = {
method: "POST",
headers: {
Authorization: accessToken,
"Content-Type": "application/json"
},
mode: "cors",
body: JSON.stringify({
displayName: "#COOLMONDAY"
})
};
var graphEndpoint = "https://outlook.office.com/api/v2.0/me/Inbox/";
fetch(graphEndpoint, options)
.then(resp => {
console.log(resp);
})
.catch(err => {
console.log(err);
});
}
A recommendation would be to get this working in Graph Explorer first. As this eliminates any issues with language being used and access token permissions.
https://developer.microsoft.com/en-us/graph/graph-explorer/preview
The Microsoft Graph endpoint is actually https://graph.microsoft.com/ , you can use the outlook url but moving forward Graph is where we invest in documentation, sdks and tooling.
As per the documentation https://learn.microsoft.com/en-us/graph/api/user-post-mailfolders?view=graph-rest-1.0&tabs=http
You should be using, you're missing 'mailfolders'
POST /me/mailFolders
You could also use our JavaScript SDK which makes mistakes like these a little easier with intellisense and strongly typed objects.
const options = {
authProvider,
};
const client = Client.init(options);
const mailFolder = {
displayName: "displayName-value"
};
let res = await client.api('/me/mailFolders')
.post(mailFolder);
https://learn.microsoft.com/en-us/graph/api/user-post-mailfolders?view=graph-rest-1.0&tabs=javascript

React Native ios One signal Push notification playerid

I am trying to get playerid for Onesignal, while doing that it is working strangely.
onIds = async (device) => {
console.log("Device info: ", device.userId);
let playerid = device.userId;
AsyncStorage.setItem('playerid', playerid);
//this.setState({device_id: playerid})
alert(playerid);
}
the above code gives me this error, but in alert I am getting the player id. check the picture attached.
Please help me resolve this. Thanks in advance.
Like you, I tried a lot, but I could not at least not in the conventional ways, I chose to do the following, saving the ID in the BD directly from the function
async onIds(device) {
let uri = await AsyncStorage.getItem('uri');
let token = await AsyncStorage.getItem('token');
try {
let formData = new FormData();
formData.append(
'PNToken',
JSON.stringify({
PushNotificationsID: device.userId
})
);
await fetch(uri, {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
Authorization: 'Bearer ' + token
},
body: formData
});
} catch (e) {
console.warn(e);
}
}

Method being called before Promise is complete

I am attemting to add an item to a sharepoint list from an Apache Cordova application. It first prompts the user to login then it will make a HTTP Post to so the data entry.
I have the following code:
function saveToSharepoint(data) {
var authority = "https://login.microsoftonline.com/common/";
var authContext = new Microsoft.ADAL.AuthenticationContext(authority);
var authResult = authContext.acquireTokenAsync("https://my.sharepoint.com", "4be098f8-2184-4831-9ef7-3d17dbbef6a0", "http://localhost:4400/services/office365/redirectTarget.html")
.then(FormatAndUpload(authResult, data), errorCallback);
}
function FormatAndUpload(authResponse, data) {
var token = authResponse.accessToken;
var expiry = authResponse.expiresOn;
console.log("Token acquired: " + authResponse.accessToken);
console.log("Token will expire on: " + authResponse.expiresOn);
$.ajax({
url: "https://my.sharepoint.com/_api/web/lists/getbytitle('" + Test + "')/items",
type: "POST",
contentType: "application/json;odata=verbose",
data: JSON.stringify(data),
headers: {
"Accept": "application/json;odata=verbose",
"Authoriztion":"Bearer " + token
},
success: function (data) {
success(data);
},
error: function (data) {
failure(data);
}
});
}
The problem I am having is that the FormatAndUpload method is being called before acquireTokenAsync has completed, so the authResponse variable passed into the FormatAndUpload method is null.
I'm not too familiar with the promise framework in Javascript/JQuery but I was under the impression that the event should only fire on completion of the previous method.
Does anyone have any pointers in how I can correctly wait for the login to complete before attempting the POST?
what you did FormatAndUpload(authResult, data); is wrong the correct way to pass a callback is
.then(function(authResult){
FormatAndUpload(authResult, data);
}, errorCallback);
so your saveToSharepoint will be like this
function saveToSharepoint(data) {
var authority = "https://login.microsoftonline.com/common/";
var authContext = new Microsoft.ADAL.AuthenticationContext(authority);
var authResult = authContext.acquireTokenAsync("https://my.sharepoint.com", "4be098f8-2184-4831-9ef7-3d17dbbef6a0", "http://localhost:4400/services/office365/redirectTarget.html")
.then(function(authResult){
FormatAndUpload(authResult, data);
}, errorCallback);
}
Thanks for the answer Newbee Dev, you were correct in that I didn't formulate the then method correctly.
For any others who see this regarding SharePoint, I actually reformatted the code for it to work as expected, so the saveToSharepoint method looks like so:
function saveToSharepoint(data) {
var AuthenticationContext = Microsoft.ADAL.AuthenticationContext;
AuthenticationContext.createAsync("https://login.microsoftonline.com/common/")
.then(function (authContext) {
authContext.acquireTokenAsync(
"https://my.sharepoint.com", // Resource URI
"4be098f8-2184-4831-9ef7-3d17dbbef6a0", // Client ID
"http://localhost:4400/services/office365/redirectTarget.html" // Redirect URI
).then(function (authResult) {
FormatAndUpload(authResult, data);
}, function (err) {
console.log(err);
});
}, function (err) {
console.log(err);
});
}
The main thing to note is creating the AuthenticationContext asynchronously and this way, the FormatAndUpload calls after the whole login process is complete. Just thought I would post this for other people who see this regarding Sharepoint and are stuck.

Categories