Get Relationships in py_jama_rest_client

Aaron Riede
Aaron Riede Member Posts: 6

Hi all,

I want to use the JAMA Rest API in Python to get all relationships of my project.

My minimal example is:

from py_jama_rest_client.client import JamaClient
client = JamaClient(<JAMA URL>, credentials=(<Username>, <Password>))
relationships = client.get_relationships(project_id=53)

The error, I get is: "py_jama_rest_client.client.APIClientException: 400  Client Error.  Bad Request.  API response message: The lastId parameter is now required to call GET /relationships API endpoint."

The login to Jama client works, since I can use other endpoints. It's only the third line that has a problem.
Can anybody help me with that issue or propose another solution, how to loop through all downstream relationships of an item?

Thanks and best regards, 
Aaron

------------------------------
Aaron Riede
Spacetech
------------------------------

Comments

  • Dimitrios Pananakis
    Dimitrios Pananakis Member, Jama Validation Kit (JVK) + Functional Safety Kit (FSK) Posts: 57
    edited February 26

    Hello Aaron,

    The following guide should help you understand why it is necessary to pass a lastId parameter (in addition to the project id) in order to retrieve all relationships: https://dev.jamasoftware.com/cookbook/#getrelationships

    In order to find all API end-points easily, you can open a new browser tab (after you login to your instance) and point it to https://your instance.jamacloud.com/api-docs#/

    Suppose you have all items for which you want to find downstream relationships for, you can call the GET/items/{id}/downstreamrelationships end-point. This will retrieve only the downstream relationships for the item with the specified id.

    Warm regards

    Dimitrios

    -------------------------------------------
    Original Message:
    Sent: 02-26-2024 05:58
    From: Aaron Riede
    Subject: Get Relationships in py_jama_rest_client

    Hi all,

    I want to use the JAMA Rest API in Python to get all relationships of my project.

    My minimal example is:

    from py_jama_rest_client.client import JamaClient
    client = JamaClient(<JAMA URL>, credentials=(<Username>, <Password>))
    relationships = client.get_relationships(project_id=53)

    The error, I get is: "py_jama_rest_client.client.APIClientException: 400  Client Error.  Bad Request.  API response message: The lastId parameter is now required to call GET /relationships API endpoint."

    The login to Jama client works, since I can use other endpoints. It's only the third line that has a problem.
    Can anybody help me with that issue or propose another solution, how to loop through all downstream relationships of an item?

    Thanks and best regards, 
    Aaron

    ------------------------------
    Aaron Riede
    Spacetech
    ------------------------------
  • Aaron Riede
    Aaron Riede Member Posts: 6
    edited February 26

    Hi Dimitrios, 

    thank you very much for your response. 
    Using the Swaggr UI, it works perfectly to set a lastID. However, with Python, if I try something like:

    relationships = client.get_relationships(project_id=55, last_Id=0)

    I will get the error: "JamaClient.get_relationships() got an unexpected keyword argument 'last_Id'."

    Any ideas, how I can set the lastId in Python?

    Thanks,
    Aaron 

    ------------------------------
    Aaron Riede
    Spacetech
    ------------------------------
    -------------------------------------------
    Original Message:
    Sent: 02-26-2024 08:12
    From: Dimitrios Pananakis
    Subject: Get Relationships in py_jama_rest_client

    Hello Aaron,

    The following guide should help you understand why it is necessary to pass a lastId parameter (in addition to the project id) in order to retrieve all relationships: https://dev.jamasoftware.com/cookbook/#getrelationships

    In order to find all API end-points easily, you can open a new browser tab (after you login to your instance) and point it to https://your instance.jamacloud.com/api-docs#/

    Suppose you have all items for which you want to find downstream relationships for, you can call the GET/items/{id}/downstreamrelationships end-point. This will retrieve only the downstream relationships for the item with the specified id.

    Warm regards

    Dimitrios

    Original Message:
    Sent: 02-26-2024 05:58
    From: Aaron Riede
    Subject: Get Relationships in py_jama_rest_client

    Hi all,

    I want to use the JAMA Rest API in Python to get all relationships of my project.

    My minimal example is:

    from py_jama_rest_client.client import JamaClient
    client = JamaClient(<JAMA URL>, credentials=(<Username>, <Password>))
    relationships = client.get_relationships(project_id=53)

    The error, I get is: "py_jama_rest_client.client.APIClientException: 400  Client Error.  Bad Request.  API response message: The lastId parameter is now required to call GET /relationships API endpoint."

    The login to Jama client works, since I can use other endpoints. It's only the third line that has a problem.
    Can anybody help me with that issue or propose another solution, how to loop through all downstream relationships of an item?

    Thanks and best regards, 
    Aaron

    ------------------------------
    Aaron Riede
    Spacetech
    ------------------------------
  • Dimitrios Pananakis
    Dimitrios Pananakis Member, Jama Validation Kit (JVK) + Functional Safety Kit (FSK) Posts: 57
    edited February 26

    Hi Aaron

    You need to lookup the implementation of the client code.

    Open it and see that probably there is no argument for last_id in the get_relationships() method.
    You really need to lookup the cookbook article and modify the get_relationships() method according to that. The one you are probably using (from github) is an outdated method that Jama never modified/updated after the API update - i don't know why they decided to abandon the client to rot.

    Warm regards

    Dimitrios

    -------------------------------------------
    Original Message:
    Sent: 02-26-2024 08:39
    From: Aaron Riede
    Subject: Get Relationships in py_jama_rest_client

    Hi Dimitrios, 

    thank you very much for your response. 
    Using the Swaggr UI, it works perfectly to set a lastID. However, with Python, if I try something like:

    relationships = client.get_relationships(project_id=55, last_Id=0)

    I will get the error: "JamaClient.get_relationships() got an unexpected keyword argument 'last_Id'."

    Any ideas, how I can set the lastId in Python?

    Thanks,
    Aaron 

    ------------------------------
    Aaron Riede
    Spacetech
    ------------------------------

    Original Message:
    Sent: 02-26-2024 08:12
    From: Dimitrios Pananakis
    Subject: Get Relationships in py_jama_rest_client

    Hello Aaron,

    The following guide should help you understand why it is necessary to pass a lastId parameter (in addition to the project id) in order to retrieve all relationships: https://dev.jamasoftware.com/cookbook/#getrelationships

    In order to find all API end-points easily, you can open a new browser tab (after you login to your instance) and point it to https://your instance.jamacloud.com/api-docs#/

    Suppose you have all items for which you want to find downstream relationships for, you can call the GET/items/{id}/downstreamrelationships end-point. This will retrieve only the downstream relationships for the item with the specified id.

    Warm regards

    Dimitrios

    Original Message:
    Sent: 02-26-2024 05:58
    From: Aaron Riede
    Subject: Get Relationships in py_jama_rest_client

    Hi all,

    I want to use the JAMA Rest API in Python to get all relationships of my project.

    My minimal example is:

    from py_jama_rest_client.client import JamaClient
    client = JamaClient(<JAMA URL>, credentials=(<Username>, <Password>))
    relationships = client.get_relationships(project_id=53)

    The error, I get is: "py_jama_rest_client.client.APIClientException: 400  Client Error.  Bad Request.  API response message: The lastId parameter is now required to call GET /relationships API endpoint."

    The login to Jama client works, since I can use other endpoints. It's only the third line that has a problem.
    Can anybody help me with that issue or propose another solution, how to loop through all downstream relationships of an item?

    Thanks and best regards, 
    Aaron

    ------------------------------
    Aaron Riede
    Spacetech
    ------------------------------
  • Nils Reichert
    Nils Reichert Member Posts: 1
    edited March 7

    Actually I do have some kind of workaround solution for you:

    image

    visit the /api-docs/  page and in the inner, the api URL, change it from
    .../rest/v1/api-docs
    to
    .../rest/labs/api-docs

    this one allows you to use the method without lastId.

    And no, even if maybe items may change while fetching and you may get a result multiple times, I also strongly disagree with the force that lastId has to be used. no matter what you use with startAt, since lastId was used, the startAt is completely useless.

    Also in the past it was possible to run multiple read commands in parallel.
    one to read 0..49
    second one to read 50..99
    third one to read 100-149
    etc.

    but with lastId you cannot do this anymore, since you need to wait for the complete response of first one to know item number 49 and then you can use its id for the second read.

    here some changed parts. build url will select one of the 2 urls,

    __init__ will store also __host_name_labs so this can also be used by using a parameter

        def build_url(self, resource, api_labs):
            if api_labs:
                result = self.__host_name_labs + resource
            else:
                result = self.__host_name + resource
            return result
    
       def __init__(self, host_name, user_credentials, api_version='/rest/v1/', oauth=False, verify=True):
            # Instance variables
            self.__api_labs_version = '/rest/labs/'
            self.__api_version = api_version
            self.__host_name = host_name + self.__api_version
            self.__host_name_labs = host_name + self.__api_labs_version
            self.__credentials = user_credentials
            self.__oauth = oauth
            self.__verify = verify
            self.__session = requests.Session()
    [...]
    
       def get(self, resource, params=None, api_labs=False, **kwargs):
            """ This method will perform a get operation on the specified resource"""
            url = self.build_url(resource, api_labs)

    doing those changes, you can use..

        def get_all_relationships(self, project_id, use_labs=True):
            """
            This method will return JSON data about all the relationships in the specified project.
            Args:
                project_id: the api id of the project to fetch all relationships
                use_labs: which rest api to use. In case labs i no more supported, set to False
            Returns: a list of relationships with id, type, from, and to
            """
    
            if use_labs:
                params = {'project': project_id}
                relationships = self._JamaClient__get_all('relationships', params,
                                                          api_labs=True, omitCount=True,
                                                          allowed_results_per_page=1000)
            else:
                # Method to read relationships with v1 instead of labs (in case labs is no more supported)
                relationships = self.get_relationships(project_id, allowed_results_per_page=10000)
            return relationships

    important also to mention, since it seems to be nowhere documented either: the max results per page is 50 for most requests, but here it is much higher, I think up to 10.000

    seemed to make a difference in speed when using it up to 1000, so use the allowed_results_per_page=1000

    oh, and also need to modify the core methods to also accept that parameter as well..

    internally you can use a ..

    with ThreadPoolExecutor(max_workers=workers) as executor:

    and since the order may be different from parallel readings, also sort results by id, to have the correct last id.

    here how the __get_page in client.py is modified:

    def __get_page(self, resource, start_at, last_id=None, api_labs=False, params=None,
                       allowed_results_per_page=__allowed_results_per_page,  **kwargs):
            """This method will return one page of results from the specified resource type.
            Pass any needed parameters along
            The response object will be returned"""
            parameters = {
                'startAt': start_at,
                'maxResults': allowed_results_per_page
            }
            if last_id or last_id == 0:
                parameters['lastId'] = last_id
    
            if params is not None:
                for k, v in params.items():
                    parameters[k] = v
    
            try:
                response = self.__core.get(resource, params=parameters, api_labs=api_labs, **kwargs)
            except CoreException as err:
                py_jama_rest_client_logger.error(err)
                raise APIException(str(err))
            JamaClient.__handle_response_status(response)
            return response

    This should help you more than enough.

    Ah, about the get all, this is a method that repeats reading things until you got all items, but not one after the other, run things in parallel, much much faster, and needed since we can never get more than 50 results per read.

    best regards,

    Nils Reichert

    ------------------------------
    Nils Reichert
    Atlas Copco
    ------------------------------
    -------------------------------------------
    Original Message:
    Sent: 02-26-2024 05:58
    From: Aaron Riede
    Subject: Get Relationships in py_jama_rest_client

    Hi all,

    I want to use the JAMA Rest API in Python to get all relationships of my project.

    My minimal example is:

    from py_jama_rest_client.client import JamaClient
    client = JamaClient(<JAMA URL>, credentials=(<Username>, <Password>))
    relationships = client.get_relationships(project_id=53)

    The error, I get is: "py_jama_rest_client.client.APIClientException: 400  Client Error.  Bad Request.  API response message: The lastId parameter is now required to call GET /relationships API endpoint."

    The login to Jama client works, since I can use other endpoints. It's only the third line that has a problem.
    Can anybody help me with that issue or propose another solution, how to loop through all downstream relationships of an item?

    Thanks and best regards, 
    Aaron



    ------------------------------
    Aaron Riede
    Spacetech
    ------------------------------