frootbox / rest-api
Frootbox REST API Framework
Requires
- php: >=8.3
- firebase/php-jwt: ^7
- php-di/php-di: ^6.3
- zircote/swagger-php: ^4.10
README
A lightweight, attribute-based REST API framework for PHP.
This package provides a simple way to build versioned REST APIs with support for multiple authentication methods like API keys, Bearer tokens, Basic Auth, and custom client credentials.
β¨ Features
- Attribute-based routing (OpenAPI compatible)
- API versioning via namespace (
V1,V2, ...) - Multiple authentication methods:
- API Key
- Bearer (JWT)
- Basic Auth
- Client credentials
- Dependency Injection support (PHP-DI)
- Automatic route discovery
- Named route parameters (
{id},{int:id}) - JSON response handling
π¦ Installation
composer require frootbox/restapi
π Getting Started
1. Create a Server instance
use Frootbox\\RestApi\\Server; use DI\\Container; $container = new Container(); $server = new Server( clientRepository: $clientRepository, // implements ClientRepositoryInterface baseUriRegex: '#^/api/v(?P<Version>[0-9]+)(?P<Path>/.*)$#', controllerDirectory: __DIR__ . '/Controller', namespace: 'App\\\\Controller', container: $container, hashKey: 'your-secret-key' ); $server->execute();
π Controller Structure
Controllers must follow a versioned namespace structure:
src/
βββ Controller/
βββ V1/
βββ UserController.php
π§© Example Controller
namespace App\\Controller\\V1; use OpenApi\\Attributes as OA; use Frootbox\\RestApi\\Attribute\\Auth; use Frootbox\\RestApi\\Attribute\\ApiKey; use Frootbox\\RestApi\\Response\\Payload; class UserController { #[OA\\Get(path: '/users/{int:id}')] #[Auth(type: new ApiKey())] public function getUser(int $id): Payload { return new Payload([ 'id' => $id, 'name' => 'John Doe' ]); } }
π Authentication
You can define one or multiple authentication methods per endpoint:
#[Auth(type: new ApiKey())] #[Auth(type: new Bearer())]
Supported Auth Methods
API Key
Send via header:
x-api-key: your-api-key
Bearer Token (JWT)
Authorization: Bearer <token>
Basic Auth
Authorization: Basic base64(clientId:clientSecret)
Client Credentials (GET or Basic)
GET /endpoint?client_id=xxx&client_secret=yyy
or via Basic Auth.
π§ Client Validation
You must provide a repository implementing:
Frootbox\\RestApi\\Interface\\ClientRepositoryInterface
Example:
class ClientRepository implements ClientRepositoryInterface
{
public function validate(string $clientId, string $clientSecret): void
{
if ($clientId !== 'test' || $clientSecret !== 'secret') {
throw new \\Exception('Invalid client credentials');
}
}
public function validateApiKey(string $apiKey): void
{
if ($apiKey !== 'abc123') {
throw new \\Exception('Invalid API key');
}
}
}
π Versioning
API version is extracted from the URL:
/api/v1/users/1
Your controllers must match the version namespace:
namespace App\\Controller\\V1;
π§Ύ Route Parameters
Integer parameter
/users/{int:id}
String parameter
/users/{slug}
Parameters are automatically injected into the method.
π€ Responses
All responses must return:
Frootbox\\RestApi\\Response\\Payload
Example:
return new Payload([ 'success' => true ]);
βοΈ Dependency Injection
Controllers are resolved via the provided DI container:
$container->call([$controller, $method]);
You can inject services directly into controller methods:
public function getUser(UserService $service, int $id)
π§ Hooks
Token decoding hook
$server = new Server(..., onDecodeToken: function ($token) {
// custom logic
});
Client validation hook
$server = new Server(..., onValidateClient: function ($clientId) {
// custom logic
});
β οΈ Important Notes
- Always use HTTPS when transmitting credentials
- API keys should be treated like passwords
- Bearer tokens are validated using HS256
- Route matching is case-insensitive
π License
MIT """