Directivas
Las directivas son pequeños fragmentos de funcionalidad que se invocan desde el flujo del api.yaml.
- Hay muchas directivas ya desarrolladas que el cliente incluye al crear una API, y que puedes utilizar directamente. Están en
hefesto-client/Directives/. - También puedes desarrollar tus propias directivas e implementar la lógica que desees. Se escriben en PHP, y no existe ninguna limitación: puedes usar todo el lenguaje.
- Desde dentro de una directiva, puedes acceder al estado: leer la request y escribir la response a través del message, pasar información entre directivas a través de memory, alterar el flujo por medio de los groups, leer/escribir a base de datos, disco o redis, y hacer conexiones HTTP contra otros servidores.
- Desde el archivo
api.yaml, puedes pasar parámetros de configuración a las directivas mediante alias.
Catálogo de directivas reutilizables
Todas estas directivas están disponibles en hefesto-client/Directives/. Se añaden automáticamente al desplegar cualquier API.
🔀 Flujo y control
CacheDisabled
Elimina las cabeceras de caché de la respuesta.
Se usa normalmente en "before:" para garantizar que
ningún endpoint haga cachear sus respuestas.
PropagateCorrelationId
Lee la cabecera X-Correlation-Id de la request,
y la propaga automáticamente en cualquier conexión HTTP que hagas después.
ExecuteIf
Ejecuta otra directiva solo si se cumple una condición.
Parámetros: execute (directive), if (condición)
ForTheWorker
Encola las directivas posteriores para que las ejecute
un worker en segundo plano (ver jobs).
Parámetros: identifier (bool), delay (segundos)
CheckStatus
Verifica que el status HTTP actual sea < 400.
Si falla, lanza excepción con status 502 (o el indicado).
Parámetros: status (int opcional), message (string opcional)
EnableDebug
Activa el modo debug detallado de directivas.
🔒 Seguridad
CheckKey
Compara una clave esperada con la enviada por el cliente.
Si no coinciden, lanza excepción 401.
Parámetros: expected, current
CheckLocalCall
Lanza excepción 401 si la petición NO es una llamada
local desde otra API en el mismo virtual-host.
RateLimit
Limita el número de peticiones por día/minuto, tanto
totales como por IP. Usa Redis como backend.
Parámetros: path (identificador), dayTotal, minuteTotal,
dayIp, minuteIp
🌐 Conexiones HTTP
Http
Envía la request actual (con los modificadores aplicados)
a otro host. Actúa como proxy.
Parámetros: host (obligatorio), timeout, connectTimeout
Pull
Realiza una petición GET (o POST si tiene body), valida
la respuesta contra un JSON Schema y la guarda en memory.
Opcionalmente cachea la respuesta en Redis.
Parámetros: host, path, target, body, headers, queryParams,
cache, verify, verifyStatus, serverSideError, timeout,
connectTimeout
Push
Realiza una petición POST/PUT para escritura, sin
validación de esquema. Por defecto POST, o PUT si
se usa "id".
Parámetros: host, path, verb, id, body, headers,
queryParams, verify, timeout, connectTimeout
✉️ Message y respuesta
ModifyMessage
Modifica el mensaje: path, verb, headers, body,
queryParams, status. Es la directiva más versátil
para preparar requests y responses.
Ping
Devuelve {"message":"pong"} con status 200.
Útil para health checks.
IdResponse
Devuelve {"id": "valor"} con status 201.
Útil para respuestas de creación.
Parámetros: id
ResultResponse
Devuelve {"result": "valor"} con status 200.
✅ Validación
LoadAndValidateModel
Carga un objeto (normalmente el body), lo valida
contra un JSON Schema en Maps/, y si es correcto
lo guarda en memory.
Parámetros: source, target, server-side-error
LoadModel
Carga un objeto directamente en memory sin validar.
Parámetros: source, target
ValidateModel
Valida un objeto ya cargado en memory contra un
JSON Schema.
Parámetros: name, server-side-error
🗄️ Base de datos
DatabaseConnect
Conecta a PostgreSQL y guarda la conexión PDO
en memory con la clave "db-conn".
DatabaseCreate
Crea la base de datos de la API (aislada).
Debe ejecutarse antes de DatabaseConnect.
DatabaseDrop
Elimina la base de datos de la API.
DatabaseMigrate
Ejecuta migraciones SQL desde Assets/sql/.
Solo ejecuta las no ejecutadas previamente.
Parámetros: files (ruta a los SQL)
DatabaseBeginTransaction
Inicia una transacción (BEGIN).
DatabaseCommitTransaction
Confirma una transacción (COMMIT).
📡 Redis
RedisSet
Guarda un array en Redis con expiración.
Parámetros: key, value (array), expire (segundos),
global (bool, accesible desde otras APIs)
RedisGet
Lee un array de Redis.
Parámetros: key, target (clave en memory),
global (bool)
⚡ Caché
CacheUrl
Hace que nginx cachee la URL actual.
Parámetros: expirationMinutes
CacheStatic
Cachea automáticamente estáticos según su Content-Type
(CSS, JS, imágenes, fuentes).
Parámetros: expirationMinutes
💾 Archivos
SaveFile
Guarda contenido en un fichero en el espacio reservado
de la API.
Parámetros: name, content
DeleteFile
Elimina un fichero del espacio reservado.
Parámetros: name, verify, status, message
ServeStatic
Sirve un fichero estático (imagen, JSON, etc.).
Parámetros: file, type, path, storage (bool),
attachment (string)
ServeCompiledStatic
Sirve CSS/JS compilados combinando múltiples ficheros
en una sola respuesta comprimida.
Parámetros: extension, type
🎨 Vistas
View
Renderiza una plantilla Blade con datos.
Parámetros: name, staticBasePath, css, js, data,
fragments
🔧 Utilidades
Concat
Concatena strings y guarda el resultado en memory.
Parámetros: element1, element2, ..., target
StringToFriendlyUrl
Convierte un string en una URL amigable (slug).
Parámetros: string, target
CalculateIp
Calcula la IP real del cliente (REMOTE_ADDR).
La guarda en memory con clave "ip".
XmlToModel
Convierte XML a array y lo guarda en memory.
Parámetros: source, target
WriteToJob
Escribe un valor en el estado del job actual.
Parámetros: value
Event
Dispara un evento Push a otra API local.
Parámetros: target
⚠️ Errores
OnError
Captura excepciones y devuelve un JSON con
el error y el status almacenados en memory.
Se usa en ERROR_FLOW.
ThrowError
Lanza una excepción con status y mensaje.
Parámetros: status, message
Uso de directivas existentes
Para utilizar una directiva existente, por ejemplo CheckKey, editamos el api.yaml de esta manera:
key: poems
endpoints:
get /ping:
CheckKeyPatata:
directive: CheckKey
expected: patata
current: $.message.header.api-key
Ping:
directive: Ping
En el endpoint, creamos un elemento al que podemos dar cualquier nombre (en este caso CheckKeyPatata). Dentro usamos directive para referirnos a la directiva concreta que queremos ejecutar (CheckKey). Luego cada directiva puede admitir o no parámetros de configuración.
Crear directivas personalizadas
Si quisiéramos crear nuestra propia directiva, primero crearemos el fichero dentro de la carpeta Directives de la API:
mi-api/
├── api.yaml
├── Directives/
│ └── MyDirective.php
├── Maps/
└── Assets/
Las directivas personalizadas deben empezar con el encabezado exacto: <?php /*dlv-code-engine***/. Ejemplo básico:
<?php /*dlv-code-engine***/
$output = 'Hola hombre desconocido';
$name = $state->message()->getQueryParam('myname');
if ($name === 'isidoro') {
$output = 'Hola creador';
}
$state->message()->setHeader('Content-Type','application/json');
$state->message()->setBodyAsArray([
'text' => $output
]);
Luego se invoca desde el api.yaml:
key: poems
endpoints:
get /ping:
MyCustomDirective:
directive: MyDirective
Paso de parámetros y ejecución anidada
Puedes parametrizar tu directiva pasando parámetros desde el api.yaml:
get /ping:
MyCustomDirective:
directive: MyDirective
nameQueryParam: myname
Y recoger ese parámetro en la directiva usando el array $config:
<?php /*dlv-code-engine***/
$output = 'Hola hombre desconocido';
$name = $state->message()->getQueryParam($config['nameQueryParam']);
if ($name === 'isidoro') {
$output = 'Hola creador';
}
$state->message()->setHeader('Content-Type','application/json');
$state->message()->setBodyAsArray([
'text' => $output
]);
Una directiva puede llamar a otra directiva desde su código usando el método estático ::run():
<?php /*dlv-code-engine***/
CheckKey::run($state, [
'expected' => 'patata',
'current' => $state->message()->getHeader('api-key')
]);
MyDirective::run($state, [
'nameQueryParam' => 'myname'
]);
No existen limitaciones: puedes ejecutar cualquier lógica, acceder al estado, combinarlo con llamadas a otras directivas dentro de un bucle, etc. Sin embargo, es recomendable que desde el api.yaml se vean rápidamente las directivas que se ejecutan para lograr una mayor comprensión del flujo, y evitar delegar toda la funcionalidad a una super-directiva indescifrable.
Ejemplo avanzado: directiva de validación con base de datos
Este ejemplo es una directiva real (CheckRouteNotExist) que verifica si una ruta ya existe antes de crearla:
<?php /*dlv-code-engine***/
$db = $state->memory()->get('db-conn');
$sth = $db->prepare(
'SELECT id FROM vias_bike_routes WHERE id = ?'
);
$sth->execute([$config['routeId']]);
$data = $sth->fetchObject();
if ($data) {
$state->memory()->set('error.status', 409);
$state->memory()->set('error.message', 'Route already exists');
throw new \Exception();
}
Observa el patrón: se obtiene la conexión a BD de memory (previamente establecida con DatabaseConnect), se ejecuta una consulta y, si la ruta ya existe, se lanza una excepción con status 409 (Conflict) que será capturada por OnError en el ERROR_FLOW.