1

I've been given the following curl command as part of API documentation, and I'm trying to implement it using the requests library.

curl -v --cookie cookie.txt -X POST -H 'Accept: application/json' -F 'spot[photo]'=@rails.png -F 'spot[description]'=spot_description -F 'spot[location_id]'=9  -F 'spot[categories][]'='See the Sights' -F 'spot[categories][]'='Learn Something' http://some.server.com/api/v1/spots

my python code looks something like this:

import requests
import json

_user = 'redacted'
_password = 'redacted'
_session = requests.session()
_server = 'http://some.server.com'

_hdr = {'content-type': 'application/json', 'accept': 'application/json'}

_login_payload = {
    'user': {
        'email': _user,
        'password': _password
    }
}
r = _session.post(_server + "/users/sign_in", data=json.dumps(_login_payload), headers=_hdr)
print json.loads(r.content)

_spot_payload = {
    'spot': {
        'photo': '@rails.gif',
        'description': 'asdfghjkl',
        'location_id': 9,
        'categories': ['See the Sights',]
    }
}
r = _session.post(_server + '/api/v1/spots', data=json.dumps(_spot_payload), headers=_hdr)
print json.loads(r.content)

I've heard tell that you can use open('file').read() to post files, but the json encoder doesn't much like this, and I'm not sure about a way around it.

Leah
  • 103
  • 2
  • 6

1 Answers1

3
C:\>cat file.txt
Some text.

When you issue this command:

C:\>curl -X POST -H "Accept:application/json" -F "spot[photo]=@file.txt"
-F "spot[description]=spot_description" http://localhost:8888

what's being sent looks like this:

POST / HTTP/1.1 User-Agent: curl/7.25.0 (i386-pc-win32) libcurl/7.25.0 OpenSSL/0.9.8u zlib/1.2.6 libssh2/1.4.0 Host: localhost:8888 Accept: application/json Content-Length: 325 Expect: 100-continue Content-Type: multipart/form-data; boundary=----------------------------e71aebf115cd

------------------------------e71aebf115cd Content-Disposition: form-data; name="spot[photo]"; filename="file.txt" Content-Type: text/plain

Some text. ------------------------------e71aebf115cd Content-Disposition: form-data; name="spot[description]"

spot_description ------------------------------e71aebf115cd--

As you can see curl sends request with Content-Type set to multipart/form-data; Requests support sending files using the same Content-Type. You should use files argument for this.

(2.7) C:\>python
Python 2.7.3 (default, Apr 10 2012, 23:24:47) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> requests.__version__
'0.11.1'
>>> requests.post('http://localhost:8888', files={'spot[photo]': open('file.txt', 'rb')}, data={'spot[description]': 'spot_description'})
<Response [200]>

And what's being sent looks like this:

POST http://localhost:8888/ HTTP/1.1
Host: localhost:8888
Content-Length: 342
Content-Type: multipart/form-data; boundary=192.168.1.101.1.8000.1334865122.004.1
Accept-Encoding: identity, deflate, compress, gzip
Accept: */*
User-Agent: python-requests/0.11.1

--192.168.1.101.1.8000.1334865122.004.1
Content-Disposition: form-data; name="spot[description]"
Content-Type: text/plain

spot_description
--192.168.1.101.1.8000.1334865122.004.1
Content-Disposition: form-data; name="spot[photo]"; filename="file.txt"
Content-Type: text/plain

Some text.
--192.168.1.101.1.8000.1334865122.004.1--
Piotr Dobrogost
  • 41,292
  • 40
  • 236
  • 366
  • Thank you for pointing out how oblivious I was =). I probably should have been able to figure that out for myself. However, it took me this long to get back to you because it didn't actually work in real life, and it took a while before I got a useful error out of it. – Leah May 02 '12 at 00:49
  • The error in question is "TypeError: is not JSON serializable". – Leah May 02 '12 at 00:59
  • I since found there was a problem in my in-between code where I was sending the file to data rather than to files. The server still isn't receiving the file properly, but python is no longer throwing any erros about it. I am afraid that for confidentiality reasons, I cannot share the actual code / server address. My next step is to find a tool to capture the network traffic going from my mac to the server so I have something concrete to give the developers. Thank you for all of your help. – Leah May 02 '12 at 19:33
  • May be you know why encoding data with json fails: data=json.dumps({'spot[description]': 'spot_description'}) – Alex Kreimer Dec 05 '12 at 18:14
  • @AlexKreimer You should ask this as separate question. Also make sure it hasn't been asked already. – Piotr Dobrogost Dec 05 '12 at 19:16