Unable to target Web Services After Operation Rule response

Hello,

For a web services source we need an after operation rule to make changes to the original response returned by the target API and concatenate differente values.

The problem lies in mapping the response in the source configuration. Even though the rule prints show that the result returned by the rule is correct in the logs, the JSON path does not work (tried with and without “data”). The only value I can retrieve is by replacing “data” with the name of the account attribute and returning the “processedResponseObject” variable, but in this case, the assigned value is a string that contains the original response received by the API before it was processed by the rule.

Example :

Original API response :

{

  "id": "7C",

  "grants": [

      {

          "subjectId": "7C",

          "division": {

              "id": "1",

              "name": "D1",

              "description": "D1"

          },

          "role": {

              "id": "2",

              "name": "R2",

              "description": "R2"

          }

      },

      {

        "subjectId": "7C",

        "division": {

            "id": "11",

            "name": "D11",

            "description": "D11"

        },

        "role": {

            "id": "22",

            "name": "R22",

            "description": "R22"

        }

    }

  ]

}

Response returned by the after rule (after the concatenation) :

{

  "data": [

      {

          "subjectId": "8C",

          "divisionRole": {

              "id": "1 | 2"

          },

          "userId": "7C",

      },

      {

        "subjectId": "8C",

        "divisionRole": {

            "id": "11 | 22"

        },

        "userId": "7C",

    }

  ]

}

I am using the following after rule based on the oficial sailpoint tamplate :

import connector.common.JsonUtil;

import java.util.HashMap;

import java.util.Map.Entry;

import java.util.Map;

import java.util.List;

import java.util.ArrayList;

import javax.net.ssl.HttpsURLConnection;

import java.io.BufferedReader;

import java.io.PrintStream;

import java.io.StringWriter;

import java.text.SimpleDateFormat;

import sailpoint.tools.GeneralException;




Map updatedMapInfo = new HashMap();

List list = new ArrayList();

ArrayList<String> Roles = new ArrayList<String>();

Map response = (Map) JsonUtil.toMap(rawResponseObject);

List Finallist = new ArrayList();




log.info("=> RULES response at start" + response);

if (response.get("grants") != null) {

    String userId = (String) response.get("id");

    log.info("=> this is userId" + userId);

    list = (ArrayList) response.get("grants");

    log.info("=> this is grants list" + list);




    for(int d = 0; d < list.size(); d++ ){




        Map responseMap = (Map) list.get(d);

        log.info("=> Processing grant " + d);

        log.info("=> this is responseMap" + responseMap);




        String subjectId = (String) responseMap.get("subjectId");




        Map division = (Map) responseMap.get("division");

        Map role = (Map) responseMap.get("role");




        if (division != null && role != null) {

            // Create the divisionRole object

            Map divisionRole = new HashMap();

            String divisionId = division.get("id");

            String roleId = role.get("id");

            String concatenatedDivisionRoleId = divisionId + " | " + roleId;

            divisionRole.put("id", concatenatedDivisionRoleId);

            // divisionRole.put("id", division.get("id") + " | " + role.get("id"));

            // divisionRole.put("name", division.get("name") + " | " + role.get("name"));

            // divisionRole.put("description", division.get("description") + " | " + role.get("description"));




            log.info("=> Created divisionRole: " + divisionRole);




            // Create the transformed object

            Map transformedGrant = new HashMap();

            transformedGrant.put("subjectId", subjectId);

            transformedGrant.put("divisionRole", divisionRole);

            transformedGrant.put("userId", userId);




            Finallist.add(transformedGrant);

        }

    }




}




log.info("=> RULES Finallist at end" + Finallist);




log.info("=> RULES processedResponseObject Before is " + processedResponseObject);




updatedMapInfo.put("data", Finallist);

log.info("=> RULES updatedMapInfo is " + updatedMapInfo);




return updatedMapInfo;

The rule is used in the account aggregation and the get object calls.

Thanks in advance for your help !

Hi @khalil_sb ,

I have tested the below rule,

import sailpoint.connector.*;

import sailpoint.object.*;

import sailpoint.tools.GeneralException;

import connector.common.JsonUtil;

import java.util.*;



Map resultMap = new HashMap();        // final map to return

List finalList = new ArrayList();     // final list of processed objects



try {

// Convert the raw JSON string into a Java Map

Map response = (Map) JsonUtil.toMap(rawResponseObject);

log.info("=> RULES response at start" + response);



// Extract the list array

List list = (List) response.get("grants");

log.info("=> this is grants list" + list);



if (list != null && !list.isEmpty()) {

String userId = (String) response.get("id");

log.info("=> this is userId" + userId);



for (int i = 0; i < list.size(); i++) {

Map responseMap = (Map) list.get(i);

log.info("=> Processing grant " + i);

log.info("=> this is responseMap" + responseMap);



Map division = (Map) responseMap.get("division");

Map role = (Map) responseMap.get("role");



if (division != null && role != null) {

// Build concatenated divisionRole

Map divisionRole = new HashMap();

divisionRole.put("id", division.get("id") + " | " + role.get("id"));

log.info("=> Created divisionRole: " + divisionRole);



// Create the transformed object

Map transformedGrant = new HashMap();

transformedGrant.put("subjectId", responseMap.get("subjectId"));

transformedGrant.put("divisionRole", divisionRole);

transformedGrant.put("userId", userId);



finalList.add(transformedGrant);

            }

        }

    }



log.info("=> RULES Finallist at end" + finalList);



resultMap.put("data", finalList);

log.info("=> RULES resultMap is " + resultMap);



} catch (Exception e) {

log.error("AFTER-OP: Error processing response: " + e);

throw new GeneralException("Error in After Operation Rule", e);

}



return resultMap;


Got the response like the below,

{data=[{divisionRole={id=1 | 2}, userId=10c, subjectId=10C}, {divisionRole={id=11 | 22}, userId=10c, subjectId=10C}]}

Thank you!

I have used the below JAVA code as well to test the functionality. Use it for testing, if needed.

import java.util.*;

public class WebServiceAfterTestRule {
	
	public static void main(String[] args) {

        // --- Step 1: Simulate the JSON response manually as nested maps ---
        Map<String, Object> division1 = new HashMap<>();
        division1.put("id", "1");
        division1.put("name", "A1");
        division1.put("description", "A1 IS SOME");

        Map<String, Object> role1 = new HashMap<>();
        role1.put("id", "2");
        role1.put("name", "C2");
        role1.put("description", "C2 IS ANOTH");

        Map<String, Object> grant1 = new HashMap<>();
        grant1.put("subjectId", "10C");
        grant1.put("division", division1);
        grant1.put("role", role1);

        Map<String, Object> division2 = new HashMap<>();
        division2.put("id", "11");
        division2.put("name", "D11");
        division2.put("description", "D11");

        Map<String, Object> role2 = new HashMap<>();
        role2.put("id", "22");
        role2.put("name", "R22");
        role2.put("description", "R22");

        Map<String, Object> grant2 = new HashMap<>();
        grant2.put("subjectId", "10C");
        grant2.put("division", division2);
        grant2.put("role", role2);

        List<Map<String, Object>> grants = new ArrayList<>();
        grants.add(grant1);
        grants.add(grant2);

        Map<String, Object> response = new HashMap<>();
        response.put("id", "10c");
        response.put("grants", grants);

        // --- Step 2: Rule logic starts here ---
        Map<String, Object> resultMap = new HashMap<>();
        List<Map<String, Object>> finalList = new ArrayList<>();

        List<Map> list = (List<Map>) response.get("grants");

        if (list != null && !list.isEmpty()) {
            String userId = (String) response.get("id");

            for (int i = 0; i < list.size(); i++) {
                Map responseMap = list.get(i);
                Map division = (Map) responseMap.get("division");
                Map role = (Map) responseMap.get("role");

                if (division != null && role != null) {
                    Map divisionRole = new HashMap();
                    divisionRole.put("id", division.get("id") + " | " + role.get("id"));

                    Map transformedGrant = new HashMap();
                    transformedGrant.put("subjectId", responseMap.get("subjectId"));
                    transformedGrant.put("divisionRole", divisionRole);
                    transformedGrant.put("userId", userId);

                    finalList.add(transformedGrant);
                }
            }
        }

        resultMap.put("data", finalList);

        // --- Step 3: Print the final output ---
        System.out.println("=== Final Output ===");
        System.out.println(resultMap);
    }

}

Hi Gokul,

Same problem with you rule, first to be able to use your rule in ISC i had to replace the initialization of the variable finalList with the following code :

if (finalList == null) {

    finalList = new ArrayList();

} else {

    finalList.clear();

}

and even if the resluts are the same as the rule i provided earlier in this post, im unable to target any field in the response in the response mapping interface of the get object or account aggregation calls in ISC. no matter the JSON path it’s always blank.

Kind regards.

Hi,

I was able to find the solution, the probleme was in name of the key in the body generated by the rule, for example in your user schema if the entitlement attribut is named division-role, and in the body you generate in the rule you return the values inside a key named roles or anything else, it will not be mapped, i dont know if someone else encountered this case but, at least for entitlement attributs, you need to return a body with the exact same name that is mentioned in the schema (for the user id i have the attribute “id” in the schema and “userId” in the body returned by the rule and it still works).
I dont really know why but you have to do that for entitlements, at least in my case, the curious thing is that if we dont use a rule, the response doesn’t have the same name for the key but the mapping works :man_shrugging:

Kind regards

3 Likes

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.