diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php
index ebc3d9a053..e1d8919c8d 100644
--- a/src/wp-includes/rest-api.php
+++ b/src/wp-includes/rest-api.php
@@ -250,6 +250,10 @@ function create_initial_rest_routes() {
 	$controller = new WP_REST_Search_Controller( $search_handlers );
 	$controller->register_routes();
 
+	// Block Renderer.
+	$controller = new WP_REST_Block_Renderer_Controller;
+	$controller->register_routes();
+
 	// Settings.
 	$controller = new WP_REST_Settings_Controller;
 	$controller->register_routes();
@@ -257,6 +261,7 @@ function create_initial_rest_routes() {
 	// Themes.
 	$controller = new WP_REST_Themes_Controller;
 	$controller->register_routes();
+
 }
 
 /**
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php
new file mode 100644
index 0000000000..a4f17283c5
--- /dev/null
+++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php
@@ -0,0 +1,177 @@
+<?php
+/**
+ * Block Renderer REST API: WP_REST_Block_Renderer_Controller class
+ *
+ * @package WordPress
+ * @subpackage REST_API
+ * @since 5.0.0
+ */
+
+/**
+ * Controller which provides REST endpoint for rendering a block.
+ *
+ * @since 5.0.0
+ *
+ * @see WP_REST_Controller
+ */
+class WP_REST_Block_Renderer_Controller extends WP_REST_Controller {
+
+	/**
+	 * Constructs the controller.
+	 *
+	 * @since 5.0.0
+	 */
+	public function __construct() {
+		$this->namespace = 'wp/v2';
+		$this->rest_base = 'block-renderer';
+	}
+
+	/**
+	 * Registers the necessary REST API routes, one for each dynamic block.
+	 *
+	 * @since 5.0.0
+	 */
+	public function register_routes() {
+		$block_types = WP_Block_Type_Registry::get_instance()->get_all_registered();
+
+		foreach ( $block_types as $block_type ) {
+			if ( ! $block_type->is_dynamic() ) {
+				continue;
+			}
+
+			register_rest_route(
+				$this->namespace,
+				'/' . $this->rest_base . '/(?P<name>' . $block_type->name . ')',
+				array(
+					'args'   => array(
+						'name' => array(
+							'description' => __( 'Unique registered name for the block.' ),
+							'type'        => 'string',
+						),
+					),
+					array(
+						'methods'             => WP_REST_Server::READABLE,
+						'callback'            => array( $this, 'get_item' ),
+						'permission_callback' => array( $this, 'get_item_permissions_check' ),
+						'args'                => array(
+							'context'    => $this->get_context_param( array( 'default' => 'view' ) ),
+							'attributes' => array(
+								/* translators: %s is the name of the block */
+								'description'          => sprintf( __( 'Attributes for %s block' ), $block_type->name ),
+								'type'                 => 'object',
+								'additionalProperties' => false,
+								'properties'           => $block_type->get_attributes(),
+							),
+							'post_id'    => array(
+								'description' => __( 'ID of the post context.' ),
+								'type'        => 'integer',
+							),
+						),
+					),
+					'schema' => array( $this, 'get_public_item_schema' ),
+				)
+			);
+		}
+	}
+
+	/**
+	 * Checks if a given request has access to read blocks.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @param WP_REST_Request $request Request.
+	 * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
+	 */
+	public function get_item_permissions_check( $request ) {
+		global $post;
+
+		$post_id = isset( $request['post_id'] ) ? intval( $request['post_id'] ) : 0;
+
+		if ( 0 < $post_id ) {
+			$post = get_post( $post_id );
+
+			if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) {
+				return new WP_Error(
+					'block_cannot_read',
+					__( 'Sorry, you are not allowed to read blocks of this post' ),
+					array(
+						'status' => rest_authorization_required_code(),
+					)
+				);
+			}
+		} else {
+			if ( ! current_user_can( 'edit_posts' ) ) {
+				return new WP_Error(
+					'block_cannot_read',
+					__( 'Sorry, you are not allowed to read blocks as this user.' ),
+					array(
+						'status' => rest_authorization_required_code(),
+					)
+				);
+			}
+		}
+
+		return true;
+	}
+
+	/**
+	 * Returns block output from block's registered render_callback.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @param WP_REST_Request $request Full details about the request.
+	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
+	 */
+	public function get_item( $request ) {
+		global $post;
+
+		$post_id = isset( $request['post_id'] ) ? intval( $request['post_id'] ) : 0;
+
+		if ( 0 < $post_id ) {
+			$post = get_post( $post_id );
+
+			// Set up postdata since this will be needed if post_id was set.
+			setup_postdata( $post );
+		}
+		$registry = WP_Block_Type_Registry::get_instance();
+		$block    = $registry->get_registered( $request['name'] );
+
+		if ( null === $block ) {
+			return new WP_Error(
+				'block_invalid',
+				__( 'Invalid block.' ),
+				array(
+					'status' => 404,
+				)
+			);
+		}
+
+		$data = array(
+			'rendered' => $block->render( $request->get_param( 'attributes' ) ),
+		);
+		return rest_ensure_response( $data );
+	}
+
+	/**
+	 * Retrieves block's output schema, conforming to JSON Schema.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @return array Item schema data.
+	 */
+	public function get_item_schema() {
+		return array(
+			'$schema'    => 'http://json-schema.org/schema#',
+			'title'      => 'rendered-block',
+			'type'       => 'object',
+			'properties' => array(
+				'rendered' => array(
+					'description' => __( 'The rendered block.' ),
+					'type'        => 'string',
+					'required'    => true,
+					'context'     => array( 'edit' ),
+				),
+			),
+		);
+	}
+}
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php
new file mode 100644
index 0000000000..66a2e7adad
--- /dev/null
+++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Reusable blocks REST API: WP_REST_Blocks_Controller class
+ *
+ * @package WordPress
+ * @subpackage REST_API
+ * @since 5.0.0
+ */
+
+/**
+ * Controller which provides a REST endpoint for the editor to read, create,
+ * edit and delete reusable blocks. Blocks are stored as posts with the wp_block
+ * post type.
+ *
+ * @since 5.0.0
+ *
+ * @see WP_REST_Posts_Controller
+ * @see WP_REST_Controller
+ */
+class WP_REST_Blocks_Controller extends WP_REST_Posts_Controller {
+
+	/**
+	 * Checks if a block can be read.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @param object $post Post object that backs the block.
+	 * @return bool Whether the block can be read.
+	 */
+	public function check_read_permission( $post ) {
+		// Ensure that the user is logged in and has the read_blocks capability.
+		$post_type = get_post_type_object( $post->post_type );
+		if ( ! current_user_can( $post_type->cap->read_post, $post->ID ) ) {
+			return false;
+		}
+
+		return parent::check_read_permission( $post );
+	}
+}
diff --git a/src/wp-settings.php b/src/wp-settings.php
index f711b9167b..efefa1b214 100644
--- a/src/wp-settings.php
+++ b/src/wp-settings.php
@@ -235,6 +235,8 @@ require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-terms-controller.p
 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-users-controller.php' );
 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-comments-controller.php' );
 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-search-controller.php' );
+require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-blocks-controller.php' );
+require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-block-renderer-controller.php' );
 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-settings-controller.php' );
 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-themes-controller.php' );
 require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php' );
diff --git a/tests/phpunit/tests/rest-api/rest-block-renderer-controller.php b/tests/phpunit/tests/rest-api/rest-block-renderer-controller.php
new file mode 100644
index 0000000000..472e448b10
--- /dev/null
+++ b/tests/phpunit/tests/rest-api/rest-block-renderer-controller.php
@@ -0,0 +1,529 @@
+<?php
+/**
+ * WP_REST_Block_Renderer_Controller tests.
+ *
+ * @package WordPress
+ * @subpackage REST_API
+ * @since 5.0.0
+ */
+
+/**
+ * Tests for WP_REST_Block_Renderer_Controller.
+ *
+ * @since 5.0.0
+ *
+ * @covers WP_REST_Block_Renderer_Controller
+ *
+ * @group restapi-blocks
+ * @group restapi
+ */
+class REST_Block_Renderer_Controller_Test extends WP_Test_REST_Controller_Testcase {
+
+	/**
+	 * The REST API route for the block renderer.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @var string
+	 */
+	protected static $rest_api_route = '/wp/v2/block-renderer/';
+
+	/**
+	 * Test block's name.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @var string
+	 */
+	protected static $block_name = 'core/test-block';
+
+	/**
+	 * Test post context block's name.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @var string
+	 */
+	protected static $context_block_name = 'core/context-test-block';
+
+	/**
+	 * Test API user's ID.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @var int
+	 */
+	protected static $user_id;
+
+	/**
+	 * Test post ID.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @var int
+	 */
+	protected static $post_id;
+
+	/**
+	 * Author test user ID.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @var int
+	 */
+	protected static $author_id;
+
+	/**
+	 * Create test data before the tests run.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @param WP_UnitTest_Factory $factory Helper that lets us create fake data.
+	 */
+	public static function wpSetUpBeforeClass( $factory ) {
+		self::$user_id = $factory->user->create(
+			array(
+				'role' => 'editor',
+			)
+		);
+
+		self::$author_id = $factory->user->create(
+			array(
+				'role' => 'author',
+			)
+		);
+
+		self::$post_id = $factory->post->create(
+			array(
+				'post_title' => 'Test Post',
+			)
+		);
+	}
+
+	/**
+	 * Delete test data after our tests run.
+	 *
+	 * @since 5.0.0
+	 */
+	public static function wpTearDownAfterClass() {
+		self::delete_user( self::$user_id );
+	}
+
+	/**
+	 * Set up each test method.
+	 *
+	 * @since 5.0.0
+	 */
+	public function setUp() {
+		$this->register_test_block();
+		$this->register_post_context_test_block();
+		parent::setUp();
+	}
+
+	/**
+	 * Tear down each test method.
+	 *
+	 * @since 5.0.0
+	 */
+	public function tearDown() {
+		WP_Block_Type_Registry::get_instance()->unregister( self::$block_name );
+		WP_Block_Type_Registry::get_instance()->unregister( self::$context_block_name );
+		parent::tearDown();
+	}
+
+	/**
+	 * Register test block.
+	 *
+	 * @since 5.0.0
+	 */
+	public function register_test_block() {
+		register_block_type(
+			self::$block_name,
+			array(
+				'attributes'      => array(
+					'some_string' => array(
+						'type'    => 'string',
+						'default' => 'some_default',
+					),
+					'some_int'    => array(
+						'type' => 'integer',
+					),
+					'some_array'  => array(
+						'type'  => 'array',
+						'items' => array(
+							'type' => 'integer',
+						),
+					),
+				),
+				'render_callback' => array( $this, 'render_test_block' ),
+			)
+		);
+	}
+
+	/**
+	 * Register test block with post_id as attribute for post context test.
+	 *
+	 * @since 5.0.0
+	 */
+	public function register_post_context_test_block() {
+		register_block_type(
+			self::$context_block_name,
+			array(
+				'attributes'      => array(),
+				'render_callback' => array( $this, 'render_post_context_test_block' ),
+			)
+		);
+	}
+
+	/**
+	 * Test render callback.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @param array $attributes Props.
+	 * @return string Rendered attributes, which is here just JSON.
+	 */
+	public function render_test_block( $attributes ) {
+		return wp_json_encode( $attributes );
+	}
+
+	/**
+	 * Test render callback for testing post context.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @return string
+	 */
+	public function render_post_context_test_block() {
+		return get_the_title();
+	}
+
+	/**
+	 * Check that the route was registered properly.
+	 *
+	 * @ticket 45098
+	 *
+	 * @covers WP_REST_Block_Renderer_Controller::register_routes()
+	 */
+	public function test_register_routes() {
+		$dynamic_block_names = get_dynamic_block_names();
+		$this->assertContains( self::$block_name, $dynamic_block_names );
+
+		$routes = rest_get_server()->get_routes();
+		foreach ( $dynamic_block_names as $dynamic_block_name ) {
+			$this->assertArrayHasKey( self::$rest_api_route . "(?P<name>$dynamic_block_name)", $routes );
+		}
+	}
+
+	/**
+	 * Test getting item without permissions.
+	 *
+	 * @ticket 45098
+	 *
+	 * @covers WP_REST_Block_Renderer_Controller::get_item()
+	 */
+	public function test_get_item_without_permissions() {
+		wp_set_current_user( 0 );
+
+		$request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
+		$request->set_param( 'context', 'edit' );
+
+		$response = rest_get_server()->dispatch( $request );
+
+		$this->assertErrorResponse( 'block_cannot_read', $response, rest_authorization_required_code() );
+	}
+
+	/**
+	 * Test getting item without 'edit' context.
+	 *
+	 * @ticket 45098
+	 */
+	public function test_get_item_with_invalid_context() {
+		wp_set_current_user( self::$user_id );
+
+		$request  = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
+		$response = rest_get_server()->dispatch( $request );
+
+		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+	}
+
+	/**
+	 * Test getting item with invalid block name.
+	 *
+	 * @ticket 45098
+	 *
+	 * @covers WP_REST_Block_Renderer_Controller::get_item()
+	 */
+	public function test_get_item_invalid_block_name() {
+		wp_set_current_user( self::$user_id );
+		$request = new WP_REST_Request( 'GET', self::$rest_api_route . 'core/123' );
+
+		$request->set_param( 'context', 'edit' );
+		$response = rest_get_server()->dispatch( $request );
+
+		$this->assertErrorResponse( 'rest_no_route', $response, 404 );
+	}
+
+	/**
+	 * Check getting item with an invalid param provided.
+	 *
+	 * @ticket 45098
+	 *
+	 * @covers WP_REST_Block_Renderer_Controller::get_item()
+	 */
+	public function test_get_item_invalid_attribute() {
+		wp_set_current_user( self::$user_id );
+		$request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
+		$request->set_param( 'context', 'edit' );
+		$request->set_param(
+			'attributes',
+			array(
+				'some_string' => array( 'no!' ),
+			)
+		);
+		$response = rest_get_server()->dispatch( $request );
+		$this->assertEquals( 400, $response->get_status() );
+	}
+
+	/**
+	 * Check getting item with an invalid param provided.
+	 *
+	 * @ticket 45098
+	 *
+	 * @covers WP_REST_Block_Renderer_Controller::get_item()
+	 */
+	public function test_get_item_unrecognized_attribute() {
+		wp_set_current_user( self::$user_id );
+		$request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
+		$request->set_param( 'context', 'edit' );
+		$request->set_param(
+			'attributes',
+			array(
+				'unrecognized' => 'yes',
+			)
+		);
+		$response = rest_get_server()->dispatch( $request );
+		$this->assertEquals( 400, $response->get_status() );
+	}
+
+	/**
+	 * Check getting item with default attributes provided.
+	 *
+	 * @ticket 45098
+	 *
+	 * @covers WP_REST_Block_Renderer_Controller::get_item()
+	 */
+	public function test_get_item_default_attributes() {
+		wp_set_current_user( self::$user_id );
+
+		$block_type = WP_Block_Type_Registry::get_instance()->get_registered( self::$block_name );
+		$defaults   = array();
+		foreach ( $block_type->attributes as $key => $attribute ) {
+			$defaults[ $key ] = isset( $attribute['default'] ) ? $attribute['default'] : null;
+		}
+
+		$request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
+		$request->set_param( 'context', 'edit' );
+		$request->set_param( 'attributes', array() );
+		$response = rest_get_server()->dispatch( $request );
+		$this->assertEquals( 200, $response->get_status() );
+		$data = $response->get_data();
+
+		$this->assertEquals( $defaults, json_decode( $data['rendered'], true ) );
+		$this->assertEquals(
+			json_decode( $block_type->render( $defaults ) ),
+			json_decode( $data['rendered'] )
+		);
+	}
+
+	/**
+	 * Check getting item with attributes provided.
+	 *
+	 * @ticket 45098
+	 *
+	 * @covers WP_REST_Block_Renderer_Controller::get_item()
+	 */
+	public function test_get_item() {
+		wp_set_current_user( self::$user_id );
+
+		$block_type = WP_Block_Type_Registry::get_instance()->get_registered( self::$block_name );
+		$attributes = array(
+			'some_int'    => '123',
+			'some_string' => 'foo',
+			'some_array'  => array( 1, '2', 3 ),
+		);
+
+		$expected_attributes               = $attributes;
+		$expected_attributes['some_int']   = (int) $expected_attributes['some_int'];
+		$expected_attributes['some_array'] = array_map( 'intval', $expected_attributes['some_array'] );
+
+		$request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
+		$request->set_param( 'context', 'edit' );
+		$request->set_param( 'attributes', $attributes );
+		$response = rest_get_server()->dispatch( $request );
+		$this->assertEquals( 200, $response->get_status() );
+		$data = $response->get_data();
+
+		$this->assertEquals( $expected_attributes, json_decode( $data['rendered'], true ) );
+		$this->assertEquals(
+			json_decode( $block_type->render( $attributes ), true ),
+			json_decode( $data['rendered'], true )
+		);
+	}
+
+
+
+	/**
+	 * Check success response for getting item with layout attribute provided.
+	 *
+	 * @ticket 45098
+	 */
+	public function test_get_item_with_layout() {
+		wp_set_current_user( self::$user_id );
+
+		$attributes = array(
+			'layout' => 'foo',
+		);
+
+		$request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
+		$request->set_param( 'context', 'edit' );
+		$request->set_param( 'attributes', $attributes );
+		$response = rest_get_server()->dispatch( $request );
+		$this->assertEquals( 200, $response->get_status() );
+	}
+
+	/**
+	 * Test getting item with post context.
+	 *
+	 * @ticket 45098
+	 */
+	public function test_get_item_with_post_context() {
+		wp_set_current_user( self::$user_id );
+
+		$expected_title = 'Test Post';
+		$request        = new WP_REST_Request( 'GET', self::$rest_api_route . self::$context_block_name );
+		$request->set_param( 'context', 'edit' );
+
+		// Test without post ID.
+		$response = rest_get_server()->dispatch( $request );
+
+		$this->assertEquals( 200, $response->get_status() );
+		$data = $response->get_data();
+
+		$this->assertTrue( empty( $data['rendered'] ) );
+
+		// Now test with post ID.
+		$request->set_param( 'post_id', self::$post_id );
+		$response = rest_get_server()->dispatch( $request );
+
+		$this->assertEquals( 200, $response->get_status() );
+		$data = $response->get_data();
+
+		$this->assertEquals( $expected_title, $data['rendered'] );
+	}
+
+	/**
+	 * Test getting item with invalid post ID.
+	 *
+	 * @ticket 45098
+	 */
+	public function test_get_item_without_permissions_invalid_post() {
+		wp_set_current_user( self::$user_id );
+
+		$request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$context_block_name );
+		$request->set_param( 'context', 'edit' );
+
+		// Test with invalid post ID.
+		$request->set_param( 'post_id', PHP_INT_MAX );
+		$response = rest_get_server()->dispatch( $request );
+
+		$this->assertErrorResponse( 'block_cannot_read', $response, 403 );
+	}
+
+	/**
+	 * Test getting item without permissions to edit context post.
+	 *
+	 * @ticket 45098
+	 */
+	public function test_get_item_without_permissions_cannot_edit_post() {
+		wp_set_current_user( self::$author_id );
+
+		$request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$context_block_name );
+		$request->set_param( 'context', 'edit' );
+
+		// Test with private post ID.
+		$request->set_param( 'post_id', self::$post_id );
+		$response = rest_get_server()->dispatch( $request );
+
+		$this->assertErrorResponse( 'block_cannot_read', $response, 403 );
+	}
+
+	/**
+	 * Get item schema.
+	 *
+	 * @ticket 45098
+	 *
+	 * @covers WP_REST_Block_Renderer_Controller::get_item_schema()
+	 */
+	public function test_get_item_schema() {
+		$request  = new WP_REST_Request( 'OPTIONS', self::$rest_api_route . self::$block_name );
+		$response = rest_get_server()->dispatch( $request );
+		$data     = $response->get_data();
+
+		$this->assertEqualSets( array( 'GET' ), $data['endpoints'][0]['methods'] );
+		$this->assertEqualSets(
+			array( 'name', 'context', 'attributes', 'post_id' ),
+			array_keys( $data['endpoints'][0]['args'] )
+		);
+		$this->assertEquals( 'object', $data['endpoints'][0]['args']['attributes']['type'] );
+
+		$this->assertArrayHasKey( 'schema', $data );
+		$this->assertEquals( 'rendered-block', $data['schema']['title'] );
+		$this->assertEquals( 'object', $data['schema']['type'] );
+		$this->arrayHasKey( 'rendered', $data['schema']['properties'] );
+		$this->arrayHasKey( 'string', $data['schema']['properties']['rendered']['type'] );
+		$this->assertEquals( array( 'edit' ), $data['schema']['properties']['rendered']['context'] );
+	}
+
+	/**
+	 * The update_item() method does not exist for block rendering.
+	 */
+	public function test_update_item() {
+		$this->markTestSkipped( 'Controller does not implement update_item().' );
+	}
+
+	/**
+	 * The create_item() method does not exist for block rendering.
+	 */
+	public function test_create_item() {
+		$this->markTestSkipped( 'Controller does not implement create_item().' );
+	}
+
+	/**
+	 * The delete_item() method does not exist for block rendering.
+	 */
+	public function test_delete_item() {
+		$this->markTestSkipped( 'Controller does not implement delete_item().' );
+	}
+
+	/**
+	 * The get_items() method does not exist for block rendering.
+	 */
+	public function test_get_items() {
+		$this->markTestSkipped( 'Controller does not implement get_items().' );
+	}
+
+	/**
+	 * The context_param() method does not exist for block rendering.
+	 */
+	public function test_context_param() {
+		$this->markTestSkipped( 'Controller does not implement context_param().' );
+	}
+
+	/**
+	 * The prepare_item() method does not exist for block rendering.
+	 */
+	public function test_prepare_item() {
+		$this->markTestSkipped( 'Controller does not implement prepare_item().' );
+	}
+}
diff --git a/tests/phpunit/tests/rest-api/rest-blocks-controller.php b/tests/phpunit/tests/rest-api/rest-blocks-controller.php
new file mode 100644
index 0000000000..70798b2756
--- /dev/null
+++ b/tests/phpunit/tests/rest-api/rest-blocks-controller.php
@@ -0,0 +1,204 @@
+<?php
+/**
+ * WP_REST_Blocks_Controller tests
+ *
+ * @package WordPress
+ * @subpackage REST_API
+ * @since 5.0.0
+ */
+
+/**
+ * Tests for WP_REST_Blocks_Controller.
+ *
+ * @since 5.0.0
+ *
+ * @see WP_Test_REST_Controller_Testcase
+ *
+ * @group restapi-blocks
+ * @group restapi
+ */
+class REST_Blocks_Controller_Test extends WP_UnitTestCase {
+
+	/**
+	 * Our fake block's post ID.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @var int
+	 */
+	protected static $post_id;
+
+	/**
+	 * Our fake user's ID.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @var int
+	 */
+	protected static $user_id;
+
+	/**
+	 * Create fake data before our tests run.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @param WP_UnitTest_Factory $factory Helper that lets us create fake data.
+	 */
+	public static function wpSetUpBeforeClass( $factory ) {
+		self::$post_id = wp_insert_post(
+			array(
+				'post_type'    => 'wp_block',
+				'post_status'  => 'publish',
+				'post_title'   => 'My cool block',
+				'post_content' => '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->',
+			)
+		);
+
+		self::$user_id = $factory->user->create(
+			array(
+				'role' => 'editor',
+			)
+		);
+	}
+
+	/**
+	 * Delete our fake data after our tests run.
+	 *
+	 * @since 5.0.0
+	 */
+	public static function wpTearDownAfterClass() {
+		wp_delete_post( self::$post_id );
+
+		self::delete_user( self::$user_id );
+	}
+
+	/**
+	 * Test cases for test_capabilities().
+	 *
+	 * @since 5.0.0
+	 */
+	public function data_capabilities() {
+		return array(
+			array( 'create', 'editor', 201 ),
+			array( 'create', 'author', 201 ),
+			array( 'create', 'contributor', 403 ),
+			array( 'create', null, 401 ),
+
+			array( 'read', 'editor', 200 ),
+			array( 'read', 'author', 200 ),
+			array( 'read', 'contributor', 200 ),
+			array( 'read', null, 401 ),
+
+			array( 'update_delete_own', 'editor', 200 ),
+			array( 'update_delete_own', 'author', 200 ),
+			array( 'update_delete_own', 'contributor', 403 ),
+
+			array( 'update_delete_others', 'editor', 200 ),
+			array( 'update_delete_others', 'author', 403 ),
+			array( 'update_delete_others', 'contributor', 403 ),
+			array( 'update_delete_others', null, 401 ),
+		);
+	}
+
+	/**
+	 * Exhaustively check that each role either can or cannot create, edit,
+	 * update, and delete reusable blocks.
+	 *
+	 * @ticket 45098
+	 *
+	 * @dataProvider data_capabilities
+	 *
+	 * @param string $action          Action to perform in the test.
+	 * @param string $role            User role to test.
+	 * @param int    $expected_status Expected HTTP response status.
+	 */
+	public function test_capabilities( $action, $role, $expected_status ) {
+		if ( $role ) {
+			$user_id = $this->factory->user->create( array( 'role' => $role ) );
+			wp_set_current_user( $user_id );
+		} else {
+			wp_set_current_user( 0 );
+		}
+
+		switch ( $action ) {
+			case 'create':
+				$request = new WP_REST_Request( 'POST', '/wp/v2/blocks' );
+				$request->set_body_params(
+					array(
+						'title'   => 'Test',
+						'content' => '<!-- wp:core/paragraph --><p>Test</p><!-- /wp:core/paragraph -->',
+					)
+				);
+
+				$response = rest_get_server()->dispatch( $request );
+				$this->assertEquals( $expected_status, $response->get_status() );
+
+				break;
+
+			case 'read':
+				$request = new WP_REST_Request( 'GET', '/wp/v2/blocks/' . self::$post_id );
+
+				$response = rest_get_server()->dispatch( $request );
+				$this->assertEquals( $expected_status, $response->get_status() );
+
+				break;
+
+			case 'update_delete_own':
+				$post_id = wp_insert_post(
+					array(
+						'post_type'    => 'wp_block',
+						'post_status'  => 'publish',
+						'post_title'   => 'My cool block',
+						'post_content' => '<!-- wp:core/paragraph --><p>Hello!</p><!-- /wp:core/paragraph -->',
+						'post_author'  => $user_id,
+					)
+				);
+
+				$request = new WP_REST_Request( 'PUT', '/wp/v2/blocks/' . $post_id );
+				$request->set_body_params(
+					array(
+						'title'   => 'Test',
+						'content' => '<!-- wp:core/paragraph --><p>Test</p><!-- /wp:core/paragraph -->',
+					)
+				);
+
+				$response = rest_get_server()->dispatch( $request );
+				$this->assertEquals( $expected_status, $response->get_status() );
+
+				$request = new WP_REST_Request( 'DELETE', '/wp/v2/blocks/' . $post_id );
+
+				$response = rest_get_server()->dispatch( $request );
+				$this->assertEquals( $expected_status, $response->get_status() );
+
+				wp_delete_post( $post_id );
+
+				break;
+
+			case 'update_delete_others':
+				$request = new WP_REST_Request( 'PUT', '/wp/v2/blocks/' . self::$post_id );
+				$request->set_body_params(
+					array(
+						'title'   => 'Test',
+						'content' => '<!-- wp:core/paragraph --><p>Test</p><!-- /wp:core/paragraph -->',
+					)
+				);
+
+				$response = rest_get_server()->dispatch( $request );
+				$this->assertEquals( $expected_status, $response->get_status() );
+
+				$request = new WP_REST_Request( 'DELETE', '/wp/v2/blocks/' . self::$post_id );
+
+				$response = rest_get_server()->dispatch( $request );
+				$this->assertEquals( $expected_status, $response->get_status() );
+
+				break;
+
+			default:
+				$this->fail( "'$action' is not a valid action." );
+		}
+
+		if ( isset( $user_id ) ) {
+			self::delete_user( $user_id );
+		}
+	}
+}
diff --git a/tests/phpunit/tests/rest-api/rest-schema-setup.php b/tests/phpunit/tests/rest-api/rest-schema-setup.php
index 70330b7f03..e9de00aa4f 100644
--- a/tests/phpunit/tests/rest-api/rest-schema-setup.php
+++ b/tests/phpunit/tests/rest-api/rest-schema-setup.php
@@ -99,6 +99,10 @@ class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase {
 			'/wp/v2/pages/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)',
 			'/wp/v2/media',
 			'/wp/v2/media/(?P<id>[\\d]+)',
+			'/wp/v2/blocks',
+			'/wp/v2/blocks/(?P<id>[\d]+)',
+			'/wp/v2/blocks/(?P<parent>[\d]+)/autosaves',
+			'/wp/v2/blocks/(?P<parent>[\d]+)/autosaves/(?P<id>[\d]+)',
 			'/wp/v2/types',
 			'/wp/v2/types/(?P<type>[\\w-]+)',
 			'/wp/v2/statuses',
diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js
index 8a236da00d..8576875105 100644
--- a/tests/qunit/fixtures/wp-api-generated.js
+++ b/tests/qunit/fixtures/wp-api-generated.js
@@ -2271,6 +2271,508 @@ mockedApiResponse.Schema = {
                 }
             ]
         },
+        "/wp/v2/blocks": {
+            "namespace": "wp/v2",
+            "methods": [
+                "GET",
+                "POST"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": {
+                        "context": {
+                            "required": false,
+                            "default": "view",
+                            "enum": [
+                                "view",
+                                "embed",
+                                "edit"
+                            ],
+                            "description": "Scope under which the request is made; determines fields present in response.",
+                            "type": "string"
+                        },
+                        "page": {
+                            "required": false,
+                            "default": 1,
+                            "description": "Current page of the collection.",
+                            "type": "integer"
+                        },
+                        "per_page": {
+                            "required": false,
+                            "default": 10,
+                            "description": "Maximum number of items to be returned in result set.",
+                            "type": "integer"
+                        },
+                        "search": {
+                            "required": false,
+                            "description": "Limit results to those matching a string.",
+                            "type": "string"
+                        },
+                        "after": {
+                            "required": false,
+                            "description": "Limit response to posts published after a given ISO8601 compliant date.",
+                            "type": "string"
+                        },
+                        "before": {
+                            "required": false,
+                            "description": "Limit response to posts published before a given ISO8601 compliant date.",
+                            "type": "string"
+                        },
+                        "exclude": {
+                            "required": false,
+                            "default": [],
+                            "description": "Ensure result set excludes specific IDs.",
+                            "type": "array",
+                            "items": {
+                                "type": "integer"
+                            }
+                        },
+                        "include": {
+                            "required": false,
+                            "default": [],
+                            "description": "Limit result set to specific IDs.",
+                            "type": "array",
+                            "items": {
+                                "type": "integer"
+                            }
+                        },
+                        "offset": {
+                            "required": false,
+                            "description": "Offset the result set by a specific number of items.",
+                            "type": "integer"
+                        },
+                        "order": {
+                            "required": false,
+                            "default": "desc",
+                            "enum": [
+                                "asc",
+                                "desc"
+                            ],
+                            "description": "Order sort attribute ascending or descending.",
+                            "type": "string"
+                        },
+                        "orderby": {
+                            "required": false,
+                            "default": "date",
+                            "enum": [
+                                "author",
+                                "date",
+                                "id",
+                                "include",
+                                "modified",
+                                "parent",
+                                "relevance",
+                                "slug",
+                                "include_slugs",
+                                "title"
+                            ],
+                            "description": "Sort collection by object attribute.",
+                            "type": "string"
+                        },
+                        "slug": {
+                            "required": false,
+                            "description": "Limit result set to posts with one or more specific slugs.",
+                            "type": "array",
+                            "items": {
+                                "type": "string"
+                            }
+                        },
+                        "status": {
+                            "required": false,
+                            "default": "publish",
+                            "description": "Limit result set to posts assigned one or more statuses.",
+                            "type": "array",
+                            "items": {
+                                "enum": [
+                                    "publish",
+                                    "future",
+                                    "draft",
+                                    "pending",
+                                    "private",
+                                    "trash",
+                                    "auto-draft",
+                                    "inherit",
+                                    "request-pending",
+                                    "request-confirmed",
+                                    "request-failed",
+                                    "request-completed",
+                                    "any"
+                                ],
+                                "type": "string"
+                            }
+                        }
+                    }
+                },
+                {
+                    "methods": [
+                        "POST"
+                    ],
+                    "args": {
+                        "date": {
+                            "required": false,
+                            "description": "The date the object was published, in the site's timezone.",
+                            "type": "string"
+                        },
+                        "date_gmt": {
+                            "required": false,
+                            "description": "The date the object was published, as GMT.",
+                            "type": "string"
+                        },
+                        "slug": {
+                            "required": false,
+                            "description": "An alphanumeric identifier for the object unique to its type.",
+                            "type": "string"
+                        },
+                        "status": {
+                            "required": false,
+                            "enum": [
+                                "publish",
+                                "future",
+                                "draft",
+                                "pending",
+                                "private"
+                            ],
+                            "description": "A named status for the object.",
+                            "type": "string"
+                        },
+                        "password": {
+                            "required": false,
+                            "description": "A password to protect access to the content and excerpt.",
+                            "type": "string"
+                        },
+                        "title": {
+                            "required": false,
+                            "description": "The title for the object.",
+                            "type": "object"
+                        },
+                        "content": {
+                            "required": false,
+                            "description": "The content for the object.",
+                            "type": "object"
+                        },
+                        "template": {
+                            "required": false,
+                            "description": "The theme file to use to display the object.",
+                            "type": "string"
+                        }
+                    }
+                }
+            ],
+            "_links": {
+                "self": "http://example.org/index.php?rest_route=/wp/v2/blocks"
+            }
+        },
+        "/wp/v2/blocks/(?P<id>[\\d]+)": {
+            "namespace": "wp/v2",
+            "methods": [
+                "GET",
+                "POST",
+                "PUT",
+                "PATCH",
+                "DELETE"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": {
+                        "id": {
+                            "required": false,
+                            "description": "Unique identifier for the object.",
+                            "type": "integer"
+                        },
+                        "context": {
+                            "required": false,
+                            "default": "view",
+                            "enum": [
+                                "view",
+                                "embed",
+                                "edit"
+                            ],
+                            "description": "Scope under which the request is made; determines fields present in response.",
+                            "type": "string"
+                        },
+                        "password": {
+                            "required": false,
+                            "description": "The password for the post if it is password protected.",
+                            "type": "string"
+                        }
+                    }
+                },
+                {
+                    "methods": [
+                        "POST",
+                        "PUT",
+                        "PATCH"
+                    ],
+                    "args": {
+                        "id": {
+                            "required": false,
+                            "description": "Unique identifier for the object.",
+                            "type": "integer"
+                        },
+                        "date": {
+                            "required": false,
+                            "description": "The date the object was published, in the site's timezone.",
+                            "type": "string"
+                        },
+                        "date_gmt": {
+                            "required": false,
+                            "description": "The date the object was published, as GMT.",
+                            "type": "string"
+                        },
+                        "slug": {
+                            "required": false,
+                            "description": "An alphanumeric identifier for the object unique to its type.",
+                            "type": "string"
+                        },
+                        "status": {
+                            "required": false,
+                            "enum": [
+                                "publish",
+                                "future",
+                                "draft",
+                                "pending",
+                                "private"
+                            ],
+                            "description": "A named status for the object.",
+                            "type": "string"
+                        },
+                        "password": {
+                            "required": false,
+                            "description": "A password to protect access to the content and excerpt.",
+                            "type": "string"
+                        },
+                        "title": {
+                            "required": false,
+                            "description": "The title for the object.",
+                            "type": "object"
+                        },
+                        "content": {
+                            "required": false,
+                            "description": "The content for the object.",
+                            "type": "object"
+                        },
+                        "template": {
+                            "required": false,
+                            "description": "The theme file to use to display the object.",
+                            "type": "string"
+                        }
+                    }
+                },
+                {
+                    "methods": [
+                        "DELETE"
+                    ],
+                    "args": {
+                        "id": {
+                            "required": false,
+                            "description": "Unique identifier for the object.",
+                            "type": "integer"
+                        },
+                        "force": {
+                            "required": false,
+                            "default": false,
+                            "description": "Whether to bypass trash and force deletion.",
+                            "type": "boolean"
+                        }
+                    }
+                }
+            ]
+        },
+        "/wp/v2/blocks/(?P<parent>[\\d]+)/autosaves": {
+            "namespace": "wp/v2",
+            "methods": [
+                "GET",
+                "POST"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": {
+                        "parent": {
+                            "required": false,
+                            "description": "The ID for the parent of the object.",
+                            "type": "integer"
+                        },
+                        "context": {
+                            "required": false,
+                            "default": "view",
+                            "enum": [
+                                "view",
+                                "embed",
+                                "edit"
+                            ],
+                            "description": "Scope under which the request is made; determines fields present in response.",
+                            "type": "string"
+                        },
+                        "page": {
+                            "required": false,
+                            "default": 1,
+                            "description": "Current page of the collection.",
+                            "type": "integer"
+                        },
+                        "per_page": {
+                            "required": false,
+                            "description": "Maximum number of items to be returned in result set.",
+                            "type": "integer"
+                        },
+                        "search": {
+                            "required": false,
+                            "description": "Limit results to those matching a string.",
+                            "type": "string"
+                        },
+                        "exclude": {
+                            "required": false,
+                            "default": [],
+                            "description": "Ensure result set excludes specific IDs.",
+                            "type": "array",
+                            "items": {
+                                "type": "integer"
+                            }
+                        },
+                        "include": {
+                            "required": false,
+                            "default": [],
+                            "description": "Limit result set to specific IDs.",
+                            "type": "array",
+                            "items": {
+                                "type": "integer"
+                            }
+                        },
+                        "offset": {
+                            "required": false,
+                            "description": "Offset the result set by a specific number of items.",
+                            "type": "integer"
+                        },
+                        "order": {
+                            "required": false,
+                            "default": "desc",
+                            "enum": [
+                                "asc",
+                                "desc"
+                            ],
+                            "description": "Order sort attribute ascending or descending.",
+                            "type": "string"
+                        },
+                        "orderby": {
+                            "required": false,
+                            "default": "date",
+                            "enum": [
+                                "date",
+                                "id",
+                                "include",
+                                "relevance",
+                                "slug",
+                                "include_slugs",
+                                "title"
+                            ],
+                            "description": "Sort collection by object attribute.",
+                            "type": "string"
+                        }
+                    }
+                },
+                {
+                    "methods": [
+                        "POST"
+                    ],
+                    "args": {
+                        "parent": {
+                            "required": false,
+                            "description": "The ID for the parent of the object.",
+                            "type": "integer"
+                        },
+                        "author": {
+                            "required": false,
+                            "description": "The ID for the author of the object.",
+                            "type": "integer"
+                        },
+                        "date": {
+                            "required": false,
+                            "description": "The date the object was published, in the site's timezone.",
+                            "type": "string"
+                        },
+                        "date_gmt": {
+                            "required": false,
+                            "description": "The date the object was published, as GMT.",
+                            "type": "string"
+                        },
+                        "id": {
+                            "required": false,
+                            "description": "Unique identifier for the object.",
+                            "type": "integer"
+                        },
+                        "modified": {
+                            "required": false,
+                            "description": "The date the object was last modified, in the site's timezone.",
+                            "type": "string"
+                        },
+                        "modified_gmt": {
+                            "required": false,
+                            "description": "The date the object was last modified, as GMT.",
+                            "type": "string"
+                        },
+                        "slug": {
+                            "required": false,
+                            "description": "An alphanumeric identifier for the object unique to its type.",
+                            "type": "string"
+                        },
+                        "title": {
+                            "required": false,
+                            "description": "The title for the object.",
+                            "type": "object"
+                        },
+                        "content": {
+                            "required": false,
+                            "description": "The content for the object.",
+                            "type": "object"
+                        }
+                    }
+                }
+            ]
+        },
+        "/wp/v2/blocks/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)": {
+            "namespace": "wp/v2",
+            "methods": [
+                "GET"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": {
+                        "parent": {
+                            "required": false,
+                            "description": "The ID for the parent of the object.",
+                            "type": "integer"
+                        },
+                        "id": {
+                            "required": false,
+                            "description": "The ID for the object.",
+                            "type": "integer"
+                        },
+                        "context": {
+                            "required": false,
+                            "default": "view",
+                            "enum": [
+                                "view",
+                                "embed",
+                                "edit"
+                            ],
+                            "description": "Scope under which the request is made; determines fields present in response.",
+                            "type": "string"
+                        }
+                    }
+                }
+            ]
+        },
         "/wp/v2/types": {
             "namespace": "wp/v2",
             "methods": [
@@ -3862,6 +4364,240 @@ mockedApiResponse.Schema = {
                 "self": "http://example.org/index.php?rest_route=/wp/v2/search"
             }
         },
+        "/wp/v2/block-renderer/(?P<name>core/block)": {
+            "namespace": "wp/v2",
+            "methods": [
+                "GET"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": {
+                        "name": {
+                            "required": false,
+                            "description": "Unique registered name for the block.",
+                            "type": "string"
+                        },
+                        "context": {
+                            "required": false,
+                            "default": "view",
+                            "enum": [
+                                "edit"
+                            ],
+                            "description": "Scope under which the request is made; determines fields present in response.",
+                            "type": "string"
+                        },
+                        "attributes": {
+                            "required": false,
+                            "description": "Attributes for core/block block",
+                            "type": "object"
+                        },
+                        "post_id": {
+                            "required": false,
+                            "description": "ID of the post context.",
+                            "type": "integer"
+                        }
+                    }
+                }
+            ]
+        },
+        "/wp/v2/block-renderer/(?P<name>core/latest-comments)": {
+            "namespace": "wp/v2",
+            "methods": [
+                "GET"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": {
+                        "name": {
+                            "required": false,
+                            "description": "Unique registered name for the block.",
+                            "type": "string"
+                        },
+                        "context": {
+                            "required": false,
+                            "default": "view",
+                            "enum": [
+                                "edit"
+                            ],
+                            "description": "Scope under which the request is made; determines fields present in response.",
+                            "type": "string"
+                        },
+                        "attributes": {
+                            "required": false,
+                            "description": "Attributes for core/latest-comments block",
+                            "type": "object"
+                        },
+                        "post_id": {
+                            "required": false,
+                            "description": "ID of the post context.",
+                            "type": "integer"
+                        }
+                    }
+                }
+            ]
+        },
+        "/wp/v2/block-renderer/(?P<name>core/archives)": {
+            "namespace": "wp/v2",
+            "methods": [
+                "GET"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": {
+                        "name": {
+                            "required": false,
+                            "description": "Unique registered name for the block.",
+                            "type": "string"
+                        },
+                        "context": {
+                            "required": false,
+                            "default": "view",
+                            "enum": [
+                                "edit"
+                            ],
+                            "description": "Scope under which the request is made; determines fields present in response.",
+                            "type": "string"
+                        },
+                        "attributes": {
+                            "required": false,
+                            "description": "Attributes for core/archives block",
+                            "type": "object"
+                        },
+                        "post_id": {
+                            "required": false,
+                            "description": "ID of the post context.",
+                            "type": "integer"
+                        }
+                    }
+                }
+            ]
+        },
+        "/wp/v2/block-renderer/(?P<name>core/categories)": {
+            "namespace": "wp/v2",
+            "methods": [
+                "GET"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": {
+                        "name": {
+                            "required": false,
+                            "description": "Unique registered name for the block.",
+                            "type": "string"
+                        },
+                        "context": {
+                            "required": false,
+                            "default": "view",
+                            "enum": [
+                                "edit"
+                            ],
+                            "description": "Scope under which the request is made; determines fields present in response.",
+                            "type": "string"
+                        },
+                        "attributes": {
+                            "required": false,
+                            "description": "Attributes for core/categories block",
+                            "type": "object"
+                        },
+                        "post_id": {
+                            "required": false,
+                            "description": "ID of the post context.",
+                            "type": "integer"
+                        }
+                    }
+                }
+            ]
+        },
+        "/wp/v2/block-renderer/(?P<name>core/latest-posts)": {
+            "namespace": "wp/v2",
+            "methods": [
+                "GET"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": {
+                        "name": {
+                            "required": false,
+                            "description": "Unique registered name for the block.",
+                            "type": "string"
+                        },
+                        "context": {
+                            "required": false,
+                            "default": "view",
+                            "enum": [
+                                "edit"
+                            ],
+                            "description": "Scope under which the request is made; determines fields present in response.",
+                            "type": "string"
+                        },
+                        "attributes": {
+                            "required": false,
+                            "description": "Attributes for core/latest-posts block",
+                            "type": "object"
+                        },
+                        "post_id": {
+                            "required": false,
+                            "description": "ID of the post context.",
+                            "type": "integer"
+                        }
+                    }
+                }
+            ]
+        },
+        "/wp/v2/block-renderer/(?P<name>core/shortcode)": {
+            "namespace": "wp/v2",
+            "methods": [
+                "GET"
+            ],
+            "endpoints": [
+                {
+                    "methods": [
+                        "GET"
+                    ],
+                    "args": {
+                        "name": {
+                            "required": false,
+                            "description": "Unique registered name for the block.",
+                            "type": "string"
+                        },
+                        "context": {
+                            "required": false,
+                            "default": "view",
+                            "enum": [
+                                "edit"
+                            ],
+                            "description": "Scope under which the request is made; determines fields present in response.",
+                            "type": "string"
+                        },
+                        "attributes": {
+                            "required": false,
+                            "description": "Attributes for core/shortcode block",
+                            "type": "object"
+                        },
+                        "post_id": {
+                            "required": false,
+                            "description": "ID of the post context.",
+                            "type": "integer"
+                        }
+                    }
+                }
+            ]
+        },
         "/wp/v2/settings": {
             "namespace": "wp/v2",
             "methods": [
@@ -4339,16 +5075,16 @@ mockedApiResponse.postRevisions = [
         }
     },
     {
-        "author": 389,
+        "author": 404,
         "date": "2017-02-14T00:00:00",
         "date_gmt": "2017-02-14T00:00:00",
-        "id": 36710,
+        "id": 36717,
         "modified": "2017-02-14T00:00:00",
         "modified_gmt": "2017-02-14T00:00:00",
-        "parent": 36709,
-        "slug": "36709-revision-v1",
+        "parent": 36716,
+        "slug": "36716-revision-v1",
         "guid": {
-            "rendered": "http://example.org/?p=36710"
+            "rendered": "http://example.org/?p=36717"
         },
         "title": {
             "rendered": "REST API Client Fixture: Post"
@@ -4362,7 +5098,7 @@ mockedApiResponse.postRevisions = [
         "_links": {
             "parent": [
                 {
-                    "href": "http://example.org/index.php?rest_route=/wp/v2/posts/36709"
+                    "href": "http://example.org/index.php?rest_route=/wp/v2/posts/36716"
                 }
             ]
         }
@@ -4394,16 +5130,16 @@ mockedApiResponse.revision = {
 
 mockedApiResponse.postAutosaves = [
     {
-        "author": 389,
+        "author": 404,
         "date": "2017-02-14T00:00:00",
         "date_gmt": "2017-02-14T00:00:00",
-        "id": 36711,
+        "id": 36718,
         "modified": "2017-02-14T00:00:00",
         "modified_gmt": "2017-02-14T00:00:00",
-        "parent": 36709,
-        "slug": "36709-autosave-v1",
+        "parent": 36716,
+        "slug": "36716-autosave-v1",
         "guid": {
-            "rendered": "http://example.org/?p=36711"
+            "rendered": "http://example.org/?p=36718"
         },
         "title": {
             "rendered": ""
@@ -4417,7 +5153,7 @@ mockedApiResponse.postAutosaves = [
         "_links": {
             "parent": [
                 {
-                    "href": "http://example.org/index.php?rest_route=/wp/v2/posts/36709"
+                    "href": "http://example.org/index.php?rest_route=/wp/v2/posts/36716"
                 }
             ]
         }
@@ -4425,16 +5161,16 @@ mockedApiResponse.postAutosaves = [
 ];
 
 mockedApiResponse.autosave = {
-    "author": 389,
+    "author": 404,
     "date": "2017-02-14T00:00:00",
     "date_gmt": "2017-02-14T00:00:00",
-    "id": 36711,
+    "id": 36718,
     "modified": "2017-02-14T00:00:00",
     "modified_gmt": "2017-02-14T00:00:00",
-    "parent": 36709,
-    "slug": "36709-autosave-v1",
+    "parent": 36716,
+    "slug": "36716-autosave-v1",
     "guid": {
-        "rendered": "http://example.org/?p=36711"
+        "rendered": "http://example.org/?p=36718"
     },
     "title": {
         "rendered": ""
@@ -4599,16 +5335,16 @@ mockedApiResponse.pageRevisions = [
         }
     },
     {
-        "author": 389,
+        "author": 404,
         "date": "2017-02-14T00:00:00",
         "date_gmt": "2017-02-14T00:00:00",
-        "id": 36713,
+        "id": 36720,
         "modified": "2017-02-14T00:00:00",
         "modified_gmt": "2017-02-14T00:00:00",
-        "parent": 36712,
-        "slug": "36712-revision-v1",
+        "parent": 36719,
+        "slug": "36719-revision-v1",
         "guid": {
-            "rendered": "http://example.org/?p=36713"
+            "rendered": "http://example.org/?p=36720"
         },
         "title": {
             "rendered": "REST API Client Fixture: Page"
@@ -4622,7 +5358,7 @@ mockedApiResponse.pageRevisions = [
         "_links": {
             "parent": [
                 {
-                    "href": "http://example.org/index.php?rest_route=/wp/v2/pages/36712"
+                    "href": "http://example.org/index.php?rest_route=/wp/v2/pages/36719"
                 }
             ]
         }
@@ -4654,16 +5390,16 @@ mockedApiResponse.pageRevision = {
 
 mockedApiResponse.pageAutosaves = [
     {
-        "author": 389,
+        "author": 404,
         "date": "2017-02-14T00:00:00",
         "date_gmt": "2017-02-14T00:00:00",
-        "id": 36714,
+        "id": 36721,
         "modified": "2017-02-14T00:00:00",
         "modified_gmt": "2017-02-14T00:00:00",
-        "parent": 36712,
-        "slug": "36712-autosave-v1",
+        "parent": 36719,
+        "slug": "36719-autosave-v1",
         "guid": {
-            "rendered": "http://example.org/?p=36714"
+            "rendered": "http://example.org/?p=36721"
         },
         "title": {
             "rendered": ""
@@ -4677,7 +5413,7 @@ mockedApiResponse.pageAutosaves = [
         "_links": {
             "parent": [
                 {
-                    "href": "http://example.org/index.php?rest_route=/wp/v2/pages/36712"
+                    "href": "http://example.org/index.php?rest_route=/wp/v2/pages/36719"
                 }
             ]
         }
@@ -4685,16 +5421,16 @@ mockedApiResponse.pageAutosaves = [
 ];
 
 mockedApiResponse.pageAutosave = {
-    "author": 389,
+    "author": 404,
     "date": "2017-02-14T00:00:00",
     "date_gmt": "2017-02-14T00:00:00",
-    "id": 36714,
+    "id": 36721,
     "modified": "2017-02-14T00:00:00",
     "modified_gmt": "2017-02-14T00:00:00",
-    "parent": 36712,
-    "slug": "36712-autosave-v1",
+    "parent": 36719,
+    "slug": "36719-autosave-v1",
     "guid": {
-        "rendered": "http://example.org/?p=36714"
+        "rendered": "http://example.org/?p=36721"
     },
     "title": {
         "rendered": ""
@@ -4890,6 +5626,33 @@ mockedApiResponse.TypesCollection = {
                 }
             ]
         }
+    },
+    "wp_block": {
+        "description": "",
+        "hierarchical": false,
+        "name": "Blocks",
+        "slug": "wp_block",
+        "taxonomies": [],
+        "rest_base": "blocks",
+        "_links": {
+            "collection": [
+                {
+                    "href": "http://example.org/index.php?rest_route=/wp/v2/types"
+                }
+            ],
+            "wp:items": [
+                {
+                    "href": "http://example.org/index.php?rest_route=/wp/v2/blocks"
+                }
+            ],
+            "curies": [
+                {
+                    "name": "wp",
+                    "href": "https://api.w.org/{rel}",
+                    "templated": true
+                }
+            ]
+        }
     }
 };
 
