Web Services connector : Add entitlement with PATCH

Hello,

Context :

I am trying to integrate an application to ISC using APIs. The accounts aggregation works fine, but the app does not have a dedicated endpoint to add or remove an entitlement.
It does however have a PATCH operation that can be used, but it replaces all existing entitlements with the new value provided.

What I tried :

Following some threads on the forum, I tried to used 2 chained HTTP operations :

1rst operation :
Type : Add Entitlement-role
Retrieve the current users, including the current roles.
Through postman, the response body is the following :

{
    "id": "ID-12345",
    "name": {
        "firstName": "John",
        "gender": "UNKNOWN",
        "lastName": "Doe"
    },
    "email": "john.doe@company.com",
    "timeZoneCode": "Europe/Amsterdam",
    "username": "john.doe@company.com",
    "roles": [
        "role1",
        "role2"
    ]
}

And my response mapping is :

2nd operation :
Type : Get Object
Is the actual PATCH operation, set with the 1rst operation as the parent endpoint.

To populate this operation with the proper body, I set the following beforeProvisioningRule to it :

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.Set;
import java.util.LinkedHashSet;

Map body = requestEndPoint.getBody();
if (body == null) body = new HashMap();
String jsonBody = (String) body.get("jsonBody");


log.info("App PATCH oldresponse: " + oldResponseMap);

// 1) Read existing roles from oldResponseMap (roles only), normalizing to a List<String>
List currentRoles = null;
if (oldResponseMap != null) {
  Object cur = oldResponseMap.get("roles");
  if (cur instanceof List) {
    currentRoles = (List) cur;
  } else if (cur != null) {
    currentRoles = new ArrayList();
    currentRoles.add(String.valueOf(cur));
  }
}

// 2) Merge existing first, then add the new role (de-duplicated, order-preserving)
Set merged = new LinkedHashSet();

// Add existing first
if (currentRoles != null) {
  for (Object o : currentRoles) {
    if (o != null) merged.add(String.valueOf(o));
  }
}

// 3) Parse new roles from jsonBody (roles only)
if (jsonBody != null) {
  String trimmed = jsonBody.trim();
  try {
    if (trimmed.startsWith("{")) {
      // jsonBody is a JSON object; use 'roles' field only
      Map jsonMap = JsonUtil.toMap(trimmed);
      Object rolesField = (jsonMap != null) ? jsonMap.get("roles") : null;
      if (rolesField instanceof List) {
        for (Object o : (List) rolesField) if (o != null) merged.add(String.valueOf(o));
      } else if (rolesField != null) {
        merged.add(String.valueOf(rolesField));
      } else {
        // No 'roles' in object; treat object string as a single value (optional behavior)
        merged.add(trimmed);
      }
    } else {
      // Single string value
      merged.add(trimmed);
    }
  } catch (Exception e) {
    log.warn(application.getName() + " Combine Roles: Failed to parse jsonBody; treating as single value. Err=" + e);
    merged.add(trimmed);
  }
}

// 4) Build final JSON body: {"roles":[ ... ]}
Map payload = new HashMap();
payload.put("roles", new ArrayList(merged));
String finalBody = connector.common.JsonUtil.render(payload);

body.put("jsonBody", finalBody);
requestEndPoint.setBody(body);

Still, the body is always empty.

Anyone has a guess on what is wrong ?

Thank you !

Hi @davidtrn

I’ve worked on a similar scenario where I used the below web service before operation rule.

List teamIds = new ArrayList();

if (currentRoles != null) {
    for (Object role : currentRoles) {
        if (role instanceof String) {
            try {
                String[] rolesArray = ((String) role).split(",");
                for (String roleStr : rolesArray) {
                    String roleId = roleStr.trim();
                    if (!teamIds.contains(roleId)) {
                        teamIds.add(roleId);
                    }
                }
            } catch (Exception e) {
                throw new GeneralException("Error parsing team_ids String: " + role, e);
            }
        } else {
            throw new Exception("Unexpected type for team ID: " + role.getClass().getName());
        }
    }
} else {
    throw new Exception("currentRoles is null in one of the user objects");
}

} else {
    throw new Exception("Expected a Map in the list but got: " + obj.getClass().getName());
}

}
} else {
    throw new Exception("Expected a List for userObj but got: " + userObj.getClass().getName());
}

Map body = requestEndPoint.getBody();
String jsonBody = (String) body.get("jsonBody");
Map jsonMap = JsonUtil.toMap(jsonBody);
Map usersMap = (Map) jsonMap.get("user");

if (provisioningPlan != null) {
    for (AccountRequest accReq : provisioningPlan.getAccountRequests()) {
        for (ProvisioningPlan.AttributeRequest attReq : accReq.getAttributeRequests()) {
            if ("team_ids".equalsIgnoreCase(attReq.getName())) {
                Object ids = attReq.getValue();
                if (ids instanceof List) {
                    List idsList = (List) ids;
                    for (Object id : idsList) {
                        if (id instanceof String) {
                            String idStr = ((String) id).trim();
                            if (!teamIds.contains(idStr)) {
                                teamIds.add(idStr);
                            }
                        } else {
                            throw new Exception("Unexpected type in team_ids list: " + id.getClass().getName());
                        }
                    }
                } else if (ids instanceof String) {
                    String[] idsArray = ((String) ids).split(",");
                    for (String idStr : idsArray) {
                        String trimmedId = idStr.trim();
                        if (!teamIds.contains(trimmedId)) {
                            teamIds.add(trimmedId);
                        }
                    }
                } else {
                    throw new Exception("Unexpected type for team_ids attribute: " + ids.getClass().getName());
                }
            }
        }
    }
}

Hi Gopi,

Thanks for your input. I have two questions :
1 - Once you have the correct values to use, how do you map it to the body of the request to be sent ?
2 - How do you set this rule to the HTTP operation ? Are you using “beforeRule” or something else ?

Kind regards

Hi @davidtrn

  1. Object existingTeamIds = usersMap.get("team_ids"); – This piece of code is used to retrieve the existing team IDs. If that is not possible, we can use an API call to retrieve the existing values. After processing, we update the body using the code:
    usersMap.put("team_ids", teamIds);
  2. I have attached this Before Operation Rule in the Add Entitlement operation.

After adding logs to my rule :

Map body = requestEndPoint.getBody();
if (body == null) body = new HashMap();
String jsonBody = (String) body.get("jsonBody");

log.info(application.getName() + " Combine Roles: body: " + body);

The ccg logs :

“message”:“STG - APP VA [source-1757425274935] Combine Roles: body: {jsonBody=null, bodyFormat=raw}”

Map body = requestEndPoint.getBody(); is returning an empty body even if I configured it as this :

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