NAV
javascript

Introduction

Welcome to the App Capture Backend API Docs!

You can use our API to manage requests made from apps to our backends. The main purpose of this is to allow custom responses for requests to be set at the replay-level. This could be used for a variety of different things including solving authentication state bugs, inserting data where needed to fix 404 errors, or customizing data in a replay.

All code is written in JavaScript! You can view code examples in the dark area to the right.

Usage

In order to use the App Capture Backend API, you need to be logged into your Reprise platform account.

Find the application capture replay you are looking to modify and click into the 'Editor'. On the lefthand navigation bar, go to the settings tab (which has a gear icon), and click "Add Snippet". The new snippet modal should pop up. Set your new snippet type to "Replay Backend" and add your code into the given code box.

Congradulations! You are now writing to the App Capture Backend API for your corresponding replay.

Configuring request processing consists of 2 steps:

  1. Defining what request we want to process (aka Request Interception)
  2. Defining what to do with request (aka Request Processing)

Request Interception

There is a Global Interface replay_backend that has following methods to configure intercepting requests:

Match Domain

Example code:

// Intercept only GET requests sent to the "reprise" domain
replay_backend.match_domain("reprise");

// Intercept only GET requests sent to the "reprise.com" domain
replay_backend.match_domain("reprise.com");

// Intercept only GET requests sent to the domain with a wildcard
// (meaning the information at the * can be anything)
replay_backend.match_domain("https://www.reprise.com/platform/*");

// Intercept any request sent to the "reprise" domain
replay_backend.match_domain("reprise", true);

replay_backend.match_domain(match, any_request = false);

This command intercepts requests that contain the given domain.

Query Parameters

Parameter Type Default Description
match string, regular expression Defines the domain where requests are being checked for.
any_request (optional) boolean false By default only GET requests are intercepted; to intercept all requests, set any_request to true.

Get Request

Example code:

// Intercept GET requests at the given path (with a dynamic URL)
replay_backend.get("/order-configurator/api/v1/sections/:section_id");

// Intercept GET requests to '/api/user/graphql' that has "host" in
// the request set to "reprise.com"
replay_backend.get("/api/user/graphql", (request) => {
  return request.host === "reprise.com";
});

replay_backend.get(route, request_filter);

This command intercepts GET requests made to the given route

Query Parameters

Parameter Type Description
route Route The path where we will intercept requests from.
request_filter (optional) RequestFilter This param receives 2 arguments - request and body (as string) and should return boolean (falsy value means that request should not be intercepted).

Head Request

Example code:

// Intercept HEAD requests at the given path (with a dynamic URL)
replay_backend.head("/order-configurator/api/v1/sections/:section_id");

replay_backend.head(route);

This command intercepts HEAD requests made to the given route.

Query Parameters

Parameter Type Description
route Route The path where we will intercept requests from.

Post Request

Example code:

// Intercept POST requests at the given path (with a dynamic URL)
replay_backend.post("/order-configurator/api/v1/sections/:section_id");

// Intercept POST requests to '/api/user/graphql' that have "userId"
// in "variables" in the body
replay_backend.post("/api/user/graphql", (request, body) => {
  const json = JSON.parse(body);
  return json.variables && json.variables.userId;
});

replay_backend.post(route, request_filter);

This command intercepts POST requests made to the given route.

Query Parameters

Parameter Type Description
route Route The path where we will intercept requests from.
request_filter (optional) RequestFilter This param receives 2 arguments - request and body (as string) and should return boolean (falsy value means that request should not be intercepted).

Put Request

Example code:

// Intercept PUT requests at the given path (with a dynamic URL)
replay_backend.put("/order-configurator/api/v1/sections/:section_id");

// Intercept PUT requests to '/api/user/graphql' that have "userId"
// in "variables" in the body
replay_backend.put("/api/user/graphql", (request, body) => {
  const json = JSON.parse(body);
  return json.variables && json.variables.userId;
});

replay_backend.put(route, request_filter);

This command intercepts PUT requests made to the given route.

Query Parameters

Parameter Type Description
route Route The path where we will intercept requests from.
request_filter (optional) RequestFilter This param receives 2 arguments - request and body (as string) and should return boolean (falsy value means that request should not be intercepted).

Patch Request

Example code:

// Intercept PATCH requests at the given path (with a dynamic URL)
replay_backend.patch("/order-configurator/api/v1/sections/:section_id");

// Intercept PATCH requests to '/api/user/graphql' that have "userId"
// in "variables" in the body
replay_backend.patch("/api/user/graphql", (request, body) => {
  const json = JSON.parse(body);
  return json.variables && json.variables.userId;
});

replay_backend.patch(route, request_filter);

This command intercepts PATCH requests made to the given route.

Query Parameters

Parameter Type Description
route Route The path where we will intercept requests from.
request_filter (optional) RequestFilter This param receives 2 arguments - request and body (as string) and should return boolean (falsy value means that request should not be intercepted).

Delete Request

Example code:

// Intercept DELETE requests at the given path (with a dynamic URL)
replay_backend.delete("/order-configurator/api/v1/sections/:section_id");

replay_backend.delete(route);

This command intercepts DELETE requests made to the given route.

Query Parameters

Parameter Type Description
route Route The path where we will intercept requests from.

Any Method

Example code:

// Intercept GET, PUT, and PATCH requests at the given path (with a dynamic URL)
replay_backend.any_method(
  ["GET", "PUT", "PATCH"],
  "/order-configurator/api/v1/sections/:section_id"
);

// Intercept PATCH and DELETE requests at the given path (with a dynamic URL)
replay_backend.any_method(
  ["PATCH", "DELETE"],
  "/order-configurator/api/v1/sections/:section_id"
);

replay_backend.any_method(methods, route);

This command allows describing several HTTP methods at once to intercept.

Query Parameters

Parameter Type Description
methods array A comma-separated list of HTTP methods we are looking to intercept from the options: 'DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT'
route Route The path where we will intercept requests from

All Methods

Example code:

// Intercept GET, HEAD, POST, PUT, PATCH and DELETE requests at the given path (with a dynamic URL)
replay_backend.all_methods("/order-configurator/api/v1/sections/:section_id");

replay_backend.all_methods(route);

This command intercepts all requests made to given path.

Query Parameters

Parameter Type Description
route Route The path where we will intercept requests from.

Request Processing

Once you have intercepted your target requests using the methods above, you can process them in a variety of ways:

Block

Example code:

// Block any request send to the "/products/new" path
replay_backend.get("/reprise", true).block();

request.block(options, body = "");

This command makes your replay return a custom response (defaulted to empty) for the request.

Query Parameters

Parameter Type Default Description
options (optional) Response A custom response to return for the reqeust.
body Blob or BufferSource or FormData or URLSearchParams or ReadableStream<Uint8Array> or string "" The body of the response returned for the request (defaulted to an empty string).

Pass

Example code:

// Allow all matching request send to the "/products/new" path to
// go to the real app
replay_backend.get("/products/new").pass();

request.pass();

This command causes matching requests go to your real app.

Redirect

Example code:

// Redirect requests from "https://banclyinc.atlassian.net"
// to go to "https://app.getreprise.com/livedemo/wl98nq9"
replay_backend.get("/").redirect((url) => {
  return url.replace(
    "https://banclyinc.atlassian.net",
    "https://app.getreprise.com/livedemo/wl98nq9"
  );
}, {
  method: "POST"
});

request.redirect(callback);

This command redirects the request to a new url.

Query Parameters

Parameter Type Description
callback (url: string) => string This param takes in a url string and returns the new url we should be redirected to
options (optional) RedirectOptions Options object

Handle

Example code:

// Intercept requests to '/api/user/graphql' that have "userId" in variables in post body and
// modify the "userId" in "variables" in the body
replay_backend
  .post("/api/user/graphql", (request, body) => {
    const json = JSON.parse(body);
    return json.variables && json.variables.userId;
  })
  .handle(async (request) => {
    const body = await request.json();
    body.variables.userId = 888;
    return JSON.stringify(body);
  });

// Fix missing saved search (which usually is being cached)
// in order to trigger the filter's endpoint
replay_backend.get("/api/user/savedsearch", false).handle(async (request) => {
  const search_type = new URLSearchParams(new URL(request.url).search).get(
    "search_type"
  );
  let res = "";
  if (search_type === "pipeline_view") {
    res = JSON.stringify([
      {
        created_by: 196611,
        created_on: "2022-09-28T18:31:18.940200",
        id: -1,
        name: "All Deals",
        updated_on: "2022-09-28T18:31:18.940200",
        user: 196611,
      },
    ]);
  } else if (search_type === "filter") {
    res = JSON.stringify([
      {
        created_by: 196611,
        created_on: "2022-09-27T15:07:17.926778",
        id: -1000,
        name: "My Recordings",
        search_type: "filter",
        show: {
          custom_columns: {
            columnOrders: {
              recordingsInfoColumnsOrder: ["date", "duration"],
            },
            version: 2,
          },
        },
        updated_on: "2022-09-27T15:07:17.926778",
        user: 196611,
      },
    ]);
  }
  return new Blob([res], { type: "application/json" });
});

request.handle(callback);

This command enables custom processing of a request and returns the modified request as a string. Handle prevents the request from reaching our server, and instead returns a promise (as a Blob or string) with whatever content you pass into the callback parameter.

Query Parameters

Parameter Type Description
callback (request: Request) => Promise<Blob or string> This param takes in a Request and returns the promise of a Blob or string.

Pre Process

Example code:

// Intercept requests to '/api/user/graphql' that have "userId" in variables in post body and
// using custom filters to influence how we search request in DB
replay_backend
  .post("/api/user/graphql", (request, body) => {
    const json = JSON.parse(body);
    return json.variables && json.variables.userId;
  })
  .pre_process(async (request) => {
    const body = await request.json();
    const url = new URL(request.url, location.href);
    return new Request(url.toString(), {
      ...request,
      headers: {
        ...request.headers,
        "Custom-Details-Filter": body.operationName,
        "No-Hash-Check": true,
      },
      method: request.method,
      body: JSON.stringify(body),
    });
  });

request.pre_process(callback, setup = true);

This command uses a callback to pre process a request. This means that we handle the request before it hists our server in order to change the data that goes into the server (e.g. replace request variables).

Query Parameters

Parameter Type Default Description
callback (request: Request) => Promise<Request> This param takes in a Request and returns the promise of a Request.
setup boolean true Indicate if the network is setup or not.

Headers

You can modify the body of a request and maniputlate data using request headers. Here are some header values you can set:

Example using No-Hash-Check:

// Ignore the payload and check to see if the request target
// exists in the database (if not, return 404 error)
replay_backend.post("/api/user/graphql", (request, body) => {
  const json = JSON.parse(body);
  return json.variables && json.variables.userId;
}).pre_process(async (request) => {
  const body = await request.json();
  const url = new URL(request.url, location.href);
  return new Request(url.toString(), {
    ...request,
    headers: {
      ...request.headers,
      "No-Hash-Check": true,
    },
    method: request.method,
    body: JSON.stringify(body),
  });

"No-Hash-Check"

Generally, when trying to find a request in the backend we compare both the target and the request payload. If the request is not in the database, we return a 404 error. Otherwise, we return the first request in the database that matches.

Setting this header to true tells us to disregard the payload when searching for this request in the database. As long as the request target is in the database, we grab the first target value that matches from the database.

"No-Hash-Check": boolean











Example using Custom-Details-Filter:

// Search for request payload in the database that contains the
// strings defined by "MyOperationName", "AnotherOperationName" and "OperationName3"
// return the corresponding request
replay_backend.post("/api/user/graphql", (request, body) => {
  const json = JSON.parse(body);
  return json.variables && json.variables.userId;
}).pre_process(async (request) => {
  const body = await request.json();
  const url = new URL(request.url, location.href);
  return new Request(url.toString(), {
    ...request,
    headers: {
      ...request.headers,
      "Custom-Details-Filter": "MyOperationName, AnotherOperationName, OperationName3"
    },
    method: request.method,
    body: JSON.stringify(body),
  });

"Custom-Details-Filter"

Look for the request payload that contains specific string(s), defined by a comma separated list within a string, and return that request from the database.

"Custom-Details-Filter": string















Example using Encode-URL:

// Encode the request url
replay_backend.post("/api/user/graphql", (request, body) => {
  const json = JSON.parse(body);
  return json.variables && json.variables.userId;
}).pre_process(async (request) => {
  const body = await request.json();
  const url = new URL(request.url, location.href);
  return new Request(url.toString(), {
    ...request,
    headers: {
      ...request.headers,
      "Encode-URL": url,
    },
    method: request.method,
    body: JSON.stringify(body),
  });

"Encode-URL"

Perform URL encoding on a given URL and return the encoded URL. This will rewrite the request target in our database to the newly encoded one.

"Encode-URL": string
















Example using Explicit-Target:

// Point the request to the request target "www.reprise.com" in our database defined by

replay_backend.post("/api/user/graphql", (request, body) => {
  const json = JSON.parse(body);
  return json.variables && json.variables.userId;
}).pre_process(async (request) => {
  const body = await request.json();
  const url = new URL(request.url, location.href);
  return new Request(url.toString(), {
    ...request,
    headers: {
      ...request.headers,
      "Explicit-Target": "www.reprise.com",
    },
    method: request.method,
    body: JSON.stringify(body),
  });

"Explicit-Target"

Point any request to a specific request target in our database.

"Explicit-Target": string
















Example using Partial-Target:

// Point the request to any request target that contains
// the substring "/founders/new_application" in our database
replay_backend.post("/api/user/graphql", (request, body) => {
  const json = JSON.parse(body);
  return json.variables && json.variables.userId;
}).pre_process(async (request) => {
  const body = await request.json();
  const url = new URL(request.url, location.href);
  return new Request(url.toString(), {
    ...request,
    headers: {
      ...request.headers,
      "Partial Target": "/founders/new_application",
    },
    method: request.method,
    body: JSON.stringify(body),
  });

"Partial-Target"

Point the request to any request target that contains a given substring in our database.

"Partial-Target": string
















Example using Ignore-Post-Data (DEPRECATED):

// Ignore the fields user, system_default, and visibility.admin_id in the
// post body data
replay_backend.post("/api/user/graphql", (request, body) => {
  const json = JSON.parse(body);
  return json.variables && json.variables.userId;
}).pre_process(async (request) => {
  const body = await request.json();
  const url = new URL(request.url, location.href);
  return new Request(url.toString(), {
    ...request,
    headers: {
      ...request.headers,
      "Ignore-Post-Data": "user, system_default, visibility.admin_id",
    },
    method: request.method,
    body: JSON.stringify(body),
  });

"Ignore-Post-Data" (DEPRECATED)

Ignore specific fields in a post body by passing in those fields as a string which contains a comma separated list of fields.

If you want to ignore a nested field, you can put dots in between the fields to get to the right field name. For example, if the field year is nested within the field date, you call date by passing in date.year.

Since this feature is deprecated, use the "Modify-Post-Data" header with action set to remove_json_field to achieve the same results.

"Ignore-Post-Data": string












Example using Modify-Post-Data:

// Modify post data by replacing the fields defined within params
  const mod = [
      {
          action: "regexp_replace",
          params: {
              pattern: "&filter=(.*?)&",
              replacement: "",
              ignore_case: true,
          },
      },
  ];
  const modification = replay_utils.base64_encode(JSON.stringify(mod));

  return new Request(url.toString(), {
      ...request,
      headers: {
          ...request.headers,
          "Modify-Post-Data": modification,
      },
      method: request.method,
      body: JSON.stringify(body),
  });

// Modify post data by ignoring/removing the fields defined within paths
  const mod = [
      {
          action: "remove_json_field",
          params: {
              paths: "user, system_default, visibility.admin_id"
          },
      },
  ];
  const modification = replay_utils.base64_encode(JSON.stringify(mod));

  return new Request(url.toString(), {
      ...request,
      headers: {
          ...request.headers,
          "Modify-Post-Data": modification,
      },
      method: request.method,
      body: JSON.stringify(body),
  });

});

"Modify-Post-Data"

Modify specific fields in the post body data based off of the list of modifications passed in during pre processing.

There are two options for modification actions you can perform:

This enables you to replace any string in the post body data that matches the given regular expression.

Define the regular expression in params.pattern, the string we want to replace this regular expression with in params.replacement, and whether we want to ignore the expression case or not in params.ignore_case.

This enables you to remove any fields in the post body data that matches the ones passed into params.path as a string containing a list of field names.

"Modify-Post-Data": list of dictionaries

























Example using Remove-Response-Headers:

replay_backend.post("/api/user/graphql", (request, body) => {
  const json = JSON.parse(body);
  return json.variables && json.variables.userId;
}).pre_process(async (request) => {
  const body = await request.json();
  const url = new URL(request.url, location.href);
  return new Request(url.toString(), {
    ...request,
    headers: {
      ...request.headers,
      "Remove-Response-Headers": "Cache-Info, Keep-Alive, Etag",
    },
    method: request.method,
    body: JSON.stringify(body),
  });

"Remove-Response-Headers"

Remove the given headers from a Response in the server. These headers should be passed in as a string containing a comma-separated list of header names.

"Remove-Response-Headers": string

Example using Response-Content-Type:

// Override the response's content type to be text/html
replay_backend.post("/api/user/graphql", (request, body) => {
  const json = JSON.parse(body);
  return json.variables && json.variables.userId;
}).pre_process(async (request) => {
  const body = await request.json();
  const url = new URL(request.url, location.href);
  return new Request(url.toString(), {
    ...request,
    headers: {
      ...request.headers,
      "Response-Content-Type": "text/html; charset=UTF-8",
    },
    method: request.method,
    body: JSON.stringify(body),
  });

"Response-Content-Type"

Override the Content-Type of the Response.

"Response-Content-Type": string











Example using Check-Timestamps:

// Ignore the payload and check to see if the request target
// exists in the database (if not, return 404 error)
replay_backend.post("/api/user/graphql")
  .pre_process(async (request) => {
    const body = await request.json();
    const url = new URL(request.url, location.href);
    return new Request(url.toString(), {
      ...request,
      headers: {
        ...request.headers,
        "Check-Timestamps": true,
      },
      method: request.method,
      body: JSON.stringify(body),
    });
  });

"Check-Timestamps"

By default, Replicate will ignore any timestamp in the request body and URL when comparing requests in the database.
Use this method to override the default behavior, and instruct Replicate to include the timestamps in the request body and URL when comparing requests.

"Check-Timestamps": boolean











Post Process

Example code:

// Change one field in response with updated tocken (with new expiration time)
replay_backend
  .post("/api/session/accesstoken/:session_id")
  .post_process(async (response) => {
    const json = await response.json();
    json.refreshToken =
      "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." +
      replay_utils.base64_encode(
        JSON.stringify({
          userName: "sergey@getreprise.com",
          iat: Date.now() - 1000,
          exp: Date.now() + 60 * 60 * 1000, // 1 hour
        })
      ) +
      ".";
    return JSON.stringify(json);
  });

request.post_process(callback);

This command uses a callback to post process a responce. This means we handle the response from the server in order to manipulate the data that comes back.

Query Parameters

Parameter Type Description
callback (response: Response) => Promise<Blob or string> This param takes in a Response and returns the promise of a Blob or string.

Check Timestamps

Example code:

// Change one field in response with updated tocken (with new expiration time)
replay_backend
  .post("/api/session/accesstoken/:session_id")
  .check_timestamps();

request.check_timestamps();

By default, Replicate will ignore any timestamp in the request body and URL when comparing requests in the database.
Use this method to override the default behavior, and instruct Replicate to include the timestamps in the request body and URL when comparing requests.

Storage

This class provides access to the IndexedDB storage so we can modify storage values. Request processing for the get, set, and remove calls involves returning a promise or executing a callback function.

Get

Example code:

// get an item with key "foo" and, if successful,
// log the result
replay_backend.storage.get("foo").then((res) => {
  console.log(res);
});

// get an item and execute the callback function
replay_backend.storage.get("foo", function () {
  console.log("Getting storage item");
});

replay_backend.storage.get(key, callback);

This function allows you to get the value of a specific IndexedDB storage object. Returns null if the given key does not exist within the IndexedDB storage.

Query Parameters

Parameter Type Description
key string The key name of the storage object
callback (optional) function The callback function to be executed

Set

Example code:

// set an item with key "foo" to value "bar and,
// if successful, log the result
replay_backend.storage.set("foo", "bar").then((res) => {
  console.log(res);
});

// set an item and execute the callback function
replay_backend.storage.set("foo", "bar", function () {
  console.log("Setting storage item");
});

replay_backend.storage.set(key, value, callback);

This function allows you to set a specific IndexedDB storage object to a new value.

Query Parameters

Parameter Type Description
key string The key name of the storage object
value any The new value of the storage object
callback (optional) function The callback function to be executed

Remove

Example code:

// remove an item with key "foo" and, if successful,
// log the result
replay_backend.storage.remove("foo").then((res) => {
  console.log(res);
});

// remove an item and execute the callback function
replay_backend.storage.remove("foo", function () {
  console.log("Removing storage item");
});

replay_backend.storage.remove(key, callback);

This function allows you to remove a specific IndexedDB storage object.

Query Parameters

Parameter Type Description
key string The key name of the storage object
callback (optional) function The callback function to be executed

Clear

Example code:

// clear all storage items
replay_backend.storage.clear();

replay_backend.storage.clear();

This function allows you to clear all of the IndexedDB storage objects.

API Reference

Route

The Route object is a string that defines the path from the original domain where we will attempt to intercept requests from. It can contain dynamic parts starting with : that allow the value to change at that part of the path.

An example of a Route is "/order-configurator/api/v1/sections/:section_id" where :section_id is a dynamic part of the path.

RequestFilter

The RequestFilter object takes in a Request (and optionally a new request body) and returns true if the request recieved by the request interception call matches the Request in the RequestFilter object.

RequestFilter = (request: Request, body?: string) => boolean;

Request

The Request object represents a resource request.

Refer to the mozilla developer web docs to learn more about Request.

Response

The Response object represents the response to a request.

Refer to the mozilla developer web docs to learn more about Response.

Blob

The Blob object represents a blob, which is a file-like object of immutable, raw data; they can be read as text or binary data, or converted into a ReadableStream so its methods can be used for processing the data.

Refer to the mozilla developer web docs to learn more about Blob.

Content-Type

The Content-Type representation header is used to indicate the original media type of the resource (prior to any content encoding applied for sending).

Refer to the the mozilla developer web docs to learn more about Content-Type.

RedirectOptions

Options for redirecting a request.

Parameter Type Description
method string Response type override (GET, POST, PUT...)