Is it able to read javascript file object in phython? - javascript

There is a client sending a file object in JavaScript.
There is a server written in Python.
Please have a look following code of both client and server.
Client(JavaScript):
function sendFile(file) {
fetch('http://localhost:8088', {
method: 'POST',
body: JSON.stringify({
name: "file",
code: file
})
})
.then(res => {
// handle response
var reader = res.body.getReader();
reader.read()
.then(({done, value}) => {
// need to check done
let chunks = new Uint8Array(value.length);
chunks.set(value, 0);
let result = new TextDecoder("utf-8").decode(chunks);
console.log(result);
});
})
.catch(err => {
// handle error
console.log('fetch error:', err);
});
}
document.getElementById('sendBtn').addEventListener('change',
()=>{this.sendFile(document.getElementById('fileInput').files[0]);});
Server(Python):
#!/usr/bin/python
import BaseHTTPServer
import json
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers.getheader('content-length'))
body = self.rfile.read(length)
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.end_headers()
self.wfile.write("post response")
data = json.loads(body)
# print data['file'] just returns '{ }'
# I would like to save this file on sever side.
# Is it possible??
server = BaseHTTPServer.HTTPServer(("localhost", 8088), MyHandler)
server.serve_forever()
I would like to want to know if there is a way to read file object written in javascript on python world.

I had to send file content How can I serialize an input File object to JSON?
And it is able to read and save it using dcodestring
How to parse data-uri in python?
Thank you all.

Related

trying to send a POST request using python with a JSON object and print the response into a CSV file

I am trying to send a post request using python script and want to store the response. Below are the two file. Everything is fine when i do the same thing using node.js but when I use a python script instead of node.js it give me this error. Any one know why? not able to find the proper reason why this error pop up.
in request sending first name and last name and in response i will get the full name
Node.js Code (used fastify)
const conn=require('fastify')({
logger:true
})
const PORT=80
const axios = require('axios')
//take first and last name as request and in response return full name
conn.post('/user',async(req,res)=>{
const user=req.body
const fullname=user.first_name + user.last_name
console.log(full)
res.json(fullname)
})
const start_server=async()=>{
try
{
await conn.listen(PORT)
console.log(`server start at PORT ${PORT}`)
}
catch(error)
{
conn.log.error(error)
process.exit(1)
}
}
start_server()
my Python script
import requests
import json
API_ENDPOINT = 'http://localhost:80/user'
headers = {'Content-type': 'application/json'}
data = {
"first_name": "jayanta",
"last_name": "lahkar"
}
r = requests.post('http://localhost:80/user', data)
print(r.json())
Error message
{'statusCode': 415, 'code': 'FST_ERR_CTP_INVALID_MEDIA_TYPE', 'error': 'Unsupported Media Type', 'message': 'Unsupported Media Type: application/x-www-form-urlencoded'}
Try:
r = requests.post(url = 'http://localhost:80/user', headers=headers, data=data)
print(r.json())
in the python script:
use json
r = requests.post(url = 'http://localhost:80/user', headers=headers, json=data)
in the node script:
use .send method
const {first_name, last_name} =req.body;
const fullname={first_name, last_name};
res.send(fullname);
here is the answer to your error:
axios.post('url', data, {
headers: {
'Content-Type': 'application/json',
}
}

Uploading Image to AWS presigned post URL using axios

I am trying to upload an image to an S3 bucket using a presigned URL generated using boto3 on Python. I have been using the example python code that was provided in the documentation and was successful (the image got correctly uploaded with the correct Content-Type). However, when trying to do this in Javascript for the purposes of our frontend application, I am really struggling to get it to work.
Here's the example dictionary returned by the backend:
{
"fields": {
"AWSAccessKeyId": "AKIAYS3VM3EBIFL7FKE5",
"key": "posts/623255a762fd9bdfbd13f91a",
"policy": "<very long string>",
"signature": "Qvc/sGBHk0uzirzIfR1YmE2kFlo="
},
"url": "https://hotspot-storage.s3.amazonaws.com/"
}
Here is the functioning Python code:
response = <json response object>
object_name = 'playground/example_profile_group.png'
response['fields']['Content-Type'] = "image/png"
# Demonstrate how another Python program can use the presigned URL to upload a file
with open(object_name, 'rb') as f:
files = {'file': (object_name, f)}
http_response = requests.post(response['url'], data=response['fields'], files=files)
# If successful, returns HTTP status code 204
print(http_response)
print(http_response.text)
Here is the non-functioning Javascript code:
const data = response.data;
let payload = data.fields;
payload['Content-Type'] = 'image/jpeg';
const file = {
uri: previewPath,
name: previewPath,
type: 'image/jpeg',
};
payload.file = file;
const url = data.url;
console.log(payload, "MY PAYLOAD")
axios({
method: 'post',
headers: {'Content-Type': 'multipart/form-data'},
url: url,
data: payload,
})
.then(function (response) {
console.log(response.data, 'uploaded');
const data = response.data;
})
.catch(function (error) {
console.log(
'error uploading image',
error.response.data,
);
});
})
.catch(function (error) {
console.log(
'error getting media link',
error.response.data,
);
});
This is the error that keeps getting returned:
error uploading image <?xml version="1.0" encoding="UTF-8"?>
<Error><Code>MalformedPOSTRequest</Code><Message>The body of your POST request is not well-formed multipart/form-data.</Message><RequestId>Q0ES6P4QP75YVVED</RequestId><HostId>eowLxSJQD1xP1EfHPnzGSJzXVGpPjurIMhkdwAD22JMvi9zRoFGg6Bq+mnUt/Lu7DNPY80iBDMc=</HostId></Error>
I have been stuck on this for an absurd amount of time, and cannot tell what I am doing wrong. Any help would be very much appreciated.
In order to send a multipart/form-data request body, you'll need to use a FormData instance instead of a JavaScript object.
For example
const { url, fields } = response.data;
const payload = new FormData();
payload.append("file", file); // this is the file blob, eg from <input type="file">
payload.append("Content-Type", "image/jpeg");
// add all the other fields
Object.entries(fields).forEach(([ key, val ]) => {
payload.append(key, val);
});
// No need to manually set content-type header, your browser knows what to do
const { data: result } = await axios.post(url, payload);
console.log("uploaded", result);

Having trouble uploading files from Javascript and receiving it through Go

I set up a simple frontend service in JavaScript using Axios. This service takes a list of files and sends to my server code using a post request. My JavaScript looks like this
const testPost = async (files) => {
let formData = new FormData();
files.forEach((file) => {
formData.append("file", file);
});
const res = await axios({
method: "POST",
url: baseUrl,
data: formData,
headers: {
"Content-Type": "multipart/form-data",
},
});
return res;
};
And my Go code looks like this:
func (h *SendHandler) TestPost(w http.ResponseWriter, r *http.Request) {
//Allow CORS here By * or specific origin
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
formdata := r.MultipartForm
fmt.Println(formdata)
}
I think my problem lies in the body of my TestPost function in Go because I click send in my frontend code, I receive a response. In my Go function, when I print my formdata, it outputs <nil>. I want to be able to access each file in the list but I can't even access the formdata. I'm still new to both web dev and Go so there is definitely something I am misunderstanding here. Any pointers?
The documentation for MultipartForm says:
MultipartForm is the parsed multipart form, including file uploads. This field is only available after ParseMultipartForm is called.
Fix by calling ParseMultipartForm before using r.MultipartForm.
err := r.ParseMultipartForm(maxMemory)
if err != nil {
http.Error(w, "Bad Request", http.StatusBadRequest)
return
}
// r.MultipartForm is now set.
fmt.Println(r.MultipartForm) // does not print nil

How to return error from Flask so JavaScript catches it

I have an application running a Flask backend with a React frontend and I'm trying to do some error handling for the front end and display the error message to the user. Here is a simplified version of my files:
Flask
#app.route('/api/download', methods=['POST'])
def download():
data = request.json
#Get data from external API via a post request here
try:
req = urllib.request.Request(url, data, headers)
with urllib.request.urlopen(req) as f:
res = f.read()
print("Success")
data = json.loads(res.decode())
df = pd.json_normalize(data['observationList'])
#Do some pandas magic here
retData = df.to_json(orient="records")
return retData
except Exception as e:
pprint(e)
return jsonify(message='password_update_error'),500
JavaScript
fetch("/api/download", {
method:"POST",
cache: "no-cache",
headers:{
'Content-Type': 'application/json'
},
body: JSON.stringify({
values: this.state.values
})
}).then((response) => response.json())
.then(data => {
this.setState({ sdata: data }, () => {
// click the CSVLink component to trigger the CSV download
setTimeout(() => {
this.csvLink.current.link.click();
});
})
}).catch(err => {
errorBox.innerHTML = "<span style='color: red;'>"+
"Could not get data.</span>"
})
This currently gives me two errors:
TypeError: Data should be a "String", "Array of arrays" OR "Array of objects"
TypeError: Cannot read property 'link' of null
I understand what the problem is but I don't know how to return errors so javascript catches it and then displays it in the box like I want it to. Any ideas? Thank you!
At first glance, why don't you just return the error code? It should solve the errors you're getting.
#app.route('/api/download', methods=['POST'])
def download():
data = request.json
#Get data from external API via a post request here
try:
req = urllib.request.Request(url, data, headers)
with urllib.request.urlopen(req) as f:
res = f.read()
print("Success")
data = json.loads(res.decode())
df = pd.json_normalize(data['observationList'])
#Do some pandas magic here
retData = df.to_json(orient="records")
return retData
except Exception as e:
pprint(e)
return 500

Download and upload image without saving to disk

Using Node.js, I am trying to get an image from a URL and upload that image to another service without saving image to disk. I have the following code that works when saving the file to disk and using fs to create a readablestream. But as I am doing this as a cron job on a read-only file system (webtask.io) I'd want to achieve the same result without saving the file to disk temporarily. Shouldn't that be possible?
request(image.Url)
.pipe(
fs
.createWriteStream(image.Id)
.on('finish', () => {
client.assets
.upload('image', fs.createReadStream(image.Id))
.then(imageAsset => {
resolve(imageAsset)
})
})
)
Do you have any suggestions of how to achieve this without saving the file to disk? The upload client will take the following
client.asset.upload(type: 'file' | image', body: File | Blob | Buffer | NodeStream, options = {}): Promise<AssetDocument>
Thanks!
How about passing the buffer down to the upload function? Since as per your statement it'll accept a buffer.
As a side note... This will keep it in memory for the duration of the method execution, so if you call this numerous times you might run out of resources.
request.get(url, function (res) {
var data = [];
res.on('data', function(chunk) {
data.push(chunk);
}).on('end', function() {
var buffer = Buffer.concat(data);
// Pass the buffer
client.asset.upload(type: 'buffer', body: buffer);
});
});
I tried some various libraries and it turns out that node-fetch provides a way to return a buffer. So this code works:
fetch(image.Url)
.then(res => res.buffer())
.then(buffer => client.assets
.upload('image', buffer, {filename: image.Id}))
.then(imageAsset => {
resolve(imageAsset)
})
well I know it has been a few years since the question was originally asked, but I have encountered this problem now, and since I didn't find an answer with a comprehensive example I made one myself.
i'm assuming that the file path is a valid URL and that the end of it is the file name, I need to pass an apikey to this API endpoint, and a successful upload sends me back a response with a token.
I'm using node-fetch and form-data as dependencies.
const fetch = require('node-fetch');
const FormData = require('form-data');
const secretKey = 'secretKey';
const downloadAndUploadFile = async (filePath) => {
const fileName = new URL(filePath).pathname.split("/").pop();
const endpoint = `the-upload-endpoint-url`;
const formData = new FormData();
let jsonResponse = null;
try {
const download = await fetch(filePath);
const buffer = await download.buffer();
if (!buffer) {
console.log('file not found', filePath);
return null;
}
formData.append('file', buffer, fileName);
const response = await fetch(endpoint, {
method: 'POST', body: formData, headers: {
...formData.getHeaders(),
"Authorization": `Bearer ${secretKey}`,
},
});
jsonResponse = await response.json();
} catch (error) {
console.log('error on file upload', error);
}
return jsonResponse ? jsonResponse.token : null;
}

Categories

Resources