The request that I send to the Spotify API responds with 404 - python

Here is the code of mine. I censored the CLIENT_SECRET and the CLIENT_ID.
import requests
import json
import base64
CLIENT_ID = "CLIENT_ID"
CLIENT_SECRET = "CLIENT_SECRET"
def get_acces_token(CLIENT_ID: str, CLIENT_SECRET: str) -> str:
authURL = "https://accounts.spotify.com/api/token"
authHeader = {}
authData = {
"grant_type" : "client_credentials"
}
# Base 64
combinated = f"{CLIENT_ID}:{CLIENT_SECRET}"
message = combinated
message_bytes = message.encode('ascii')
base64_bytes = base64.b64encode(message_bytes)
base64_combinated = base64_bytes.decode('ascii')
# request
authHeader['Authorization'] = f"Basic {base64_combinated}"
res = requests.post(authURL,headers = authHeader,data = authData)
ACCCES_TOKEN = res.json()['access_token']
return ACCCES_TOKEN
def get_playlist_tracks(acces_token: str, playlist_id:str) -> dict:
playlist_end_point = f"https://accounts.spotify.com/api/playlists/{playlist_id}"
get_header = {
"Authorization" : f"Bearer {acces_token}"
}
res = requests.get(playlist_end_point,headers=get_header)
return res
token = get_acces_token(CLIENT_ID=CLIENT_ID,CLIENT_SECRET=CLIENT_SECRET)
playlist_id = "3SPj0H71ii0CnhdO6CrhkL?si=c8c41e7c79764265"
tracklist = get_playlist_tracks(token,playlist_id)
print(tracklist)
I don't know why does it respond with 404. The access_token is good. I think that the playlist_end_point should be wrong. Do you have any idea what's wrong in the code?

According to this reference, the right endpoint is https://api.spotify.com/v1/playlists/{playlist_id}/tracks

Related

Extracting data from Pinterest using gRPC, Python

I want to grab all chats of my Pinterest account
I have a Proto Service:
syntax = "proto3";
service Pinterest{
rpc GetConversations (request_chat_info) returns (chat_response);
}
message request_chat_info{
string conversation_id = 1;
string csrftoken = 2;
string _b = 3;
string _pinterest_sess = 4;
}
message chat_response{
string type = 1;
string id = 2;
string text = 3;
}
message chat_response_array{
repeated chat_response messages = 1;
}
and this is my Pinterest Servicer:
# GRPC Service
class PinterestService(pb2_grpc.PinterestServicer):
def GetConversations(self, request, context):
conversation_id = request.conversation_id
csrftoken = request.csrftoken
_b = request._b
_pinterest_sess = request._pinterest_sess
chats = _exec(
get_chat,
{"conversation_id": conversation_id, "csrftoken": csrftoken, "_b": _b, "_pinterest_sess": _pinterest_sess}
)
return pb2.chat_response_array(messages=chats)
and main Program is something like this:
# ENDPOINTS
CHAT_API = "https://www.pinterest.com/resource/ConversationMessagesResource/get/"
# Execute Fucntion
def _exec(func, params):
return func(**params)
# Make Requests here
def _get(url:str, cookies:Dict = None, headers:Dict = None) -> requests.Response:
response = requests.request("GET", url=url, cookies=cookies, headers=headers)
response.raise_for_status()
return response
# Chat Parser Function
def _chat_parser(chat_dict: Dict) -> Dict:
return {
"type": chat_dict.get("type", ""),
"id": chat_dict.get("id", ""),
"text": chat_dict.get("text", ""),
}
# Function to handle GRPC
def get_chat(conversation_id:str, csrftoken:str, _b:str, _pinterest_sess:str) -> Dict:
options = {"page_size":25,"conversation_id":conversation_id,"no_fetch_context_on_resource":False}
_cookies = {"csrftoken":csrftoken, "_b":_b, "_pinterest_sess":_pinterest_sess}
query = {"data": json.dumps({"options":options})}
encoded_query = urlencode(query).replace("+", "%20")
url = "{}?{}".format(CHAT_API, encoded_query)
msg_counter = 0
while True:
try:
return _chat_parser(_get(url, _cookies).json()["resource_response"]["data"][msg_counter])
except IndexError:
break
finally:
msg_counter += 1
I need to get all CHAT and I Don't know how to do that!
The Response JSON in Pinterest is exactly Like this:
["resource_response"]["data"][0]
["resource_response"]["data"][1]
["resource_response"]["data"][2]
["resource_response"]["data"][...]
Based on Messages Count the last number change from 0 to any number
I don't know how to handle that!
does the fault in my proto or what?
should I use stream in proto, if yes, bidirectional stream or for Client, Server...
Thank you for Helping me.
I found the answer
it must be server stream and use for loop and yield

Python Mocking a request for a bearer token?

I'm trying to figure out how to mock my request for a bearer token in python.
I have a class:
class grab_apitokens(object):
def __init__(self, consumer_key, first_api_url, second_api_user, second_api_password, second_api_url):
self.consumer_key = consumer_key
self.second_api_user = second_api_user
self.second_api_password = second_api_password
self.first_api_url = first_api_url
self.second_api_url = second_api_url
def logintofirstsite(self):
b64val = base64.b64encode(self.consumer_key.encode()).decode()
headers = {"Authorization": "Basic %s" % b64val}
data = {'grant_type': 'client_credentials', 'validity_period': '3600'}
try:
response = requests.post(self.first_api_url, headers=headers, data=data)
decodedresponse = json.loads(response.content.decode())
access_token = decodedresponse['access_token']
return access_token
except:
return None
def logintosecondsite(self):
header = {"accept": "application/json", "Content-Type": "application/x-www-form-urlencoded"}
logindata = {'grant_type': 'password',
'username': "" + self.second_api_user + "", 'password': "" + self.second_api_password + ""
}
try:
returnedfromsite = requests.post(self.second_api_url + '/api/V1/token',
headers=header, data=logindata)
return returnedfromsite.json()['access_token']
except:
return None
What I can't figure out is how to mock that requests call and what it would look like in Python.
My test currently looks like:
class MyTestCase(unittest.TestCase):
def setUp(self) -> None: # PROBLEM BEGINS HERE
self.grab_apitokens = grab_apitokens(actual_key, actual_site1, actual_user, actual_pass, actual_2nd_site)
#patch('grab_apitokens.requests.get')
def test_login(self, mock_get):
mock_get.return_value.ok = True
response = self.grab_apitokens.logintosite()
assert_is_not_none(response)
# self.assertEqual(True, False)
if __name__ == '__main__':
unittest.main()
How would I mock the requests.post functionality?
With the help of a good mentor I figured out that my approach was all wrong. Here's what I ended up with for the unit test:
class MyTestCase(unittest.TestCase):
def setUp(self) -> None:
self.grab_apitokens = grab_apitokens("complete","gibberish","it really doesnt","matter","what is","in","here")
#patch('grab_apitokens.requests.posts')
def test_login(self, mock_get):
mock_json = {'token': 'foo'}
mock_get.return_value = Mock(ok=True)
mock_get.return_value.json.return_value = mock_json
mock_get.return_value.content = b'{"token": "foo"}'
response = self.grab_apitokens.logintofirstsite()
assert_equal(response, "foo")
if __name__ == '__main_
To understand what this does, I needed to know that what we're really mocking isn't the method logintofirstsite(), we're mocking the response that requests.post is making in the method. With mock_get, we're inject requests.posts to always be: {'token': 'foo'} . So everything after
response = requests.post(self.first_api_url, headers=headers, data=data)
in logintofirstsite() is what I'm really testing. Which is:
decodedresponse = json.loads(response.content.decode())
access_token = decodedresponse['token']
return access_token
The setup before the requests.post call doesn't matter one bit. Since with {'token': 'foo'} is what my requests.post call returns, the returned value after that bit of logic is 'foo', and so the assert_equal back in MyTestCase passes.

Spotify API Python

I am following a tutorial from CodingEntrepreneurs and i have come across a road bump where it returns a 400 error when i run it.
Here is my code
import base64, requests
import datetime
from urllib.parse import urlencode
client_id = "my id"
client_secret = "my secret"
class SpotifyAPI(object):
access_token = None
access_token_expires = datetime.datetime.now()
access_token_did_expire = True
client_id = None
client_secret = None
token_url = "https://accounts.spotify.com/api/token"
def __init__(self, client_id, client_secret, *args, **kwargs):
super().__init__(*args, **kwargs)
self.client_id = client_id
self.client_secret = client_secret
def getClientCreds(self):
'''Returns b64 encoded string'''
client_id = self.client_id
client_secret = self.client_secret
if client_id == None or client_secret == None:
raise Exception('Must set a client id and secret')
client_creds = f"{client_id}:{client_secret}"
client_creds_b64 = base64.b64encode(client_creds.encode())
return client_creds_b64.decode()
def getTokenHeader(self):
client_creds_b64 = self.getClientCreds()
return {
'Authorization':f"Basic {client_creds_b64}"
}
def getTokenData(self):
return {
"grant_type":"client_credentials"
}
def perform_auth(self):
token_url = self.token_url
token_data = self.getTokenData()
token_header = self.getTokenHeader()
r = requests.post(token_url, data=token_data, headers=token_header)
if r.status_code not in range(200,299):
return False
now = datetime.datetime.now()
token_response_data = r.json()
access_token = token_response_data['access_token']
expires_in = token_response_data['expires_in']
expires = now + datetime.timedelta(seconds=expires_in)
self.access_token = access_token
self.access_token_expires = expires
self.access_token_did_expire = expires < now
return True
spotify = SpotifyAPI(client_id, client_secret)
print(spotify.perform_auth())
token = spotify.access_token
header = {
"Authorization": f"Bearer{token}",
}
endpoint = "https://api.spotify.com/v1/search"
data = urlencode({"q": "Time", "type": "track"})
lookupURL = f"{endpoint}?{data}"
r = requests.get(lookupURL, headers=header)
print(r.json())
When i run this it returns this
"
True
{'error': {'status': 400, 'message': 'Only valid bearer authentication supported'}}
"
Please could someone help and explain the solution.
Thanks,
Sam :)
I think it could be a problem here, as you are leaving no space between the Bearer keyword and the token:
# previous
header = {
"Authorization": f"Bearer{token}",
}
# correct
header = {
"Authorization": f"Bearer {token}",
}

Meeting room calendars missing - Office 365 API

I am trying to get the list of all calendars for a user. This user has delegate permissions to view the calendar of all the meeting rooms (resources). If I log into the user's account and I am able to see the meeting room calendars in the "Other Calendars" section. I also created my own calendar called "Test" in the "Other Calendars" section.
When I get all the calendar groups first and then iterate through the calendar group list and get the calendars, the list for "Other Calendars" only has "Test" calendar.
Not sure why this is the case. The user is a global administrator as well.
def get_access_info_from_authcode(auth_code, redirect_uri):
post_data = { 'grant_type': 'authorization_code',
'code': auth_code,
'redirect_uri': redirect_uri,
'scope': ' '.join(str(i) for i in scopes),
'client_id': client_registration.client_id(),
'client_secret': client_registration.client_secret()
}
r = requests.post(access_token_url, data = post_data, verify = verifySSL)
try:
return r.json()
except:
return 'Error retrieving token: {0} - {1}'.format(r.status_code, r.text)
def get_access_token_from_refresh_token(refresh_token, resource_id):
post_data = { 'grant_type' : 'refresh_token',
'client_id' : client_registration.client_id(),
'client_secret' : client_registration.client_secret(),
'refresh_token' : refresh_token,
'resource' : resource_id }
r = requests.post(access_token_url, data = post_data, verify = verifySSL)
# Return the token as a JSON object
return r.json()
def get_calendars_from_calendar_groups(calendar_endpoint, token, calendar_groups):
results = []
for group_id in calendar_groups:
get_calendars = '{0}/me/calendargroups/{1}/calendars'.format(calendar_endpoint, group_id)
r = make_api_call('GET', get_calendars, token)
if (r.status_code == requests.codes.unauthorized):
logger.debug('Response Headers: {0}'.format(r.headers))
logger.debug('Response: {0}'.format(r.json()))
results.append(None)
results.append(r.json())
return results
def get_calendars(calendar_endpoint, token, parameters=None):
if (not parameters is None):
logger.debug(' parameters: {0}'.format(parameters))
get_calendars = '{0}/me/calendars'.format(calendar_endpoint)
if (not parameters is None):
get_calendars = '{0}{1}'.format(get_calendars, parameters)
r = make_api_call('GET', get_calendars, token)
if(r.status_code == requests.codes.unauthorized):
logger.debug('Unauthorized request. Leaving get_calendars.')
return None
return r.json()
Logic + Code:
Step 1) Get the authorization URL:
authority = "https://login.microsoftonline.com/common"
authorize_url = '{0}{1}'.format(authority, '/oauth2/authorize?client_id={0}&redirect_uri={1}&response_type=code&state={2}&prompt=consent')
Step 2) Opening the URL takes us to https://login.microsoftonline.com/common where I login as the user:
Step 3) This redirects back to my localhost then the following:
discovery_result = exchoauth.get_access_info_from_authcode(auth_code, Office365.redirect_uri)
refresh_token = discovery_result['refresh_token']
client_id = client_registration.client_id()
client_secret = client_registration.client_secret()
access_token_json = exchoauth.get_access_token_from_refresh_token(refresh_token, Office365.resource_id)
access_token = access_token_json['access_token']
calendar_groups_json = exchoauth.get_calendar_groups(Office365.api_endpoint, access_token)
cal_groups = {}
if calendar_groups_json is not None:
for entry in calendar_groups_json['value']:
cal_group_id = entry['Id']
cal_group_name = entry['Name']
cal_groups[cal_group_id] = cal_group_name
calendars_json_list = exchoauth.get_calendars_from_calendar_groups(Office365.api_endpoint,
access_token, cal_groups)
for calendars_json in calendars_json_list:
if calendars_json is not None:
for ent in calendars_json['value']:
cal_id = ent['Id']
cal_name = ent['Name']
calendar_ids[cal_id] = cal_name
Let me know if you need any other information
The delegate-token which request with the Auth code grant flow only able to get the calendars of sign-in user.
If you want to the get the events from the specific room, you can use the app-only token request with client credential flow.
Here is an helpful link for your reference.

Suds Python Array Response

Using Python 2.7 and SUDS. How would I print just URL from these arrays/objects? I'd like to be able to pick any of the arrays/objects (such as URL) and just print an entire list of them instead of/or in addition to the response already being given from the server.
Here is my request:
from suds.client import Client
import logging
# Specify Login Information
developer_key = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
password = 'xxxxxxxx'
account_guid = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx'
sku = ['A30938', 'B84727']
# Specify URLs
wsdl_url = 'https://api.channeladvisor.com/ChannelAdvisorAPI/v6/InventoryService.asmx?WSDL'
service_url = 'https://api.channeladvisor.com/ChannelAdvisorAPI/v6/InventoryService.asmx'
# Initialize client.
client = Client(wsdl_url, location = service_url)
# Pass login information
login = client.factory.create('APICredentials')
login.DeveloperKey = developer_key
login.Password = password
client.set_options(soapheaders=login)
# Initiate request
for i in sku:
result = client.service.GetInventoryItemImageList(account_guid, i)
# Print the result to the screen.
print result
And here is the results:
(APIResultOfArrayOfImageInfoResponse){
Status = "Success"
MessageCode = 0
ResultData =
(ArrayOfImageInfoResponse){
ImageInfoResponse[] =
(ImageInfoResponse){
PlacementName = "ITEMIMAGEURL1"
FolderName = None
Url = "d3t71aa9ase5oz.cloudfront.net/12801479/images/bear_white.jpg"
},
(ImageInfoResponse){
PlacementName = "ITEMIMAGEURL2"
FolderName = None
Url = "d3t71aa9ase5oz.cloudfront.net/12801479/images/bear_black.jpg"
},
}
}
(APIResultOfArrayOfImageInfoResponse){
Status = "Success"
MessageCode = 0
ResultData =
(ArrayOfImageInfoResponse){
ImageInfoResponse[] =
(ImageInfoResponse){
PlacementName = "ITEMIMAGEURL1"
FolderName = None
Url = "http://d3t71aa9ase5oz.cloudfront.net/12801479/images/m89851.jpg"
},
}
}
Just iterate through the items and get the attribute you want. Something like:
for item in response:
for data in item.ResultData:
print data.Url

Categories

Resources