1. Go to this page and download the library: Download dr2gsistemas/xpress library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
dr2gsistemas / xpress example snippets
press\XRouter;
$router = new XRouter();
$router->setBasePath('/api/v1');
use Xpress\XRouter;
use Xpress\XRequest;
use Xpress\XResponse;
use Xpress\Attributes\{XRoute, XMiddleware, XGroup};
$router = xpress();
// Rutas simples con closures
$router->get('/hello', function (XRequest $req) {
return json(['message' => '¡Hola Mundo!']);
});
// Rutas con parámetros
$router->get('/users/{id}', function (XRequest $req, array $params) {
return json(['user_id' => $params['id']]);
});
// Rutas con query parameters
$router->get('/search', function (XRequest $req) {
$query = $req->getQuery('q', '');
$page = $req->getQuery('page', 1);
return json(['query' => $query, 'page' => (int)$page]);
});
// Rutas POST con body JSON
$router->post('/users', function (XRequest $req) {
$data = $req->getJson();
return json(['created' => $data], 201);
});
// Middleware inline
$router->get('/admin', function () {
return json(['secret' => 'data']);
}, [function (XRequest $req, callable $next) {
if ($req->getHeader('X-Admin-Token') !== 'secret123') {
return json(['error' => 'Unauthorized'], 401);
}
return $next($req);
}]);
// src/Controllers/UserController.php
namespace App\Controllers;
use Xpress\XRouter;
use Xpress\XRequest;
use Xpress\XResponse;
use Xpress\Attributes\{XRoute, XMiddleware, XGroup};
#[XGroup('/users')]
class UserController
{
#[XRoute('', 'GET')]
public function index(XRequest $request): XResponse
{
$users = [
['id' => 1, 'name' => 'Juan Pérez', 'email' => '[email protected]'],
['id' => 2, 'name' => 'María García', 'email' => '[email protected]'],
];
return (new XResponse())->json([
'data' => $users,
'total' => count($users)
]);
}
#[XRoute('/{id}', 'GET')]
public function show(XRequest $request, array $params): XResponse
{
$id = (int) $params['id'];
$user = $this->findUser($id);
if (!$user) {
return (new XResponse())->json([
'error' => 'Usuario no encontrado'
], 404);
}
return (new XResponse())->json([
'data' => $user
]);
}
#[XRoute('', 'POST')]
#[XMiddleware(AuthMiddleware::class)]
public function store(XRequest $request): XResponse
{
$data = $request->getJson();
if (empty($data['name']) || empty($data['email'])) {
return (new XResponse())->json([
'error' => 'Nombre y email son requeridos'
], 422);
}
$user = [
'id' => random_int(100, 9999),
'name' => $data['name'],
'email' => $data['email'],
'created_at' => date('Y-m-d H:i:s')
];
return (new XResponse())->json([
'data' => $user,
'message' => 'Usuario creado exitosamente'
], 201);
}
#[XRoute('/{id}', 'PUT')]
#[XMiddleware([AuthMiddleware::class, ValidateMiddleware::class])]
public function update(XRequest $request, array $params): XResponse
{
$id = (int) $params['id'];
$data = $request->getJson();
return (new XResponse())->json([
'data' => [
'id' => $id,
'name' => $data['name'] ?? 'Nombre actualizado',
'email' => $data['email'] ?? '[email protected]'
],
'message' => 'Usuario actualizado'
]);
}
#[XRoute('/{id}', 'DELETE')]
#[XMiddleware(AuthMiddleware::class)]
public function destroy(XRequest $request, array $params): XResponse
{
$id = (int) $params['id'];
return (new XResponse())->json([
'message' => "Usuario {$id} eliminado"
]);
}
private function findUser(int $id): ?array
{
$users = [
1 => ['id' => 1, 'name' => 'Juan Pérez', 'email' => '[email protected]'],
2 => ['id' => 2, 'name' => 'María García', 'email' => '[email protected]'],
];
return $users[$id] ?? null;
}
}
// public/index.php
pp\Controllers\UserController;
use App\Controllers\PostController;
use App\Middleware\CorsMiddleware;
$router = new XRouter();
// Middleware global (se ejecuta en todas las rutas)
$router->use(CorsMiddleware::class);
// Rutas con parámetros (orden importante - específico primero)
$router->get('/users/{id}/posts/{postId}', [PostController::class, 'getComment']);
// Rutas normales
$router->get('/users', [UserController::class, 'index']);
$router->get('/users/{id}', [UserController::class, 'show']);
$router->post('/users', [UserController::class, 'store']);
$router->put('/users/{id}', [UserController::class, 'update']);
$router->delete('/users/{id}', [UserController::class, 'destroy']);
// O simplemente registrar todos los controladores
$router->registerControllers([
UserController::class,
PostController::class
]);
$response = $router->dispatch();
$response->send();
// src/Middleware/AuthMiddleware.php
namespace App\Middleware;
use Xpress\XRequest;
use Xpress\XResponse;
class AuthMiddleware
{
public function handle(XRequest $request, callable $next): XResponse
{
$authHeader = $request->getHeader('Authorization');
if (empty($authHeader)) {
return (new XResponse())->json([
'error' => 'Autenticación requerida',
'message' => 'Por favor proporcione el header Authorization'
], 401);
}
if (!str_starts_with($authHeader, 'Bearer ')) {
return (new XResponse())->json([
'error' => 'Token inválido',
'message' => 'El token debe comenzar con "Bearer "'
], 401);
}
$token = substr($authHeader, 7);
if (!$this->validateToken($token)) {
return (new XResponse())->json([
'error' => 'Token expirado o inválido'
], 401);
}
$request = $request->withAttribute('user_id', $this->getUserId($token));
return $next($request);
}
private function validateToken(string $token): bool
{
// Lógica de validación de token
return strlen($token) > 10;
}
private function getUserId(string $token): ?int
{
return 1; // Retornar ID del usuario del token
}
}
// src/Controllers/AdminController.php
namespace App\Controllers;
use Xpress\XRequest;
use Xpress\XResponse;
use Xpress\Attributes\{XRoute, XMiddleware, XGroup};
#[XGroup('/admin', [AuthMiddleware::class, AdminMiddleware::class])]
class AdminController
{
#[XRoute('/dashboard', 'GET')]
public function dashboard(): XResponse
{
return (new XResponse())->json([
'stats' => [
'users' => 1250,
'orders' => 342,
'revenue' => 45890.50
]
]);
}
#[XRoute('/settings', 'GET')]
public function settings(): XResponse
{
return (new XResponse())->json([
'settings' => [
'site_name' => 'Mi Tienda',
'timezone' => 'America/Mexico_City',
'currency' => 'MXN'
]
]);
}
}
$router = new XRouter();
// Configuración
$router->setBasePath('/api/v1'); // Prefijo base para todas las rutas
// Middleware global
$router->use(CorsMiddleware::class);
$router->use(LoggerMiddleware::class);
// Métodos HTTP
$router->get('/ruta', $handler);
$router->post('/ruta', $handler);
$router->put('/ruta', $handler);
$router->patch('/ruta', $handler);
$router->delete('/ruta', $handler);
$router->options('/ruta', $handler);
$router->head('/ruta', $handler);
// Múltiples métodos
$router->any(['GET', 'POST'], '/ruta', $handler);
// Con middlewares
$router->get('/protegida', $handler, [AuthMiddleware::class]);
$router->post('/recurso', $handler, [AuthMiddleware::class, ValidateMiddleware::class]);
// Registrar controladores con atributos
$router->registerControllers([UserController::class, ProductController::class]);
// Dispatch
$response = $router->dispatch(); // Desde globals
$response = $router->dispatch($request); // Con request custom
// Crear desde globals
$request = XRequest::fromGlobals();
// Crear desde URI (útil para testing)
$request = new XRequest(new ServerRequest('GET', new Uri('/users/123')));
// Métodos HTTP
$request->getMethod(); // 'GET', 'POST', etc.
$request->getPath(); // '/users/123'
$request->getUri(); // UriInterface
// Query parameters
$request->getQueryParams(); // ['page' => 1, 'limit' => 10]
$request->getQuery('page'); // '1'
$request->getQuery('page', 1); // 1 (default)
$request->getQuery('q', 'default'); // 'default'
// Body y JSON
$request->getBody(); // string raw
$request->getParsedBody(); // parsed form data
$request->getJson(); // ['key' => 'value'] o null
$request->isJson(); // true/false
// Headers
$request->getHeader('Authorization'); // 'Bearer token' o null
$request->getHeader('Content-Type'); // 'application/json' o null
$request->getHeaders(); // todos los headers
$request->hasHeader('X-Custom'); // true/false
// Parámetros de ruta (capturados de {param})
$request->getRouteParams(); // ['id' => '123', 'action' => 'edit']
$request->getRouteParam('id'); // '123'
$request->getRouteParam('id', 0); // 0 (default)
$request->setRouteParams(['id' => '123']); // setear params
// Attributes (para pasar datos entre middlewares)
$request->getAttribute('user_id'); // valor o null
$request->withAttribute('user_id', 123); // nuevo request con attribute
// Cookies
$request->getCookies(); // ['session' => 'abc123']
$request->getCookie('session'); // 'abc123'
// Server params
$request->getServerParams(); // $_SERVER
$request->getProtocolVersion(); // '1.1'
// Files upload
$request->getUploadedFiles(); // uploaded files array
// Constructor básico
$response = new XResponse();
$response = new XResponse(200);
$response = new XResponse(404, ['Content-Type' => 'text/plain'], 'Not Found');
// Crear con contenido
(new XResponse())->json(['key' => 'value']);
(new XResponse())->text('Hello World');
(new XResponse())->html('<h1>Título</h1>');
(new XResponse())->xml('<root><item>valor</item></root>');
// Con código de estado
(new XResponse())->json(['error' => 'Not found'], 404);
(new XResponse())->text('Created', 201);
// Helpers estáticos
XResponse::ok(); // 200
XResponse::created(['id' => 1]); // 201
XResponse::noContent(); // 204
XResponse::notFound(); // 404
XResponse::unauthorized(); // 401
XResponse::forbidden(); // 403
XResponse::badRequest(); // 400
XResponse::error('Server error', 500); // 500
// Métodos fluidos
$response
->withHeader('X-Custom-Header', 'value')
->withHeader('X-Another', 'another')
->withStatus(200, 'OK');
// Redirección
$response->redirect('/new-location');
$response->redirect('/new-location', 301); // permanent
$response->redirect('/new-location', 307); // temporary
// CORS
$response->cors([
'origin' => '*', // o dominio específico
'methods' => 'GET, POST, PUT',
'headers' => 'Content-Type, Authorization',
'expose_headers' => 'X-Custom',
'max_age' => 86400,
'credentials' => false
]);
// Cookie
$response->cookie('session', 'abc123');
$response->cookie('token', 'xyz', [
'expires' => time() + 3600,
'path' => '/',
'domain' => '',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]);
// Enviar respuesta
$response->send(); // headers + body
// Getters
$response->getStatusCode(); // 200
$response->getReasonPhrase(); // 'OK'
$response->getHeaders(); // todos los headers
$response->getHeaderLine('Content-Type'); // 'application/json'
$response->getBody(); // StreamInterface
$response->getProtocolVersion(); // '1.1'
// Instancia global del router
xpress();
// Respuestas rápidas
json(['key' => 'value']);
json(['error' => 'msg'], 400);
text('Hello');
html('<h1>Title</h1>');
// Redirecciones y errores
redirect('/new-path');
redirect('/login', 302);
notFound();
unauthorized();
badRequest();
error('Server error');
error('Custom error', 500);
// Helpers con XResponse
json() → (new XResponse())->json()
text() → (new XResponse())->text()
html() → (new XResponse())->html()
redirect() → (new XResponse())->redirect()
notFound() → XResponse::notFound()->text()
// public/index.php
press\XRequest;
use Xpress\XResponse;
use Xpress\Attributes\{XRoute, XMiddleware, XGroup};
class Database
{
private static array $users = [];
private static int $lastId = 0;
public static function users(): array { return self::$users; }
public static function findUser(int $id): ?array
{
return self::$users[$id] ?? null;
}
public static function createUser(array $data): array
{
self::$users[++self::$lastId] = [
'id' => self::$lastId,
'name' => $data['name'] ?? '',
'email' => $data['email'] ?? '',
'created_at' => date('Y-m-d H:i:s')
];
return self::$users[self::$lastId];
}
public static function updateUser(int $id, array $data): ?array
{
if (!isset(self::$users[$id])) return null;
self::$users[$id] = array_merge(self::$users[$id], $data);
return self::$users[$id];
}
public static function deleteUser(int $id): bool
{
if (!isset(self::$users[$id])) return false;
unset(self::$users[$id]);
return true;
}
}
#[XGroup('/api')]
class ApiController
{
#[XRoute('/health', 'GET')]
public function health(): XResponse
{
return (new XResponse())->json([
'status' => 'healthy',
'timestamp' => date('Y-m-d H:i:s'),
'version' => '1.0.0'
]);
}
}
#[XGroup('/api/users')]
class UserController
{
#[XRoute('', 'GET')]
public function index(XRequest $request): XResponse
{
$page = max(1, (int) $request->getQuery('page', 1));
$limit = min(100, max(1, (int) $request->getQuery('limit', 10)));
$search = $request->getQuery('search', '');
$users = array_values(Database::users());
if ($search) {
$users = array_filter($users, fn($u) =>
stripos($u['name'], $search) !== false ||
stripos($u['email'], $search) !== false
);
}
$total = count($users);
$offset = ($page - 1) * $limit;
$users = array_slice($users, $offset, $limit);
return (new XResponse())->json([
'data' => $users,
'pagination' => [
'page' => $page,
'limit' => $limit,
'total' => $total,
'pages' => ceil($total / $limit)
]
]);
}
#[XRoute('/{id}', 'GET')]
public function show(XRequest $request, array $params): XResponse
{
$id = (int) $params['id'];
$user = Database::findUser($id);
if (!$user) {
return (new XResponse())->json([
'error' => 'Usuario no encontrado'
], 404);
}
return (new XResponse())->json(['data' => $user]);
}
#[XRoute('', 'POST')]
public function store(XRequest $request): XResponse
{
$data = $request->getJson();
$errors = [];
if (empty($data['name'])) {
$errors['name'] = 'El nombre es requerido';
}
if (empty($data['email'])) {
$errors['email'] = 'El email es requerido';
} elseif (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'El email no es válido';
}
if (!empty($errors)) {
return (new XResponse())->json([
'error' => 'Datos de validación fallidos',
'errors' => $errors
], 422);
}
$user = Database::createUser($data);
return (new XResponse())->json([
'data' => $user,
'message' => 'Usuario creado exitosamente'
], 201);
}
#[XRoute('/{id}', 'PUT')]
public function update(XRequest $request, array $params): XResponse
{
$id = (int) $params['id'];
$data = $request->getJson();
$user = Database::updateUser($id, $data);
if (!$user) {
return (new XResponse())->json([
'error' => 'Usuario no encontrado'
], 404);
}
return (new XResponse())->json([
'data' => $user,
'message' => 'Usuario actualizado'
]);
}
#[XRoute('/{id}', 'DELETE')]
public function destroy(XRequest $request, array $params): XResponse
{
$id = (int) $params['id'];
if (!Database::deleteUser($id)) {
return (new XResponse())->json([
'error' => 'Usuario no encontrado'
], 404);
}
return (new XResponse())->json([
'message' => 'Usuario eliminado'
]);
}
}
// Configurar router
$router = new XRouter();
$router->use(function (XRequest $req, callable $next) {
$response = $next($req);
return $response->withHeader('X-API-Version', '1.0');
});
$router->registerControllers([ApiController::class, UserController::class]);
// Ejecutar
$response = $router->dispatch();
$response->send();
use Xpress\Result\XResult;
use Xpress\Result\XError;
// Retornar éxito
$result = XResult::ok(['user' => ['id' => 1, 'name' => 'Juan']]);
// Retornar error
$result = XResult::fail('Usuario no encontrado', 404);
// Con datos adicionales
$result = XResult::fail('Validación fallida', 422, ['errors' => ['email' => 'inválido']]);
use Xpress\Result\XError;
XError::badRequest('Datos inválidos'); // 400
XError::unauthorized('No autenticado'); // 401
XError::forbidden('Sin permisos'); // 403
XError::notFound('Recurso no encontrado'); // 404
XError::conflict('Conflicto de datos'); // 409
XError::unprocessable('Entidad no procesable'); // 422
XError::validation(['email' => 'inválido']); // 422 con errores
XError::internal('Error interno'); // 500
$result = XResult::ok(['data' => 'value']);
// Verificación
$result->isSuccess(); // true
$result->isFailure(); // false
$result->isNotFound(); // false
$result->isUnauthorized(); // false
// Extracción de valores
$result->getValue(); // ['data' => 'value']
$result->getValueOr('default'); // 'default' si es error
$result->unwrap(); // Lanza excepción si es error
$result->unwrapOr('default'); // 'default' si es error
// Manejo de errores
$result->getError(); // null (éxito) o XError
$result->getErrorMessage(); // string del error
$result->getErrorCode(); // código HTTP del error
$result->getErrorData(); // datos adicionales del error
// Modificación
$result->withCode(201); // Cambiar código HTTP a 201
$result->withHttpCode(203); // Similar, más semántico
$result = XResult::ok(['user_id' => 1])
->andThen(fn($data) => findUserById($data['user_id']))
->andThen(fn($user) => $user->isActive()
? XResult::ok($user)
: XResult::fail('Usuario inactivo', 403))
->map(fn($user) => $user->toArray());
// map: transforma el valor si es éxito
// mapError: transforma el error si es fallo
// andThen: encadena operaciones que retornan Result
// orElse: maneja errores y puede recuperarlos
use Xpress\XRequest;
use Xpress\Result\XResult;
use Xpress\Result\XResultController;
class UserController
{
use XResultController;
public function show(XRequest $request, array $params): XResult
{
return $this->try(function() use ($params) {
$id = (int) $params['id'];
$user = $this->findUser($id);
if (!$user) {
return $this->notFound('Usuario no encontrado');
}
return $this->ok($user->toArray());
});
}
public function store(XRequest $request): XResult
{
return $this->try(function() use ($request) {
$data = $request->getJson();
$this->validate($data, [
'name' => '
use Xpress\XRouter;
use Xpress\XRequest;
use Xpress\Result\XResult;
use Xpress\Result\XResultController;
class ProductController
{
use XResultController;
#[XRoute('/products', 'GET')]
public function index(XRequest $request): XResult
{
return $this->try(function() use ($request) {
$page = (int) $request->getQuery('page', 1);
$limit = min(100, (int) $request->getQuery('limit', 10));
$products = $this->getProductRepository()->paginate($page, $limit);
return $this->ok([
'products' => $products['data'],
'pagination' => $products['pagination']
]);
});
}
#[XRoute('/products/{id}', 'GET')]
public function show(XRequest $request, array $params): XResult
{
return $this->try(function() use ($params) {
$product = $this->getProductRepository()->find((int) $params['id']);
if (!$product) {
return $this->notFound('Producto no encontrado');
}
return $this->ok($product->toArray());
});
}
#[XRoute('/products', 'POST')]
public function store(XRequest $request): XResult
{
return $this->try(function() use ($request) {
$data = $request->getJson();
$errors = $this->validate($data, [
'name' => '
public function index(): XResponse // XResponse directo
{
return (new XResponse())->json(['data' => []]);
}
public function show(): XResult // Con Result pattern
{
return $this->ok(['data' => []]);
}
// Ambos funcionan en el router
apache
# Xpress Router - Apache Configuration
RewriteEngine On
# Redirigir requests al index.php
RewriteCond %{REQUEST_URI} -f [OR]
RewriteCond %{REQUEST_URI} -d
RewriteRule ^ - [L]
RewriteRule ^ index.php [QSA,L]
# Security headers
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
</IfModule>
# Prevenir listing de directorios
Options -Indexes
# Cache estáticos
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
</IfModule>