How do I send a POST request as a JSON?
Asked Answered
T

9

127
data = {
        'ids': [12, 3, 4, 5, 6 , ...]
    }
    urllib2.urlopen("http://abc.example/api/posts/create",urllib.urlencode(data))

I want to send a POST request, but one of the fields should be a list of numbers. How can I do that? (JSON?)

Tva answered 17/3, 2012 at 0:53 Comment(5)
Isn't that already a list of numbers, though?Inquisition
This can't be answered without knowing what kind of input the API expects.Yu
@WaynnLue the API server is getting that as a string, not a list.Tva
Do I have to set headers as "application/json" or something?Tva
Related: Python 3 urlopen context manager mockingGahl
C
160

If your server is expecting the POST request to be json, then you would need to add a header, and also serialize the data for your request...

Python 2.x

import json
import urllib2

data = {
        'ids': [12, 3, 4, 5, 6]
}

req = urllib2.Request('http://example.com/api/posts/create')
req.add_header('Content-Type', 'application/json')

response = urllib2.urlopen(req, json.dumps(data))

Python 3.x

https://mcmap.net/q/174164/-how-do-i-send-a-post-request-as-a-json


If you don't specify the header, it will be the default application/x-www-form-urlencoded type.

Curtice answered 17/3, 2012 at 1:19 Comment(11)
I have a question. is it possible to add multiple items in the header... like content type & client-id... @CurticeBanlieue
@OmarJandali, just call add_header() again, for each header you want to add.Curtice
i have the following coded but it is not printing anything. it was supposed to print the url and headers but nothing was printed... req = urllib.Request('http://uat-api.synapsefi.com') req.add_header('X-SP-GATEWAY', 'client_id_asdfeavea561va9685e1gre5ara|client_secret_4651av5sa1edgvawegv1a6we1v5a6s51gv') req.add_header('X-SP-USER-IP', '127.0.0.1') req.add_header('X-SP-USER', '| ge85a41v8e16v1a618gea164g65') req.add_header('Content-Type', 'application/json') print(req)...Banlieue
urllib2 was not recognized so i just used urllib. i am also getting an error with the request. The view tab.views.profileSetup didn't return an HttpResponse object. It returned None instead. @CurticeBanlieue
@OmarJandali, please keep in mind that this answer was originally given in 2012, under python 2.x. You are using Python3 so the imports will be different. It would now be import urllib.request and urllib.request.Request(). Furthermore, printing the req object does nothing interesting. You can clearly see the headers have been added by printing req.headers. Beyond that, I am not sur why it isn't working in your application.Curtice
So i have two lines that i made changes to response = urllib.request.Request(req, json.dumps(data)) and req = urllib.request.Request('http://uat-api.synapsefi.com'). i am getting a message saying unknown url type: 'urllib.request.Request object at 0x00000250B05474A8' from the second line that i made changes to... what is the way fro me to change the url type @CurticeBanlieue
@OmarJandali, you aren't calling urlopen() like the original example. That is why you are getting an error. See: pastebin.com/1gUdGYcPCurtice
Let us continue this discussion in chat.Banlieue
Than you so much, it is working and sending a response. it is sending a response in the wrong format POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str.Banlieue
The python3 version is the one here: https://mcmap.net/q/174164/-how-do-i-send-a-post-request-as-a-json – better merge it with the accepted answerHorseshoe
@Kuzeko, thanks. I have added that reference to my answerCurtice
W
121

I recommend using the incredible requests module.

http://docs.python-requests.org/en/v0.10.7/user/quickstart/#custom-headers

url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}

response = requests.post(url, data=json.dumps(payload), headers=headers)
Williswillison answered 17/3, 2012 at 1:33 Comment(2)
This gives me TypeError: post() takes from 1 to 2 positional arguments but 3 were givenLamarckism
It is much more succinct to just use json=payload (which may have been introduced since this answer was written long ago) without specifying the header or calling json.dumps(). See other answers on this page.Sharlenesharline
P
94

For python 3.4.2, I found the following will work:

import urllib.request
import json

body = {'ids': [12, 14, 50]}
myurl = "http://www.testmycode.example"

req = urllib.request.Request(myurl)
req.add_header('Content-Type', 'application/json; charset=utf-8')
jsondata = json.dumps(body)
jsondataasbytes = jsondata.encode('utf-8')   # needs to be bytes
req.add_header('Content-Length', len(jsondataasbytes))
response = urllib.request.urlopen(req, jsondataasbytes)
Praetorian answered 11/11, 2014 at 23:7 Comment(2)
Python3.6.2 this worked. Only adding header with req.add_header(...) worked for me.Steapsin
You do not need to specify the Content-Length header, it will be calculated by urllib automatically.Sharlenesharline
K
20

This works perfect for Python 3.5, if the URL contains Query String / Parameter value,

Request URL = https://bah2.example/ws/rest/v1/concept/ Parameter value = 21f6bb43-98a1-419d-8f0c-8133669e40ca

import requests

url = 'https://bahbah2.example/ws/rest/v1/concept/21f6bb43-98a1-419d-8f0c-8133669e40ca'
data = {"name": "Value"}
r = requests.post(url, auth=('username', 'password'), json=data)
print(r.status_code)
Kanya answered 13/10, 2016 at 9:34 Comment(3)
in your code snipper, headers variable stays unusedYeargain
This answer is insecure. Do not pass verify=False, which disables certificate validation and opens your code up to man-the-middle attacks.Sharlenesharline
I removed verify=False from the code sample to resolve the above comment.Sharlenesharline
S
14

Here is an example of how to use urllib.request object from Python standard library.

import urllib.request
import json
from pprint import pprint

url = "https://app.close.com/hackwithus/3d63efa04a08a9e0/"

values = {
    "first_name": "Vlad",
    "last_name": "Bezden",
    "urls": [
        "https://twitter.com/VladBezden",
        "https://github.com/vlad-bezden",
    ],
}


headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
}

data = json.dumps(values).encode("utf-8")
pprint(data)

try:
    req = urllib.request.Request(url, data, headers)
    with urllib.request.urlopen(req) as f:
        res = f.read()
    pprint(res.decode())
except Exception as e:
    pprint(e)
Subjectivism answered 8/8, 2019 at 14:24 Comment(3)
works great using standard library urllib. Don't forget the data in Request(url, data, headers), otherwise it would look like a GET to the server.Talamantes
@ApurvaSingh Putting the data automatically creates a 'Content-Type', 'application/json; charset=utf-8' header, like in the other answer?Couscous
@Couscous turn on http connection debugging in Python code and check request headers in the output logTalamantes
S
4

You have to add header,or you will get http 400 error. The code works well on python2.6,centos5.4

code:

    import urllib2,json

    url = 'http://www.google.com/someservice'
    postdata = {'key':'value'}

    req = urllib2.Request(url)
    req.add_header('Content-Type','application/json')
    data = json.dumps(postdata)

    response = urllib2.urlopen(req,data)
Sealskin answered 24/2, 2014 at 13:56 Comment(1)
Note: This answer is very old and urllib2 has been removed in Python 3. Look for other examples using urllib or requests.Sharlenesharline
P
4

In the lastest requests package, you can use json parameter in requests.post() method to send a json dict, and the Content-Type in header will be set to application/json. There is no need to specify header explicitly.

import requests

payload = {'key': 'value'}
requests.post(url, json=payload)
Pegu answered 11/2, 2020 at 5:4 Comment(3)
Note that this will result in POSTed json with single quotes, which is technically invalid.Verdha
@Verdha Have you observed errors when using single quotes? It is valid to use single quotes in Python. Personally, I haven't met any issues regarding this.Pegu
Aah apologies I was mistaken, I thought my server was receiving single-quoted JSON but It turned out to be a separate issue and some misleading debugging. Cheers, this is much tidier than having to specify the header manually!Verdha
S
3

The Requests package used in many answers here is great but not necessary. You can perform a POST of JSON data succinctly with the Python 3 standard library in one step:

import json
from urllib import request

request.urlopen(request.Request(
    'https://example.com/url',
    headers={'Content-Type': 'application/json'},
    data=json.dumps({
        'pi': 3.14159
    }).encode()
))

If you need to read the result, you can .read() from the returned file-like object and use json.loads() to decode a JSON response.

Sharlenesharline answered 4/11, 2021 at 12:56 Comment(0)
Y
1

This one works fine for me with apis

import requests

data={'Id':id ,'name': name}
r = requests.post( url = 'https://apiurllink', data = data)
Yocum answered 11/2, 2020 at 8:0 Comment(1)
This is an incorrect answer. The data=data parameter sends a form-encoded request, which is not JSON. Use json=data instead.Sharlenesharline

© 2022 - 2024 — McMap. All rights reserved.