I'm trying to use fetch() to perform a media upload in WP Rest API using JS (React Native).
Here's what I've done so far:
fetch('https://www.example.fr/wp-json/wp/v2/media', {
method: 'post',
headers: new Headers({
'Content-Type': 'image/jpeg',
'Authorization': 'Basic d3GtcmVzdC1sdfGktY2xpZW50Onefepbl9hdh90aWJldA==',
'Content-Disposition': 'attachment; filename="user-'+userId+'.jpg"'
}),
body: imageBase64Data
})
.then(function (response) {
console.log(response);
});
imageBase64Data is set like this:
let imageBase64Data = 'data:image/png;base64,'+ imageData;
and imageData is react-native-image-picker response.data: https://github.com/react-community/react-native-image-picker#the-response-object
Here's my issue: the media is created successfully on my WP, but the image is empty (no data, around 15B). So I'm guessing something is messing up with the data I'm sending as the body of my request. But I don't know what.
Any ideas?
For the record, here's how I finally ended up with this issue, using react-native-fetch-blob module:
RNFetchBlob.fetch('post', 'https://www.example.fr/wp-json/wp/v2/media',
{
'Content-Type': 'image/jpeg',
'Authorization': 'Basic dqdsfqsdfpbl9hqsdfdsfWJldA==',
'Content-Disposition': 'attachment; filename="user-'+userId+'.jpg"'
}
,imageUri) // imageUri = RNFetchBlob.wrap(imageUri);
.then(function (response) {
console.log(response); // returns a 201 response with id of the attached media
});
Related
Here is my code:
function uploadImage(payload) {
return fetch('/api/storage/upload/image/', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
Accept: 'application/json',
Authorization: 'Bearer <token>',
},
body: payload,
});
}
function uploadImage2(payload) {
return axios.post('/api/storage/upload/image/', payload, {
headers: {
'Content-Type': 'multipart/form-data',
Accept: 'application/json',
Authorization: 'Bearer <token>',
},
});
}
function test(file, meta_data) {
var formBody = new FormData();
formBody.set('image', file);
formBody.set('meta_data', meta_data);
uploadImage(formBody);
// doesn't work
uploadImage2(formBody);
// works
}
Can someone please explain to me how I'm supposed to send multipart requests with fetch?
The error I get with this code is: 400 bad request, file and meta_data are null.
Do not use this header: 'Content-Type': 'multipart/form-data'.
Remove the header and it should work.
Explanation:
When using fetch with the 'Content-Type': 'multipart/form-data' you also have to set the boundary (the separator between the fields that are being sent in the request).
Without the boundary, the server receiving the request won't know where a field starts and where it ends.
You could set the boundary yourself, but it's better to let the browser do that automatically by removing the 'Content-Type' header altogether.
Here's some more insight: Uploading files using 'fetch' and 'FormData'
Here is what worked for me:
function uploadImage(payload) {
return fetch('/api/storage/upload/image/', {
method: 'POST',
headers: {
Authorization: 'Bearer <token>',
},
body: payload,
});
}
By comparing the cURL requests sent by the browser I discovered that in the axios request has this:
"Content-Type": "multipart/form-data; boundary=---------------------------19679527153991285751414616421",
So I figured that when you manually specify the content type, fetch respects that and doesn't touch anything while still does it's thing the way it wants:-/ so you just shouldn't specify it, fetch will know itself since you are using formData()
I have a rest api endpoint and I am checking it using POSTMAN which is posting correctly. But, when I am doing it using JAVASCRIPT FETCH, I am not able to post it. Below is my code for fetch:
const { inputAOI, wktForCreation } = this.state
fetch('http://192.168.1.127:8080/aoi/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ userName: 'fuseim', aoiName: inputAOI, wkt: wktForCreation }),
mode: 'no-cors'
}).then(function (response) {
if (response.ok) {
return response.json()
} else {
throw new Error('Could not reach the API: ' + response.statusText)
}
}).then(function (data) {
console.log({ data })
}).catch(function (error) {
console.log({ error })
})
Below is the image for the request headers.
It is seen in the above image that in Request Headers, the Content-Type is still text/plain but I am sending application/json as shown in above fetch code.
Check the response preview in console.
Below is correct POSTMAN request:
As hinted in the comments, the problem is with the mode:"no-cors"
Content-Type is considered a simple header, and should be allowed without cors, but only with the following values:
application/x-www-form-urlencoded
multipart/form-data
text/plain
See: https://fetch.spec.whatwg.org/#simple-header
If you are running the API on the same host/port as the script, you should use mode: "same-origin" alternatively add the host/port that the script is running on as an allowed origin on the API.
For more information about CORS: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Instead of
headers: {
'Content-Type': 'application/json'
}
you could try:
headers: new Headers({
'Content-Type': 'application/json'
})
I have used https://graph.microsoft.com/beta/me/photo/$value API to get the profile picture of the outlook user. I get an image on running the above API in the rest-client. The content-type of the API is "image/jpg"
But, in Node.js, the response of the API is as follows:
����\u0000\u0010JFIF\u0000\u0001\u0001\u0000\u0000\u0001\u0000\u0001\u0000\u0000��\u0000�\u0000\u0005\u0005\u0005\u0005\u0005\u0005\u0006\u0006\u0006\u0006\b\t\b\t\b\f\u000b\n\n\u000b\f\u0012\r\u000e\r\u000e\r\u0012\u001b\u0011\u0014\u0011\u0011\u0014\u0011\u001b\u0018\u001d\u0018\u0016\u0018\u001d\u0018+"\u001e\u001e"+2*(*2<66<LHLdd�\u
I used 'fs' to create an image file. The code is as follows:
const options = {
url: "https://graph.microsoft.com/beta/me/photo/$value",
method: 'GET',
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${locals.access_token}`,
'Content-type': 'image/jpg',
}
};
request(options, (err, res, body) => {
if(err){
reject(err);
}
console.log(res);
const fs = require('fs');
const data = new Buffer(body).toString("base64");
// const data = new Buffer(body);
fs.writeFileSync('profile.jpg', data, (err) => {
if (err) {
console.log("There was an error writing the image")
}
else {
console.log("The file is written successfully");
}
});
});
The file is written successfully, but the .jpg image file generated is broken. I am unable to open the image.
The output of the image file is as follows:
77+977+977+977+9ABBKRklGAAEBAAABAAEAAO+/ve
You can do this by streaming the response like this,
request(options,(err,res,body)=>{
console.log('Done!');
}).pipe(fs.createWriteStream('./profile.jpg'));
https://www.npmjs.com/package/request#streaming
https://nodejs.org/api/fs.html#fs_class_fs_writestream
The reason for this is that by default, request will call .toString() on the response data. In case of binary data, like a RAW JPEG, this isn't what you want.
It's also explained in the request documentation (albeit vaguely):
(Note: if you expect binary data, you should set encoding: null.)
Which means that you can use this as well:
const options = {
encoding : null,
url : "https://graph.microsoft.com/beta/me/photo/$value",
method : 'GET',
headers : {
'Accept' : 'application/json',
'Authorization' : `Bearer ${locals.access_token}`,
'Content-type' : 'image/jpg',
}
};
However, streaming is probably still the better solution, because it won't require the entire response being read into memory first.
Request is deprecated. You can do this with axios;
// GET request for remote image in node.js
axios({
method: 'get',
url: 'http://example.com/file.jpg',
responseType: 'stream'
})
.then(function (response) {
response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});
I have been struggling with this one for a while now, and need your guys help! I am trying to streamline the process of downloading a report from my website. With node this is fairly straightforward with a readStream, like so:
router.post('/report', (req, res) => {
const filename = 'test.png';
const filePath = path.join(__dirname, filename);
fs.exists(filePath, exists => {
if (exists) {
const stat = fs.statSync(filePath);
res.writeHead(200, {
'Content-Type': 'image/png',
'Content-Length': stat.size,
'Content-Disposition': 'attachment; filename=' + filename,
});
fs.createReadStream(filePath).pipe(res);
} else {
res.writeHead(400, { 'Content-Type': 'text/plain' });
res.end('ERROR File does NOT Exists');
}
});
});
Now if I try this with Postman or some other API tester, it works perfectly, the file is downloaded and saved correctly. Now I am struggling to get this to work my front-end. I am currently running AngularJS and have tried to use FileSaver.js as a way to take this data and save it, however it never works. The file is saved, but the data is unreadable, aka the image previewer says the image is broken. I think I am creating the Blob incorrectly?
function exportReport(_id) {
this.$http
.post(
'/api/report',
{ _id },
{
headers: {
'Content-type': 'application/json',
Accept: 'image/png',
},
}
)
.then(data => {
console.log(data);
const blob = new Blob([data], {
type: 'image/png',
});
this.FileSaver.saveAs(blob, 'testing.png');
});
}
The console log result is as so:
Object {data: "�PNG
↵↵
IHDRRX��iCCPICC Profi…g�x #� #������Z��IEND�B`�", status: 200, config: Object, statusText: "OK", headers: function}
Am I suppose to decode the object.data?
Try adding responseType: 'blob' to the request and omit creating a new blob:
function exportReport(_id) {
this.$http
.post(
'/api/report',
{ _id },
{
headers: {
'Content-type': 'application/json',
Accept: 'image/png',
},
responseType: 'blob'
}
)
.then(data => {
console.log(data);
this.FileSaver.saveAs(data.data, 'testing.png');
});
}
I'm right now working on a react native project that have a taking image and upload function, and I'm using react-native-fetch-blob for passing multipart data to upload a single file. However, it seems to be not passing any data to my api.
I'm also using react-native-camera for capturing image. According to some usage of that module, my project is able to capture image and display the image by calling this function.
this.camera.capture({ metadata: options })
.then((data) => {
console.log("image path: ", data.path);
})
.catch(err => console.error(err));
Then I got the result like this,
image path: /var/mobile/Containers/Data/Application/.../AE1E52F0-8522-44D5-8603-21FB4EC9EAF9.jpg
So I used RNFetchBlob with this path to send image to my api like this,
RNFetchBlob.fetch(
'POST',
[url],
{
Authorization: jwtToken,
'Content-Type': 'multipart/form-data'
},
[
{
name: 'file',
filename: 'AE1E52F0-8522-44D5-8603-21FB4EC9EAF9.jpg',
type: 'image/jpeg',
data: RNFetchBlob.wrap('/var/mobile/Containers/Data/Application/.../AE1E52F0-8522-44D5-8603-21FB4EC9EAF9.jpg')
}
]
).then((response) => {
console.log("res: ", response.text());
})
.catch((error) => {
console.log(error);
});
After that, I checked the request that I can get from my API, it shows like this:
{
host: 'localhost:3000',
connection: 'close',
'content-type': 'multipart/form-data; charset=utf-8; boundary=RNFetchBlob1881293472',
'user-agent': 'app/1 CFNetwork/811.5.4 Darwin/16.6.0',
accept: '*/*',
'accept-language': 'zh-tw',
authorization: 'JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI1OTUxMzYxZDBkMTk3MjczNjNiMzRhN2EiLCJ1c2VyVHlwZSI6InVzZXIiLCJpYXQiOjE0OTg0OTQ1MTUsImV4cCI6MTQ5OTA5OTMxNX0.8vhDJtFugi4OQAJ48PTsBlAp8bw6x__KwOXvk6xuYW8',
'content-length': '552434',
'accept-encoding': 'gzip, deflate'
}
But I tried console my req.body I got empty object {} from that. Can you give me some suggestion on that? Thank you~
I'm using "react-native-fetch-blob": "^0.10.5" and "node": "v6.10.2"