Having some issues running Suiteql queries through...
# suiteql
p
Having some issues running Suiteql queries through REST, I can't see to be able to add a limit onto the url as a parameter without it breaking the generated oauth signature, if I generate the signature without the params and try adding it to the header data it fails to login. a little confused as postman seems to do it via the headers. anyone had any experience with that?
p
By chance, will this is end up being in
python
?
p
it is in PHP
p
Ahh okay nvm, I just went through all of this in python (for data pipelines) and figured I could share come code there.
p
it's partly a psuedo question, if you were changing the limit or offset in your code where you needed to add that into the signature generation or was it sent elsewhere?
p
I first obtain an authorized oauth session (using an oauth library), then using that session I do a POST request with the initial query in the payload -- which is where I've added the limit & offset params when needed. but since the result set is limited to 1000 records anyway, it's not needed for my use case.
Copy code
def get_netsuite_session(secrets: dict) -> OAuth1Session:
    session = OAuth1Session(
        client_key=secrets['CONSUMER_KEY'],
        client_secret=secrets['CONSUMER_SECRET'],
        resource_owner_key=secrets['ACCESS_TOKEN'],
        resource_owner_secret=secrets['ACCESS_TOKEN_SECRET'],
        realm=secrets['REALM'],
        signature_type='AUTH_HEADER',
        signature_method='HMAC-SHA256')
    return session
p
I don't seem to get very far including the limit in the actual post data
p
i first started out doing everything entirely manually (based off docs & what i found online) but then i saw some posts that recommended using standard libraries for managing Oauth sessions.
p
Don't think the PHP one is updated to current version for OAuth1 at this time, so think i'm stuck doing so manually
p
I'm not sure if PHP has libraries like python does -- but using that first function i sent above and this one below:
Copy code
def get_netsuite_data(env: str, query: str):
    secrets = get_netsuite_secret(env)
    with get_netsuite_session(secrets=secrets) as session:
        url = f"https://{secrets['REALM']}.<http://suitetalk.api.netsuite.com/services/rest/query/v1/suiteql|suitetalk.api.netsuite.com/services/rest/query/v1/suiteql>"
        headers = {'Content-Type': 'application/json', 'Prefer': 'transient'}
        payload = {'q': query}
        row_count = 0
        results = []
        try:
            while True:
                response = <http://session.post|session.post>(url=url, headers=headers, json=payload)
                response.raise_for_status()
                count, total_results, next_url, items = parse_suiteql_response(resp=response)
                results += items
                row_count += count
                print(f'retrieved {row_count} rows out of {total_results}.\nnext URL is: {next_url}\n')
                if next_url:
                    url = next_url
                else:
                    break
        except requests.exceptions.HTTPError as e:
            raise Exception(f'SuiteQL request failed. {e}. Status Code: Response: {response.text}')
        # df = pd.json_normalize(results)
        return results
You would be able to retrieve all data from a call without needing to concern yourself with the limit/offset -- since it is provided for you in the response of your initial call (if there are more records to retrieve), that is the
next_url
.
p
well yes, can manage without limit, however offset will be a requirement as some queries will call over 1000
p
right, the response of your initial call will default limit to the max 1k records --- but if there are more records (lets say total of 10k), then in the response it provides you with the next url to use, which includes the limit and offset for you. so that you don't need to manage it manually (even though you could if you wanted).
p
yeah, problem is being able to call the next url
p
you would use the same authorized session and same query, but the url would change to include the offset and limit (provided in the url for you by the responses).
I left out the simple parse function:
Copy code
def parse_suiteql_response(resp: requests.Response):
    items = resp.json()['items']
    count = resp.json()['count']
    total_results = resp.json()['totalResults']
    has_more = resp.json()['hasMore']
    next_url = None
    if has_more:
        next_url = next(link for link in resp.json()['links'] if link['rel'] == 'next')['href']
    return count, total_results, next_url, items
p
Oh, I thought the auth headers had to go every request, interesting. I'll see if i can get anything going under that assumption
p
After initially doing it all manually (generate nonce, signature..etc.), this ended up being so much easier.