Help with Python API 2.0 & Transactional API

Hello 

 

I am attempting to utilize the transactional API in Python. Specifically trying to retrieve all line items in a model w/ID

 

DaanishSoomar_0-1627056642907.png

 

I tried doing this in Anaplan Connect earlier, however, it did not work for me. I am now trying in Python. However, it's quite the challenge as 1 article does not have the steps, I am having to read 5+ articles to piece together the script, though because each author has slightly different naming variables, I am having a bit of difficulty piecing it all together. 

 

Anyone have a template which can call the transactional API? I will ideally need a template that takes me from authentication all the way through retrieving all line items and then putting that data into a csv.

 

Tagging Python pros: @Kevin_Cho @jesse_wilson @christophe_keom @JaredDolich 

 

Best Answer

  • kevin.cho
    Answer ✓

    Cheers @DaanishSoomar  for picking that up, there is indeed a typo! 

     

    And yeah, you can consolidate it all into one script if you'd like. You can create a function like how Karan had done it, if you will be calling it multiple times. 

    E.g.

    def auth_token_basic(email, password):
        user_pw = b64encode(bytes(email+':'+password, 'utf-8'))
        auth_headers = {} 
        auth_headers['Authorization'] = 'Basic ' + user_pw
        auth_url = 'https://auth.anaplan.com/token/authenticate'
        auth_json = requests.post(auth_url, headers=auth_headers).json()
        try:
            auth_token = auth_json['tokenInfo']['tokenValue']
            return auth_token
        except KeyError:
            print('No Token Info found - check your credentials?')

     

    You can then just call this function 

    my_email = '...'
    my_password = '...'
    token = auth_token_basic(my_email, my_password)

     

    Can do the same for the CSV script I gave before too 

Answers

  • @DaanishSoomar 

    Sorry Daanish! I haven't dug into the Transactional APIs yet primarily because they use V2 API. I have every scenario under the sun for bulk APIs using Python. The issue is the tokenization for me. I have to figure out how to get that working.

  • Yeah that’s also exactly where I’m struggling too. I’ve tried compiling research and applying it from other articles in community. I guess my execution is off.

  • @DaanishSoomar i was able to do it . What error are you getting ? may be share your python code i should be able to debug

     

    My code ( function to get all line items for a given module)

     

    def getAlllineitems(mID,t):
        url = 'https://api.anaplan.com/2/0/models/'+mID+'/lineItems'
        header = {'Authorization':'AnaplanAuthToken ' + t,'Accept':'application/json','Content-Type': 'application/json'}
        response = requests.get(url, headers= header)
        return response.json()

     

    mID = model ID

    t = Token value 

     

    Karan Kochhar

  • Hey @DaanishSoomar and @JaredDolich 

     

    Take a look at this (draft) article that I had written Python and Anaplan: Pt 2—Anaplan Model Registry Ca... - Anaplan Community It's the next part in my series, but just awaiting review before publication. 

     

    It has some sample code to generate an authentication token using your username and password, and also has a link to a great article by @scott.smith for generating the auth strings using a CA Certificate. 

     

    To specifically retrieve all line items in a model and then turn it into a CSV, you can follow the below: 

     

    import csv
    import json
    import requests
    
    auth_token = ''
    mdl_id = '' # insert your model ID here
    lineitem_url = 'https://api.anaplan.com/2/0/models/{}/lineItems/'.format(mdl_id) 
    #.format() method replaces each set of curly braces with the variables listed 
    
    #define headers as a dict
    request_headers = {}
    request_headers['Authorization'] = 'AnaplanAuthToken ' + auth_token
    
    #pass request headers through
    lineitem_json = requests.get(lineitem_url, headers=request_headers).json()
    #line item endpoint returns specific json schema, we want the object "items" which is a list of dict objects representing each individual line item
    lineitem_dict = lineitem_json['items']
    
    #converting to csv 
    keys = lineitem_dict[0].keys() #get column headers as the keys per object
    file_name = 'lineitems.csv'
    with open(file_name, 'w', newline='') as output_file:
        dict_writer = csv.DictWriter(output_file, keys)
        dict_writer.writeheader()
        dict_writer.writerows(lineitem_dict)
    

     

  • You are amazing @kevin.cho!

     

    Just to validate my understanding. Below is the script I should utilize for transactional api and retrieving all line items in a model. 

    However, before I also need another script that creates an auth token? 

    So the order of operations would be:

     

    1. Run script that generates auth token in a separate script that is used only for generating a token. 
    2. Copy/paste that token into my desired script into the token variable line. 
    3. Run that desired script.

     

    Can you please confirm if I have the steps correctly? 

  • Also quick follow up, I copied and pasted the basic authentication script from the article that is still in review, I received this error message. I also made sure to swap in my username and password above (hid it for privacy)

     

    DaanishSoomar_0-1627314427588.png

     

  • Figured it out! There is a typo in the referenced article, line 31. Correction in red. @kevin.cho 
     
    # %% - this defines our Jupyter code cell (more on this below)
    import requests # tells our Python interpreter that we will be using functions from the requests module
    from base64 import b64encode # tells our Python interpreter that we will be using the b64encode function from the base64 module

    # the authentication API takes the Base64 encoded format of a string with the value "email:password". 
    # The function b64encode takes a "bytes-like object", hence the b that prepends the 'email:password' string. 
    # The function b64encode ouputs a "bytes" object, but since we need it as a string, we can call the function .decode() on the result. 

    user_pw = b64encode(b'email:password').decode() 

    # To make our first API call, we need to define our headers. We first define a variable called auth_headers, with an empty dict object ({})

    auth_headers = {} 

    # We can then add a key called 'Authorization' to this dict.
    # We set the value of this key to 'Basic <encoded_user_pw>'
    auth_headers['Authorization'] = 'Basic ' + user_pw

    # We need to define our request URL - in this case as we are trying to authenticate with the Anaplan API, it will be the authenticate URL. 


    # Finally, we can make our first API call - the authentication API expects a POST method, so we use the function in our requests module called post. It expects at least the API endpoint URL, which we pass through as auth_url, and then we define the headers value as auth_headers. As we want to be able to interpret the response, we append the .json() to retrieve the response as a JSON. This is stored as a dict object in auth_json. 

    auth_json = requests.post(auth_urlheaders=auth_headers).json()

    # The token value (that we need for later calls) is in a key called 'tokenValue', which in turn is in an object called 'tokenInfo'. 
    # We can reference the auth_request 

    try:
        auth_token = auth_json['tokenInfo']['tokenValue']
        print(auth_token)
    # If this key is not found, it means that the response is not in the expected structure, and we would get a KeyError. To error handle this, we can then print a friendly debug message. 
    except KeyError:
        print('No Token Info found - check your credentials?')
  • Thanks Kevin!

  • @DaanishSoomar @kevin.cho Thanks for sharing this. I just wanted to share my experience on setting up the Python Environment using the helpful article: 

    https://community.anaplan.com/t5/How-To/Python-and-Anaplan-Pt-1-Setting-Up-Your-Environment/ta-p/106781 

     

    And this is for the version of Python (Python 3.9.6) and VSCode version 1.58.2 for Windows 10.

     

    After installing Python 3.9.6, VSCode version 1.58.2 and installing the recommended Python extensions for VSCode, although I was able to create .py scripts and execute them successfully, I was not able to use "requests" module to call requests functions required for Anaplan API calls.

     

    Then I installed Powershell extension on VSCode and reinstalled "requests" module. This helped me get rid of the error and the Python code to call "request" module ran like a charm 🙂

     

    Sharing this so that other do not have to spend time figuring out the solution while setting up Python environment for Anaplan API calls.

     

    AB

     

  • No worries @ashish.banka - I think to prevent issues like this in the future, ensure you've activated your Python virtual environment, and have the Python interpreter in VS Code set to the one within your virtual environment. The installation of Python modules is local to the environment that you are in, whether you are in the global/system one, or your personal virtual one, which may have been the cause of your issue. 

     

    Good luck!