SkillAgentSearch skills...

Restler

Zero-boilerplate REST API framework for PHP 8+. Auto-generates routes, docs, validation.

Install / Use

/learn @Luracast/Restler

README

Restler Restler v6

Latest Stable Version Total Downloads License

Write your API logic in PHP. Get routing, validation, and OpenAPI docs—automatically.

Production-ready since 2010. Battle-tested. Now rebuilt for modern PHP 8+ with async superpowers.

use Luracast\Restler\Restler;
use Luracast\Restler\Routes;

class Products {
    function get(int $id): array {
        return Database::findProduct($id);
    }
}

Routes::mapApiClasses([Products::class]);
(new Restler)->handle();

That's it. You just created a REST API that:

  • ✅ Automatically validates $id as an integer
  • ✅ Returns JSON by default
  • ✅ Handles routing (GET /products/123)
  • ✅ Generates OpenAPI/Swagger docs
  • ✅ Provides proper HTTP status codes
  • ✅ Supports content negotiation (configure other formats as needed)

No controllers. No routing files. No configuration. Just PHP.


Why Restler in 2025?

🎯 Zero Boilerplate

While other frameworks make you write controllers, routes, DTOs, validation rules, and transformers—Restler uses PHP reflection to do it all automatically. Write business logic, not plumbing.

// Laravel/Symfony: 50+ lines of controllers, routes, requests, resources
// Restler: 5 lines
class Users {
    function create(string $email, string $name): User {
        return User::create(compact('email', 'name'));
    }
}

Async Performance

Run on Swoole/OpenSwoole for 10-20x throughput vs traditional PHP-FPM. Or use ReactPHP for true async I/O. Deploy to AWS Lambda for serverless scale.

# Traditional PHP-FPM: ~1,000 req/sec
# Swoole/OpenSwoole: ~15,000 req/sec (same code!)
composer swoole-server

🌐 Multi-Format Output

JSON is the default format. Configure additional formats (XML, CSV, Excel, HTML) via Routes::setOverridingResponseMediaTypes(). Perfect for:

  • Mobile apps → JSON (default)
  • Legacy systems → XML
  • Data exports → CSV/Excel
  • Admin panels → HTML with Blade/Twig
curl api.example.com/products/123       # JSON (default)
curl api.example.com/products/123.xml   # XML (if configured)
curl api.example.com/products.csv       # CSV (if configured)
curl api.example.com/products.xlsx      # Excel (if configured)

🚀 Modern PHP 8+

Built for PHP 8 with attributes, union types, named arguments, and strict typing. PSR-7 and PSR-11 compliant.

use Luracast\Restler\Attribute\{Get, Post};

class Orders {
    #[Get('orders/{id}')]
    function getOrder(int $id): Order|null {
        return Order::find($id);
    }

    #[Post('orders')]
    function createOrder(string $product, int $quantity = 1): Order {
        return Order::create(compact('product', 'quantity'));
    }
}

📚 Auto-Generated Docs

OpenAPI 3.0 (Swagger) docs generated from your PHPDoc comments. Interactive API explorer included.

class Products {
    /**
     * Get product details
     *
     * @param int $id Product ID
     * @return Product product information
     * @throws 404 Product not found
     */
    function get(int $id): Product {
        return Product::findOrFail($id);
    }
}
// Visit /explorer for interactive Swagger UI

Real-World Use Cases

🏢 Internal APIs & Microservices

Perfect for building internal APIs that need to integrate with various systems. Multi-format support means you can serve JSON to your React app and XML to that ancient CRM system—from the same endpoint.

📱 Mobile Backend

Low latency on Swoole, automatic validation, built-in rate limiting, and OAuth2 support. Everything you need for a production mobile backend.

📊 Data Export APIs

Built-in CSV and Excel streaming support. Export millions of rows without running out of memory using generators.

function exportUsers(): Generator {
    foreach (User::cursor() as $user) {
        yield $user->toArray();
    }
}
// GET /users.csv streams all users as CSV
// GET /users.xlsx downloads Excel file

🔗 Legacy System Integration

Need to modernize an old PHP app? Add Restler to get a REST API instantly. Works alongside existing code—no rewrite needed.


Quick Start

Install

composer require luracast/restler:^6.0

Create Your First API (3 files)

1. API Class (api/Hello.php)

<?php
class Hello {
    function sayHello(string $name = 'World'): string {
        return "Hello, $name!";
    }

    function getTime(): array {
        return ['time' => date('Y-m-d H:i:s'), 'timezone' => date_default_timezone_get()];
    }
}

2. Gateway (public/index.php)

<?php
require __DIR__ . '/../vendor/autoload.php';

Luracast\Restler\Routes::mapApiClasses([Hello::class]);
(new Luracast\Restler\Restler)->handle();

3. URL Rewriting (.htaccess or nginx.conf)

# Apache
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

Test It

# Start server
php -S localhost:8080 -t public

# Try your API
curl http://localhost:8080/hello/sayHello/Restler
# Output: "Hello, Restler!"

curl http://localhost:8080/hello/getTime
# Output: {"time":"2025-01-15 10:30:45","timezone":"UTC"}

curl http://localhost:8080/hello/getTime.xml
# Output: <?xml version="1.0"?><response><time>2025-01-15 10:30:45</time>...

That's it! You have a working REST API with automatic routing, validation, and multi-format support.


Production Deployment

Traditional (Apache/Nginx + PHP-FPM)

Standard deployment. Works everywhere. ~1,000-2,000 req/sec depending on hardware.

// Enable production mode for route caching
$api = new Restler(productionMode: true);

High Performance (Swoole/OpenSwoole)

10-20x faster than PHP-FPM. Persistent connections, coroutines, built-in HTTP server.

# Install extension (choose one)
pecl install swoole        # Original
pecl install openswoole    # Fork with same API

# Run server
php public/index_swoole.php

Benchmarks: 15,000+ req/sec on modest hardware (vs ~1,000 for PHP-FPM)

Async I/O (ReactPHP)

True non-blocking async operations. Perfect for I/O-heavy workloads (database, HTTP calls, etc.).

composer react-server

Serverless (AWS Lambda)

Zero-downtime deploys, automatic scaling, pay-per-request pricing.

# Uses Bref for Laravel-style Lambda deployment
vendor/bin/bref deploy

See public/index_lambda.php for complete example.

Event-Driven (Workerman)

Alternative to Swoole with pure PHP implementation (no extension required).

php public/index_workerman.php start

What's New in v6

🔥 Breaking Changes from v5

  • PHP 8.0+ required (was PHP 7.4)
  • PSR-7 HTTP messages (modern request/response objects)
  • PSR-11 Container (standard dependency injection)
  • Stricter typing (full PHP 8 type hints)

Migration Guide →

New Features

Modern PHP 8 Support

  • ✅ Attributes (#[Get], #[Post], etc.)
  • ✅ Union types (string|int, User|null)
  • ✅ Named arguments
  • ✅ Constructor property promotion
  • ✅ Match expressions
  • ✅ Enums

Async & Performance

  • Swoole/OpenSwoole integration (10-20x faster)
  • ReactPHP async server
  • Workerman event-driven server
  • AWS Lambda serverless support
  • Generator streaming for large datasets (CSV, Excel)
  • ✅ Route caching & opcode optimization

Enhanced Security

  • ✅ Secure session serialization (JSON, not unserialize())
  • ✅ JSONP callback validation (XSS prevention)
  • ✅ Template injection protection
  • ✅ Configurable CORS with proper defaults
  • ✅ Built-in rate limiting
  • ✅ OAuth 2.0 server support

Developer Experience

  • GraphQL support
  • Excel export (XLSX streaming)
  • OpenAPI 3.0 spec generation
  • ✅ Interactive API Explorer (Swagger UI)
  • ✅ Better error messages
  • Blade, Twig, Mustache template engines
  • ✅ Modern DI container with auto-wiring

Multi-Format Support

All formats work automatically—just add file extension to URL:

  • JSON (default)
  • XML
  • YAML
  • CSV (with streaming)
  • Excel (XLSX)
  • HTML (with templates)
  • AMF (Flash/Flex)
  • Plist (iOS/macOS)

Advanced Examples

API Versioning

// v1/Users.php
namespace v1;
class Users {
    function get(int $id): array {
        return ['id' => $id, 'name' => 'John'];
    }
}

// v2/Users.php
namespace v2;
class Users {
    function get(int $id): User {
        return User::with('profile')->find($id);
    }
}

// index.php
use Luracast\Restler\Routes;

Routes::mapApiClasses([
    'v1/users' => 'v1\\Users',
    'v2/users' => 'v2\\Users'
]);

Usage:

curl api.example.com/v1/users/123  # Old format
curl api.example.com/v2/users/123  # New format with profile

Authentication & Rate Limiting

use Luracast\Restler\Contracts\AuthenticationInterface;

class ApiKeyAuth implements AuthenticationInterface {
    public function __isAuthenticated(): bool {
        $key = $_SERVER['HTTP_X_API_KEY'] ?? null;
        return $key && ApiKey::validate($key);
    }
}

use Luracast\Restler\Restler;
use Luracast\Restler\Routes;

Routes::addAuthenticator(ApiKeyAuth::class);
Routes::setFilters(RateLimit::class);  // Built-in rate limiting
Routes::mapApiClasses([ProtectedAPI::class]);
(new Restler)->handle();

Database Integration

class Products {
    /**
     * List all products with pagination
     *
     * @param int $page Page number (default: 1)
     * @param int $limit Items per page (default: 20)
     */
    function index(i

Related Skills

View on GitHub
GitHub Stars1.4k
CategoryDevelopment
Updated8d ago
Forks310

Languages

PHP

Security Score

85/100

Audited on Mar 19, 2026

No findings