Example: Reading a User's Apps and Authorizations (GraphQL)

The sample code below displays a user's team and Personal Account apps and authorizations.

๐Ÿ“˜

Primarily GraphQL

This example primarily uses the GraphQL Platform API, though it uses the REST Platform API for two functions. This example is approximately 50 percent faster than the primarily REST Platform API example.

This code uses a combination of the GraphQL and REST Platform APIs. Because it uses on-behalf-of functionality of the REST Platform API, you must configure the config.json object with a X-RapidAPI-Key from a team that has enterprise access to the platform API.

You can specify any Hub user's email address in the config.json file and read their apps and authorizations. Those users need no access to the Platform API.

Place the getAppsForAnyUserGQL.js file in the same directory as config.json. The admin_user_id must be the user ID of a user with enterprise access to the Platform API.

You can set the reportStatsToConsole variable to true to see more details on the type and duration of the API calls made.

const reportStatsToConsole = true;
let totalRestAPICalls = 0;
let totalTimeOnRestCalls = 0;
let totalGQLAPICalls = 0;
const axios = require("axios").default;

let optionsCommonRest;
let optionsCommonGql;

let userKeyCache = {};

let resultsLog = []; //used to log messages and a subset of the data obtained

// set specific user email address, Hub urls, key, category and preferences in config.json
let config = require("./config.json");

optionsCommonRest = {
  headers: {
    "x-rapidapi-host": config.rapidapi_host_rest,
    "x-rapidapi-key": config.key,
  },
};

optionsCommonGql = {
  method: "POST",
  url: config.base_url_gql,
  headers: {
    "x-rapidapi-host": config.rapidapi_host_gql,
    "x-rapidapi-key": config.key,
    "content-type": "application/json",
  },
};

runAll();

async function runAll() {
  console.log("working...");
  if (reportStatsToConsole) console.time("total execution time");
  if (reportStatsToConsole) console.time("getUserByEmail execution time");
  let results = {};
  results.aUser = await getUserByEmail(config.useremail, config.admin_user_id);
  if (results.aUser) {
    results.aUser.email = config.useremail;
    if (reportStatsToConsole) console.timeEnd("getUserByEmail execution time");
    if (reportStatsToConsole) console.log("userid: " + results.aUser.id);

    if (reportStatsToConsole)
      console.time("getAUsersTeamsAndAppsFromId execution time");
    results = await getAUsersTeamsAndAppsFromId(results);
    if (reportStatsToConsole)
      console.timeEnd("getAUsersTeamsAndAppsFromId execution time");

    if (reportStatsToConsole) console.time("team auths execution time");
    results = await getAuthorizationsForAllTeamApps(results);
    if (reportStatsToConsole) console.timeEnd("team auths execution time");

    if (reportStatsToConsole) console.time("personal auths execution time");
    results = await getAuthorizationsForAllPersonalApps(results);
    if (reportStatsToConsole) console.timeEnd("personal auths execution time");

    logResults(results);
    if (reportStatsToConsole) console.timeEnd("total execution time");
    if (reportStatsToConsole)
      console.log(
        `total time on REST calls: ${Math.round(totalTimeOnRestCalls) / 1000}s`
      );
    if (reportStatsToConsole)
      console.log(`total number of REST calls: ${totalRestAPICalls}`);
    if (reportStatsToConsole)
      console.log(`total number GQL calls: ${totalGQLAPICalls}`);
  } else {
    resultsLog.push(`User ${config.useremail} not found!`);
    displayResultsLog();
  }
}

async function getUserByEmail(email, adminUserId) {
  totalGQLAPICalls++;
  const optionsUnique = {
    data: {
      query: `query Users($where: UserWhereInput!) {
        users(where: $where) {
            id
            username
            name
            email
          }
      }`,
      variables: {
        where: {
          email: email,
        },
      },
    },
  };
  const optionsCommonClone = JSON.parse(JSON.stringify(optionsCommonGql)); // deep clone
  let options = { ...optionsCommonClone, ...optionsUnique };
  options = await transformOptionsForOnBehalfOf(options, adminUserId, "user");

  let response = await axios.request(options);
  return response?.data?.data?.users[0];
}

async function getAUsersTeamsAndAppsFromId(results) {
  const optionsUnique = {
    data: {
      query: `query Users($where: UserWhereInput!) {
        users(where: $where) {
          id
          username
          name
          email
          createdAt
          ProjectAcls{
            Project{
              name
              id
              description
            }
          }
          Teams{
            id
            name
            ProjectAcls{
              Project{
                name
                id
                description
              }
            }
          }
        }
      }`,
      variables: {
        where: {
          userIds: [results.aUser.id],
        },
      },
    },
  };
  const optionsCommonClone = JSON.parse(JSON.stringify(optionsCommonGql)); // deep clone
  let options = { ...optionsCommonClone, ...optionsUnique };
  options = await transformOptionsForOnBehalfOf(
    options,
    results.aUser.id,
    "user"
  );

  totalGQLAPICalls++;
  let response = await axios.request(options);
  results.aUserTeams = [];
  for (const team of response?.data?.data?.users[0]?.Teams) {
    results.aUserTeams.push(team);
  }
  results.aUser.ProjectAcls = [];
  for (const projectAcl of response?.data?.data?.users[0]?.ProjectAcls) {
    if (projectAcl.Project) {
      // some Projects are null
      results.aUser.ProjectAcls.push(projectAcl);
    }
  }
  return results;
}

async function getApps(entityID) {
  const start = performance.now();
  const optionsUnique = {
    method: "GET",
    url: `${config.base_url_rest}apps`,
  };
  const optionsCommonClone = JSON.parse(JSON.stringify(optionsCommonRest)); // deep clone
  const options = { ...optionsCommonClone, ...optionsUnique };
  options.headers["on-behalf-of"] = entityID;
  totalRestAPICalls++;
  let response = await axios.request(options);
  const end = performance.now();
  totalTimeOnRestCalls = totalTimeOnRestCalls + end - start;
  return response.data;
}

async function getAuthorizationsForAllPersonalApps(resultObj) {
  const appPromises = resultObj.aUser.ProjectAcls.map((app) => {
    return getAppAuthorizations(app.Project.id, resultObj.aUser.id).then(
      (authorizations) => {
        app.authorizations = authorizations;
      }
    );
  });

  await Promise.all(appPromises);

  return resultObj;
}

async function getAuthorizationsForAllTeamApps(resultObj) {
  const promises = [];
  for (const team of resultObj.aUserTeams) {
    for (const app of team.ProjectAcls) {
      const promise = getAppAuthorizations(
        app.Project.id,
        resultObj.aUser.id
      ).then((authorizations) => {
        app.authorizations = authorizations;
      });
      promises.push(promise);
    }
  }
  await Promise.all(promises);
  return resultObj;
}

async function getAppKeys(entityID, projectID) {
  const start = performance.now();
  const optionsUnique = {
    method: "GET",
    url: `${config.base_url_rest}apps/${projectID}/keys`,
  };
  const optionsCommonClone = JSON.parse(JSON.stringify(optionsCommonRest)); // deep clone
  const options = { ...optionsCommonClone, ...optionsUnique };
  options.headers["on-behalf-of"] = entityID;
  totalRestAPICalls++;
  let response = await axios.request(options);
  // return only active production keys
  const validKeys = [];
  response.data.environments.forEach((env) => {
    if (
      env.applicationEnvironmentName === "Production" &&
      env.status === "ACTIVE"
    )
      validKeys.push(env);
  });
  const end = performance.now();
  totalTimeOnRestCalls = totalTimeOnRestCalls + end - start;
  return validKeys;
}

async function getAppAuthorizations(projectId, userId) {
  const optionsUnique = {
    data: {
      query: `query ApplicationAuthorizations($projectId: ID!) {
      applicationAuthorizations(where: {projectId: $projectId}) {
      id
      key
      name
      authorizationType
      authorizationValues
      }
    }`,
      variables: { projectId: projectId },
    },
  };
  const optionsCommonClone = JSON.parse(JSON.stringify(optionsCommonGql)); // deep clone
  let options = { ...optionsCommonClone, ...optionsUnique };
  options = await transformOptionsForOnBehalfOf(options, userId, "user");
  totalGQLAPICalls++;
  let response = await axios.request(options);
  return response.data.data.applicationAuthorizations;
}

async function getAPersonalKeyForUser(userId) {
  if (userKeyCache[userId]) {
    return userKeyCache[userId];
  }
  let personalApps = await getApps(userId);
  let keys = await getAppKeys(userId, personalApps[0].projectId);
  let key;
  keys.forEach((env) => {
    if (
      env.applicationEnvironmentName === "Production" &&
      env.status === "ACTIVE"
    )
      if (!key) {
        key = env.key; //return first valid key
        userKeyCache[userId] = key;
      }
  });
  return key || "no key found";
}

async function transformOptionsForOnBehalfOf(options, entityID, entityType) {
  let results = {};
  if (entityType === "user") {
    options.headers["x-rapidapi-identity-key"] = await getAPersonalKeyForUser(
      entityID
    );
  }
  return options;
}

function logResults(results) {
  resultsLog.push(`Userid for ${results.aUser.email} is ${results.aUser.id}`);
  resultsLog.push(``);
  resultsLog.push(
    `Number of apps for ${results.aUser.email} in Personal Account: ${results.aUser.ProjectAcls.length}`
  );
  results.aUser.ProjectAcls.forEach((app) => {
    resultsLog.push(`    ${app.Project.id} ${app.Project.name}`);
    resultsLog.push(`       Authorizations: ${app.authorizations.length}`);
    app.authorizations.forEach((auth) => {
      if (auth.authorizationType === "RAPIDAPI") {
        resultsLog.push(`         RAPIDKEY ${auth.name} ${auth.key}`);
      } else {
        resultsLog.push(
          `         AUTHORIZATION ${auth.name} ${auth.authorizationType} ${auth.authorizationValues}`
        );
      }
    });
  });

  resultsLog.push(``);

  resultsLog.push(
    `Teams for ${results.aUser.email}: ${results.aUserTeams.length}`
  );
  results.aUserTeams.forEach((team) => {
    resultsLog.push(`  Team: ${team.name} (${team.id})`);
    resultsLog.push(`    Apps for team: ${team.ProjectAcls.length}`);
    team.ProjectAcls.forEach((app) => {
      resultsLog.push(`       ${app.Project.id} ${app.Project.name}`);
      resultsLog.push(
        `       Authorizations for team: ${app.authorizations.length}`
      );
      app.authorizations.forEach((auth) => {
        if (auth.authorizationType === "RAPIDAPI") {
          resultsLog.push(`         RAPIDKEY ${auth.name} ${auth.key}`);
        } else {
          resultsLog.push(
            `         AUTHORIZATION ${auth.name} ${auth.authorizationType} ${auth.authorizationValues}`
          );
        }
      });
    });
  });

  displayResultsLog();
}

function displayResultsLog() {
  resultsLog.forEach((entry) => console.log(entry));
}

{
    "rapidapi_host_rest": "[HOST FROM REST SAMPLE CODE].rapidapi.com",
    "base_url_rest": "https://[URL FROM REST SAMPLE CODE].rapidapi.com/v1/",
    "rapidapi_host_gql": "[HOST FROM GQL SAMPLE CODE].rapidapi.com",
    "base_url_gql": "[URL FROM REST SAMPLE CODE].rapidapi.com/",
    "key": "[KEY FROM TEAM WITH ENTERPRISE PLATFORM API ACCESS]",
    "useremail": "[email protected]",
    "admin_user_id": "5713300"
}