Contenido del curso

Consultas con relaciones en Laravel API

Resumen

Cuando construyes una API con Laravel, no basta con devolver registros sueltos. Necesitas que cada consulta de datos con relaciones traiga la información conectada: una categoría con sus recetas, una receta con sus etiquetas y su autor, una etiqueta con todas las recetas asociadas. Eso es justo lo que vas a configurar aquí.

¿Cómo traer recetas dentro de una categoría con Laravel?

La idea es simple: cuando consultas una categoría, quieres ver también las recetas que le pertenecen. El problema es que Laravel no conoce esa relación de manera automática, aunque exista físicamente en la base de datos. Tú se la tienes que declarar.

En el CategoriesController, la consulta original solo devuelve la información de la categoría. Para que traiga las recetas relacionadas, usas el método load sobre la instancia ya consultada.

php $category->load('recipes');

Y en el modelo Category, registras el método que define la relación:

php public function recipes() { return $this->hasMany(Recipe::class); }

Con esto le estás diciendo a Laravel: tú, como categoría, tienes muchas recetas. Una categoría puede contener varias recetas, pero una receta pertenece solo a una categoría. Esa es una relación uno a muchos clásica.

¿Cuál es la diferencia entre with y load en Laravel? with se usa cuando construyes la consulta desde cero (eager loading inicial). load se usa cuando ya tienes el modelo consultado y quieres añadir relaciones después (lazy eager loading).

¿Cómo cargar varias relaciones en una receta al mismo tiempo?

En el RecipesController el escenario cambia, porque la consulta se construye desde cero. Ahí sí puedes usar with para encadenar varias relaciones en una sola llamada.

php Recipe::with('category', 'tags', 'user')->get();

Fíjate en un detalle importante: ya no usas all(). El método all simplemente trae todos los registros sin opciones de personalización. En cambio, get te permite combinar filtros, relaciones y otras condiciones antes de ejecutar la consulta.

  • all(): trae todos los registros, sin flexibilidad.
  • get(): ejecuta la consulta personalizada que armaste con el query builder.
  • with(): precarga relaciones en una consulta nueva.
  • load(): precarga relaciones en un modelo ya obtenido.

Después registras las relaciones inversas en el modelo Recipe:

php public function category() { return $this->belongsTo(Category::class); }

public function user() { return $this->belongsTo(User::class); }

Aquí usas belongsTo porque una receta pertenece a una sola categoría y fue creada por un solo usuario. No es muchos a muchos, es una referencia directa.

Al probar el endpoint en Postman, cada receta llega con su categoría anidada, sus etiquetas y el usuario que la creó. Todo en una sola respuesta JSON.

¿Cómo defines una relación muchos a muchos entre tags y recipes?

En el TagsController haces lo mismo, pero con un matiz: una etiqueta puede pertenecer a muchas recetas, y una receta puede tener muchas etiquetas. Esa es una relación muchos a muchos.

php $tags->load('recipes');

Y en el modelo Tag:

php public function recipes() { return $this->belongsToMany(Recipe::class); }

El método belongsToMany es el que indica esa doble dirección. Laravel asume que existe una tabla pivote intermedia que conecta ambas entidades.

¿Cuándo uso belongsToMany en Laravel? Cuando dos modelos se relacionan en ambas direcciones: A puede tener muchos B, y B puede tener muchos A. Necesitas una tabla pivote que guarde las combinaciones.

Al consultar el listado de tags, cada etiqueta llega con su colección de recetas. Y si consultas una sola etiqueta, obtienes el mismo resultado: la etiqueta más todas las recetas vinculadas.

¿Por qué hay que registrar las relaciones aunque existan en la base de datos?

Aquí está el punto clave que se repite a lo largo de toda la clase. Las relaciones existen físicamente en tu base de datos a través de llaves foráneas, pero Laravel no las detecta solo. Tienes que declararlas en cada modelo con métodos como hasMany, belongsTo o belongsToMany.

Esa declaración es lo que conecta el ORM Eloquent con la estructura real de tus tablas. Sin ella, no importa cuántos with o load escribas: la consulta no sabrá a dónde ir.

Conceptos y métodos importantes que aparecieron a lo largo de la clase:

  • hasMany: relación uno a muchos desde el lado padre [01:30].
  • belongsTo: relación inversa, el hijo apunta al padre [04:10].
  • belongsToMany: relación muchos a muchos con tabla pivote [05:50].
  • with: eager loading al construir la query [02:40].
  • load: eager loading sobre un modelo ya consultado [01:50].
  • get vs all: flexibilidad en la consulta [03:20].

Si estás siguiendo este curso con otra herramienta, por ejemplo Django u otro framework profesional, cuéntame en los comentarios cómo configuras tú esta relación para que una sola consulta traiga datos de la tabla principal y de tablas adicionales.