Is there a way to use the Fetch API to upload a binary file (for instance to S3 using a signed URL) ?
That would be a simple PUT for some 'application/octet-stream'.
The XHR library is working, but I believe Fetch is better, especially in a React-Native environment.
Does React-Native Fetch support Blob nowadays?
Ideally I would like to do something like this, but Blob is undefined:
fetch('https://s3.amazonaws.com/signedUrl/', {
method: 'PUT',
headers: {
'Content-Type': 'application/octet-stream',
},
body: Blob(filePath)
})
This works on Android/iOS and simulators, if you have the file system path to your binary, such as an image using the built-in XMLHttpRequest to send requests:
const xhr = new XMLHttpRequest();
xhr.open('post', serviceUrl);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(xhr.response);
} else {
reject(xhr.response);
}
}
};
xhr.setRequestHeader('Content-Type', 'image/jpeg');
xhr.send({ uri: 'pathToFile', type: 'image/jpeg', name: 'file' });
A sample pathToFile on macOS is file:///Users/username/Library/Developer/CoreSimulator/Devices/061D4A47-6363-4996-A157-03E6AD2DD9E4/data/Containers/Data/Application/3900F3EF-3259-43CF-9400-87B638EF9A1B/Library/Caches/Camera/F86E7345-080A-4D51-A80E-0CAD3370A353.jpg
I would recommend to use: https://github.com/github/fetch as polyfill for Fetch since is not widely supported.
Fetch documentation sample:
var input = document.querySelector('input[type="file"]')
var data = new FormData()
data.append('file', input.files[0])
data.append('user', 'hubot')
fetch('/avatars', {
method: 'POST',
body: data
})
I am using it as follows:
var input = document.querySelector('input[type="file"]')
function upload(e) {
const file = input.files[0];
const reader = new FileReader();
reader.onload = (e) => {
fetch('/avatars', {
method: 'POST',
body: e.currentTarget.result
})
};
reader.readAsArrayBuffer(file);
}
input.addEventListener('change', upload, false)
Related
I want to upload image from my nuxtjs app to WordPress media library using WordPress rest API, with below code I get below error:
"Sorry, you are not allowed to upload this file type."
onUpload() {
const fd = new FormData();
fd.append("image", this.selectedFile, this.selectedFile.name);
/* reader */
const reader = new FileReader();
reader.readAsDataURL(this.selectedFile);
reader.onload = e =>{
this.previewImage = e.target.result;
};
/* set request header */
const headers = {
'Content-Disposition':`attachment; filename=${this.selectedFile.name}`,
Authorization: "Bearer" + this.$cookiz.get("AdminToken"),
'content-type': 'image'
};
this.$axios.post('/wp-json/wp/v2/media', {fd}, { headers })
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
});
},
As I readed other answers i should send image binary instaed of form data but i dont know how can i do this.in this post described to send image binary but there is no vuejs example
finally, I find out the solution in WordPress for sending images you should append a title and caption also I had a problem with my code fd constant should not be in curly braces below code works fine
onUpload() {
const fd = new FormData();
fd.append("file", this.selectedFile, this.selectedFile.name);
fd.append("title", "pedram");
fd.append("caption", "this is caption");
/* file reader for prview image */
const reader = new FileReader();
reader.readAsDataURL(this.selectedFile);
reader.onload = e =>{
this.previewImage = e.target.result;
};
/* set request header */
const headers = {
'Content-Disposition':`attachment; filename=${this.selectedFile.name}`,
Authorization: "Bearer" + this.$cookiz.get("AdminToken"),
'content-type': 'image'
};
this.$axios.post('/wp-json/wp/v2/media', fd, { headers })
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
});
},
Firstly I have to say that I'm using Expo, so from one library I get a data url (I have already checked that it is correct) and then tries to save this image in Firebase Storage, but every time I send it to the base I see the error 'Error loading preview'. I've tried many ways, such as changing it to a Blob using a request, and here I get another error:
[Unhandled promise rejection: TypeError: Network request failed]
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function () {
reject(new TypeError('Network request failed'));
};
xhr.responseType = 'blob';
xhr.open('GET', dataUrl, true);
xhr.send(null);
});
uploadBytes(storageDatabaseReference, blob as Blob).then(() => {
console.log('Uploaded a blob or file!');
});
And there are my previous tries:
const base64result = dataUrl.split(',')[1];
await uploadString(storageDatabaseReference, base64result, 'base64', {
contentType: 'image/png',
}).then(async () => {
const url = await getDownloadURL(storageDatabaseReference);
return url;
});
await uploadString(storageDatabaseReference, dataUrl, 'data_url', {
contentType: 'image/png',
}).then(async () => {
const url = await getDownloadURL(storageDatabaseReference);
return url;
});
for example dataUrl can have value:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKgAAAA8CAYAAADyvPHhAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAASdEVYdFNvZnR3YXJlAEdyZWVuc2hvdF5VCAUAAAXVSURBVHhe7ZvBbhNHGMfzBMkTmHuFw61SFeeChFBjVKnqhaQPQHKtRNxTK0STPkATEOJGQD1Dey/QeymIqqdCENdWfYXp/tb63PFkYq/j9c5s+B9+ibMe7+7s/Pb7vpl1lj7qXnJC5IoEFVkzEvTjT9bc5StXhUgC/vliGqWg39y67d6+e+/+/udfIZJx9979k4J+dXMQbSxECvBxTFCsjTUUIgVHj34cF5QNsYZCpECCiqyRoCJrJKjIGgkqskaCiqyRoCJrJKjIGgkqsuaDEPTF769Knj771T1+8nO0jciTcyfom7fH7oeDO257Z8d1u6tueWXFLS0tjbG5tRX9rMiPcyEo0XFv/3vX662fkNHnYrfrbmzvuN9evIzuR+RH6wQlQiKkRclO58JIwOXl5TI63twduO7q6mjb7mBQpPfn0f2JvGlcUBOMWhAeHD0qZSMCItzm1peu379WRkPkg1iaNjqdThkVHz/5yf315tgdHN4Ztb+xvV1ui52HaAeNC3qxqAtDyUKIeohHSl7r9dxGv19GRmN38HUh9WEh+stSeJv4ICqf57MIGx5btI/GBUUsBPtub798DchECka42GdOw4T0QWhFzfND44LWxfXNrVJIoq3JSaSNtRXtpZWCWuRcKWpN6k0rCfg71l40ByVcnYGidYJSHljEBMT85enzcpLF35qtp4VJba8os2LvnYVWCRrKSb1pa5qsBrCNWXz4OdEcjMEHGUERz5eTJST/fUQdbt8Z2y6ag8lp3WPQCkFJ2ybmpCUk3j8PjzFZOiNb2JMxypdYu9xgua/u881eUDrduTB8WvTpRn/iEhL1T7fbjb7XBugrDyvsQYOtUNRZ0y0SmwfUuQadtaDWYdjb34+28aH2mWcmT+SKbV80iOl/j4DamkG2sqZK33OA68/51rkOnaWgiOIPGM/SY+1CbPmp6oI/x+ExK49XLWo1OcniWH4/Wdv1ow+Zg5KmLV9u4RrWHe2zExS5LKUDaT3WLgaDy2eo32LvA1ISmRHDpASiFn9TIhDREBfYF/B61iddMay+9NM4N2AYdSx68qTN3z4r9JVjAfV5HX2IsYj6E7ISlMmQL81Zooct2PsD4Utp+0YMpEQAk4PHr/b+aUySfxJVxTTWinOd98GDScNNR1/n7cMkkJ991x3tsxHU5LSJAbAAH2s7CYuiwBeWw6/jhVKGPDh6WL7Pb/aF6Jwbr63G8tPwNJBko39tdA4cn33H2vrUMeGzksek4Tc3MNuYjIXt54Gst4gJahaCmpxcPLsTq9adMRiI60U9x7eh7EvKSDVv8c5+h+c2PQKdNvGJtY3BMfjcweHZU7ztIzyuiYtQdaR8i9TzliMxkgvKBbLJABeSjvI61jY1th57mqCWxq2GJmIjA5+LtZ8EN5NFuyo3RAz2Ud74xfmENycBgH0DNxIRFdHog9+uCotK75BcUBtM5OQ1g7qIjtaBPU4NUzT/jBeuX06qL6vip2SuDSLMKpHV1THJiXiULX5ZVZ5/0Q+TltqdY9LH8Lj8bdFzUWu1SQW1FMRgWtrJec2PweIcuZkYHIQN03iV+nJWEMlENYZfylgfwVJZiP1nAu2nTbiI8hyHcaAfobTTWES/IZmgpHY6NqzNhnchr2Ntc4GlJs6zt/7/EpWl8Vnqy7NiElFfc62QNhTXh3Pjfdqe5cYnA9AvjkkwoZ9EcaIuv4EIvciMl0xQllG4iFz03FO7wYDZ4DPoDM68aVxMJomgFjGJBG1I7T4IKSmbI4mgNuuzpyW5p3aRjsYFtdqT6NmW1C7S0bigftRsU2oXaWhcUP//4pXaxTQaFdTSOyi1iyo0KqjN3oG1tVgbIXwaFZTlGb68obpTVKVRQYWYFQkqskaCiqyRoCJrJKjIGgkqskaCiqw5Iei3t25HGwqRgrv37o8LevnKVff6jz+jjYVokuN37x0+jgnKDzZi7sMivAqRAvz77PMvxuQcCSpErkhQkTGX3H9vRj4tTBadfwAAAABJRU5ErkJggg==
And this happens always after upload (which works only with uploadString currently):
.
I was experimenting with workbox and service workers in general. I tried using NetworkFirst Strategy for my api calls. Console seems its working as expected but I could not display the cached response from service worker. Same is happening when using CacheFirst, response is not recieved by my dom render scripts. Am I missing something?
importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.0.0/workbox-sw.js');`
if (workbox) {
console.log(`Yay! Workbox is loaded 🎉`);
workbox.precaching.precacheAndRoute([]);
const cacheName = 'collection';
workbox.routing.registerRoute(
new RegExp('http://13.232.112.165/api/'),
workbox.strategies.networkFirst()
);
/*
const bgSyncPlugin = new workbox.backgroundSync.Plugin('post-req-queue', {
maxRetentionTime: 24 * 60 // Retry for max of 24 Hours
});
workbox.routing.registerRoute(
new RegExp("http://13.232.112.165/api/"),
workbox.strategies.networkOnly({
plugins: [bgSyncPlugin]
}),
'POST'
);
workbox.routing.registerRoute(
new RegExp("http://13.232.112.165/api/"),
workbox.strategies.networkOnly({
plugins: [bgSyncPlugin]
}),
'PUT'
);
workbox.routing.registerRoute(
new RegExp("http://13.232.112.165/api/"),
workbox.strategies.networkOnly({
plugins: [bgSyncPlugin]
}),
'DELETE'
);
*/
} else {
console.log(`Boo! Workbox didn't load 😬`);
}`
My Api call is as follows :
async function getAccounts() {
url = backend_uri+"accounts";
try{
var jsonResponse = await fetch(url, {headers: {
'Authorization' : "Token "+localStorage.getItem('user-token')
}});
const json = await jsonResponse.json();
const accounts = await json;
let renderString = "";
await accounts.forEach(element => {
renderString = renderString + `<div class='card'><div class='card-body'><strong>${element.name}</strong></div></div>`
});
containerElement.innerHTML += renderString;
}catch(e) {
console.log(e);
}
}
Should api calls in PWA made differently?
(I don't think your question is related to Workbox or PWAs; it appears to be more about using the Fetch API.)
There are some extra awaits and a few other issues that I see with your code; can you try the following?
async function getAccounts() {
const url = `${backend_uri}accounts`;
const response = await fetch(url, {
headers: {
'Authorization' : "Token "+localStorage.getItem('user-token')
},
});
const accounts = await response.json();
const divs = accounts.map(account => `<div class='card'>
<div class='card-body'>
<strong>${account.name}</strong>
</div>
</div>`);
containerElement.innerHTML += divs.join('');
}
I am using http://mailin.io/doc to parse e-mails to my (future) Meteor application. Therefore I created a webhook using Iron-Router that should process the message and the attachments.
Using the following code, a { } is written in the console.
Router.route('/receive/', {where: 'server'})
.post(function(req, res) {
console.log(this.request.body);
});
I found some people reporting similar issues but the provided solutions don't work for me.
https://github.com/iron-meteor/iron-router/issues/909
https://github.com/iron-meteor/iron-router/issues/1003
Any ideas?
In the links the correct workaround was described, seems as is I had another error as well. The following code did the trick for me:
if (Meteor.isServer) {
var Busboy = Meteor.npmRequire("busboy"),
fs = Npm.require("fs"),
os = Npm.require("os"),
path = Npm.require("path");
Router.onBeforeAction(function (req, res, next) {
var filenames = []; // Store filenames and then pass them to request.
_.extend(req, {postData: {}});
if (req.method === "POST") {
var busboy = new Busboy({ headers: req.headers });
busboy.on("file", function (fieldname, file, filename, encoding, mimetype) {
var saveTo = path.join(os.tmpDir(), filename);
file.pipe(fs.createWriteStream(saveTo));
filenames.push(saveTo);
});
busboy.on("field", function(fieldname, value) {
req.postData[fieldname] = value;
});
busboy.on("finish", function () {
// Pass filenames to request
req.filenames = filenames;
next();
});
// Pass request to busboy
req.pipe(busboy);
} else {
this.next();
}
});
}
and the required route looks like this:
Router.route('/receive/', {where: 'server'})
.post(function() {
// Use this.request.postData to access the message content
postData = this.request.postData;
});
The following code is to make HTTP POST request with fetch polyfill:
fetch(url, {
method: 'post',
body: JSON.stringify({
token: this.state.token,
}),
})
.then((response) => response.json())
.then((responseData) => {
console.log(responseData);
})
.done();
This request sends data as a stringified JSON obj. Is there a way to send data as key-value pair similar to requests? post(URL, data=payload) in python.
Sounds like you want the same format as a querystring, so import/require a package like https://www.npmjs.com/package/query-string which doesn't appear to depend on any browser features and has a stringify method:
queryString.stringify({
foo: 'bar',
nested: JSON.stringify({
unicorn: 'cake',
}),
});
//=> foo=bar&nested=%7B%22unicorn%22%3A%22cake%22%7D
Alternatively you could just use the relevant part of its source code, though this would still be subject to its license:
function toQueryString(obj) {
return obj
? Object.keys(obj)
.sort()
.map(function (key) {
var val = obj[key];
if (Array.isArray(val)) {
return val
.sort()
.map(function (val2) {
return encodeURIComponent(key) + '=' + encodeURIComponent(val2);
})
.join('&');
}
return encodeURIComponent(key) + '=' + encodeURIComponent(val);
})
.join('&')
: '';
}
You can then use the return value in your body parameter in fetch:
fetch(url, {
method: 'post',
body: toQueryString({ token: this.state.token }),
});
Sure. Look at the fetch documentation in github: https://github.com/github/fetch
It uses document/DOM web, but it should be the same for react-native case - just use FormData object and append all the form fields to send.
var form = document.querySelector('form')
fetch('/users', {
method: 'post',
body: new FormData(form)
})
And:
var input = document.querySelector('input[type="file"]')
var data = new FormData()
data.append('file', input.files[0])
data.append('user', 'hubot')
fetch('/avatars', {
method: 'post',
body: data
})