ustroetz
ustroetz

Reputation: 6292

Python requests doesn't upload file

I am trying to reproduce this curl command with Python requests:

curl -X POST -H 'Content-Type: application/gpx+xml' -H 'Accept: application/json' --data-binary @test.gpx "http://test.roadmatching.com/rest/mapmatch/?app_id=my_id&app_key=my_key" -o output.json

The request with curl works fine. Now I try it with Python:

import requests

file =  {'test.gpx': open('test.gpx', 'rb')}

payload = {'app_id': 'my_id', 'app_key': 'my_key'}
headers = {'Content-Type':'application/gpx+xml', 'Accept':'application/json'}


r = requests.post("https://test.roadmatching.com/rest/mapmatch/", files=file, headers=headers, params=payload)

And I get the error:

<Response [400]>
{u'messages': [], u'error': u'Invalid GPX format'}

What am I doing wrong? Do I have to specify data-binary somewhere?

The API is documented here: https://mapmatching.3scale.net/mmswag

Upvotes: 2

Views: 2187

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1121854

Curl uploads the file as the POST body itself, but you are asking requests to encode it to a multipart/form-data body. Don't use files here, pass in the file object as the data argument:

import requests

file = open('test.gpx', 'rb')

payload = {'app_id': 'my_id', 'app_key': 'my_key'}
headers = {'Content-Type':'application/gpx+xml', 'Accept':'application/json'}

r = requests.post(
    "https://test.roadmatching.com/rest/mapmatch/",
    data=file, headers=headers, params=payload)

If you use the file in a with statement it'll be closed for you after uploading:

payload = {'app_id': 'my_id', 'app_key': 'my_key'}
headers = {'Content-Type':'application/gpx+xml', 'Accept':'application/json'}

with open('test.gpx', 'rb') as file:
    r = requests.post(
        "https://test.roadmatching.com/rest/mapmatch/",
        data=file, headers=headers, params=payload)

From the curl documentation for --data-binary:

(HTTP) This posts data exactly as specified with no extra processing whatsoever.

If you start the data with the letter @, the rest should be a filename. Data is posted in a similar manner as --data-ascii does, except that newlines and carriage returns are preserved and conversions are never done.

Upvotes: 4

Related Questions