Skip to content

Commit

Permalink
Using the Opis JSON Schema Validator for the settings endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
aldavigdis committed Mar 5, 2024
1 parent bcd0902 commit 73587fa
Show file tree
Hide file tree
Showing 4 changed files with 275 additions and 30 deletions.
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,8 @@
"NineteenEightyFour\\NinteenEightyWoo\\": "src/"
}
},
"minimum-stability": "dev"
"minimum-stability": "dev",
"require": {
"opis/json-schema": "^2.0@dev"
}
}
198 changes: 196 additions & 2 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 28 additions & 4 deletions src/Rest/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,37 @@
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use Opis\JsonSchema\Validator;

/**
* The REST API Settings endpoint class
*
* Handles the `NinteenEightyWoo/v1/settings/` REST endpoint.
*/
class Settings {
const JSON_SCHEMA = <<<'JSON'
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"api_key": { "type": "string" },
"payment_methods": {
"type": "array",
"items": {
"type": "object",
"properties": {
"woo_id": { "type": "string" },
"dk_id": { "type": "number" },
"dk_name": { "type": "string" }
},
"required": ["woo_id", "dk_id", "dk_name" ]
}
}
},
"required": ["api_key", "payment_methods" ]
}
JSON;

/**
* The Constructor for the Settings REST endpoint
*
Expand Down Expand Up @@ -52,10 +76,10 @@ public static function rest_api_callback(
$rest_body = $request->get_body();
$rest_json = json_decode( $rest_body );

if (
false === is_object( $rest_json ) ||
( false === self::validate_post_schema( $rest_json ) )
) {
$validator = new Validator();
$validation = $validator->validate( $rest_json, self::JSON_SCHEMA );

if ( true === $validation->hasError() ) {
return new WP_Error(
'bad_request',
'Bad Request',
Expand Down
70 changes: 47 additions & 23 deletions tests/RestSettingsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@

#[TestDox( 'The Rest Settings JSON API endpoint class' )]
final class RestSettingstest extends TestCase {
const VALID_POST_BODY = [
'api_key' => 'MwmTtCTfhVQvlEOKCqFxfRAuPYHgy17E',
'payment_methods' => [
[
'woo_id' => 'bacs',
'dk_id' => 10,
'dk_name' => 'Direct bank transfer',
],
],
];

/**
* The WordPress administrator user
*
Expand Down Expand Up @@ -43,21 +54,10 @@ final class RestSettingstest extends TestCase {
public array $valid_post_body;

public function setUp(): void {
$settings = new Settings();
new Settings();

do_action( 'rest_api_init' );

$this->valid_post_body = [
'api_key' => 'MwmTtCTfhVQvlEOKCqFxfRAuPYHgy17E',
'payment_methods' => [
[
'woo_id' => 'bacs',
'dk_id' => 10,
'dk_name' => 'Direct bank transfer',
],
],
];

$user_factory = new WP_UnitTest_Factory_For_User();
$this->admin_user = $user_factory->create_and_get();
$this->admin_user->add_role( 'administrator' );
Expand All @@ -72,7 +72,10 @@ public function tearDown(): void {

#[TestDox( 'creates the NinteenEightyWoo/v1 namespace in the WP REST API' )]
public function testNamespaceExsists(): void {
$request = new WP_REST_Request( 'GET', '/NinteenEightyWoo/v1' );
$request = new WP_REST_Request(
'GET',
'/NinteenEightyWoo/v1'
);
$response = rest_do_request( $request );

assertEquals( 200, $response->status );
Expand All @@ -81,7 +84,10 @@ public function testNamespaceExsists(): void {
#[TestDox( 'protects the settings endpoint from outside requests' )]
public function tesEndpointIsSecureFromOutsiders(): void {
// We're assuming an external request here, so we're not using a nonce value.
$request = new WP_REST_Request( 'POST', '/NinteenEightyWoo/v1/settings' );
$request = new WP_REST_Request(
'POST',
'/NinteenEightyWoo/v1/settings'
);
$response = rest_do_request( $request );

assertEquals( 401, $response->status );
Expand All @@ -92,10 +98,13 @@ public function testEndpointProcessesValidRequest(): void {
// Start by setting the current user to our admin user and creating a nonce
// for that user for the REST API request.
wp_set_current_user( $this->admin_user_id );
$request = new WP_REST_Request( 'POST', '/NinteenEightyWoo/v1/settings' );
$request = new WP_REST_Request(
'POST',
'/NinteenEightyWoo/v1/settings'
);

$request->add_header( 'X-WP-Nonce', wp_create_nonce( 'wp_rest' ) );
$request->set_body( wp_json_encode( $this->valid_post_body ) );
$request->set_body( wp_json_encode( self::VALID_POST_BODY ) );

$response = rest_do_request( $request );

Expand All @@ -110,26 +119,41 @@ public function testEndpointRejectsInvalidTypeRequest(): void {
'/NinteenEightyWoo/v1/settings'
);

$string_request->add_header( 'X-WP-Nonce', wp_create_nonce( 'wp_rest' ) );
$string_request->add_header(
'X-WP-Nonce',
wp_create_nonce( 'wp_rest' )
);
$string_request->set_body( wp_json_encode( 'This string is invalid' ) );
$string_response = rest_do_request( $string_request );
assertEquals( 400, $string_response->status );

$object_request = new WP_REST_Request( 'POST', '/NinteenEightyWoo/v1/settings' );
$object_request->add_header( 'X-WP-Nonce', wp_create_nonce( 'wp_rest' ) );
$object_request = new WP_REST_Request(
'POST',
'/NinteenEightyWoo/v1/settings'
);
$object_request->add_header(
'X-WP-Nonce',
wp_create_nonce( 'wp_rest' )
);
$object_request->set_body(
wp_json_encode(
[ 'foo' => 'This is an object, but has none of the required keys.' ]
[ 'foo' => 'This is an object with no valid keys.' ]
)
);
$object_response = rest_do_request( $object_request );
assertEquals( 400, $object_response->status );

$api_key_unset_request = new WP_REST_Request( 'POST', '/NinteenEightyWoo/v1/settings' );
$api_key_unset_request->add_header( 'X-WP-Nonce', wp_create_nonce( 'wp_rest' ) );
$api_key_unset_request = new WP_REST_Request(
'POST',
'/NinteenEightyWoo/v1/settings'
);
$api_key_unset_request->add_header(
'X-WP-Nonce',
wp_create_nonce( 'wp_rest' )
);
$api_key_unset_request->set_body(
wp_json_encode(
array( 'payment_methods' => $this->valid_post_body['payment_methods'] )
[ 'payment_methods' => self::VALID_POST_BODY['payment_methods'] ]
)
);
$api_key_unset_response = rest_do_request( $api_key_unset_request );
Expand Down

0 comments on commit 73587fa

Please sign in to comment.