diff --git src/wp-includes/rest-api.php src/wp-includes/rest-api.php
index 0b2da7f..d1bcb85 100644
--- src/wp-includes/rest-api.php
+++ src/wp-includes/rest-api.php
@@ -273,9 +273,87 @@ function rest_url( $path = '', $scheme = 'json' ) {
  * @return WP_REST_Response REST response.
  */
 function rest_do_request( $request ) {
-	global $wp_rest_server;
 	$request = rest_ensure_request( $request );
-	return $wp_rest_server->dispatch( $request );
+	return rest_get_server()->dispatch( $request );
+}
+
+/**
+ * Make an internal REST request
+ *
+ * @since 4.5.0
+ *
+ * @global WP_REST_Server $wp_rest_server ResponseHandler instance (usually WP_REST_Server).
+ *
+ * @param WP_REST_Request|string $request_or_method WP_REST_Request object or a request method.
+ * @param string                 $path              Optional. Path to retrieve data from if not already specified in `$request_or_method`.
+ *                                                  Default null.
+ * @param array                  $data              Optional. Data passed to the request. Default empty array.
+ * @return WP_Error|array Response data on success, WP_Error object on failure.
+ */
+function rest_internal_request( $request_or_method, $path = null, $data = array() ) {
+	if ( $request_or_method instanceof WP_REST_Request ) {
+		$request = $request_or_method;
+	} else {
+		$request = new WP_REST_Request( $request_or_method, $path );
+
+		foreach ( $data as $k => $v ) {
+			$request->set_param( $k, $v );
+		}
+	}
+
+	$result = rest_get_server()->dispatch( $request );
+
+	if ( $result->is_error() ) {
+		return $result->as_error();
+	}
+
+	return rest_get_server()->response_to_data( $result, ! empty( $data['_embed'] ) );
+}
+
+/**
+ * Get the current REST server instance.
+ *
+ * Instantiates a new instance if none exists already.
+ *
+ * @since 4.5.0
+ *
+ * @global WP_REST_Server $wp_rest_server REST server instance.
+ *
+ * @return  WP_REST_Server REST server instance.
+ */
+function rest_get_server() {
+	/* @var WP_REST_Server $wp_rest_server */
+	global $wp_rest_server;
+
+	if ( empty( $wp_rest_server ) ) {
+		/**
+		 * Filter the REST Server Class.
+		 *
+		 * This filter allows you to adjust the server class used by the API, using a
+		 * different class to handle requests.
+		 *
+		 * @since 4.5.0
+		 *
+		 * @param string $class_name The name of the server class. Default 'WP_REST_Server'.
+		 */
+		$wp_rest_server_class = apply_filters( 'wp_rest_server_class', 'WP_REST_Server' );
+
+		$wp_rest_server = new $wp_rest_server_class;
+
+		/**
+		 * Fires when preparing to serve an API request.
+		 *
+		 * Endpoint objects should be created and register their hooks on this action rather
+		 * than another action to ensure they're only loaded when needed.
+		 *
+		 * @since 4.5.0
+		 *
+		 * @param WP_REST_Server $wp_rest_server Server object.
+		 */
+		do_action( 'rest_api_init', $wp_rest_server );
+	}
+
+	return $wp_rest_server;
 }
 
 /**
