A powerful and flexible PHP library for creating RESTful web APIs with built-in input filtering, data validation, and comprehensive HTTP utilities. The library provides a clean, object-oriented approach to building web services with automatic parameter validation, authentication support, and JSON response handling.
| Build Status |
|---|
- RESTful API Development: Full support for creating REST services with JSON request/response handling
- Automatic Input Validation: Built-in parameter validation with support for multiple data types
- Custom Filtering: Ability to create user-defined input filters and validation rules
- Authentication Support: Built-in support for various authentication schemes (Basic, Bearer, etc.)
- HTTP Method Support: Support for all standard HTTP methods (GET, POST, PUT, DELETE, etc.)
- Content Type Handling: Support for
application/json,application/x-www-form-urlencoded, andmultipart/form-data - Object Mapping: Automatic mapping of request parameters to PHP objects
- Comprehensive Testing: Built-in testing utilities with
APITestCaseclass - Error Handling: Structured error responses with appropriate HTTP status codes
- Stream Support: Custom input/output stream handling for advanced use cases
composer require webfiori/httpDownload the latest release from GitHub Releases and include the autoloader:
require_once 'path/to/webfiori-http/vendor/autoload.php';PHP 8+ attributes provide a clean, declarative way to define web services:
<?php
use WebFiori\Http\WebService;
use WebFiori\Http\Annotations\RestController;
use WebFiori\Http\Annotations\GetMapping;
use WebFiori\Http\Annotations\PostMapping;
use WebFiori\Http\Annotations\RequestParam;
use WebFiori\Http\Annotations\ResponseBody;
use WebFiori\Http\Annotations\AllowAnonymous;
use WebFiori\Http\ParamType;
#[RestController('hello', 'A simple greeting service')]
class HelloService extends WebService {
#[GetMapping]
#[ResponseBody]
#[AllowAnonymous]
#[RequestParam('name', ParamType::STRING, true)]
public function sayHello(?string $name): string {
return $name ? "Hello, $name!" : "Hello, World!";
}
#[PostMapping]
#[ResponseBody]
#[AllowAnonymous]
#[RequestParam('message', ParamType::STRING)]
public function customGreeting(string $message): array {
return ['greeting' => $message, 'timestamp' => time()];
}
}For comparison, here's the traditional approach using constructor configuration:
<?php
use WebFiori\Http\AbstractWebService;
use WebFiori\Http\RequestMethod;
use WebFiori\Http\ParamType;
use WebFiori\Http\ParamOption;
class HelloService extends AbstractWebService {
public function __construct() {
parent::__construct('hello');
$this->setRequestMethods([RequestMethod::GET]);
$this->addParameters([
'name' => [
ParamOption::TYPE => ParamType::STRING,
ParamOption::OPTIONAL => true
]
]);
}
public function isAuthorized() {
return true;
}
public function processRequest() {
$name = $this->getParamVal('name');
$this->sendResponse($name ? "Hello, $name!" : "Hello, World!");
}
}Both approaches work with WebServicesManager:
$manager = new WebServicesManager();
$manager->addService(new HelloService());
$manager->process();| Term | Definition |
|---|---|
| Web Service | A single endpoint that implements a REST service, represented by AbstractWebService |
| Services Manager | An entity that manages multiple web services, represented by WebServicesManager |
| Request Parameter | A way to pass values from client to server, represented by RequestParameter |
| API Filter | A component that validates and sanitizes request parameters |
The library follows a service-oriented architecture:
- AbstractWebService: Base class for all web services
- WebServicesManager: Manages multiple services and handles request routing
- RequestParameter: Defines and validates individual parameters
- APIFilter: Handles parameter filtering and validation
- Request/Response: Utilities for handling HTTP requests and responses
PHP 8+ attributes provide a modern, declarative approach:
<?php
use WebFiori\Http\WebService;
use WebFiori\Http\Annotations\RestController;
use WebFiori\Http\Annotations\GetMapping;
use WebFiori\Http\Annotations\PostMapping;
use WebFiori\Http\Annotations\PutMapping;
use WebFiori\Http\Annotations\DeleteMapping;
use WebFiori\Http\Annotations\RequestParam;
use WebFiori\Http\Annotations\ResponseBody;
use WebFiori\Http\Annotations\RequiresAuth;
use WebFiori\Http\ParamType;
#[RestController('users', 'User management operations')]
#[RequiresAuth]
class UserService extends WebService {
#[GetMapping]
#[ResponseBody]
#[RequestParam('id', ParamType::INT, true)]
public function getUser(?int $id): array {
return ['id' => $id ?? 1, 'name' => 'John Doe'];
}
#[PostMapping]
#[ResponseBody]
#[RequestParam('name', ParamType::STRING)]
#[RequestParam('email', ParamType::EMAIL)]
public function createUser(string $name, string $email): array {
return ['id' => 2, 'name' => $name, 'email' => $email];
}
#[PutMapping]
#[ResponseBody]
#[RequestParam('id', ParamType::INT)]
#[RequestParam('name', ParamType::STRING)]
public function updateUser(int $id, string $name): array {
return ['id' => $id, 'name' => $name];
}
#[DeleteMapping]
#[ResponseBody]
#[RequestParam('id', ParamType::INT)]
public function deleteUser(int $id): array {
return ['deleted' => $id];
}
}Every web service must extend AbstractWebService and implement the processRequest() method:
<?php
use WebFiori\Http\AbstractWebService;
use WebFiori\Http\RequestMethod;
class MyService extends AbstractWebService {
public function __construct() {
parent::__construct('my-service');
$this->setRequestMethods([RequestMethod::GET, RequestMethod::POST]);
$this->setDescription('A sample web service');
}
public function isAuthorized() {
// Implement authorization logic
return true;
}
public function processRequest() {
// Implement service logic
$this->sendResponse('Service executed successfully');
}
}// Single method
$this->addRequestMethod(RequestMethod::POST);
// Multiple methods
$this->setRequestMethods([
RequestMethod::GET,
RequestMethod::POST,
RequestMethod::PUT
]);$this->setDescription('Creates a new user profile');
$this->setSince('1.2.0');
$this->addResponseDescription('Returns user profile data on success');
$this->addResponseDescription('Returns error message on failure');The library supports various parameter types through ParamType:
ParamType::STRING // String values
ParamType::INT // Integer values
ParamType::DOUBLE // Float/double values
ParamType::BOOL // Boolean values
ParamType::EMAIL // Email addresses (validated)
ParamType::URL // URLs (validated)
ParamType::ARR // Arrays
ParamType::JSON_OBJ // JSON objectsuse WebFiori\Http\RequestParameter;
$param = new RequestParameter('username', ParamType::STRING);
$this->addParameter($param);$this->addParameters([
'username' => [
ParamOption::TYPE => ParamType::STRING,
ParamOption::OPTIONAL => false
],
'age' => [
ParamOption::TYPE => ParamType::INT,
ParamOption::OPTIONAL => true,
ParamOption::MIN => 18,
ParamOption::MAX => 120,
ParamOption::DEFAULT => 25
],
'email' => [
ParamOption::TYPE => ParamType::EMAIL,
ParamOption::OPTIONAL => false
]
]);Available options through ParamOption:
ParamOption::TYPE // Parameter data type
ParamOption::OPTIONAL // Whether parameter is optional
ParamOption::DEFAULT // Default value for optional parameters
ParamOption::MIN // Minimum value (numeric types)
ParamOption::MAX // Maximum value (numeric types)
ParamOption::MIN_LENGTH // Minimum length (string types)
ParamOption::MAX_LENGTH // Maximum length (string types)
ParamOption::EMPTY // Allow empty strings
ParamOption::FILTER // Custom filter function
ParamOption::DESCRIPTION // Parameter description$this->addParameters([
'password' => [
ParamOption::TYPE => ParamType::STRING,
ParamOption::MIN_LENGTH => 8,
ParamOption::FILTER => function($original, $basic) {
// Custom validation logic
if (strlen($basic) < 8) {
return APIFilter::INVALID;
}
// Additional password strength checks
return $basic;
}
]
]);public function processRequest() {
$username = $this->getParamVal('username');
$age = $this->getParamVal('age');
$email = $this->getParamVal('email');
// Get all inputs as array
$allInputs = $this->getInputs();
}<?php
use WebFiori\Http\APITestCase;
class MyServiceTest extends APITestCase {
public function testGetRequest() {
$manager = new WebServicesManager();
$manager->addService(new MyService());
$response = $this->getRequest($manager, 'my-service', [
'param1' => 'value1',
'param2' => 'value2'
]);
$this->assertJson($response);
$this->assertContains('success', $response);
}
public function testPostRequest() {
$manager = new WebServicesManager();
$manager->addService(new MyService());
$response = $this->postRequest($manager, 'my-service', [
'name' => 'John Doe',
'email' => '[email protected]'
]);
$this->assertJson($response);
}
}<?php
use WebFiori\Http\WebService;
use WebFiori\Http\Annotations\RestController;
use WebFiori\Http\Annotations\GetMapping;
use WebFiori\Http\Annotations\PostMapping;
use WebFiori\Http\Annotations\PutMapping;
use WebFiori\Http\Annotations\DeleteMapping;
use WebFiori\Http\Annotations\RequestParam;
use WebFiori\Http\Annotations\ResponseBody;
use WebFiori\Http\Annotations\AllowAnonymous;
use WebFiori\Http\ParamType;
#[RestController('tasks', 'Task management service')]
class TaskService extends WebService {
#[GetMapping]
#[ResponseBody]
#[AllowAnonymous]
public function getTasks(): array {
return [
'tasks' => [
['id' => 1, 'title' => 'Task 1', 'completed' => false],
['id' => 2, 'title' => 'Task 2', 'completed' => true]
],
'count' => 2
];
}
#[PostMapping]
#[ResponseBody]
#[AllowAnonymous]
#[RequestParam('title', ParamType::STRING)]
#[RequestParam('description', ParamType::STRING, true)]
public function createTask(string $title, ?string $description): array {
return [
'id' => 3,
'title' => $title,
'description' => $description ?: '',
'completed' => false
];
}
#[PutMapping]
#[ResponseBody]
#[AllowAnonymous]
#[RequestParam('id', ParamType::INT)]
#[RequestParam('title', ParamType::STRING, true)]
public function updateTask(int $id, ?string $title): array {
return [
'id' => $id,
'title' => $title,
'updated_at' => date('Y-m-d H:i:s')
];
}
#[DeleteMapping]
#[ResponseBody]
#[AllowAnonymous]
#[RequestParam('id', ParamType::INT)]
public function deleteTask(int $id): array {
return [
'id' => $id,
'deleted_at' => date('Y-m-d H:i:s')
];
}
}For more examples, check the examples directory in this repository.
AbstractWebService- Base class for web servicesWebServicesManager- Services managementRequestParameter- Parameter definition and validationAPIFilter- Input filtering and validationRequest- HTTP request utilitiesResponse- HTTP response utilities
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
This project is licensed under the MIT License - see the LICENSE file for details.
- Issues: GitHub Issues
- Examples: Examples Directory
See CHANGELOG.md for a list of changes and version history.