Saltar al contenido principal

¿Qué es una respuesta?

Los controladores y las rutas necesitan devolver alguna respuesta al navegador del usuario. Laravel ofrece mecanismos sencillos para devolver diversos formatos: cadenas, arrays, vistas, redirecciones, JSON, etc.

Respuestas básicas

Devolver una cadena

La respuesta más simple es devolver una cadena. Laravel la convierte automáticamente en la respuesta HTTP adecuada.
Route::get('/', function () {
    return 'Hello World';
});

Devolver un array

Al devolver un array, Laravel lo convierte automáticamente a JSON.
Route::get('/users', function () {
    return [
        ['id' => 1, 'name' => 'Tanaka'],
        ['id' => 2, 'name' => 'Suzuki'],
    ];
});
Si devuelves un modelo Eloquent o una colección directamente, también se convierten automáticamente a JSON. Es un patrón muy usado para APIs sencillas.

Devolver un modelo Eloquent

use App\Models\User;

Route::get('/user/{user}', function (User $user) {
    return $user;
});

Objeto Response

Con el helper response() puedes devolver una respuesta detallada con código de estado HTTP y cabeceras específicas.
Route::get('/home', function () {
    return response('Hello World', 200)
        ->header('Content-Type', 'text/plain');
});
El primer argumento de response() es el cuerpo y el segundo el código de estado HTTP.

Códigos de estado HTTP habituales

CódigoSignificado
200OK (éxito)
201Created (recurso creado)
204No Content (sin contenido)
301Moved Permanently (redirección permanente)
302Found (redirección temporal)
404Not Found (no encontrado)
422Unprocessable Entity (error de validación)
500Internal Server Error (error del servidor)

Respuestas con vistas

Para mostrar una plantilla Blade desde el controlador usa view(). Es la respuesta más común en aplicaciones web.
<?php

namespace App\Http\Controllers;

use Illuminate\View\View;

class HomeController extends Controller
{
    public function index(): View
    {
        $users = [
            ['name' => 'Tanaka', 'email' => '[email protected]'],
            ['name' => 'Suzuki', 'email' => '[email protected]'],
        ];

        return view('users.index', ['users' => $users]);
    }
}
view() recibe el nombre de la vista como primer argumento y un array de datos como segundo.
Tipar el retorno como Illuminate\View\View deja más clara la intención del código.

response()->view() para más control

Si necesitas indicar código de estado o cabeceras, usa response()->view().
return response()
    ->view('errors.404', ['message' => 'Página no encontrada'], 404);

Redirecciones

Redirección básica

El helper redirect() devuelve una respuesta de redirección. Se usa mucho para llevar al usuario a otra página tras enviar un formulario.
use Illuminate\Http\RedirectResponse;

Route::get('/old-page', function (): RedirectResponse {
    return redirect('/new-page');
});
Uso en controlador:
<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function store(Request $request): RedirectResponse
    {
        // Procesamiento para guardar el post...

        return redirect('/posts');
    }
}

Redirección a ruta con nombre

Con route() puedes indicar el destino de la redirección por el nombre de la ruta, sin escribir la URL. Aunque la URL cambie, no hay que modificar nada; usar rutas con nombre es una buena práctica.
// Da nombre a la ruta
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
// Redirige a la ruta con nombre
return redirect()->route('posts.index');

// Con parámetros
return redirect()->route('posts.show', ['post' => $post->id]);

Volver a la página anterior

Con back() vuelves a la página donde estaba el usuario. Muy usado tras un fallo de validación.
return back();

// Vuelve manteniendo los datos introducidos
return back()->withInput();

Redirección con mensaje flash

Con with() puedes redirigir dejando un mensaje en la sesión. Útil para mostrar un mensaje tras enviar un formulario con éxito.
return redirect('/posts')->with('success', 'Post creado.');
Muéstralo en la plantilla Blade.
@if (session('success'))
    <div class="alert alert-success">
        {{ session('success') }}
    </div>
@endif

Respuestas JSON

Para APIs, usa response()->json(). La cabecera Content-Type: application/json se configura automáticamente.
use Illuminate\Http\JsonResponse;

Route::get('/api/users', function (): JsonResponse {
    $users = [
        ['id' => 1, 'name' => 'Tanaka'],
        ['id' => 2, 'name' => 'Suzuki'],
    ];

    return response()->json($users);
});
También puedes indicar el código de estado.
return response()->json(['message' => 'Creado'], 201);
Uso en controlador:
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function index(): JsonResponse
    {
        $users = User::all();

        return response()->json($users);
    }

    public function store(Request $request): JsonResponse
    {
        // Crear con los datos validados (tras usar form request o $request->validate())
        $user = User::create($request->validated());

        return response()->json($user, 201);
    }
}
Devolver directamente un array o un modelo Eloquent también produce una respuesta JSON, pero response()->json() te da control fino sobre el código de estado y las cabeceras.

Cabeceras de respuesta

Con header() añades una cabecera HTTP a la respuesta.
return response('Hello World')
    ->header('Content-Type', 'text/plain')
    ->header('X-Custom-Header', 'MyValue');
Para configurar varias a la vez, usa withHeaders().
return response('Hello World')
    ->withHeaders([
        'Content-Type' => 'text/plain',
        'X-Custom-Header' => 'MyValue',
        'Cache-Control' => 'no-cache',
    ]);

Ejemplo práctico: elección según la acción del controlador

Ejemplo de uso de respuestas según el caso.
1

Definir las rutas

use App\Http\Controllers\PostController;

Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/create', [PostController::class, 'create'])->name('posts.create');
Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
Route::delete('/posts/{post}', [PostController::class, 'destroy'])->name('posts.destroy');
2

Implementar el controlador

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class PostController extends Controller
{
    // Listar: devuelve una vista
    public function index(): View
    {
        $posts = Post::latest()->get();

        return view('posts.index', ['posts' => $posts]);
    }

    // Formulario de creación: devuelve una vista
    public function create(): View
    {
        return view('posts.create');
    }

    // Guardar: devuelve una redirección
    public function store(Request $request): RedirectResponse
    {
        // Crear con datos validados (si usas una form request)
        $post = Post::create($request->validated());

        return redirect()
            ->route('posts.show', ['post' => $post->id])
            ->with('success', 'Post creado.');
    }

    // Detalle: devuelve una vista
    public function show(Post $post): View
    {
        return view('posts.show', ['post' => $post]);
    }

    // Eliminar: devuelve una redirección
    public function destroy(Post $post): RedirectResponse
    {
        $post->delete();

        return redirect()
            ->route('posts.index')
            ->with('success', 'Post eliminado.');
    }
}
En una aplicación web, la elección básica es entre View y RedirectResponse. Las acciones de visualización devuelven View; las de cambio (crear/actualizar/eliminar) tras procesar devuelven RedirectResponse. Es el patrón habitual.

Próximos pasos

Validación

Aprende a validar los datos de entrada antes de devolver la respuesta.
Última modificación el 13 de julio de 2026