iron-bound-designs / wp-rest-api-schema-validator

Validate WP REST API requests using a complete JSON Schema validator.
https://timothybjacobs.com/2017/05/17/json-schema-and-the-wp-rest-api/
MIT License
12 stars 2 forks source link

String value found, but an array is required #4

Open thefrosty opened 3 years ago

thefrosty commented 3 years ago

Running a curl on my local WordPress install:

curl --location --request GET 'https://local.test/wp-json/wp/v2/posts' \
--header 'Authorization: Basic SomeAweseomKey' \
--header 'Cookie: PHPSESSID=ba5ea78b3f9eeddf3cd064674e1381c2'

Returns:

{
    "code": "rest_invalid_param",
    "message": "Invalid parameter(s): status",
    "data": {
        "status": 400,
        "params": {
            "status": "String value found, but an array is required"
        }
    }
}

I could send the OPTIONS request since I do see status listed twice, but they are both core fields. 🤔 Curious if it's a core issue or something else.

TimothyBJacobs commented 3 years ago

Hm, is there anything else on the install? The problem is that the default value for the status parameter doesn't pass strict type checking. But the Middleware is supposed to only validate the passed parameters, not the default values. https://github.com/iron-bound-designs/wp-rest-api-schema-validator/blob/c5452e3ae972a13a1581a219c96c4cf1c81d5e60/src/Middleware.php#L347

TBH though, I've never used this with wp/v2 as the namespace, since the Core REST API schemas and endpoints aren't 100% compatible with JSON Schema. I've just used this for endpoints that I have complete control over.

thefrosty commented 3 years ago

In the Schema it's a string, but in the endpoints GET args, it's an array. Which seems fine buy the Middleware is blocking the request above, with nothing being passed.

thefrosty commented 3 years ago

TBH though, I've never used this with wp/v2 as the namespace, since the Core REST API schemas and endpoints aren't 100% compatible with JSON Schema. I've just used this for endpoints that I have complete control over.

Thanks, just thought I would drop a note. I will continue to look into it and see if I can come up with a solution (until we move out of the wp/v2 namespace)

TimothyBJacobs commented 3 years ago

In the Schema it's a string, but in the endpoints GET args, it's an array. Which seems fine buy the Middleware is blocking the request above, with nothing being passed.

Right, but it's the default value in the collection params that is a string. https://github.com/WordPress/wordpress-develop/blob/953e1c5f8313a89d4d3b99ab5996b4660045c976/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php#L2847

Really, we should make that [ 'publish' ].

thefrosty commented 3 years ago

https://core.trac.wordpress.org/ticket/53622#ticket

thefrosty commented 3 years ago

Quick fix:

<?php
$post_types = \get_post_types();
$fixQueryParams = static function (array $query_params): array {
    if (
        isset($query_params['status']) &&
        (isset($query_params['status']['type']) && \strcasecmp($query_params['status']['type'], 'array') === 0) &&
        (isset($query_params['status']['default']) && \gettype($query_params['status']['default']) !== 'array')
    ) {
        $query_params['status']['default'] = (array)$query_params['status']['default'];
    }

    return $query_params;
};
\array_walk(
    $post_types,
    fn(string $post_type): bool => \add_filter("rest_{$post_type}_collection_params", $fixQueryParams)
);