1

I have to convert js code to python. The js code performs a file upload via a POST request, using fetch(). This is the js code:

<input type="file" />
<button onclick="upload()">Upload data</button>
<script>
          upload = async() =>
          {             
             const fileField = document.querySelector('input[type="file"]');
             await uploadDoc(fileField.files[0] );
          };
          
          uploadDoc = async( file ) =>
          {             
              let fd = new FormData();
              fd.append( 'file', file ); 
              fd.append( 'descr', 'demo_upload' );
              fd.append( 'title', name );
              fd.append( 'contentType', 'text' );
              fd.append( 'editor', user );
              let resp = await fetch( url, { method: 'POST', mode: 'cors', body: fd }); 
          };
</script>

The code works and complies with the fetch() docs, provided here: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#uploading_a_file

Now when i try to recreate this in python, i get a 500 HTTP Status Code This is the python code:

from urllib import request
from urllib.parse import urlencode
import json
with open('README.md', 'rb') as f:
          upload_credentials = {
            "file": f,
            "descr": "testing",
            "title": "READMEE.md",
            "contentType": "text",
            "editor": username,
          }
          url_for_upload = "" #here you place the upload URL
          
          req = request.Request(url_for_upload, method="POST")
          form_data = urlencode(upload_credentials)
          form_data = form_data.encode()
    
          response = request.urlopen(req, data=form_data)
          http_status_code = response.getcode()
          content = response.read()
          print(http_status_code)
          print(content)

This doesn't work however and i get this error:

raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 500:

Someone with both js and python experience might be able to see what is wrong in the python side, or how to convert the fetch() function to python.

user1584421
  • 3,499
  • 11
  • 46
  • 86

1 Answers1

1

I think the problem is that you're reading the file in binary mode (rb). You need just r:

with open('README.md', 'r') as f: # r instead of rb

However, I still reccomend the requests module, which is more widely used, and is easier in this case.

import requests # pip install requests

url = "https://www.example.com/upload_file"

headers = {
    "content-type": "text/plain" # force text file content type
}

files = {
   "my_file": ("FILE_NAME.md", open("README.md","r")) # tuple containing file name, and io.BytesIO file buffer
}

data = { # in case you want to send a request payload too
    "foo": "bar"
}

r = requests.post(url, headers=headers, files=files, data=data)

if r.status_code == 200:
    print(r.text) # print response as a string (r.content for bytes, if response is binary like an image)

MmBaguette
  • 340
  • 3
  • 13
  • Thanks a lot! The first idea about the `r` instead of `rb` did not work. On your second implementation, where exactly should i place the key value pairs on the dictionary called `upload_credentials` in my code? Could you modify your code example adding these parameters, so i know where to place them? Is it in the dictionary called `data`? – user1584421 Jan 14 '22 at 22:31
  • Are you uploading a multipart/form data payload? The files paramter is just like headers, except it's form data: https://2.python-requests.org/en/master/user/quickstart/#post-a-multipart-encoded-file. The tuple in my code is an example of how you can attach a binary file while choosing the name of the file you're uploading. – MmBaguette Jan 15 '22 at 01:01