How to handle FormData in Miragejs? - fetch

Miragejs handles json out-of-the-box but seems to be unable to handle FormData. When I post FormData and log the received request in mirage endpoint, request.requestBody is empty.
Simplified code examples:
POSTing FormData:
const testFile = new File(['hello'], 'hello.png', { type: 'image/png' });
const formData = new FormData('file', testFile);
fetch('https://localhost:3000/api/endpoint', {method: 'POST', body: formData});
// ...
receiving POST in mirage mock server:
this.post('/endpoint', (schema, request) => {
console.log('request:', request);
// request.requestBody is an empty string!
});
Possibly a related issue: https://github.com/miragejs/ember-cli-mirage/issues/74

It's possible to cast the request.requestBody to FormData and then parse the file.
Shortening the excellent solution described in How to handle uploading and parsing files in your frontend app tests:
this.post('/endpoint', (schema, request) => {
const readFile = async (file: File): Promise<string> =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = () => reject(new Error('There was an error reading the file!'));
reader.onload = () => resolve(reader.result as string);
reader.readAsText(file);
});
const formData: FormData = request.requestBody as unknown as FormData;
const uploadFile: File = formData.get('file') as File;
const fileContents: string = await readFile(uploadFile);
console.log('Uploaded file contents:', fileContents);
});

Related

Saved image in Firebase Storage is invalid

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,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
And this happens always after upload (which works only with uploadString currently):
.

react native upload file form data

it is work fine on post man so i copy the whole code from post mane
formdata.append("file_1", fileInput.files[0], "file.pdf");
and i change fileInput.files[0]to response from react native document picker
my problem i am getting an error on line 166 and this is below back end side code
this code built the .net
line 166 attachments.Add(new OpportunityAttachmentInfo()
{
ContentType = file.ContentType,
FileData = content,
FileName = fileDate.FileName +
file.FileName.Substring(file.FileName.LastIndexOf(".")),
AttachmentTypeId = request[i].AttachmentTypeId,
});
}
this is my react native code
uploadFIle = async (res) => {
var myHeaders = new Headers();
myHeaders.append('Authorization', 'Bearer ' + this.props.accessToken);
var formdata = new FormData();
formdata.append('file', res, res.name);
formdata.append(
'data',
JSON.stringify({
****
}),
);
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: formdata,
redirect: 'follow',
};
fetch(
'https://****',
requestOptions,
)
.then((response) => response.text())
.then((result) => {
console.log('result', result);
this.apiGetSupplierItem();
})
.catch((error) => console.log('error', error));
};

Unable to upload image to firebase storage with firebase functions

here is my code:-
exports.uploadImage = (req, res) => {
const BusBoy = require('busboy');
const path = require('path');
const os = require('os');
const fs = require('fs');
const busboy = new BusBoy({ headers: req.headers });
let imageFileName;
let imageToBeUploaded = {};
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
const imageExtension = filename.split('.')[filename.split('.').length - 1];
imageFileName = `${Math.round(Math.random() * 100000000000)}.${imageExtension}`;
const filepath = path.join(os.tmpdir(), imageFileName);
imageToBeUploaded = { filepath, mimetype };
file.pipe(fs.createWriteStream(filepath));
});
busboy.on('finish', () => {
console.log('Busboy on started');
//code breaks here
admin.storage().bucket().upload(imageToBeUploaded.filepath, {
resumable: false,
metadata: {
metadata: {
contentType: imageToBeUploaded.mimetype
}
}
})
.then(() => {
const imageUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}?alt=media`;
console.log('logging image url' + imageUrl);
return db.doc(`/users/${req.user.handle}`).update({ imageUrl })
})
.then(() => {
return res.json({ message: 'Image uploaded successfully' });
})
.catch(err => {
console.error(err);
return res.status(500).json({ error: err.code });
})
});
busboy.end(req.rawBody);
}
I have mentioned where my code is breaking in a comment and the error I am getting is Error: Cannot parse response as JSON: Not Found
message: 'Cannot parse response as JSON: Not Found'
The error message says cannot parse response as JSON. Does that mean the response from firebase is not JSON? I have a token in the header of the request and an image in the body as form-data. I really have not clue what wrong, please help
I unfortunately can't identify the JSON parsing error, so I've instead rewritten the code to be more streamlined as #robsiemb eluded to.
Your uploadImage function appears to be configured as some middleware, so I have done the same below. This code will stream the uploaded data straight to Cloud Storage under a unique file name as generated from Reference.push().key to prevent conflicts.
In the code below,
The uploaded file will be stored at a location similar to: userData/someUserId/images/-JhLeOlGIEjaIOFHR0xd.png
The image's raw URL is not stored in the database because unless the file object or containing bucket is made public it will require a signed URL which can only last up to 7 days (see below).
More than one file can be accepted and uploaded. If this is undesired, configure the limits for the BusBoy instance.
Basic error handling for non-POST requests and missing file entries was added.
// import Firebase libraries & initialize
const admin = require('firebase-admin');
admin.initializeApp(); // initializes from environment variables
// import required modules
const BusBoy = require('busboy');
exports.uploadImage = (req, res) => {
if (req.method !== 'POST') {
res.sendStatus(405); // 405 METHOD_NOT_ALLOWED
return;
}
let busboy = new BusBoy({headers: req.headers}); // add {limits: {files: 1}} to limit to only a single file upload
let bucket = admin.storage().bucket();
let db = admin.firestore();
let storageFilepath;
let storageFile;
// Note: Currently only the last file is saved to `/users/${req.user.handle}`
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
let fileext = filename.match(/\.[0-9a-z]+$/i)[0];
storageFilepath = `userData/${req.user.handle}/images/` + getUniqueName() + fileext;
storageFile = bucket.file(storageFilepath);
file.pipe(storageFile.createWriteStream({ gzip: true }));
})
.on('finish', () => {
if (!storageFile) {
res.status(400).json({error: 'expected file'}); // 400 BAD_REQUEST
return;
}
db.doc(`/users/${req.user.handle}`).update({ imagePath: storageFilepath })
.then(() => {
res.status(201).json({ message: 'Image uploaded successfully' }); // 201 CREATED
})
.catch((err) => {
console.error(err);
res.status(500).json({ error: err.code }); // 500 INTERNAL_SERVER_ERROR
});
})
.on('error', (err) => {
console.error(err);
res.status(500).json({ error: err.code });
});
req.pipe(busboy);
});
function getUniqueName() {
// push() without arguments returns a ThennableReference, which we'll abuse for it's key generation
return admin.database().ref().push().key;
}
If you did want the uploaded image to be publicly accessible, you could use the following .on('finish', ...) handler that adds in the File.makePublic() function:
.on('finish', () => {
if (!storageFile) {
res.status(400).json({error: 'expected file'}); // 400 BAD_REQUEST
return;
}
storageFile.makePublic()
.then(() => {
return db.doc(`/users/${req.user.handle}`).update({
imagePath: storageFilepath,
imageUrl: `https://storage.googleapis.com/${config.storageBucket}/${storageFilepath}`
});
})
.then(() => {
res.status(201).json({ message: 'Image uploaded successfully' }); // 201 CREATED
})
.catch((err) => {
console.error(err);
res.status(500).json({ error: err.code }); // 500 INTERNAL_SERVER_ERROR
});
})
Found a solution to the issue!
Essentially - you need to set up your Google Application Credentials. Go into firebase and look into your settings. You need to set up the environment variable GOOGLE_APPLICATION_CREDENTIALS so that firebase has your credentials when you access these files.
https://firebase.google.com/docs/admin/setup?authuser=1 for more information.
After you've done that, check the security settings in firebase, in every area you're dealing with. This should solve the problem (it's definitely a security issue and not your code).
This was the tutorial in question as well for those looking on . https://www.youtube.com/watch?v=m_u6P5k0vP0&t=7661s .
In my case it was wrong bucket Id configured - after correcting that i was able to upload file

Batch Geocode using Axios

Testing the HERE Batch GeoCode life-cycle through node application. We have similar working with Azure Mappings but they are crazy expensive.
Seems as if the initial post request is succeeding. But is stuck on "submitted" status during status check. And failing during result check with 404. Using axius to make the queries - with the documented examples.
const getStatus = async requestId => {
const url = statusURL(requestId);
const res = await axios.get(url);
const response = res.data.Response;
return response;
};
const getResult = async requestId => {
const url = resultURL(requestId);
const config = { headers: { 'Content-type': 'text/plain' } };
const res = await axios.get(url, config);
const response = res.data.Response;
return response;
};
const requestGeo = async input => {
const url = requestURL;
const res = await axios.post(url, input, {
headers: { 'Content-type': 'text/plain' },
});
const requestId = res.data.Response.MetaInfo.RequestId;
return requestId;
};
getStatus(requestId)
.then(res => {
console.log(res);
})
.catch(e => {
console.log(e);
});
const input = `recId|street|city|postalCode|country
1|425 Randolph St|Chicago||USA
2|31 St James Ave|Boston|02116|USA
3|Invalidenstrasse 117|Berlin|10115|DEU`;
requestGeo(input)
.then(console.log)
.catch(e => {
console.log(e);
});
If you don't specify the "&action=run" parameter in your initial request, then the job is being checked, stored and set as "submitted". This does not mean that it will be executed.
Alternatively you can send an "action=start"-request to start the job.
Having applied one of these two options, the job will be scheduled for execution and flagged as "accepted".

Sending binary through HTTP with React-Native Fetch API

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)

Resources