Skip to content

📚 Relation Validation Limit

El util relation-validation-limit.ts es una herramienta para validar que las relaciones entre entidades en Strapi no excedan un número máximo permitido.

1. Importar el util

import { validateMaxRelations } from "../../../../utils/relation-validation-limit";

2. Configurar la validación

const config = {
collection: "api::mi-entidad.mi-entidad",
populate: {
miCampo: {
populate: ["relaciones"],
},
},
relations: ["miCampo.relaciones"],
maxAllowed: 4,
errorMessage: (contentType, maxAllowed) =>
`Máximo ${maxAllowed} relaciones permitidas en ${contentType}.`,
};

3. Aplicar en lifecycles

export default {
async beforeCreate(event) {
await validateMaxRelations(config, event.params, true);
},
async beforeUpdate(event) {
await validateMaxRelations(config, event.params, false);
},
};

Este util valida automáticamente que las relaciones (conexiones entre entidades) no excedan un límite máximo configurado. Funciona tanto para operaciones de creación como de actualización, y maneja diferentes tipos de operaciones de relación:

  • Connect: Agregar nuevas relaciones
  • Disconnect: Remover relaciones existentes
  • Set: Reemplazar todas las relaciones con un nuevo conjunto
interface RelationValidationConfig {
collection: string; // Nombre de la colección (ej: 'api::inspiria-serie.inspiria-serie')
populate: object; // Configuración de población de datos
relations: string[]; // Array de relaciones a validar
maxAllowed: number; // Número máximo de relaciones permitidas
errorMessage: (contentType: string, maxAllowed: number) => string;
}
const config = {
collection: "api::inspiria-serie.inspiria-serie",
populate: {
serieList: {
populate: ["series"],
},
},
relations: ["serieList.series"],
maxAllowed: 4,
errorMessage: (contentType: string, maxAllowed: number) =>
`Exceeded maximum allowed relations in ${contentType}. Maximum allowed is ${maxAllowed}.`,
};
src/api/inspiria-serie/content-types/inspiria-serie/lifecycles.ts
const config = {
collection: INSPIRIA_SERIES,
populate: COMPONENTS_INSPIRIA_SERIES,
relations: [RELATION_SERIES], // 'serieList.series'
maxAllowed: MAX_ALLOWED_RELATION, // 4
errorMessage: ERROR_EXCEEDED_MAXIMUM_ALLOWED_RELATIONS,
};
src/api/inspiria-live/content-types/inspiria-live/lifecycles.ts
const config = {
collection: INSPIRIA_LIVES,
populate: COMPONENTS_INSPIRIA_LIVE,
relations: [RELATION_LIVES],
maxAllowed: MAX_ALLOWED_RELATION,
errorMessage: ERROR_EXCEEDED_MAXIMUM_ALLOWED_RELATIONS,
};

3. Validación múltiple en Inspiria All Content

Section titled “3. Validación múltiple en Inspiria All Content”
src/api/inspiria-all-content/content-types/inspiria-all-content/lifecycles.ts
const config = {
collection: INSPIRIA_ALL_CONTENT,
populate: COMPONENTS_INSPIRIA_ALL_CONTENT,
relations: [RELATION_PRODUCTS, RELATION_SERIES], // Múltiples relaciones
maxAllowed: MAX_ALLOWED_RELATION,
errorMessage: ERROR_EXCEEDED_MAXIMUM_ALLOWED_RELATIONS,
};
src/api/osteocom-course-page/content-types/osteocom-course-page/lifecycles.ts
const config = {
collection: OSTEOCOM_COURSE_PAGE,
populate: COMPONENTS_OSTEOCOM_COURSE_PAGE,
relations: [RELATION_OSTEOCOM_PRODUCTS],
maxAllowed: MAX_ALLOWED_RELATION,
errorMessage: ERROR_EXCEEDED_MAXIMUM_ALLOWED_RELATIONS,
};
lifecycles.ts
import { validateMaxRelations } from "../../../../utils/relation-validation-limit";
const config = {
collection: "api::tu-entidad.tu-entidad",
populate: {
// Configuración de población
},
relations: ["campo.relacion"],
maxAllowed: 4,
errorMessage: ERROR_EXCEEDED_MAXIMUM_ALLOWED_RELATIONS,
};
export default {
async beforeCreate(event) {
await validateMaxRelations(config, event.params, true);
},
async beforeUpdate(event) {
await validateMaxRelations(config, event.params, false);
},
};

Implementación con validaciones adicionales

Section titled “Implementación con validaciones adicionales”
export default {
async beforeCreate(event) {
// Validación de límites de relación
await validateMaxRelations(config, event.params, true);
// Otras validaciones (ej: validación de verticales)
await validateProductVerticals(
relationsCRMconfig,
event.params,
true,
VERTICAL_INSPIRIA
);
},
async beforeUpdate(event) {
await validateMaxRelations(config, event.params, false);
await validateProductVerticals(
relationsCRMconfig,
event.params,
false,
VERTICAL_INSPIRIA
);
},
};

Cuando se excede el límite máximo, se lanza un error de validación:

// Error generado automáticamente
"Exceeded maximum allowed relations in an item of serieList. Maximum allowed is 4.";

Configuración de mensajes de error personalizados

Section titled “Configuración de mensajes de error personalizados”
const config = {
// ... otras propiedades
errorMessage: (contentType: string, maxAllowed: number) =>
`¡Ups! Has intentado agregar demasiadas ${contentType}. El máximo permitido es ${maxAllowed}.`,
};
// Para relaciones como 'serieList.series'
const relations = ["serieList.series"];
// El util automáticamente:
// - Extrae 'serieList' como containerKey
// - Extrae 'series' como fieldKey
const config = {
relations: [
"productList.products", // Primera relación
"categoryList.categories", // Segunda relación
"tagList.tags", // Tercera relación
],
// Todas serán validadas con el mismo maxAllowed
};
// Para arrays de componentes como:
{
"componentArray": [
{
"id": 1,
"relations": {
"connect": [{ "id": 1 }, { "id": 2 }]
}
},
{
"relations": {
"connect": [{ "id": 3 }, { "id": 4 }]
}
}
]
}
// Cada elemento del array es validado independientemente

4. Validación en diferentes idiomas (localización)

Section titled “4. Validación en diferentes idiomas (localización)”
// El util maneja automáticamente la localización
const content = await getContentById(
where.id,
config.collection,
config.populate,
body.locale // Idioma del request
);
// Límite estándar utilizado en la mayoría de casos
export const MAX_ALLOWED_RELATION = 4;
// Mensaje de error estándar
export const ERROR_EXCEEDED_MAXIMUM_ALLOWED_RELATIONS = (
contentType: string,
maxAllowed: number
) =>
`Exceeded maximum allowed relations in an item of ${contentType}. Maximum allowed is ${maxAllowed}.`;
// Inspiria
export const RELATION_SERIES = "serieList.series";
export const RELATION_LIVES = "liveList.lives";
export const RELATION_PRODUCTS = "productList.products";
// Osteocom
export const RELATION_OSTEOCOM_PRODUCTS =
"osteocomProductsSliders.osteocomProducts";
  1. Configuración consistente: Usa las constantes definidas en lugar de valores hardcodeados
  2. Mensajes de error claros: Personaliza los mensajes para que sean entendibles por los usuarios finales
  3. Validación temprana: Siempre valida en beforeCreate y beforeUpdate
  4. Límites razonables: Establece límites que equilibren funcionalidad y rendimiento
  5. Documentación: Documenta claramente qué relaciones se están validando y por qué
  • El util funciona antes de que se guarden los datos en la base de datos
  • Las validaciones son síncronas y bloquean la operación si fallan
  • El util maneja automáticamente las operaciones de localización
  • Las relaciones existentes se cargan automáticamente para operaciones de actualización
  • El util es compatible con arrays de componentes y relaciones anidadas

Error: “Cannot read property ‘length’ of undefined”

Section titled “❌ Error: “Cannot read property ‘length’ of undefined””

Causa: La estructura de datos no coincide con la configuración del populate.

Solución:

// ❌ Incorrecto
populate: {
wrongField: {
populate: ["series"],
}
}
// ✅ Correcto
populate: {
serieList: {
// Debe coincidir con tu estructura de datos
populate: ["series"],
}
}

Causa: El nombre de la colección es incorrecto.

Solución:

// ❌ Incorrecto
collection: "inspiria-serie";
// ✅ Correcto
collection: "api::inspiria-serie.inspiria-serie";

Causa: El util no está importado o configurado correctamente en los lifecycles.

Solución:

// Verificar que esté en beforeCreate y beforeUpdate
export default {
async beforeCreate(event) {
await validateMaxRelations(config, event.params, true); // ✅ Último parámetro true
},
async beforeUpdate(event) {
await validateMaxRelations(config, event.params, false); // ✅ Último parámetro false
},
};

Causa: Confusión entre límite por elemento vs límite total.

Explicación:

// Si tienes un array de componentes:
[
{ relations: { connect: [1, 2] } }, // 2 relaciones ✅
{ relations: { connect: [3, 4] } }, // 2 relaciones ✅
{ relations: { connect: [5, 6, 7, 8, 9] } }, // 5 relaciones ❌
];
// El límite se aplica POR ELEMENTO del array, no al total

Para debuggear problemas, puedes agregar logs temporales:

export default {
async beforeCreate(event) {
console.log("Datos recibidos:", JSON.stringify(event.params.data, null, 2));
await validateMaxRelations(config, event.params, true);
},
};