Trying to interact with an API - python

I'm in the process of moving learning how to interact with APIs in my programming training. The following script is used on the sandbox environment for a software I'm trying to interact with.
For some reason, I cannot login to the API to run the second function. Does anyone see the issue?
# import requests library
import requests
#import json library
import json
controller='apicontroller#test.com'
def getToken():
# put the ip address or dns of your apic-em controller in this url
url = "https://" + controller + "/api/aaaLogin.json"
json_object = {
"aaaUser" : {
"attributes" : {
"name" : "******",
"pwd" : "*******"
}
}
}
#Content type must be included in the header
header = {"content-type": "application/json"}
#Performs a POST on the specified url to get the service ticket
response= requests.post(url,data=json.dumps(json_object), headers=header, verify=False)
#convert response to json format
r_json=response.json()
#parse the json to get the service ticket
token = r_json["response"]["token"]
return token
def pushtenant():
# URL for network device REST API call to get list of existing devices on the network.
url = "https://" + controller + "/api/api/mo/uni"
#Content type must be included in the header as well as the ticket
headers = {"content-type": "application/json", "X-Auth-Token":Token}
json_tenant = [{
"fvTenant" : {
"attributes" : {
"name" : "ExampleCorp"
}
}
}]
# this statement performs a GET on the specified network-device url
response = requests.post(url, json.dumps(json_tenant), headers=headers,verify=False)
# json.dumps serializes the json into a string and allows us to
# print the response in a 'pretty' format with indentation etc.
print ("Response = ")
print (json.dumps(response.json(), indent=4, separators=(',', ': ')))
enter code here
#convert data to json format.
r_json=response.json()
theToken=getToken()
pushtenant(theToken)

Related

Connecting to an API endpoint to gather data with python

Hi I am trying to extract information from this API endpoint: https://graphql.icy.tools/graphql
Im trying to fetch the trending collections as shown here: https://docs.icy.tools/developer-api/common-use-cases/fetch-trending-collections
To do so Im just using this simple code:
import requests
import json
url = "https://graphql.icy.tools/graphql?query=TrendingCollections"
response= requests.get(url)
print(response.text)
However after running it I just get an error in form of a json.
Is this because the parameter TrendingCollections is not recognized by the API, if so does someone know whats the actual value that I need to use?
Thanks!
import json
import requests
# Define the endpoint URL
endpoint = "https://graphql.icy.tools/graphql"
# Define the query
query = """
query TrendingCollections {
trendingCollections(orderBy: SALES, orderDirection: DESC) {
edges {
node {
address
... on ERC721Contract {
name
stats {
totalSales
average
ceiling
floor
volume
}
symbol
}
}
}
}
}
"""
# Make the POST request to the endpoint
response = requests.post(endpoint, json={'query': query})
# Parse the JSON response
data = json.loads(response.text)
# Print the data
print(data)
This code made with python worked and retrieved all data!

Python requests PUT not updating data

I have a yaml file : file.yaml structured as follows :
index:
- uid: "uid"
name: "name"
headline: "headline"
overview: "overview"
features: "features"
instructions: "instructions"
callback_url: "https://some-url.com/params"
edit_url: "https://edit-url/params"
uninstall_hook: "https://uninstall-url/params"
svg:
screenshot1:
screenshot2:
screenshot3:
I have to upload those informations to an api endpoint by performing a PUT request. I managed to do it first using the register.py following script that I just run python register.py:
import json
import requests
from pathlib import Path
import base64
import yaml
BASE_URL = "https://url.com" # API Host
FILE_FOLDER = Path.cwd() # Current working directory
if __name__ == "__main__":
public_key = <public_key>
private_key = <private_key>
auth_key = "{}:{}".format(public_key, private_key).encode("utf-8")
encodedKey = base64.b64encode(auth_key).decode("utf-8")
headers = {"Authorization": f"Basic {encodedKey}", "Content-type": "application/json"}
def update_app_info():
infos_file = FILE_FOLDER / "file.yaml"
with open(infos_file) as infos_file_data:
yamlcontent = yaml.safe_load(infos_file_data) # Parse file.yaml and produce a dictionary of it
file_infos = yamlcontent["index"][0] # retrieve actual configuration informations
response = requests.put(
f"{BASE_URL}/path/to/api_endpoint/{public_key}", data=json.dumps(file_infos), headers=headers
)
print(response)
print(response.json())
update_app_info()
That gives a 202 success response.
As you may observe, I tried to get content of the yaml file as a dicitonary and send that in data. I proceeded that way regarding format of data at GET https://url.com/path/to/api_endpoint (mock example for illustration...) . Having the dictionary file_infos seemed more appropriate and gets me a success response. Sending directly the file itself or 'infos_file_data' gave me some errors I got over with the above script.
The issue is when I update svg, screenshot1, screenshot2 & screenshot3 so that file.yaml is now :
index:
- uid: "uid"
name: "name"
headline: "headline"
overview: "overview"
features: "features"
instructions: "instructions"
callback_url: "https://some-url.com/params"
edit_url: "https://edit-url/params"
uninstall_hook: "https://uninstall-url/params"
svg: "icon.svg"
screenshot1: "screenshot1.png"
screenshot2: "screenshot2.png"
screenshot3: "screenshot3.png"
That gives now :
<Response [400]>
{'error': {'message': {'svg': ['The submitted data was not a file. Check the encoding type on the form.'], 'screenshot1': ['The submitted data was not a file. Check the encoding type on the form.'], 'screenshot2': ['The submitted data was not a file. Check the encoding type on the form.'], 'screenshot3': ['The submitted data was not a file. Check the encoding type on the form.']}, 'code': 400}}
I've done multiple searches (1 , 2 , 3 , 4 , 5...) but their application and few other errors, eventually get me to this :
import base64
import json
from pathlib import Path
import requests
import yaml
from requests_toolbelt.multipart.encoder import MultipartEncoder
BASE_URL = "https://url.com" # API Host
FILE_FOLDER = Path.cwd() # Current working directory
if __name__ == "__main__":
public_key = <public_key>
private_key = <private_key>
auth_key = "{}:{}".format(public_key, private_key).encode("utf-8")
encodedKey = base64.b64encode(auth_key).decode("utf-8")
def update_app_info():
infos_file = FILE_FOLDER / "file.yaml"
with open(infos_file) as infos_file_data:
yamlcontent = yaml.safe_load(infos_file_data) # Parse file.yaml and produce a dictionary of it
file_infos = yamlcontent["index"][0] # retrieve actual configuration informations
m = MultipartEncoder(fields=file_infos)
#print(m.content_type)
headers = {
"Authorization": f"Basic {encodedKey}",
"Content-Type": m.content_type,
}
response = requests.put(
f"{BASE_URL}/path/to/api_endpoint/{public_key}",
data=json.dumps(file_infos),
headers=headers
)
print(response)
print(response.json())
update_app_info()
That is also giving me the 202 success response but the file svg, screenshot1, screenshot2 & screenshot3 fields are not updated.
I'll share more informations where needed. Your help is very welcome.
I've got additional resources that helped.
As I was trying to solve my issue, I found this. It happens I didn't wrote files part as it should, plus I was having data as a JSON string. That causes a ValueError: Data must not be a string. error. This was useful to get it fixed.
Now, for what it's worth, here's the working script :
import base64
from pathlib import Path
import requests
import yaml
BASE_URL = "https://url.com" # API Host
FILE_FOLDER = Path.cwd() # Current working directory
if __name__ == "__main__":
public_key = <public_key>
private_key = <private_key>
auth_key = "{}:{}".format(public_key, private_key).encode("utf-8")
encodedKey = base64.b64encode(auth_key).decode("utf-8")
def update_app_info():
infos_file = FILE_FOLDER / "file.yaml"
with open(infos_file) as infos_file_data:
yamlcontent = yaml.safe_load(infos_file_data) # Parse file.yaml and produce a dictionary of it
if "index" in yamlcontent:
file_infos = yamlcontent["index"][0] # retrieve actual configuration informations
headers = {
"Authorization": f"Basic {encodedKey}",
}
files = {
"svg": open("icon.svg", "rb"),
"screenshot1": open("screenshot1.png", "rb"),
"screenshot2": open("screenshot2.png", "rb"),
"screenshot3": open("screenshot3.png", "rb"),
}
response = requests.put(
f"{BASE_URL}/path/to/api_endpoint/{public_key}", data=file_infos, files=files, headers=headers
)
print("\n", response)
print("\n", response.headers)
print("\n", response.json())
update_app_info()

How to get temporary AWS credentials via Cognito Identity Pool

I am looking to get temporary AWS credentials through a Cognito Identity Pool to send data to a Kinesis stream through API Gateway. One thing to note is that I am trying to do this without an AWS SDK because the language it will be written in eventually does not have a compatible SDK. I am testing the solution in Python and seem to be missing something as I keep getting a 400 error. Any ideas of what I am doing wrong here?
import requests
url = 'https://cognito-identity.us-east-1.amazonaws.com' #cognito regional endpoint
headers = {
'X-AMZ-TARGET': 'com.amazonaws.cognito.identity.model.AWSCognitoIdentityService.GetCredentialsForIdentity',
'X-AMZ-DATE': '20151020T232759Z'
}
body = {
'IdentityId': 'us-east-1:123456789' #identity id
}
response = requests.post(url = url, data = body, headers = headers)
print(response)
I was able to resolve the issue by adding a content type header, converting the single quotes in the body to double quotes, and wrapping the body dictionary in quotes as well.
import requests
url = 'https://cognito-identity.us-east-1.amazonaws.com' #cognito regional endpoint
headers = {
"CONTENT-TYPE": "application/x-amz-json-1.1",
"X-AMZ-TARGET": "com.amazonaws.cognito.identity.model.AWSCognitoIdentityService.GetCredentialsForIdentity",
"X-AMZ-DATE": "20151020T232759Z"
}
body = '''{
"IdentityId": "123456789"
}'''
response = requests.post(url = url, data = body, headers = headers)
print(response.text)

Unable to retrieve the api token using requests library python

I'm trying to use requests API to login into Zabbix API, but unable to do due to the below issue.
I want to achieve the login by pyzabbix module, but I want to use API user authentication token.
Without password and username in the code (any suggestion would help me).
Error:
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Code:
import requests
from pprint import pprint
import json
url = 'http://127.0.0.1/zabbix'
########################################
# user.login
########################################
payload = {
"jsonrpc" : "2.0",
"method" : "user.login",
"params": {
'user': 'Admin',
'password':'Zabbix',
},
"auth" : None,
"id" : 0,
}
headers = {
'content-type': 'application/json',
}
res = requests.post(url, data=json.dumps(payload), headers=headers)
print(res)
res = res.json()
print('user.login response: ',res['result'])
If you want to call the Zabbix API you have to use the correct endpoint, which is api_jsonrpc.php.
So, for instance you can use:
url = 'http://127.0.0.1/api_jsonrpc.php'
However your code does not account for errors (ie: if Admin/Zabbix is wrong, your script will return a key error, because the error response does not contain a result.
A better choice is to use a library such as py-zabbix

Connect R to an API, pass it username and password

I have been trying to retrieve data from an API using R, but haven't succeeded yet. I tried doing it in R using the httr package and the GET function, but I get the following error when I enter the URL:
Error: 'new_handle' is not an exported object from 'namespace:curl'
What it comes down to is that I want to connect to data and that I have to pass some arguments like password and username.
I do have some Python code from a colleague that works (I have anonymized the URLs that are specific to our company), what I want is to connect to the data in a similar way in R:
------------- Equivalent Python code: --------------
import urllib
import datetime as dt
import dateutil
import json
headers = {u'content-type': u'application/x-www-form-urlencoded; charset=UTF-8'}
values = {"grant_type": "password",
"username": "XXXXXXXXX",
"password": "XXXXXXXXX",
"client_id": "PS"}
ko = urllib.request.Request("XXXXXX",
urllib.parse.urlencode(values).encode("utf-8"),
headers)
token = urllib.request.urlopen(ko).read()
epic = token.decode()
token_key = epic.split(",")[0].split(":")[1].replace('"', "")
lines_to_write = list()
lines_to_write.append("Identifier;Year;Period;Park Energy Availability [%]")
start_day = dt.datetime(2015, 1, 1)
data_day = start_day
headers = {u'content-type': u'application/json', u'Authorization': 'Bearer ' + token_key}
values = {'scope': {}, 'period': {'Begin': str(data_day).replace(" ", "T"), 'End': str(data_day + dateutil.relativedelta.relativedelta(months=1)).replace(" ", "T")}}
hest = urllib.request.Request("XXXXXXXXX", json.dumps(values).encode(), headers)
data = urllib.request.urlopen(hest)
vild_hest = data.read()
Any help would be greatly appreciated,
Best regards,
Tristan
The R code for API you presented will not work since it is just simply fractions of what is needed. Below you find the structure that R needs for working towards a REST API. The username and password will be passed to API server through the body of the POST (either as stated below or it could also be added as a list in the body).
You will also have to provide a key (in below case "API-KEY"). Note that you are sending a POST to initiate the authentication with the API server. Most API server will send you back 1 or 2 keys that you will use in later communication with the API server.
It is correct that all http interaction will take help of the package httr.
GET will be used in later stage in the communication between your API client and API server but not during the first authentication phase.
POST (
url = "xxx",
add_headers(
"API-KEY" = "xxx",
"VERSION" = "2",
"Content-Type" = "application/json; charset=UTF-8",
"Accept" = "application/json; charset=UTF-8"),
body = "{identifier: xxx, password: xxx}"
)

Categories

Resources