Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion WebFiori/Http/WebServicesManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,11 @@ public final function process() {
$this->configureServiceParameters($actionObj);
}

$params = $actionObj->getParameters();
// Resolve #[RequestParam] annotations for the current HTTP method.
// This ensures annotated parameters are registered before filtering,
// even for services using the traditional processRequest() pattern.
$actionObj->getParameterByName('', $this->getRequest()->getRequestMethod());

$params = $actionObj->getParameters();
$this->filter->clearParametersDef();
$this->filter->clearInputs();
Expand Down
117 changes: 117 additions & 0 deletions tests/WebFiori/Tests/Http/AnnotatedParamsProcessRequestTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php
namespace WebFiori\Tests\Http;

use WebFiori\Http\APITestCase;
use WebFiori\Http\WebServicesManager;
use WebFiori\Tests\Http\TestServices\AnnotatedParamsLegacyService;
use WebFiori\Tests\Http\TestServices\AnnotatedService;

/**
* Tests that #[RequestParam] annotations are resolved before filtering
* in WebServicesManager::process(), for services using the traditional
* processRequest() pattern (without #[ResponseBody]).
*
* Regression test for: https://github.com/WebFiori/http/issues/102
*/
class AnnotatedParamsProcessRequestTest extends APITestCase {

/**
* Test that POST parameters are received via processRequest() when
* using #[RequestParam] annotations without #[ResponseBody].
*/
public function testPostParamsResolvedInProcessRequest() {
$manager = new WebServicesManager();
$manager->addService(new AnnotatedParamsLegacyService());

$output = $this->postRequest($manager, 'annotated-params-legacy', [
'username' => 'admin@test.com',
'password' => 'secret123',
]);

$response = json_decode($output, true);
$this->assertIsArray($response);
$this->assertEquals('success', $response['type']);
$this->assertStringContainsString('admin@test.com', $response['message']);
}

/**
* Test that missing required parameters are correctly reported
* when using #[RequestParam] annotations without #[ResponseBody].
*/
public function testMissingParamsReportedInProcessRequest() {
$manager = new WebServicesManager();
$manager->addService(new AnnotatedParamsLegacyService());

$output = $this->postRequest($manager, 'annotated-params-legacy', []);

$response = json_decode($output, true);
$this->assertIsArray($response);
$this->assertEquals('error', $response['type']);
// Framework should report missing required params
$this->assertArrayHasKey('missing', $response['more-info']);
$this->assertContains('username', $response['more-info']['missing']);
$this->assertContains('password', $response['more-info']['missing']);
}

/**
* Test that partially missing parameters are reported.
*/
public function testPartialParamsMissing() {
$manager = new WebServicesManager();
$manager->addService(new AnnotatedParamsLegacyService());

$output = $this->postRequest($manager, 'annotated-params-legacy', [
'username' => 'admin@test.com',
]);

$response = json_decode($output, true);
$this->assertIsArray($response);
$this->assertEquals('error', $response['type']);
$this->assertContains('password', $response['more-info']['missing']);
}

/**
* Test that #[ResponseBody] services still work correctly after the fix.
* This ensures the fix doesn't break the existing auto-processing path.
*/
public function testResponseBodyServiceStillWorks() {
$manager = new WebServicesManager();
$manager->addService(new AnnotatedService());

$output = $this->getRequest($manager, 'annotated-service', [
'name' => 'Ibrahim',
]);

$this->assertStringContainsString('Hi Ibrahim!', $output);
}

/**
* Test that #[ResponseBody] service with no params still works.
*/
public function testResponseBodyServiceNoParams() {
$manager = new WebServicesManager();
$manager->addService(new AnnotatedService());

$output = $this->getRequest($manager, 'annotated-service');

$this->assertStringContainsString('Hi user!', $output);
}

/**
* Test wrong HTTP method is rejected for annotated legacy service.
*/
public function testWrongMethodRejected() {
$manager = new WebServicesManager();
$manager->addService(new AnnotatedParamsLegacyService());

// Service only accepts POST, sending GET should fail
$output = $this->getRequest($manager, 'annotated-params-legacy', [
'username' => 'admin@test.com',
'password' => 'secret123',
]);

$response = json_decode($output, true);
$this->assertIsArray($response);
$this->assertEquals('error', $response['type']);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
namespace WebFiori\Tests\Http\TestServices;

use WebFiori\Http\Annotations\PostMapping;
use WebFiori\Http\Annotations\GetMapping;
use WebFiori\Http\Annotations\RequestParam;
use WebFiori\Http\Annotations\RestController;
use WebFiori\Http\ParamType;
use WebFiori\Http\WebService;

/**
* A service that uses #[RequestParam] annotations with the traditional
* processRequest() pattern (no #[ResponseBody]).
* This is the pattern that was broken before the fix.
*/
#[RestController('annotated-params-legacy')]
class AnnotatedParamsLegacyService extends WebService {
public function isAuthorized(): bool {
return true;
}

#[PostMapping]
#[RequestParam(name: 'username', type: ParamType::STRING)]
#[RequestParam(name: 'password', type: ParamType::STRING)]
public function processRequest() {
$username = $this->getParamVal('username');
$password = $this->getParamVal('password');

if ($username === null) {
$this->sendResponse('Username is missing', 400, 'error');
return;
}

if ($password === null) {
$this->sendResponse('Password is missing', 400, 'error');
return;
}

$this->sendResponse('Login successful for: ' . $username, 200, 'success');
}
}
Loading