Pythonic way to add optional parameters to API request - python

I'am trying to make an API request where I add some optional values but if I don't add them I don't want them to be in the request.
In this case, I would like the parameters to be 'startblock' & 'endblock'
def get_transactions_by_address_(self, address, action='txlist'):
"""
:param address:
:param action: [txlist, txlistinternal]
:return:
"""
token = self.etherscan_api_key
return requests.get('https://api.etherscan.io/api'
'?module=account'
f'&action={action}'
f'&address={address}'
# '&startblock=0'
# '&endblock=92702578'
'&page=1'
'&offset=1000'
'&sort=desc'
f'&apikey={token}'
)
I was thinking on adding some conditionals like
request_url = 'https://api.etherscan.io/api...'
if startblock:
request_url = request_url + f'&startblock={startblock}'
if endblock:
request_url = request_url + f'&endblock={endblock}'
But I don't know if it is the most pythonic way to do it and I would like to get other options on how to do it

Use the payload option instead of constructing the URL yourself. For example, create a dict containing all the required options, then add additional parameters to the dict as necessary. requests.get will build the required URL from the base URL and the values found in your dict.
options = {
'module': 'account',
'action': action,
'address': address,
'apikey': token,
'sort': sort,
'page': page,
'offset': offset
}
if startblock:
options['startblock'] = startblock
if endblock:
options['endblock'] = endblock
return requests.get('https://api.etherscan.io/api', params=options)

The correct way to implement is:
def get_transactions_by_address_(self, address,
action='txlist',
sort='desc',
page=1,
offset=1000,
startblock=None,
endblock=None):
token = self.etherscan_api_key
options = {
'module': 'account',
'action': action,
'address': address,
'apikey': token,
'sort': sort,
'page': page,
'offset': offset
}
if startblock:
options['startblock'] = startblock
if endblock:
options['endblock'] = endblock
return requests.get('https://api.etherscan.io/api',
params=options
)

Related

Django simplejwt: How to add refresh token to dict?

I am using simplejwt to get an access and refresh tokens. In a view I need to create a dict, where the both will be stored as well as access token claims and another additional data. Everything works but by some reason when the refrsh token is added to dict, it returns its decoded value, but not the token.
my views.py
#csrf_exempt
##api_view(('GET',))
def check_token(request):
token_refresh = RefreshToken.for_user(request.user)
print('REFRESH', token_refresh)
token = request.META.get('HTTP_AUTHORIZATION', " ").split(' ')[1]
data = {'token': token, 'refresh_token': token_refresh}
try:
valid_data = TokenBackend(algorithm='HS256').decode(token, verify=False)
data['uui'] = valid_data['user_id']
data['validUntil'] = valid_data['exp']
data['clientId'] = 'default'
print(data)
return JsonResponse(data)
except ValidationError as v:
print("Validation error", v)
print('REFRESH', token_refresh) returns the token:
'REFRESH eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI...'
but data object returns:
{'token': 'eyJ0eXAiOiJKV1QiLCJhbGci...', 'refresh_token': {'token_type': 'refresh', 'exp': 1628664751, 'jti': '38f0e3a4d7bb452681834a6b149aa496', 'user_id': 'None'}, 'uui': 1, 'validUntil': 1628059131, 'clientId': 'default'}
my ideal result:
{'token': 'eyJ0eXAiOiJKV1QiLCJhbGci...', 'refresh_token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI...', 'uui': 1, 'validUntil': 1628059131, 'clientId': 'default'}
if you want to create tokens manually for user in djangorestframework-simplejwt you can do this:
from rest_framework_simplejwt.tokens import RefreshToken
def get_tokens_for_user(user):
refresh = RefreshToken.for_user(user)
return {
'refresh': str(refresh),
'access': str(refresh.access_token),
# Add additional fields here
}
now you can use this function in your views.

huobi working python 3.6 example (including signature)

Working example to generate a valid url (including signature) for the Huobi API.
In the Huobi API documenation there is no explicit example that allows you to verify your signature creation method step by step.
My intention is to create that here, but I need help, because I haven't managed yet.
Try to order using huobi api
First, I succeed to get account information
from datetime import datetime
import requests
import json
import hmac
import hashlib
import base64
from urllib.parse import urlencode
#Get all Accounts of the Current User
#apiAccessKey = hb_access, apiSecretKey = hb_secret
timestamp = str(datetime.utcnow().isoformat())[0:19]
params = urlencode({'AccessKeyId': hb_access,
'SignatureMethod': 'HmacSHA256',
'SignatureVersion': '2',
'Timestamp': timestamp
})
method = 'GET'
endpoint = '/v1/account/accounts'
base_uri = 'api.huobi.pro'
pre_signed_text = method + '\n' + base_uri + '\n' + endpoint + '\n' + params
hash_code = hmac.new(hb_secret.encode(), pre_signed_text.encode(), hashlib.sha256).digest()
signature = urlencode({'Signature': base64.b64encode(hash_code).decode()})
url = 'https://' + base_uri + endpoint + '?' + params + '&' + signature
# url = 'https://' + base_uri + endpoint2 + '?' + params + '&' + signature
response = requests.request(method, url)
accts = json.loads(response.text)
print(accts)
it gives :
{'status': 'ok', 'data': [{'id': 1153465, 'type': 'spot', 'subtype': '', 'state': 'working'}, {'id': 1170797, 'type': 'otc', 'subtype': '', 'state': 'working'}]}
but, I have problem with market order.
want to look matchresults :
here is the discription from the website
https://alphaex-api.github.io/openapi/spot/v1/en/#search-match-results
GET /v1/order/matchresults
Parameter DataType Required Default Description Value Range
symbol string true btcusdt, bccbtc.Refer to
I know I should add symbol parameter, but I don't know how I do that,,,
and my code :
timestamp = str(datetime.utcnow().isoformat())[0:19]
params = urlencode({'AccessKeyId': hb_access,
'SignatureMethod': 'HmacSHA256',
'SignatureVersion': '2',
'Timestamp': timestamp,
})
method = 'GET'
base_uri = 'api.huobi.pro'
enpoint ='/v1/order/matchresults'
pre_signed_text = base_uri + '\n' + endpoint + '\n' + params
hash_code = hmac.new(hb_secret.encode(), pre_signed_text.encode(), hashlib.sha256).digest()
signature = urlencode({'Signature': base64.b64encode(hash_code).decode()})
url = 'https://'+base_uri + endpoint +'?'+params+'&'+signature
resp = requests.request(method, url)
resp.json()
it gives :
{'status': 'error',
'err-code': 'api-signature-not-valid',
'err-msg': 'Signature not valid: Verification failure [校验失败]',
'data': None}
I need help...
and another question is :
is way to make Sinature different with using Get method from using POST method?
like placing market order(POST /v1/order/orders/place), when I request using POST do I need to give different Signature?
To get exact symbol you have to provide required parameters in param variable
params = urlencode({'AccessKeyId': hb_access,
'SignatureMethod': 'HmacSHA256',
'SignatureVersion': '2',
'Timestamp': timestamp,
"symbol": "btcusdt" # allowed symbols: GET /v1/common/symbols
})
url variable:
https://api.huobi.pro/v1/order/matchresults?AccessKeyId=39****-b******-4*****-3****&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2022-09-26T19%3A09%3A16&symbol=btcusdt&Signature=1K**************************
Output:
{'status': 'ok', 'data': []}
Here is my way adding parameters and making request:
def huobi(endpoint: str, extra_params: dict={}, AccessKeyId: str=None, SecretKey: str=None) -> dict:
AccessKeyId = 'xxxxxx-xxxxxx-xxxxxx-xxxx' # tmp
SecretKey = 'xxxxxx-xxxxxx-xxxxxx-xxxx' # tmp
timestamp = str(datetime.utcnow().isoformat())[0:19]
standart_params = {
'AccessKeyId': AccessKeyId,
'SignatureMethod': 'HmacSHA256',
'SignatureVersion': '2',
'Timestamp': timestamp
}
params = dict(standart_params, **extra_params)
params_url_enc = urlencode(
sorted(params.items(), key=lambda tup: tup[0])
)
pre_signed = 'GET\n'
pre_signed += 'api.huobi.pro\n'
pre_signed += f'{endpoint}\n'
pre_signed += params_url_enc
sig_bin = hmac.new(
SecretKey.encode(),
pre_signed.encode(),
hashlib.sha256
).digest()
sig_b64_bytes = base64.b64encode(sig_bin)
sig_b64_str = sig_b64_bytes.decode()
signature = urlencode({'Signature': sig_b64_str})
url = f'https://api.huobi.pro{endpoint}?'
url += params_url_enc + '&'
url += signature
return requests.get(url).json()
endpoint = "/v2/account/valuation"
extra_params = {
"accountType": "1",
"valuationCurrency": "BTC"
}
print(huobi(endpoint=endpoint, extra_params=extra_params))

How do I make an API call and authenticate it with a given API key using Python?

This is my code to extract player data from an endpoint containing basketball data for a Data Science project.NOTE: I changed the name of the actual API key I was given since it's subscription. And I change the username/password because for privacy purposes. Using the correct credentials, I wouldn't receive a syntax error but the status code always returns 401. Since it wasn't accepting the API key, I added my account username, password, and the HTTP authentication header as well, but the status code still returns 401.
In case this is relevant, this is the website's recommendation in the developer portal: **The API key can be passed either as a query parameter or using the following HTTP request header.
Please let me know what changes I can make to my code. Any help is appreciated.
Ocp-Apim-Subscription-Key: {key}**
PS: My code got fragmented while posting this, but it is all in one function.
def getData():
user_name = "name#gmail.com"
api_endpoint = "https://api.sportsdata.io/v3/nba/stats/json/PlayerGameStatsByDate/2020-FEB7"
api_key = "a45;lkf"
password = "ksaljd"
header = "Ocp-Apim-Subscription-Key"
PARAMS = {'user': user_name, 'pass': password, 'header': header, 'key': api_key}
response = requests.get(url = api_endpoint, data = PARAMS)
print(response.status_code)
file = open("Data.csv", "w")
file.write(response.text)
file.close()
def _get_auth_headers() -> dict:
return {
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': "`Insert key here`"
}
api_endpoint = "https://api.sportsdata.io/v3/nba/stats/json/PlayerGameStatsByDate/2020-FEB7"
PARAMS = {
# Your params here
}
response = requests.get(
api_endpoint,
headers=_get_auth_headers(),
params=PARAMS
)
Instead of just a string, you need to pass dict in the headers parameter and auth param exist so you can use it as follow:
def getData():
[...]
header = {
"Ocp-Apim-Subscription-Key": api_key
}
[...]
response = requests.get(url = api_endpoint, data = PARAMS, headers=header, auth = (user_name, password))
According to the API documentation you don't need to provide email and password. You're only need to add your API Key to header:
import requests
r = requests.get(url='https://api.sportsdata.io/v3/nba/stats/json/PlayerGameStatsByDate/2020-FEB7', headers={'Ocp-Apim-Subscription-Key': 'API_KEY'})
print(r.json())
Output:
[{
'StatID': 768904,
'TeamID': 25,
'PlayerID': 20000788,
'SeasonType': 1,
'Season': 2020,
'Name': 'Tim Hardaway Jr.',
'Team': 'DAL',
'Position': 'SF',
'Started': 1,
'FanDuelSalary': 7183,
'DraftKingsSalary': 7623,
'FantasyDataSalary': 7623,
...

KeyError handling while consuming API

I am consuming the Yelp API and using this detail view to display details of individual restaurants such as the name, rating and price of a restaurant. The detail dictionary is solid for the most part and lets me collect variables to use as context in template. However some restaurants do not provide their 'price' to the API, therefore when accessing this view I get a KeyError because there is no price in some cases. How can I create this dictionary with a None value for price to avoid this error? Or is exception handling with try & except the best solution?
def detail(request, api_id):
API_KEY = 'unique_key'
url = 'https://api.yelp.com/v3/businesses/'+ api_id
headers = {'Authorization': 'Bearer {}'.format(API_KEY)}
req = requests.get(url, headers=headers)
parsed = json.loads(req.text)
detail = {
'id': parsed['id'],
'name': parsed['name'],
'rating':parsed['rating'],
'price': parsed['price'],
}
context = {'detail': detail}
return render(request, 'API/detail.html', context)
You can use <dict>.get('key', default_value):
detail = {
'id': parsed['id'],
'name': parsed['name'],
'rating':parsed['rating'],
'price': parsed.get('price', None), # <-- here
}
W3School has a nice example on how to use .get() method.
you can try:
detail = {
'id': parsed['id'],
'name': parsed['name'],
'rating':parsed['rating'],
'price': parsed['price'] if parsed['price'] else None,
}

Find oldest to youngest record Python

I am trying to retrieve data from the first available date to present date from an API. I've tried using min and max in parameter.
def getcomplete(cid, pid, tag, type):
api_endpoint = ''
headers = {'token': get_token()['access_token'], 'Content-Type': 'application/json'}
params = {'cid': str(cid),
'from-date': datetime.datetime.min,
'to-date': datetime.datetime.max,
'tag': str(tag),
'type': str(type),
'pid': str(pid)
}
r = requests.post(url=api_endpoint, headers=headers, params=params)
return r.json()
getcomplete(10,12,'x','y')
This returns {'status': 'success', 'message': 'success', 'data': []}.
Is there anything wrong with the written function.
Thanks
Pythons min() and max() have an optional default parameter. This will prevent them from throwing errors
min("", default="")

Categories

Resources