send payload in requests python - python

How to transfer payload as a string in requests python?
my code:
def send():
url = "url"
cookies = {
"csrf_token":"",
"refresh_token":"",
"access_token":""
}
data = "id%5B%5D=52626995&id%5B%5D=52627067&result_element%5BNAME%5D=%D0%90%D1%80%D0%BA%D0%B0%D0%B4%D0%B8%D0%B9&result_element%5BMAIN_USER_ID%5D=8272126&result_element%5BTAGS%5D%5B%5D=559091&result_element%5BTAGS%5D%5B%5D=559091&result_element%5Bcfv%5D%5B664393%5D%5B%5D=%7B%22DESCRIPTION%22%3A%22WORK%22%2C%22VALUE%22%3A%2271111111111%22%7D&result_element%5Bcfv%5D%5B664393%5D%5B%5D=%7B%22DESCRIPTION%22%3A%22WORK%22%2C%22VALUE%22%3A%2271111111111%22%7D&result_element%5Bcfv%5D%5B1262415%5D=12&result_element%5Bcfv%5D%5B1256527%5D=3&result_element%5Bcfv%5D%5B1272573%5D=817683&result_element%5BLEADS%5D%5B%5D=36375665&result_element%5BID%5D=52627067"
resp = requests.post(url=url, cookies=cookies, data=data)
return resp
But i got error cause data must be dict

They are right. It has to be a dictionary. The data you have here is also an encoded dictionary. Using (https://www.url-encode-decode.com/) you can understand your data better.
id[]=52626995
id[]=52627067
result_element[NAME]=Аркадий
result_element[MAIN_USER_ID]=8272126
result_element[TAGS][]=559091
result_element[TAGS][]=559091
result_element[cfv][664393][]={"DESCRIPTION":"WORK","VALUE":"71111111111"}
result_element[cfv][664393][]={"DESCRIPTION":"WORK","VALUE":"71111111111"}
result_element[cfv][1262415]=12
result_element[cfv][1256527]=3
result_element[cfv][1272573]=817683
result_element[LEADS][]=36375665
result_element[ID]=52627067
As a normal python dictionary, this is the following
{
"id": [52626995, 52627067],
"result_element": {
"NAME": "Аркадий",
"MAIN_USER_ID": 8272126,
"TAGS": [559091, 559091],
"cfv": {
664393: [
{"DESCRIPTION":"WORK","VALUE":"71111111111"},
{"DESCRIPTION":"WORK","VALUE":"71111111111"}],
1262415: 12,
1256527: 3,
1272573: 817683,
},
"LEADS": [36375665],
"ID": 52627067
}
}
So if you have the following code, it should work:
url = "url"
cookies = {
"csrf_token":"",
"refresh_token":"",
"access_token":""
}
data = {"id": [52626995, 52627067],
"result_element": {
"NAME": "Аркадий",
"MAIN_USER_ID": 8272126,
"TAGS": [559091, 559091],
"cfv": {
664393: [
{"DESCRIPTION":"WORK","VALUE":"71111111111"},
{"DESCRIPTION":"WORK","VALUE":"71111111111"}],
1262415: 12,
1256527: 3,
1272573: 817683,
},
"LEADS": [36375665],
"ID": 52627067
}
}
resp = requests.post(url=url, cookies=cookies, data=data)
return resp
I did it manually. First, check whether I have correctly parsed your string.

Check out the requests documentation
data – (optional) Dictionary, list of tuples, bytes, or file-like object to send in the body of the Request.
So only thing you need is to encode your string to bytes:
resp = requests.post(url=url, cookies=cookies, data=data.encode())
The more detailed explanation is that strings in Python 3 are abstract representation of the characters you see. You can use Czech letter "Ř" in Python regardless what encoding is used to represent the characters as bytes in the computer memory.
However, to send it over internet, you have to send it encoded as bytes.
If you would like to get those bytes, you have to specify the encoding that converts characters to bytes representing them. For Czech, the most appropriate is UTF-8 (as for almost anything) or maybe Windows-1250 aka CP-1250:
>>> x = "Ř"
>>> x
'Ř'
>>> x.encode("utf-8")
b'\xc5\x98'
>>> x.encode("cp1250")
b'\xd8'
Plain str.encode without encoding specified uses UTF-8, probably the best choice:
>>> x.encode()
b'\xc5\x98'

Related

Swift: Incorrect Base64 Encoding

I am attempting to convert a block of code from python and it involved encoding a json string to base64. My attempt on Swift does not produce the same base64 encoded string.
Python:
payload_nonce = datetime.datetime(2022, 10, 10, 0, 0, 0).timestamp()
payload = {"request": "/v1/mytrades", "nonce": payload_nonce}
encoded_payload = json.dumps(payload).encode()
b64 = base64.b64encode(encoded_payload)
print(b64)
//prints b'eyJyZXF1ZXN0IjogIi92MS9teXRyYWRlcyIsICJub25jZSI6IDE2NjUzMzEyMDAuMH0='
Swift:
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy"
let date = formatter.date(from: "10/10/2022")
let payloadNonce = date!.timeIntervalSince1970
payload = [
"request": "/v1/mytrades",
"nonce": String(describing: payloadNonce)
]
do {
let json = try JSONSerialization.data(withJSONObject: payload)
let b64 = json.base64EncodedString()
print(b64)
//prints eyJyZXF1ZXN0IjoiXC92MVwvbXl0cmFkZXMiLCJub25jZSI6IjE2NjUzMzEyMDAuMCJ9
} catch {//handle error}
What am I missing?
Decoding the Python payload:
{"request": "/v1/mytrades", "nonce": 1665331200.0}
Decoding the Swift payload:
{"request":"\/v1\/mytrades","nonce":"1665331200.0"}
Firstly, it's clear the payloads are different.
You're using the String(describing:) initializer in Swift so nonce is being converted to a String rather than the raw floating-point value.
Secondly, JSONSerialization.data is escaping the forward slashes automatically when encoding. We can disable this optionally.
Now, other than the space between the keys in Python, the two outputs are the same.
Fixed example:
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy"
let date = formatter.date(from: "10/10/2022")
let payloadNonce = date!.timeIntervalSince1970
let payload: [String: Any] = [
"request": "/v1/mytrades",
"nonce": payloadNonce
]
do {
let json = try JSONSerialization.data(withJSONObject: payload, options: .withoutEscapingSlashes)
print(String(data: json, encoding: .utf8)!)
let b64 = json.base64EncodedString()
print(b64)
} catch {
}
When I decode the base64 strings, I get this for the Python code:
echo "eyJyZXF1ZXN0IjogIi92MS9teXRyYWRlcyIsICJub25jZSI6IDE2NjUzMzEyMDAuMH0=" | base64 -d
{"request": "/v1/mytrades", "nonce": 1665331200.0}
And this for the Swift code:
echo "eyJyZXF1ZXN0IjoiXC92MVwvbXl0cmFkZXMiLCJub25jZSI6IjE2NjUzMzEyMDAuMCJ9" | base64 -d
{"request":"\/v1\/mytrades","nonce":"1665331200.0"}
It appears that the slashes in the Swift code are escaped. To fix that, see this Stack Overflow answer: Swift String escaping when serializing to JSON using Codable.
The nonce is also a float in the Python response and a string in the Swift response.

Extracting specific JSON values in python

JSON return from spotify api. Example:
{
"tracks": {
"href": "https://api.spotify.com/v1/search?query=Stero+Hearts&type=track&offset=0&limit=1",
"items": [
{
"album": {
"album_type": "album",
"artists": [
{
"external_urls": {
"spotify": "https://open.spotify.com/artist/4IJczjB0fJ04gs4uvP0Fli"
},
"href": "https://api.spotify.com/v1/artists/4IJczjB0fJ04gs4uvP0Fli",
"id": "4IJczjB0fJ04gs4uvP0Fli",
"name": "Gym Class Heroes",
"type": "artist",
"uri": "spotify:artist:4IJczjB0fJ04gs4uvP0Fli"
}
]
}
}
]
}
}
Broken Code
import requests, json
spotifytrack = input("Name of Song?\\n")
link = "https://api.spotify.com/v1/search?q=" + spotifytrack + "&type=track&limit=1"
token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
header = {
"Authorization": "Bearer {}".format(token),
"Content-Type": "application/json",
"Accept": "application/json",
}
auth_response = requests.get(link, headers=header)
pretty_response = json.dumps(auth_response.json(), indent=4)
data_by_user = {}
for d in auth_response:
data_by_user[d["artist"]] = d
print(data_by_user["uri"])
"""
def find_track_from_json(auth_response, artist):
return [p for p in auth_response if p["artist"] == artist][0]["uri"]
urii = find_track_from_json(auth_response, "uri")
print(urii)
x = load.json(auth_response.json())
print("Here is the data whic we have imported\n")
print(pretty_response)
print(x["name"])
print(x["uri"])
print(x["spotify"])
"""
Errors noticed:
File "spotify.py", line 19, in <module>
data_by_user[d["artist"]] = d
TypeError: byte indices must be integers or slices, not str
The aim is to convert word search to link in a cli application.
I tried load.json which i saw in some website and also tried def.
I expected the program to find out the artist name and uri from the json and print it in the cli interface.
You are iterating over the encoded json string:
auth_response = requests.get(link, headers=header)
for d in auth_response:
Python is complaining that you aren't providing a numerical index, which is correct as auth_response is just a string!
You should call json.loads to decode the string, and then you can iterate over it.
auth_response = requests.get(link, headers=header)
decoded_auth_response = json.loads(auth_response)
data_by_user = {}
for d in decoded_auth_response:
data_by_user[d["artist"]] = d
As you haven't provided the full json output from the API call I'm not sure what data is actually in decoded_auth_response, and you haven't described what your expected output would look like, so you may need to do some more work to find the correct data in each iteration.
The result from requests.get() is a requests.Response object. As far as I can see you want to iterate over the response body which is JSON. The requests.Response object has a .json() method which returns a dict from the response JSON.
Looking at the response you would probably want to iterate over resp_json['tracks']['items'] which is a list.
So to summarize your code should look something like this:
auth_response = requests.get(link, headers=header)
items = auth_response.json()['tracks']['items']
for d in items:
print(d)

Transforming queries in a URL

I'm trying to use a REST API apparently constructed with LoopBack and it requires that my filter parameters be encoded in a specific way.
What is this sort of transformation called?
# this is a JSON type encoding
...?filter={"where": {"StartDate": {"gte": "2021-01-01T00:00:00.000Z"}}, "offset": 0, "limit": 100, "order": "id DESC" }
which needs to be encoded as some sort of HTTP query string
...?filter=%7B%22where%22%3A%20%7B%22StartDate%22%3A%20%7B%22gte%22%3A%20%222021-06-01T00%3A00%3A00.000Z%22%7D%7D%2C%20%22offset%22%3A%200%2C%20%22limit%22%3A%20100%2C%20%22order%22%3A%20%22id%20DESC%22%20%7D
Is there a python function to do this?
This is URL encoding.
URLs cannot contain a lot of different special characters, such as spaces (a space would be %20 in URL encoding).
Note that URL encoding is quite easy to recognize once you know it exists, due to the %xx pattern.
The urllib has functions to deal with encoding/decoding this.
To create an URL encoded string use urllib.parse.quote(string). Relevant docs here...
Example
from urllib.parse import quote
jsonstring = '{"where": {"StartDate": {"gte": "2021-01-01T00:00:00.000Z"}}, "offset": 0, "limit": 100, "order": "id DESC" }'
urlencoded = quote(jsonstring)
print(urlencoded)
# output
# %7B%22where%22%3A%20%7B%22StartDate%22%3A%20%7B%22gte%22%3A%20%222021-01-01T00%3A00%3A00.000Z%22%7D%7D%2C%20%22offset%22%3A%200%2C%20%22limit%22%3A%20100%2C%20%22order%22%3A%20%22id%20DESC%22%20%7D
You are looking for URL encoding. If you already have the JSON encoded in a variable as such, then just encode it to the filter parameter:
from urllib.parse import urlencode, quote
base_url = "..."
filter_string = """{"where": {"StartDate": {"gte": "2021-01-01T00:00:00.000Z"}}, "offset": 0, "limit": 100, "order": "id DESC" }"""
query = urlencode({"filter": filter_string}, quote_via=quote)
url = f"{base_url}?{query}"
Now, I expect that the JSON is probably coming from a Python data structure. You can use the dumps function from json to handle that encoding:
from urllib.parse import urlencode, quote
import json
base_url = "..."
data = {
"where": {
"StartDate": {
"gte": "2021-01-01T00:00:00.000Z"
}
},
"offset": 0,
"limit": 100,
"order": "id DESC"
}
filter_string = json.dumps(data)
query = urlencode({"filter": filter_string}, quote_via=quote)
url = f"{base_url}?{query}"
And you have the URL to call to in the variable url.

How to add Panda 'to_json' output to a rest call

I have the following JSON data:
x = df.to_json(orient='records')
print(x)
[{"val":"3760","id":"204","quantity":2},{"val":"8221","id":"220","quantity":8}]
I want to add the data to my REST call, but it results in the following string in the payload (note: the single quotes around the square bracket:
'updateVals': '[{"val":"3760","id":"204","quantity":2},{"val":"8221","id":"220","quantity":8}]'}}
The fact that the JASON values are listed as one big string, the REST call results in an HTTP 400 error.
The code is:
url = 'my_url'
payload = {
'client_id': 'my_id',
'api_key': 'my_key',
"data": {
"uuid": "myUUID",
"timeStamp": "2018-09-12T06:17:48+00:00",
"updateVals": x
}
}
How do I plug the JSON into the REST call? I assume I have to split the string, or maybe there is a more straightforward answer?
Still not sure what you need, JSON is really one big string:
x = [{"val":"3760","id":"204","quantity":2},
{"val":"8221","id":"220","quantity":8}]
>>> json.dumps(x)
>>> '[{"val": "3760", "id": "204", "quantity": 2}, {"val": "8221", "id": "220", "quantity": 8}]'

Convert Python dictionary to a JSON array

Here's my function which connects to an API:
def order_summary():
"""Get order summary for a specific order"""
# Oauth2 params
headerKey = api_login()
headers = {'Authorization': headerKey}
# Payload params
payloadOrderSum = {
"domainId": 15,
"domainName": "SGL",
"orderId": 3018361
}
# API response
orderSumResp = requests.post(url + "order/summary", data=payloadOrderSum, headers=headers)
print(orderSumResp.content)
The API expects a JSON array as Payload Params which essentially looks like that:
[
{
"domainId": 0,
"domainName": "string",
"orderId": 0
}
]
The other endpoints I coded for on this API didn't need for the params to be an array so I could just use them as is and send them as a dictionary and it worked.
I've tried a couple things using the JSON library but I can't seem to get it to work. I saw that the JSonEncoder converts lists and tuples to JSON arrays but I couldn't figure it out.
Not sure what other info I could provide but just ask if there are any.
Thanks!
Wrap payloadOrderSum into a list:
payloadOrderSum = {
"domainId": 15,
"domainName": "SGL",
"orderId": 3018361
}
orderSumResp = requests.post(url + "order/summary", json=[payloadOrderSum], headers=headers)
Note that I used json kwarg instead of data (added in version 2.4.2).
dump your dict with json.dumps requests-doc
r = requests.post(url, data=json.dumps(payload))
It could help if you specify what you tried with the JSON library.
However, you might wanna try this if you haven't already done so:
import json
payloadOrderSum = json.dumps(
{
"domainId": 15,
"domainName": "SGL",
"orderId": 3018361
}
)

Categories

Resources