How to write curl --form using python requests - python

I want to translate this curl command to python and I am having issue to write form properly:
"https://gitlab.example.com/api/v4/projects/1/variables/NEW_VARIABLE" --form "value=updated value"
I tried :
files = {'file': ('somename.csv', 'value=updated value')}
and
files = {}
files['value'] = 'updated value'
and
files = dict(value=value_to_update)
The whole example:
url = 'https://gitlab.com/api/v4/projects/1/variables/bla?filter[environment_scope]=production'
headers = {
'content-type': 'application/json',
'PRIVATE-TOKEN': '<token>'
}
files = dict(value=value_to_update)
x = requests.put(url, headers=headers, files=files)
Solved: This is how whole request in python using requests should look like
```
headers = {
'PRIVATE-TOKEN': '<token>',
}
files = {
'value': (None, 'update value'),
}
response = requests.put('https://gitlab.com/api/v4/projects/1/variables/variableKey', headers=headers, files=files)

this is the conversion to python requests:
import requests
files = {
'value': (None, 'updated value'),
}
response = requests.post('https://gitlab.example.com/api/v4/projects/1/variables/NEW_VARIABLE', files=files)

Related

python requests not recognizing params

I am requesting to mindbodyapi to get token with the following code using requests library
def get_staff_token(request):
URL = "https://api.mindbodyonline.com/public/v6/usertoken/issue"
payload = {
'Api-Key': API_KEY,
'SiteId': "1111111",
'Username': 'user#xyz.com',
'Password': 'xxxxxxxx',
}
r = requests.post(url=URL, params=payload)
print(r.text)
return HttpResponse('Done')
gives a response as follows
{"Error":{"Message":"Missing API key","Code":"DeniedAccess"}}
But if I request the following way it works, anybody could tell me, what I am doing wrong on the above code.
conn = http.client.HTTPSConnection("api.mindbodyonline.com")
payload = "{\r\n\t\"Username\": \"username\",\r\n\t\"Password\": \"xxxxx\"\r\n}"
headers = {
'Content-Type': "application/json",
'Api-Key': API_KEY,
'SiteId': site_id,
}
conn.request("POST", "/public/v6/usertoken/issue", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
In the second one, you are passing the API Key in headers and the credentials in the body of the request. In the first, you are sending both the API Key and credentials together in the query string, not the request body. Refer to requests.request() docs
Just use two dictionaries like in your second code and the correct keywords, I think it should work:
def get_staff_token(request):
URL = "https://api.mindbodyonline.com/public/v6/usertoken/issue"
payload = {
'Username': 'user#xyz.com',
'Password': 'xxxxxxxx',
}
headers = {
'Content-Type': "application/json",
'Api-Key': API_KEY,
'SiteId': "1111111",
}
r = requests.post(url=URL, data=payload, headers=headers)
print(r.text)
return HttpResponse('Done')

Trying to retrieve data from the Anbima API

I'm trying to automate a process in which i have to download some brazilian fund quotes from Anbima (Brazil regulator). I have been able to work around the first steps to retrieve the access token but i don't know how to use the token in order to make requests. Here is the tutorial website https://developers.anbima.com.br/en/como-acessar-nossas-apis/.
I have tried a lot of thing but all i get from the request is 'Could not find a required APP in the request, identified by HEADER client_id.'
If someone could share some light. Thank you in advance.
import requests
import base64
import json
requests.get("https://api.anbima.com.br/feed/fundos/v1/fundos")
ClientID = '2Xy1ey11****'
ClientSecret = 'faStF1Hc****'
codeString = ClientID + ":" + ClientSecret
codeStringBytes = codeString.encode('ascii')
base64CodeBytes = base64.b64encode(codeStringBytes)
base64CodeString = base64CodeBytes.decode('ascii')
url = "https://api.anbima.com.br/oauth/access-token"
headers = {
'content-type': 'application/json'
,'authorization': f'Basic {base64CodeString}'
}
body = {
"grant_type": "client_credentials"
}
r = requests.post(url=url, data=json.dumps(body), headers=headers, allow_redirects=True)
jsonDict = r.json()
##################
urlFundos = "https://api-sandbox.anbima.com.br/feed/precos-indices/v1/titulos-publicos/mercado-secundario-TPF"
token = jsonDict['access_token']
headers2 = {
'content-type': 'application/json'
,'authorization': f'Bearer {token}'
}
r2 = requests.get(url=urlFundos, headers=headers2)
r2.status_code
r2.text
I was having the same problem, but today I could advance. I believe you need to adjust some parameters in the header.
Follows the piece of code I developed.
from bs4 import BeautifulSoup
import requests
PRODUCTION_URL = 'https://api.anbima.com.br'
SANDBOX_URL = 'https://api-sandbox.anbima.com.br'
API_URL = '/feed/fundos/v1/fundos/'
CODIGO_FUNDO = '594733'
PRODUCTION = False
if PRODUCTION:
URL = PRODUCTION_URL
else:
URL = SANDBOX_URL
URL = URL + API_URL + CODIGO_FUNDO
HEADER = {'access_token': 'your token',
'client_id' : 'your client ID'}
html = requests.get(URL, headers=HEADER).content
soup = BeautifulSoup(html, 'html.parser')
print(soup.prettify())
The sandbox API will return a dummy JSON. To access the production API you will need to request access (I'm trying to do this just now).
url = 'https://api.anbima.com.br/oauth/access-token'
http = 'https://api-sandbox.anbima.com.br/feed/precos-indices/v1/titulos-publicos/pu-intradiario'
client_id = "oLRa*******"
client_secret = "6U2nefG*****"
client_credentials = "oLRa*******:6U2nefG*****"
client_credentials = client_credentials.encode('ascii')
senhabytes = base64.b64encode(client_credentials)
senha = base64.b64decode(senhabytes)
print(senhabytes, senha)
body = {
"grant_type": "client_credentials"
}
headers = {
'content-type': 'application/json',
'Authorization': 'Basic b0xSYTJFSUlOMWR*********************'
}
request = requests.post(url, headers=headers, json=body, allow_redirects=True)
informacoes = request.json()
token = informacoes['access_token']
headers2 = {
"content-type": "application/json",
"client_id": f"{client_id}",
"access_token": f"{token}"
}
titulos = requests.get(http, headers=headers2)
titulos = fundos.json()
I used your code as a model, then I've made some changes. I've printed the encode client_id:client_secret and then I've copied and pasted in the headers.
I've changed the data for json.

Hubspot API Not Populating Deal

When I'm trying to create a deal through the hubspot api, all that is being created is a completely blank deal even though I am passing through populated data
Api Url: https://developers.hubspot.com/docs/api/crm/deals
Here is the following code that I am trying:
import json
import requests
hubspot_api_key = "MY_API_KEY"
url = 'https://api.hubapi.com/crm/v3/objects/deals?hapikey={}'.format(hubspot_api_key)
headers = {"Content-Type": "application/json"}
deals_post = {
'amount': "4034.75",
'closedate': '2021-05-10T12:04:00.000Z',
'dealname': 'Custom data integrations',
'dealstage': 'closedwon',
'hubspot_owner_id': "5448459615",
'pipeline': 'default'
}
response = requests.post(url, headers=headers, data=json.dumps(deals_post))
print(response.text)
And here is the result of it:
The solution to this issue would be adding properties to the data dictionary
import json
import requests
hubspot_api_key = "MY_API_KEY"
url = 'https://api.hubapi.com/crm/v3/objects/deals?hapikey={}'.format(hubspot_api_key)
headers = {"Content-Type": "application/json"}
deals_post = {
'properties': {
'amount': "4034.75",
'closedate': '2021-05-10T12:04:00.000Z',
'dealname': 'Custom data integrations',
'dealstage': 'closedwon',
'hubspot_owner_id': 83849850,
'pipeline': 'default'
}
}
response = requests.post(url, headers=headers, data=json.dumps(deals_post))
print(response.text)
This results in a filled out deal according to the data that was passed in

How to upload PDF file using request POST method and requests must be formatted as multipart MIME using python for xeroAPI?

I'm trying to upload PDF-file in the Xero account using the python request library (POST method) and Xeros FilesAPI said "Requests must be formatted as multipart MIME" and have some required fields (link) but I don't how to do that exactly...If I do GET-request I'm getting the list of files in the Xero account but having a problem while posting the file (POST-request)...
My Code:
post_url = 'https://api.xero.com/files.xro/1.0/Files/'
files = {'file': open('/home/mobin/PycharmProjects/s3toxero/data/in_test_upload.pdf', 'rb')}
response = requests.post(
post_url,
headers={
'Authorization': 'Bearer ' + new_tokens[0],
'Xero-tenant-id': xero_tenant_id,
'Accept': 'application/json',
'Content-type': 'multipart/form-data; boundary=JLQPFBPUP0',
'Content-Length': '1068',
},
files=files,
)
json_response = response.json()
print(f'Uploading Responsoe ==> {json_response}')
print(f'Uploading Responsoe ==> {response}')
Error Mesage/Response:
Uploading Responsoe ==> [{'type': 'Validation', 'title': 'Validation failure', 'detail': 'No file is was attached'}]
Uploading Responsoe ==> <Response [400]>
As I see you're improperly set the boundary. You set it in the headers but not tell to requests library to use custom boundary. Let me show you an example:
>>> import requests
>>> post_url = 'https://api.xero.com/files.xro/1.0/Files/'
>>> files = {'file': open('/tmp/test.txt', 'rb')}
>>> headers = {
... 'Authorization': 'Bearer secret',
... 'Xero-tenant-id': '42',
... 'Accept': 'application/json',
... 'Content-type': 'multipart/form-data; boundary=JLQPFBPUP0',
... 'Content-Length': '1068',
... }
>>> print(requests.Request('POST', post_url, files=files, headers=headers).prepare().body.decode('utf8'))
--f3e21ca5e554dd96430f07bb7a0d0e77
Content-Disposition: form-data; name="file"; filename="test.txt"
--f3e21ca5e554dd96430f07bb7a0d0e77--
As you can see the real boundary (f3e21ca5e554dd96430f07bb7a0d0e77) is different from what was passed in the header (JLQPFBPUP0).
You can actually directly use the requests module to controll boundary like this:
Let's prepare a test file:
$ touch /tmp/test.txt
$ echo 'Hello, World!' > /tmp/test.txt
Test it:
>>> import requests
>>> post_url = 'https://api.xero.com/files.xro/1.0/Files/'
>>> files = {'file': open('/tmp/test.txt', 'rb')}
>>> headers = {
... 'Authorization': 'Bearer secret',
... 'Xero-tenant-id': '42',
... 'Accept': 'application/json',
... 'Content-Length': '1068',
... }
>>> body, content_type = requests.models.RequestEncodingMixin._encode_files(files, {})
>>> headers['Content-type'] = content_type
>>> print(requests.Request('POST', post_url, data=body, headers=headers).prepare().body.decode('utf8'))
--db57d23ff5dee7dc8dbab418e4bcb6dc
Content-Disposition: form-data; name="file"; filename="test.txt"
Hello, World!
--db57d23ff5dee7dc8dbab418e4bcb6dc--
>>> headers['Content-type']
'multipart/form-data; boundary=db57d23ff5dee7dc8dbab418e4bcb6dc'
Here boundary is the same as in the header.
Another alternative is using requests-toolbelt; below example taken from this GitHub issue thread:
from requests_toolbelt import MultipartEncoder
fields = {
# your multipart form fields
}
m = MultipartEncoder(fields, boundary='my_super_custom_header')
r = requests.post(url, headers={'Content-Type': m.content_type}, data=m.to_string())
But it is better not to pass bundary by hand at all and entrust this work to the requests library.
Update:
A minimal working example using Xero Files API and Python request:
from os.path import abspath
import requests
access_token = 'secret'
tenant_id = 'secret'
filename = abspath('./example.png')
post_url = 'https://api.xero.com/files.xro/1.0/Files'
files = {'filename': open(filename, 'rb')}
values = {'name': 'Xero'}
headers = {
'Authorization': f'Bearer {access_token}',
'Xero-tenant-id': f'{tenant_id}',
'Accept': 'application/json',
}
response = requests.post(
post_url,
headers=headers,
files=files,
data=values
)
assert response.status_code == 201
I've tested this with Xero's Files API to upload a file called "helloworld.rtf" in the same directory as my main app.py file.
var1 = "Bearer "
var2 = YOUR_ACCESS_TOKEN
access_token_header = var1 + var2
body = open('helloworld.rtf', 'rb')
mp_encoder = MultipartEncoder(
fields={
'helloworld.rtf': ('helloworld.rtf', body),
}
)
r = requests.post(
'https://api.xero.com/files.xro/1.0/Files',
data=mp_encoder, # The MultipartEncoder is posted as data
# The MultipartEncoder provides the content-type header with the boundary:
headers={
'Content-Type': mp_encoder.content_type,
'xero-tenant-id': YOUR_XERO_TENANT_ID,
'Authorization': access_token_header
}
)
looks like you got it solved. For reference and any future developers who are using the Xero supported package (https://github.com/XeroAPI/xero-python)
We just added the files_api example code to the sample app so the following would upload a file if you were using the Python SDK
https://github.com/XeroAPI/xero-python-oauth2-app/pull/29/files
name = "my-image"
filename= "my-image.jpg"
mime_type = "image/jpg"
with open('my-image.jpg', 'rb') as f:
body = f.read()
try:
file_object = files_api.upload_file(
xero_tenant_id,
name = name,
filename= filename,
mime_type = mime_type,
body=body
)
except AccountingBadRequestException as exception:
json = jsonify(exception.error_data)
else:
json = serialize_model(file_object)

How to convert http request to Python?

I need your help.
I am looking to communicate with a REST API containing sensor data at port number 3.
I have a Json (POST) request that works perfectly executed on a REST client like Insomnia.
My request :
{ "header": { "portNumber": 3 }, "data": { "index": 40 } }
Picture of my request
However I am unable to make it work on Python and to recover data from my sensor.
My Python code :
import requests
import json
url = 'http://192.168.1.100/iolink/sickv1' # Address of the OctoPrint Server
header = {'portNumber': '3', 'Content-Type': 'application/json'} #Basic request's header
data = {'index': 40}
def get_sensor_measure():
r = requests.post(url + '/readPort', headers=header, data=data)
print(r.content)
print(r.status_code)
I get the error:
b'{"header":{"status":1,"message":"Parsing Failed"}}'
Thank you in advance
You should pass 'portNumber': '3' in data not in header:
header = {'Content-Type': 'application/json'}
data = {'header': {'portNumber': '3'}, 'data': {'index': 40}}
And also as Karl stated in his answer you need to changes data to json:
r = requests.post(url + '/readPort', headers=header, json=data)
My guess would be that you are using the wrong field to pass your payload. It isn't really obvious, but the requests package expects JSON-type payload to be sent with the json field, not the data field, i.e.:
r = requests.post(url + '/readPort', headers=header, json=data)
With a few changes (Bold), it works. Thanks
url = 'http://192.168.1.100/iolink/sickv1' # Address of the OctoPrint Server
header = {'Content-Type': 'application/json'} #Basic request's header
**data = {'header': {'portNumber': 3}, 'data': {'index': 40}}**
def get_sensor_measure():
r = requests.post(url + '/readPort', headers=header, json=data)
print(r.content)
print(r.status_code)

Categories

Resources