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.
- Supported PHP Versions
- Key Features
- Installation
- Quick Start
- Core Concepts
- Creating Web Services
- Parameter Management
- Authentication & Authorization
- Request & Response Handling
- Advanced Features
- Testing
- Examples
- API Documentation
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
APITestCase
class - Error Handling: Structured error responses with appropriate HTTP status codes
- Stream Support: Custom input/output stream handling for advanced use cases
composer require webfiori/http
Download the latest release from GitHub Releases and include the autoloader:
require_once 'path/to/webfiori-http/vendor/autoload.php';
Here's a simple example to get you started:
<?php
require_once 'vendor/autoload.php';
use WebFiori\Http\AbstractWebService;
use WebFiori\Http\WebServicesManager;
use WebFiori\Http\RequestMethod;
use WebFiori\Http\ParamType;
use WebFiori\Http\ParamOption;
// Create a simple web service
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() {
// No authentication required
return true;
}
public function processRequest() {
$name = $this->getParamVal('name');
if ($name !== null) {
$this->sendResponse("Hello, $name!");
} else {
$this->sendResponse("Hello, World!");
}
}
}
// Set up the services manager
$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
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 objects
use 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();
}
public function isAuthorized() {
$authHeader = $this->getAuthHeader();
if ($authHeader === null) {
return false;
}
$scheme = $authHeader->getScheme();
$credentials = $authHeader->getCredentials();
if ($scheme === 'basic') {
// Decode base64 credentials
$decoded = base64_decode($credentials);
list($username, $password) = explode(':', $decoded);
// Validate credentials
return $this->validateUser($username, $password);
}
return false;
}
public function isAuthorized() {
$authHeader = $this->getAuthHeader();
if ($authHeader === null) {
return false;
}
if ($authHeader->getScheme() === 'bearer') {
$token = $authHeader->getCredentials();
return $this->validateToken($token);
}
return false;
}
public function __construct() {
parent::__construct('public-service');
$this->setIsAuthRequired(false); // Skip authentication
}
use WebFiori\Http\ResponseMessage;
public function isAuthorized() {
ResponseMessage::set('401', 'Custom unauthorized message');
// Your authorization logic
return false;
}
// Simple message response
$this->sendResponse('Operation completed successfully');
// Response with type and status code
$this->sendResponse('User created', 'success', 201);
// Response with additional data
$userData = ['id' => 123, 'name' => 'John Doe'];
$this->sendResponse('User retrieved', 'success', 200, $userData);
// Send XML response
$xmlData = '<user><id>123</id><name>John Doe</name></user>';
$this->send('application/xml', $xmlData, 200);
// Send plain text
$this->send('text/plain', 'Hello, World!', 200);
// Send file download
$this->send('application/octet-stream', $fileContent, 200);
public function processRequest() {
$method = $this->getManager()->getRequestMethod();
switch ($method) {
case RequestMethod::GET:
$this->handleGet();
break;
case RequestMethod::POST:
$this->handlePost();
break;
case RequestMethod::PUT:
$this->handlePut();
break;
case RequestMethod::DELETE:
$this->handleDelete();
break;
}
}
The library automatically handles JSON requests when Content-Type: application/json
:
public function processRequest() {
$inputs = $this->getInputs();
if ($inputs instanceof \WebFiori\Json\Json) {
// Handle JSON input
$name = $inputs->get('name');
$email = $inputs->get('email');
} else {
// Handle form data
$name = $inputs['name'] ?? null;
$email = $inputs['email'] ?? null;
}
}
Automatically map request parameters to PHP objects:
class User {
private $name;
private $email;
private $age;
public function setName($name) { $this->name = $name; }
public function setEmail($email) { $this->email = $email; }
public function setAge($age) { $this->age = $age; }
// Getters...
}
public function processRequest() {
// Automatic mapping
$user = $this->getObject(User::class);
// Custom setter mapping
$user = $this->getObject(User::class, [
'full-name' => 'setName',
'email-address' => 'setEmail'
]);
}
$manager = new WebServicesManager();
// Set API version and description
$manager->setVersion('2.1.0');
$manager->setDescription('User Management API');
// Add multiple services
$manager->addService(new CreateUserService());
$manager->addService(new GetUserService());
$manager->addService(new UpdateUserService());
$manager->addService(new DeleteUserService());
// Custom input/output streams
$manager->setInputStream('php://input');
$manager->setOutputStream(fopen('api-log.txt', 'a'));
// Process requests
$manager->process();
public function processRequest() {
try {
// Service logic
$result = $this->performOperation();
$this->sendResponse('Success', 'success', 200, $result);
} catch (ValidationException $e) {
$this->sendResponse($e->getMessage(), 'error', 400);
} catch (AuthenticationException $e) {
$this->sendResponse('Unauthorized', 'error', 401);
} catch (Exception $e) {
$this->sendResponse('Internal server error', 'error', 500);
}
}
use WebFiori\Http\APIFilter;
$customFilter = function($original, $filtered) {
// Custom validation logic
if (strlen($filtered) < 3) {
return APIFilter::INVALID;
}
// Additional processing
return strtoupper($filtered);
};
$this->addParameters([
'code' => [
ParamOption::TYPE => ParamType::STRING,
ParamOption::FILTER => $customFilter
]
]);
<?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' => 'john@example.com'
]);
$this->assertJson($response);
}
}
// Set up test environment
$_GET['service'] = 'my-service';
$_GET['param1'] = 'test-value';
$_SERVER['REQUEST_METHOD'] = 'GET';
$manager = new WebServicesManager();
$manager->addService(new MyService());
$manager->process();
<?php
class UserService extends AbstractWebService {
public function __construct() {
parent::__construct('user');
$this->setRequestMethods([
RequestMethod::GET,
RequestMethod::POST,
RequestMethod::PUT,
RequestMethod::DELETE
]);
$this->addParameters([
'id' => [
ParamOption::TYPE => ParamType::INT,
ParamOption::OPTIONAL => true
],
'name' => [
ParamOption::TYPE => ParamType::STRING,
ParamOption::OPTIONAL => true,
ParamOption::MIN_LENGTH => 2
],
'email' => [
ParamOption::TYPE => ParamType::EMAIL,
ParamOption::OPTIONAL => true
]
]);
}
public function isAuthorized() {
return true; // Implement your auth logic
}
public function processRequest() {
$method = $this->getManager()->getRequestMethod();
switch ($method) {
case RequestMethod::GET:
$this->getUser();
break;
case RequestMethod::POST:
$this->createUser();
break;
case RequestMethod::PUT:
$this->updateUser();
break;
case RequestMethod::DELETE:
$this->deleteUser();
break;
}
}
private function getUser() {
$id = $this->getParamVal('id');
if ($id) {
// Get specific user
$user = $this->findUserById($id);
$this->sendResponse('User found', 'success', 200, $user);
} else {
// Get all users
$users = $this->getAllUsers();
$this->sendResponse('Users retrieved', 'success', 200, $users);
}
}
private function createUser() {
$name = $this->getParamVal('name');
$email = $this->getParamVal('email');
$user = $this->createNewUser($name, $email);
$this->sendResponse('User created', 'success', 201, $user);
}
private function updateUser() {
$id = $this->getParamVal('id');
$name = $this->getParamVal('name');
$email = $this->getParamVal('email');
$user = $this->updateExistingUser($id, $name, $email);
$this->sendResponse('User updated', 'success', 200, $user);
}
private function deleteUser() {
$id = $this->getParamVal('id');
$this->removeUser($id);
$this->sendResponse('User deleted', 'success', 200);
}
}
<?php
class FileUploadService extends AbstractWebService {
public function __construct() {
parent::__construct('upload');
$this->setRequestMethods([RequestMethod::POST]);
$this->addParameters([
'file' => [
ParamOption::TYPE => ParamType::STRING,
ParamOption::OPTIONAL => false
],
'description' => [
ParamOption::TYPE => ParamType::STRING,
ParamOption::OPTIONAL => true
]
]);
}
public function isAuthorized() {
return true;
}
public function processRequest() {
if (isset($_FILES['file'])) {
$file = $_FILES['file'];
if ($file['error'] === UPLOAD_ERR_OK) {
$uploadPath = 'uploads/' . basename($file['name']);
if (move_uploaded_file($file['tmp_name'], $uploadPath)) {
$this->sendResponse('File uploaded successfully', 'success', 200, [
'filename' => $file['name'],
'size' => $file['size'],
'path' => $uploadPath
]);
} else {
$this->sendResponse('Failed to move uploaded file', 'error', 500);
}
} else {
$this->sendResponse('File upload error', 'error', 400);
}
} else {
$this->sendResponse('No file uploaded', 'error', 400);
}
}
}
For more examples, check the examples directory in this repository.
This library is part of the WebFiori Framework. For complete API documentation, visit: https://webfiori.com/docs/webfiori/http
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
- Documentation: WebFiori Docs
- Examples: Examples Directory
See CHANGELOG.md for a list of changes and version history.