2

I am trying to send data via an API but am getting the TypeError: can't concat bytes to str. This I understand means I need to convert part of my code to bytes but I am unsure how to do this. I've tried adding b in front or using bytes('data') but might be placing them in the wrong area.

import http.client

conn = http.client.HTTPSConnection("exampleurl.com")

payload = {
    'FilterId': "63G8Tg4LWfWjW84Qy0usld5i0f",
    'name': "Test",
    'description': "Test1",
    'deadline': "2017-12-31",
    'exclusionRuleName': "Exclude",
    'disable': "true",
    'type': "Type1"
    }

headers = {
    'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
    'x-csrf-token': "wWjeFkMcbopci1TK2cibZ2hczI",
    'cache-control': "no-cache",
    'postman-token': "23c09c76-3b030-eea1-e16ffd48e9"
    }


conn.request("POST", "/api/campaign/create", payload, headers)


res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))

This is the problem line:

conn.request("POST", "/api/campaign/create", payload, headers)

I am unsure what and how to convert to bytes.

nvachhan
  • 93
  • 3
  • 9
  • why not use the `requests` module instead? – cs95 Nov 01 '17 at 13:20
  • I receive a 'ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED]' error when trying to use that. Thought this issue might be easier to fix than that. – nvachhan Nov 01 '17 at 13:24
  • @nvachhan: the server at https://exampleurl.com does not have a valid SSL certificate. You can test with just HTTP, or try using [httpbin.org](http://httpbin.org) as shown in my answer. Better still, use `requests` as suggested. – mhawke Nov 01 '17 at 13:53
  • I will post another question with the code I used with requests – nvachhan Nov 01 '17 at 14:51

1 Answers1

3

Use requests if you can, it's much easier to work with.

Otherwise, you need to urlencode the payload to be posted to the server. The url encoded version of your payload looks like this:

description=Test1&exclusionRuleName=Exclude&FilterId=63G8Tg4LWfWjW84Qy0usld5i0f&deadline=2017-12-31&type=Type1&name=Test&disable=true

Here is a working example:

import http.client
from urllib.parse import urlencode

conn = http.client.HTTPSConnection("httpbin.org")

payload = {
    'FilterId': "63G8Tg4LWfWjW84Qy0usld5i0f",
    'name': "Test",
    'description': "Test1",
    'deadline': "2017-12-31",
    'exclusionRuleName': "Exclude",
    'disable': "true",
    'type': "Type1"
    }

headers = {
    'Content-Type': 'application/x-www-form-urlencoded',
    'x-csrf-token': "wWjeFkMcbopci1TK2cibZ2hczI",
    'cache-control': "no-cache",
    'postman-token': "23c09c76-3b030-eea1-e16ffd48e9"
    }

conn.request("POST", "/post", urlencode(payload), headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))

http://httpbin.org returns this JSON response:

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "FilterId": "63G8Tg4LWfWjW84Qy0usld5i0f", 
    "deadline": "2017-12-31", 
    "description": "Test1", 
    "disable": "true", 
    "exclusionRuleName": "Exclude", 
    "name": "Test", 
    "type": "Type1"
  }, 
  "headers": {
    "Accept-Encoding": "identity", 
    "Cache-Control": "no-cache", 
    "Connection": "close", 
    "Content-Length": "133", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "Postman-Token": "23c09c76-3b030-eea1-e16ffd48e9", 
    "X-Csrf-Token": "wWjeFkMcbopci1TK2cibZ2hczI"
  }, 
  "json": null, 
  "origin": "220.233.14.203", 
  "url": "https://httpbin.org/post"
}

Note that I am using httpbin.org as a test server, posting to https://httpbin.org/post.

Also, I have changed the Content-type header to application/x-www-form-urlencoded because that is the format returned by urlencode().

mhawke
  • 84,695
  • 9
  • 117
  • 138
  • Your code definitely works but my url does not, it is not actually 'exampleurl.com'. Mine does not return any errors now but also does not execute the api post. Could this just be a problem with my payload data? Or the site itself? – nvachhan Nov 01 '17 at 14:49
  • What is returned? Try `print('{} {}'.format(res.status, res.reason))` and print the body of the response. I'm sure that the data will be posted to any URL that you specify, but it's up to the server to process it. There is nothing wrong with your payload data, assuming that the server expects those fields. The headers are more likely the problem - especially suspect is the `content-type: multipart/form-data` header which requires that the body of the request be formatted a particular way. – mhawke Nov 01 '17 at 22:53
  • @nvachhan: are you using a public API or is it something custom? – mhawke Nov 01 '17 at 22:53
  • @nvachhan: anyway. I think that I have answered your original question, so you might consider accepting it. – mhawke Nov 01 '17 at 23:27
  • It is something custom, not a public API. I modified to what you said and got the following result printed "401 Unauthorized" – nvachhan Nov 02 '17 at 13:03