Example: Creating and Deleting Apps (GraphQL)

The sample code below creates and optionally deletes an app for any user in your Hub. The app can be created in a team or personal account context.

📘

Primarily GraphQL

This example primarily uses the GraphQL Platform API, though it also uses the REST Platform API.

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.

The following field in the config.json file can be configured:

  • create_app_context - Set to personal or team. If you specify personal, the app will be created in the user's personal account. If you specify team, you must also specify the create_app_team_id (see below).
  • create_app_team_id - If you set create_app_context to team above, you must specify the team ID that will contain the new app. If you set create_app_context to personal, this field is not used.
  • delete_app_after_creation - Set to true or false. If set to true, the app that is created will be immediately deleted and you will see a deleted: true field in the results.

Place the createAppAndOptionallyDeleteGQL.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 = false;
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("createApp execution time");
    if (config.create_app_context === "personal") {
      results = await createApp(results.aUser.id, results);
    } else {
      results = await createApp(config.create_app_team_id, results);
    }
    if (reportStatsToConsole) console.timeEnd("createApp execution time");

    if (config.delete_app_after_creation) {
      if (config.create_app_context === "personal") {
        results = await deleteApp(results.aUser.id, results);
      } else {
        results = await deleteApp(config.create_app_team_id, results);
      }
    }

    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 createApp(context, results) {
  const optionsUnique = {
    data: {
      query: `mutation CreateProject($project: ProjectCreateInput!) {
        createProject(project: $project) {
          id
          mashapeId
          name
          description
        }
       }`,
      variables: {
        project: {
          projectOwner: context,
          projectName: "app_" + new Date().toLocaleString().replace(",", ""),
          description:
            "Description for " + new Date().toLocaleString().replace(",", ""),
        },
      },
    },
  };
  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.newApp = response?.data?.data?.createProject;
  return results;
}

async function deleteApp(context, results) {
  const start = performance.now();
  const optionsUnique = {
    method: "DELETE",
    url: `${config.base_url_rest}apps/${results.newApp.id}`,
  };
  const optionsCommonClone = JSON.parse(JSON.stringify(optionsCommonRest)); // deep clone
  const options = { ...optionsCommonClone, ...optionsUnique };
  options.headers["on-behalf-of"] = context;
  totalRestAPICalls++;
  let response = await axios.request(options);
  const end = performance.now();
  totalTimeOnRestCalls = totalTimeOnRestCalls + end - start;
  if (response.status == 204) {
    results.newApp.deleted = true;
  }
  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 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 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}`);

  if (config.create_app_context === "personal") {
    resultsLog.push(`Personal app created for ${results.aUser.email}:`);
    resultsLog.push(JSON.stringify(results.newApp));
  } else {
    resultsLog.push(`Team app created for ${config.create_app_team_id}:`);
    resultsLog.push(JSON.stringify(results.newApp));
  }

  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",
    "create_app_context": "team",
    "create_app_team_id": "6028339",
    "delete_app_after_creation": true
}