RossV
RossV

Reputation: 195

How to determine required REST Get requests formatting in Python

Completely new to REST APIs and still learning python, so I apologize for a simple question and being a noob. Any help is appreciated.

I am trying to pull data from a server with with a GET request. The Instructions for doing so are provided on their website here: Ayyeka REST API and I've read through their help documentation as well. It indicates you have to use swagger_client but I had trouble getting that working. Instead I cobbled together some code using the requests module and I seem to be getting a token correctly using OAuth2.

import os, string, time
from requests.auth import HTTPBasicAuth
from requests.structures import CaseInsensitiveDict
import base64

#credentials
client_id= "[client id goes here]"
client_secret = "[secret goes here]"
secret64 = base64.b64encode(bytes(client_id + ':' + client_secret, 'utf-8')).decode('utf-8')

#time and stream to pull data from
dtime = 1617821133
AyyekaChannel_text = '183534'

token_url = 'https://restapi.ayyeka.com/auth/token'
base_url = 'https://restapi.ayyeka.com '

auth = HTTPBasicAuth(client_id, client_secret)
client = BackendApplicationClient(client_id=client_id)
oauth = OAuth2Session(client=client)
token = oauth.fetch_token(token_url='https://restapi.ayyeka.com/auth/token', auth=auth)
access_token = token['access_token']

headers = {'Authorization': 'Bearer ' + access_token}
response = requests.get(url=base_url,headers=headers)

token returns:

{'access_token': '[token string appears here]', 'token_type': 'JWT', 'expires_in': 3600,'expires_at': 1617909733.2390773}

Now I'm stuck and am not sure how to pass this through a GET to get an Authentication token, and not sure how to use the REST commands to pull data. Am I on the right track at all? Completely off the mark? response just returns a bunch of errors, but I know it's not right anyways but I can't figure out the next step since their documentation uses swagger_client . I'm not sure if I should go back to trying to get swagger_client working or if this should work?

Upvotes: 0

Views: 227

Answers (1)

dephekt
dephekt

Reputation: 456

It's hard to give a good example since I don't have access to their help documentation. That said, it looks like you're getting a JWT token and you're passing a header with said token. I would be curious to know exactly what error you're getting in the response. You can check that with response.status_code and response.text.

You have a space in your base_url variable base_url = 'https://restapi.ayyeka.com ' instead of base_url = 'https://restapi.ayyeka.com'. That could be part of your problem. You are also not appending any actual API endpoint. Also, their documentation shows in their curl example that there should be a version appended to that URL (see my base_url below).

As barny said, you probably want to be using requests.Session() here. You asked how to do that in a comment and here's how:

dtime = 1617821133
AyyekaChannel_text = "183534"

base_url = "https://restapi.ayyeka.com/v2.0"

session = requests.Session()
session.headers.update({"Authorization": f"Bearer {access_token}"})

params = {
    "sampleID": AyyekaChannel_text,
    "backfillHours": dtime,
}

session.get(url=f"{base_url}/sample/batch", params=params)

All that being said, the documentation says regarding backfillHours:

Specifies to send samples starting this many hours ago. For example, if the backfillHours value is 24, this is a request to provide all samples of the past 24 hours

I don't know what your intended use of dtime here is, but obviously 1617821133 is like 180,000+ years in the past, but I used it here as an example of how you would pass that value as a query parameter in the request assuming it were a sane value.

You would probably also have use for making this whole thing object-oriented. Here's a really short example for illustration purposes:

class AyyekaClient:
    """A client implementing the Ayyeka API."""

    def __init__(self, client_id: str, client_secret: str):
        self.base_url = "https://restapi.ayyeka.com/v2.0"
        self.client_id = client_id
        self.client_secret = client_secret
        self.auth = HTTPBasicAuth(client_id, client_secret)
        self.client = BackendApplicationClient(client_id=self.client_id)
        self.oauth = OAuth2Session(client=self.client)
        self.session = requests.Session()
        self.session.hooks["response"] = [self.raise_for_status]
        self.refresh_access_token()

    def raise_for_status(response, *args, **kwargs):
        """Requests event hook to call raise_for_status on every request."""
        response.raise_for_status()

    def refresh_access_token(self):
        """Get a fresh access token."""
        token = self.oauth.fetch_token(token_url="https://restapi.ayyeka.com/auth/token", auth=self.auth)["access_token"]
        self.session.headers.update({"Authorization": f"Bearer {token}"})

    def get_sample_scalar_batch(self, sample_id: str, backfill_hours: int) -> requests.Response:
        """Get a Batch of New SamplesScalar."""
        params = {"sampleID": sample_id, "backfillHours": backfill_hours}
        return self.session.get(url=f"{self.base_url}/sample/batch", params=params)

Then you would implement that class like:

ayyeka = AyyekaClient(client_id="123456", client_secret="78910112")
response = ayyeka.get_sample_scalar_batch(sample_id, backfill_hours)
print(response.text)
print(response.json())

Those JWT tokens only have a 1 hour lifetime, so you'd occasionally need to call ayyeka.refresh_access_token() or do some sort of error handling where if the request fails due to a 401/403 error you refresh the token and try the request again. That method will automatically get a new token and update the session's Authorization header to utilize the token.

This was just meant to be an illustrative example of how you might go about using a class here. I haven't put a tremendous amount of thought into it. You would implement the rest of the API endpoints as methods on this class, then you'd implement the client in a separate script/module.

Upvotes: 1

Related Questions