WebServices - Get Object filter the JSON response

Hello Sailers,

I’m trying to connect an application via a WebServices connector. The target app has an API working fine, so far so good. I have an issue, that there is an ephemeral ID on the source account attribute, which is not persistent. But in order to perform update operations on the source account, I need to provide the current ephemeral ID value. It changes after every Aggregate operation (could also on-top be time-limited, haven’t waited long enough to find out, but for sure after every aggregation there is a new ID). Right now, I’m trying to implement the Get Object HTTP Operation, so that the id value is current, so that I can in a second step perform the update operations.

I have the challenge, that I cannot filter for a specific user in the /get_user API query, it always returns all users (already checked with the vendor, it doesn’t exist, not just undocumented).

What I have tried for example with the WebServices Get Object operation, is set the Root path, to try and filter for just the target source account. For example using this JSON path evaluator: https://jsonpath.com/. But it seems, I cannot make it dynamic.. unless I’m doing something wrong (which is why I’m making this post) with brain fog.

  • this Root Path works:
    $.data.users[?(@.email_address == 'user1@company.com')](hardcoded email)
  • This Root Path fails:
    $.data.users[?(@.email_address == '$plan.nativeIdentity$')](using the plan.nativeIdentity field)

The Get Object operation must be dynamic though, I cannot hardcode the e-mail there.

The $plan.nativeIdentity$ does return the E-Mail, I have verified that. In my mind, it should resolve the e-mail address, but it seems that the Return path does not take variables(?). I have also tried $getObject.nativeIdentity$ to resolve the E-Mail address (also did not work).

Is there another way for me to filter the results which are being returned in the JSON? The API always returns the full JSON.

This is an example JSON from the reply:

 {
  "data": {
    "users": [
      {
        "active": true,
        "country": "TR",
        "email_address": "user1@company.com",
        "first_name": "Tony",
        "id": "WXJqPj...",
        "is_sso_active": false,
        "last_name": "Doe",
        "phone_number": "+1234567890",
        "roles": [
          {
            "description": "Company Admin",
            "name": "companyadmin",
            "title": "Companyadmin"
          }
        ],
        "send_assignee_email": false,
        "title": "Security Analyst"
      },
      {
        "active": false,
        "country": "TR",
        "email_address": "user2@company.com",
        "first_name": "Ezequiel",
        "id": "EaX34a...",
        "is_sso_active": false,
        "last_name": "Doe",
        "phone_number": "+1234567890",
        "roles": [
          {
            "description": "Company User",
            "name": "companyuser",
            "title": "Companyuser"
          }
        ],
        "send_assignee_email": false,
        "title": "Security Analyst"
      }
    ]
  },
  "is_success": true,
  "message": "Success",
  "response_code": 200
}

Screenshot of what I am trying to achieve:

Thanks in advance!

Hi @othornewill

Interesting use case and kind of ridiculous the vendor doesn’t support a filter or even a single user GET call. Unfortunately, I don’t think JSONPath expressions are supported in the Response Mapping configuration. I’ve personally never seem someone use it that way, but it’s a good idea if it worked.

I think the best and only solution here is to pass your email or filter attribute into a header using a dummy attribute, lets say X-Target-Email$getObject.nativeIdentity$ and then use that in a After Operations Rule to do the parsing there and save back the single user you want returned. Your Get Object operation would basically look exactly like your regular account aggregation operation with the exception of needing that header and an after operations rule attached to it.

Here is a sample rule you could use:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonArray;

Map updatedMapInfo = new HashMap();

// 1. Get the target email from the custom header we set in the UI
String targetEmail = "";
Map headers = requestEndPoint.getHeader();
if (headers != null && headers.containsKey("X-Target-Email")) {
    targetEmail = (String) headers.get("X-Target-Email");
}

if (targetEmail != null && !targetEmail.isEmpty()) {
    // 2. Parse the raw JSON response
    String rawResponse = rawResponseObject;
    JsonObject jsonResponse = JsonParser.parseString(rawResponse).getAsJsonObject();
    
    // 3. Navigate to the users array
    if (jsonResponse.has("data") && jsonResponse.get("data").getAsJsonObject().has("users")) {
        JsonArray usersArray = jsonResponse.get("data").getAsJsonObject().get("users").getAsJsonArray();
        
        // 4. Iterate through the array to find the matching user
        JsonObject matchedUser = null;
        for (JsonElement userElement : usersArray) {
            JsonObject userObj = userElement.getAsJsonObject();
            if (userObj.has("email_address") && userObj.get("email_address").getAsString().equals(targetEmail)) {
                matchedUser = userObj;
                break;
            }
        }
        
        // 5. If we found the user, update the response
        if (matchedUser != null) {
            // Rebuild the JSON response with ONLY the matched user 
            // so your schema mapping and root path works exactly the same
            JsonObject newResponse = new JsonObject();
            JsonObject newData = new JsonObject();
            JsonArray newUsersArray = new JsonArray();
            newUsersArray.add(matchedUser);
            newData.add("users", newUsersArray);
            newResponse.add("data", newData);
            
            updatedMapInfo.put("data", newResponse.toString());
        } else {
             // Handle case where user isn't found
             updatedMapInfo.put("data", "{\"data\": {\"users\": []}}");
        }
    }
} else {
    // Fallback if header wasn't found
    updatedMapInfo.put("data", rawResponseObject);
}

return updatedMapInfo;

Thank you Tyler, this was very useful. I got the “Get Object” HTTP Operation to work fine now!

Now I just need to find a way to string it together. I’m currently trying what you described (two Disable Account HTTP Operations, one which is basically as you wrote, followed by the POST request as required). Currently doing that, but your WebServicesAfterOperation rule worked out.

Thanks!

another note on this one,
i believe the variable you’d need is $getobject.nativeIdentity$, with a lowercase o on object.