4

rocksteady's solution worked

He did originally refer to dictionaries. But the following code to send the JSON string also worked wonders using requests:

import requests

headers = {
  'Authorization': app_token
}
url = api_url + "/b2api/v1/b2_get_upload_url"
content = json.dumps({'bucketId': bucket_id})

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

I'm working with an API that requires me to send JSON as a POST request to get results. Problem is that Python 3 won't allow me to do this.

The following Python 2 code works fine, in fact it's the official sample:

request = urllib2.Request(
    api_url +'/b2api/v1/b2_get_upload_url',
    json.dumps({ 'bucketId' : bucket_id }),
    headers = { 'Authorization': account_authorization_token }
)
response = urllib2.urlopen(request)

However, using this code in Python 3 only makes it complain about data being invalid:

import json
from urllib.request import Request, urlopen
from urllib.parse import urlencode

# -! Irrelevant code has been cut out !-

headers = {
  'Authorization': app_token
}
url = api_url + "/b2api/v1/b2_get_upload_url"

# Tested both with encode and without
content = json.dumps({'bucketId': bucket_id}).encode('utf-8')

request = Request(
  url=url,
  data=content,
  headers=headers
)

response = urlopen(req)

I've tried doing urlencode(), like you're supposed to. But this returns a 400 status code from the web server, because it's expecting pure JSON. Even if the pure JSON data is invalid, I need to somehow force Python into sending it.

EDIT: As requested, here are the errors I get. Since this is a flask application, here's a screenshot of the debugger:

Screenshot

Adding .encode('utf-8') gives me an "Expected string or buffer" error

EDIT 2: Screenshot of the debugger with .encode('utf-8') added

Quad
  • 43
  • 1
  • 1
  • 5
  • You're not "supposed" to use urlencode; that's for form-encoded data, but you're sending JSON. But if you are getting an error, you should post it. – Daniel Roseman Dec 22 '15 at 13:58
  • servers not supported unicode characters "\u2119".Create a demo server if want to test another. – dsgdfg Dec 22 '15 at 14:09
  • take a look at this: [json.dumps vs. flask.jsonify](https://stackoverflow.com/questions/7907596/json-dumps-vs-flask-jsonify) Maybe it helps. – rocksteady Dec 22 '15 at 14:17
  • The error you posted is without the `.encode('utf-8')` call. What is the error with it? – Gary van der Merwe Dec 22 '15 at 14:23
  • @rocksteady this seems interesting. But I have tried manually setting the content header without luck, it gave identical errors. This code also doesn't have flask imported. It's a module that's being used by a flask application - I'll keep looking into this though, there might be something I've missed related to content headers – Quad Dec 22 '15 at 14:23
  • @GaryvanderMerwe That is mentioned right below it. I'm currently not on a computer. But check back in ~5 minutes when I have access to one and I'll try to add an image for that as well, for convenience and details – Quad Dec 22 '15 at 14:24

1 Answers1

3

Since I have a similar application running, but the client still was missing, I tried it myself. The server which is running is from the following exercise:

Miguel Grinberg - designing a restful API using Flask

That's why it uses authentication.

But the interesting part: Using requests you can leave the dictionary as it is.

Look at this:

username = 'miguel'
password = 'python'

import requests
content = {"title":"Read a book"}

request = requests.get("http://127.0.0.1:5000/api/v1.0/projects", auth=(username, password), params=content)
print request.text

It seems to work :)

Update 1:

POST requests are done using requests.post(...) This here describes it well : python requests

Update 2:

In order to complete the answer:

requests.post("http://127.0.0.1:5000/api/v1.0/projects", json=content)

sends the json-string.

json is a valid parameter of the request and internally uses json.dumps()...

rocksteady
  • 2,320
  • 5
  • 24
  • 40
  • 2
    Dictionaries aren't the issue. Those work fine, I'm having trouble sending a single JSON string that is not part of any dictionary or list. But can test requests with a string as well, since you suggested it. – Quad Dec 22 '15 at 15:12