Reputation: 25
I have a hobby Python/Flask web application on PythonAnywhere.com to develop functionality that Spotify doesn't natively support. My web app works as expected after manually reload the web app (via the "Web" tab on PythonAnywhere). However, the problem I'm encountering is that after a period of time, when API calls are made via the front-end web pages, an "Internal Server Error" is returned.
I traced the problem and found the calls to the Spotify APIs were returning a 401 error response after about an hour - and then found that Spotify access tokens only last 1 hour.
One troubleshooting theory was that maybe pythonanywhere.com was only running the code to refresh my access tokens once (when reloading the web app), so then they would expire after 60 minutes. So I tried making the access token refresh into a function, and then calling that function from other functions that make the API calls. But this didn't work, but here's below is my code to show what I did.
My only remaining theory now is that the web server only gets the access tokens once (when the web server is refreshed) - but I'm not quite sure how to troubleshoot that.
Any thoughts on that theory, or other avenues I should explore so that I don't need to manually restart the web server to get my app to work?
set variables
AUTH_URL = 'https://accounts.spotify.com/api/token'
BASE_URL = 'https://api.spotify.com/v1/'
Code to get access token and return headers for the API call
auth_response = requests.post(AUTH_URL, {
'grant_type': 'client_credentials',
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
})
def setHeaders():
try:
auth_response.raise_for_status()
except requests.exceptions.HTTPError as e:
print("!!!Error setting auth_response. System detail:")
print(e)
raise
# convert the response to JSON
auth_response_data = auth_response.json()
# save the access token
access_token = auth_response_data['access_token']
headers = {
'Authorization': 'Bearer {token}'.format(token=access_token)
}
return headers
function that makes the call to Spotify API that returns all playlist for a user:
#API GET link: https://api.spotify.com/v1/users/{user_id}/playlists
def getRawPlaylistMetadata(username,offset_value=0):
headers = setHeaders()
r_list = []
result_limit = 50
#print(offset_value)
params = {'offset': offset_value,
'limit': result_limit}
r = requests.get(BASE_URL + 'users/' + username + '/playlists', \
headers=headers,params=params)
response_code = str(r.status_code)
sys.stderr.write("\nr response code=" + response_code + "\n\n")
r = r.json()
try:
r_list = r['items']
except KeyError:
print("Getting all of Spotify user's playlist metadata failed.")
if len(r_list) < result_limit:
#print(len(r_list))
return r_list
return r_list + getRawPlaylistMetadata(username,offset_value + len(r_list))
Upvotes: 1
Views: 816
Reputation: 3628
I'm not sure how running it in the terminal does not cause the same issue, as your function doesn't even refresh the session:
# REQUEST EXECUTED HERE
auth_response = requests.post(AUTH_URL, {
'grant_type': 'client_credentials',
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
})
def setHeaders():
# Function ran here
# the request is not re-executed
...
So you should probably put it inside the function:
def setHeaders():
auth_response = requests.post(AUTH_URL, {
'grant_type': 'client_credentials',
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
})
...
Then, to keep re-authenticating while running the Flask server, I recommend using a Thread:
from time import sleep
def reauth():
while True:
setHeaders()
sleep(30 * 60) # Sleep for half an hour, then re-authenticate
t = Thread(target=reauth)
t.start()
This would keep it running in parallel with the Flask server, and would keep calling it to reauthenticate the client every half an hour (obviously configurable, but should be under the 1 hour limit for Spotify's authentication expiry).
Upvotes: 3