I've been trying to upload a file (Encrypted DJI Log file) to a server in order to decrypt it. All of this within my react native expo app.
I have not managed to get the server to accept my file when trying to send a fetch request in the app. I keep getting the following error:
500 Internal Server Error{ "statusCode": 500, "isError": true, "responseException": { "exceptionMessage": "Unhandled Exception occurred. Unable to process the request." }}
The working samples below prove that it is not the server itself being the issue, but rather the way I upload the file.
I have managed to succeed in sending successful requests in a Node.js environment while testing out the API, but the switch to react seemed impossible. Here are 2 ways I did manage to get a successful response, but fist of all, here is the official (working) example provided in the API documentation (https://www.flightreader.com/api/documentation/):
DOC Example (works)
<html><body><input type="file" id="fileInput"><br><br><div id="output"></div><script> // Replace with your Flight Reader API secret key const secretApiKey = "sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // Note: You should never expose your API secret key like this in a production environment. // Anyone who has access to it will be able to make API requests on your behalf. // Call the "/api/v1/fields" endpoint to see a complete list of log fields that can be set here const fields = ["OSD_FlyTimeMilliseconds", "OSD_Latitude", "OSD_Longitude"]; async function processFlightLog() { try { const formData = new FormData(); formData.append("file", fileInput.files[0]); // Remove this forEach loop if you'd like to retrieve all available fields fields.forEach((value, index) => { formData.append("fields", value); }); const response = await fetch("https://api.flightreader.com/v1/logs", { method: "POST", body: formData, headers: {"Accept-Encoding": "gzip","Authorization": `Bearer ${secretApiKey}` } }); if (response.ok) { const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.setAttribute("download", "DJIFlightRecord.csv"); link.setAttribute("target", "_blank"); document.body.appendChild(link); link.click(); output.textContent = "CSV file successfully downloaded"; } else { output.textContent = `${response.status} ${response.statusText}`; } } catch (error) { output.textContent = error; } finally { fileInput.value = null; } } fileInput.addEventListener("change", () => { output.textContent = "Processing flight log file..."; processFlightLog(); });</script></body></html>
I have attempted to recreate the following process in Node.js, and here are 2 methods that did work.
- (Works)
import { LocalFileData, constructFileFromLocalFileData } from "get-file-object-from-local-path";import * as fs from "fs";async function processLog() { try { const fileData = new LocalFileData('path_to_log.txt'); const file = constructFileFromLocalFileData(fileData); const formData = new FormData(); formData.append("file", file); const response = await fetch("https://api.flightreader.com/v1/logs", { method: "POST", body: formData, headers: {"Accept-Encoding": "gzip","Authorization": `Bearer ${s_key}` } }); if (response.ok) { console.log("Success!"); const responseText = await response.text(); fs.writeFileSync('response.txt', responseText); } else { const errorText = await response.text(); console.log(`${response.status} ${response.statusText}`); console.log(errorText); } } catch (err) { console.log(err); }}
Here is the referenced NPM package: https://www.npmjs.com/package/get-file-object-from-local-path
- (Works)
import * as fs from "fs";import axios, * as others from 'axios';import FormData from 'form-data';const {getHeaders} = FormDataasync function processLog2() { const form = new FormData(); form.append('file', fs.createReadStream('path_to_log.txt')); console.log(form.getHeaders()) axios.post('https://api.flightreader.com/v1/logs', form, { headers: { ...form.getHeaders(),'Accept-Encoding': 'gzip','Authorization': `Bearer ${s_key}` }, }) .then((response) => { console.log('File uploaded successfully:', response.data); }) .catch((error) => { console.error('Error uploading file:', error); });}
Now, I am aware that "fs" and "get-file-object-from-local-path" are node-specific packages that do not work in the react-native environment. However, I believe the problem is not the reading of the files themselves, but rather the way the "packages" and sent to the server.
Within my RN app, I have tried multiple combinations of headers, like setting content-types, and others. Mainly using the (rn-fetch-blob)[https://github.com/joltup/rn-fetch-blob] library.
Here is one of my iterations: (Not working)
async function decryptLog(logFile: DocumentPickerAsset) { const form = new FormData(); form.append('file', await RNFetchBlob.fs.readStream(logFile.uri,"base64")); try { const res = await axios.post('https://api.flightreader.com/v1/logs', form, { headers: {'content-type': 'multipart/form-data','Accept-Encoding': 'gzip','Authorization': `Bearer ${s_key}` }, })} catch (err) { console.log }}
Finally, here is some information about the file trying to be uploaded received thanks the the file -I file
command: dji_log.txt: application/octet-stream; charset=binary