EducationSoftwareStrategy.com
StrategyCommunity

Knowledge Base

Product

Community

Knowledge Base

TopicsBrowse ArticlesDeveloper Zone

Product

Download SoftwareProduct DocumentationSecurity Hub

Education

Tutorial VideosSolution GalleryEducation courses

Community

GuidelinesGrandmastersEvents
x_social-icon_white.svglinkedin_social-icon_white.svg
Strategy logoCommunity

© Strategy Inc. All Rights Reserved.

LegalTerms of UsePrivacy Policy
  1. Home
  2. Topics

Using Python and REST API to find objects like reports, metrics, tables within a project (project documentation)


Robert Prochowicz

Manager, Sales Engineering • MicroStrategy


MicroStrategy REST API allows browsing metadata objects. Type, Subtype and extType parameters of objects can be used to narrow down the search. Exported data files can be later used in dossier for further analytics or visualization.

Starting with the release of Strategy ONE (March 2024), dossiers are also known as dashboards.
The Python code below performs object search. The result of the search is saved as a JSON and CSV files. Those files can be later imported back into Strategy dossier. You can also use the results to build custom HTML or Javascript interfaces that will be presented to the end users.
There are several parameters at your disposal like:
- object type
- root folder
- whether to include ancestors (folder structure)
Object Types reference:

  • Types table
  • Subtypes table
  • extTypes table

Note - 'requests' and 'pandas' are Python libraries that you need to install in your Python environment (pip install requests) 
Note - I've added color formatting in the code below (http://hilite.me/). Code copied from here might not work due to indentation issues. In that case, use attached file with sample code.
Example of a dossier based on the output JSON file. extType 1 means tables imported from DWH. extType 3 means Logical Views (based on custom SQL)

ka0PW0000001JmRYAU_0EM2R000000mvs1.jpeg

Subtype is important for filtering. In this example Subtype 768 represents "Report displayed as a grid". Subtype 779 represents a cube build with Web data import.

ka0PW0000001JmRYAU_0EM2R000000mvsB.jpeg

With outline mode you can even represent the folder structure (remember to wrangle 'path' column by splitting it by '>')

ka0PW0000001JmRYAU_0EM2R000000mvrw.jpeg

 


# Strategy JSON DATA PUSH API
# Getting information about Metadata objects - by Robert Prochowicz
# Tested with MSTR 2019 update 3 / 2019-11-27

import requests
import pandas as pd
import csv
from datetime import datetime

### Parameters ###
api_login = 'XXX'
api_password = 'YYY' 
login_mode = 1 #1-standard, 16-LDAP
project_id = 'B7CA92F04B9FAE8D941C3E9B7E0CD754' #B7CA92F04B9FAE8D941C3E9B7E0CD754 is standard Tutorial
base_url = 'http://YOR_SERVER/StrategyLibrary/api/'
root_folder = '' #D3C7D461F69C4610AA6BAA5EF51F4125
object_type = 3 #55 - document/dossier ; 3 - report/cube ; 15 - table ; 4 - metric ; 12 - attribute
# Types table: https://www2.Strategy.com/producthelp/Current/WebAPIReference/com/MicroStrategy/webapi/EnumDSSXMLObjectTypes.html#DssXmlTypeTable
# Subtypes table: https://www2.Strategy.com/producthelp/Current/WebAPIReference/com/MicroStrategy/webapi/EnumDSSXMLObjectSubTypes.html#DssXmlSubTypeAttributeTransformation
# extTypes table: https://www2.Strategy.com/producthelp/Current/WebAPIReference/com/MicroStrategy/webapi/EnumDSSExtendedType.html
get_ancestors = 'true' 
limit_search = -1

#### FUNCTIONS ###
def login(base_url,api_login,api_password,login_mode):
    print("Getting token...")
    data_get = {'username': api_login,
                'password': api_password,
                'loginMode': login_mode}
    r = requests.post(base_url + 'auth/login', data=data_get)
    if r.ok:
        authToken = r.headers['X-MSTR-AuthToken']
        cookies = dict(r.cookies)
        print("Token: " + authToken)
        return authToken, cookies
    else:
        print("HTTP %i - %s, Message %s" % (r.status_code, r.reason, r.text))

def set_headers(authToken,project_id):
    headers = {'X-MSTR-AuthToken':authToken,
               'Content-Type':'application/json',#IMPORTANT!
               'Accept':'application/json',
               'X-MSTR-ProjectID':project_id}
    return headers
        
def quickSearch(base_url, auth_token, cookies, project_id, root_folder, object_type, get_ancestors, limit_search):
    headers = set_headers(auth_token,project_id)   
    search_url = (base_url  + "searches/results?" + "root=" + root_folder + "&type=" + str(object_type)                  
                  + "&getAncestors=" + get_ancestors + "&limit=" + str(limit_search))
    print("Quick Search...")
    r = requests.get(search_url, headers=headers, cookies=cookies)
    if r.ok:
        print("Error: " + str(r.raise_for_status()) + "   ||   HTTP Status Code: " + str(r.status_code))
        print("Total Items: " + str(r.json()['totalItems']))
        return r.json()
    else:
        print("HTTP %i - %s, Message %s" % (r.status_code, r.reason, r.text))

def main():
    authToken, cookies = login(base_url,api_login,api_password,login_mode)
    #### Quick Search
    search_result = quickSearch(base_url, authToken, cookies, project_id, root_folder,
                                object_type, get_ancestors, limit_search)
    list_search = search_result['result'] # cutting out unnecessary level of data

    # Adding path info
    for row in list_search:
        path=''
        if 'ancestors' in row: # necessary if you set get_ancestors parameter to false
            for i in range(len(row['ancestors'])):
                path= path+' > '+(row['ancestors'][i]['name'])
        else:
            path="___NO PATH"
        row['path'] = path[3:]

    # Generating JSON files
    curr_date=str(datetime.now()).replace(" ", "_").replace(":", "_").replace(".", "_")
    df = pd.DataFrame(list_search)
    df.to_json(r'objects_table_'+str(object_type)+'_'+curr_date+'.json', orient='table') # this returns multiple tables (more relational structure)
    #df.to_json(r'objects_records_'+str(object_type)+'_'+curr_date+'.json', orient='records') #this returns a single table
    # Generating CSV files    
    df.to_csv (r'export_objects_'+str(object_type)+'_'+curr_date+'.csv', index = None, header=True) #Don't forget to add '.csv' at the end of the path
### Main program    
main()


Comment

0 comments

Details

Example

Published:

November 27, 2019

Last Updated:

March 21, 2024