REST API: Make sure all supported JSON Schema keywords are output in the index.

Previously, only a small subset of keywords were exposed which limited the utility of `OPTIONS` requests.

Props raubvogel, TimothyBlynJacobs.
Fixes #51020.


git-svn-id: https://develop.svn.wordpress.org/trunk@49257 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Timothy Jacobs 2020-10-20 20:17:20 +00:00
parent fdcff8b475
commit 18c1ab8e89
4 changed files with 2360 additions and 1394 deletions

View File

@ -1874,6 +1874,43 @@ function rest_find_one_matching_schema( $value, $args, $param, $stop_after_first
return $matching_schemas[0]['schema_object'];
}
/**
* Get all valid JSON schema properties.
*
* @since 5.6.0
*
* @return string[] All valid JSON schema properties.
*/
function rest_get_allowed_schema_keywords() {
return array(
'title',
'description',
'default',
'type',
'format',
'enum',
'items',
'properties',
'additionalProperties',
'patternProperties',
'minProperties',
'maxProperties',
'minimum',
'maximum',
'exclusiveMinimum',
'exclusiveMaximum',
'multipleOf',
'minLength',
'maxLength',
'pattern',
'minItems',
'maxItems',
'uniqueItems',
'anyOf',
'oneOf',
);
}
/**
* Validate a value based on a schema.
*
@ -2765,30 +2802,8 @@ function rest_get_endpoint_args_for_schema( $schema, $method = WP_REST_Server::C
$schema_properties = ! empty( $schema['properties'] ) ? $schema['properties'] : array();
$endpoint_args = array();
$valid_schema_properties = array(
'type',
'format',
'enum',
'items',
'properties',
'additionalProperties',
'patternProperties',
'minProperties',
'maxProperties',
'minimum',
'maximum',
'exclusiveMinimum',
'exclusiveMaximum',
'multipleOf',
'minLength',
'maxLength',
'pattern',
'minItems',
'maxItems',
'uniqueItems',
'anyOf',
'oneOf',
);
$valid_schema_properties = rest_get_allowed_schema_keywords();
$valid_schema_properties = array_diff( $valid_schema_properties, array( 'default', 'required' ) );
foreach ( $schema_properties as $field_id => $params ) {
@ -2802,10 +2817,6 @@ function rest_get_endpoint_args_for_schema( $schema, $method = WP_REST_Server::C
'sanitize_callback' => 'rest_sanitize_request_arg',
);
if ( isset( $params['description'] ) ) {
$endpoint_args[ $field_id ]['description'] = $params['description'];
}
if ( WP_REST_Server::CREATABLE === $method && isset( $params['default'] ) ) {
$endpoint_args[ $field_id ]['default'] = $params['default'];
}

View File

@ -1380,6 +1380,8 @@ class WP_REST_Server {
}
}
$allowed_schema_keywords = array_flip( rest_get_allowed_schema_keywords() );
$route = preg_replace( '#\(\?P<(\w+?)>.*?\)#', '{$1}', $route );
foreach ( $callbacks as $callback ) {
@ -1397,24 +1399,9 @@ class WP_REST_Server {
$endpoint_data['args'] = array();
foreach ( $callback['args'] as $key => $opts ) {
$arg_data = array(
'required' => ! empty( $opts['required'] ),
);
if ( isset( $opts['default'] ) ) {
$arg_data['default'] = $opts['default'];
}
if ( isset( $opts['enum'] ) ) {
$arg_data['enum'] = $opts['enum'];
}
if ( isset( $opts['description'] ) ) {
$arg_data['description'] = $opts['description'];
}
if ( isset( $opts['type'] ) ) {
$arg_data['type'] = $opts['type'];
}
if ( isset( $opts['items'] ) ) {
$arg_data['items'] = $opts['items'];
}
$arg_data = array_intersect_key( $opts, $allowed_schema_keywords );
$arg_data['required'] = ! empty( $opts['required'] );
$endpoint_data['args'][ $key ] = $arg_data;
}
}

View File

@ -1931,6 +1931,71 @@ class Tests_REST_Server extends WP_Test_REST_TestCase {
$this->assertEquals( 400, $response->get_status() );
}
/**
* @ticket 51020
*/
public function test_get_data_for_route_includes_permitted_schema_keywords() {
$keywords = array(
'title' => 'Hi',
'description' => 'World',
'type' => 'string',
'default' => 0,
'format' => 'uri',
'enum' => array( 'https://example.org' ),
'items' => array( 'type' => 'string' ),
'properties' => array( 'a' => array( 'type' => 'string' ) ),
'additionalProperties' => false,
'patternProperties' => array( '\d' => array( 'type' => 'string' ) ),
'minProperties' => 1,
'maxProperties' => 5,
'minimum' => 1,
'maximum' => 5,
'exclusiveMinimum' => true,
'exclusiveMaximum' => false,
'multipleOf' => 2,
'minLength' => 1,
'maxLength' => 5,
'pattern' => '\d',
'minItems' => 1,
'maxItems' => 5,
'uniqueItems' => true,
'anyOf' => array(
array( 'type' => 'string' ),
array( 'type' => 'integer' ),
),
'oneOf' => array(
array( 'type' => 'string' ),
array( 'type' => 'integer' ),
),
);
$param = $keywords;
$param['invalid'] = true;
$expected = $keywords;
$expected['required'] = false;
register_rest_route(
'test-ns/v1',
'/test',
array(
'methods' => 'POST',
'callback' => static function () {
return new WP_REST_Response( 'test' );
},
'permission_callback' => '__return_true',
'args' => array(
'param' => $param,
),
)
);
$response = rest_do_request( new WP_REST_Request( 'OPTIONS', '/test-ns/v1/test' ) );
$args = $response->get_data()['endpoints'][0]['args'];
$this->assertSameSetsWithIndex( $expected, $args['param'] );
}
public function _validate_as_integer_123( $value, $request, $key ) {
if ( ! is_int( $value ) ) {
return new WP_Error( 'some-error', 'This is not valid!' );

File diff suppressed because it is too large Load Diff