13-CRUD en Laravel para Web y API con Rutas Normales (No Resource)
Tutorial Actualizado: CRUD en Laravel para Web y API con Rutas Normales (No Resource)
Te mostraré la implementación completa y detallada con rutas normales (no resource), perfecto para principiantes.
Estructura del Proyecto
gestor-tareas/
├── app/
│ ├── Http/
│ │ ├── Controllers/
│ │ │ ├── Api/
│ │ │ │ └── TareaController.php
│ │ │ └── Web/
│ │ │ └── TareaController.php
├── routes/
│ ├── api.php
│ └── web.php
└── resources/views/tareas/
├── index.blade.php
├── create.blade.php
├── show.blade.php
└── edit.blade.phpPaso a Paso Detallado
1. Crear el Proyecto
composer create-project laravel/laravel gestor-tareas
cd gestor-tareas2. Configurar Base de Datos
Editar el archivo .env:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=gestor_tareas
DB_USERNAME=root
DB_PASSWORD=3. Crear Modelo y Migración
php artisan make:model Tarea -m4. Configurar la Migración
Editar database/migrations/xxxx_create_tareas_table.php:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('tareas', function (Blueprint $table) {
$table->id(); // ID automático
$table->string('titulo'); // Título de la tarea
$table->text('descripcion')->nullable(); // Descripción opcional
$table->boolean('completada')->default(false); // Estado
$table->timestamps(); // created_at y updated_at
});
}
public function down(): void
{
Schema::dropIfExists('tareas');
}
};5. Ejecutar la Migración
php artisan migrate6. Crear Controladores
Controlador Web:
php artisan make:controller Web/TareaControllerControlador API:
php artisan make:controller Api/TareaController7. Configurar Modelo Tarea
Editar app/Models/Tarea.php:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Tarea extends Model
{
use HasFactory;
// Campos que se pueden llenar masivamente
protected $fillable = [
'titulo',
'descripcion',
'completada'
];
// Campos que deben ser convertidos a tipos específicos
protected $casts = [
'completada' => 'boolean'
];
}8. Configurar Rutas Web (Normales)
Editar routes/web.php:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Web\TareaController;
// Ruta para la página principal (lista de tareas)
Route::get('/tareas', [TareaController::class, 'index'])->name('tareas.index');
// Ruta para mostrar el formulario de creación
Route::get('/tareas/crear', [TareaController::class, 'create'])->name('tareas.create');
// Ruta para guardar una nueva tarea
Route::post('/tareas', [TareaController::class, 'store'])->name('tareas.store');
// Ruta para mostrar una tarea específica
Route::get('/tareas/{id}', [TareaController::class, 'show'])->name('tareas.show');
// Ruta para mostrar el formulario de edición
Route::get('/tareas/{id}/editar', [TareaController::class, 'edit'])->name('tareas.edit');
// Ruta para actualizar una tarea
Route::put('/tareas/{id}', [TareaController::class, 'update'])->name('tareas.update');
// Ruta para eliminar una tarea
Route::delete('/tareas/{id}', [TareaController::class, 'destroy'])->name('tareas.destroy');9. Configurar Rutas API (Normales)
Editar routes/api.php:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\TareaController;
// Prefijo automático: /api
// Listar todas las tareas
Route::get('/tareas', [TareaController::class, 'index']);
// Crear una nueva tarea
Route::post('/tareas', [TareaController::class, 'store']);
// Mostrar una tarea específica
Route::get('/tareas/{id}', [TareaController::class, 'show']);
// Actualizar una tarea
Route::put('/tareas/{id}', [TareaController::class, 'update']);
// Eliminar una tarea
Route::delete('/tareas/{id}', [TareaController::class, 'destroy']);10. Implementar Controlador Web
Editar app/Http/Controllers/Web/TareaController.php:
<?php
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use App\Models\Tarea;
use Illuminate\Http\Request;
class TareaController extends Controller
{
/**
* Mostrar lista de todas las tareas
*/
public function index()
{
// Obtener todas las tareas ordenadas por fecha de creación
$tareas = Tarea::orderBy('created_at', 'desc')->get();
// Pasar las tareas a la vista
return view('tareas.index', [
'tareas' => $tareas
]);
}
/**
* Mostrar formulario para crear nueva tarea
*/
public function create()
{
return view('tareas.create');
}
/**
* Guardar nueva tarea en la base de datos
*/
public function store(Request $request)
{
// Validar los datos del formulario
$request->validate([
'titulo' => 'required|min:3|max:255',
'descripcion' => 'nullable|string',
]);
// Crear la tarea
Tarea::create([
'titulo' => $request->titulo,
'descripcion' => $request->descripcion,
'completada' => $request->has('completada') ? true : false
]);
// Redirigir a la lista con mensaje de éxito
return redirect()->route('tareas.index')
->with('success', '¡Tarea creada correctamente!');
}
/**
* Mostrar una tarea específica
*/
public function show($id)
{
// Buscar la tarea por ID
$tarea = Tarea::findOrFail($id);
return view('tareas.show', [
'tarea' => $tarea
]);
}
/**
* Mostrar formulario para editar tarea
*/
public function edit($id)
{
// Buscar la tarea por ID
$tarea = Tarea::findOrFail($id);
return view('tareas.edit', [
'tarea' => $tarea
]);
}
/**
* Actualizar una tarea existente
*/
public function update(Request $request, $id)
{
// Validar los datos
$request->validate([
'titulo' => 'required|min:3|max:255',
'descripcion' => 'nullable|string',
]);
// Buscar la tarea por ID
$tarea = Tarea::findOrFail($id);
// Actualizar los datos
$tarea->titulo = $request->titulo;
$tarea->descripcion = $request->descripcion;
$tarea->completada = $request->has('completada') ? true : false;
$tarea->save();
// Redirigir a la lista con mensaje de éxito
return redirect()->route('tareas.index')
->with('success', '¡Tarea actualizada correctamente!');
}
/**
* Eliminar una tarea
*/
public function destroy($id)
{
// Buscar la tarea por ID
$tarea = Tarea::findOrFail($id);
// Eliminar la tarea
$tarea->delete();
// Redirigir a la lista con mensaje de éxito
return redirect()->route('tareas.index')
->with('success', '¡Tarea eliminada correctamente!');
}
}11. Implementar Controlador API
Editar app/Http\Controllers\Api\TareaController.php:
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Tarea;
use Illuminate\Http\Request;
class TareaController extends Controller
{
/**
* Obtener todas las tareas (JSON)
*/
public function index()
{
$tareas = Tarea::orderBy('created_at', 'desc')->get();
return response()->json([
'success' => true,
'message' => 'Lista de tareas obtenida correctamente',
'data' => $tareas,
'count' => $tareas->count()
]);
}
/**
* Crear una nueva tarea (JSON)
*/
public function store(Request $request)
{
// Validar los datos
$request->validate([
'titulo' => 'required|min:3|max:255',
'descripcion' => 'nullable|string',
'completada' => 'boolean'
]);
// Crear la tarea
$tarea = Tarea::create([
'titulo' => $request->titulo,
'descripcion' => $request->descripcion,
'completada' => $request->completada ?? false
]);
return response()->json([
'success' => true,
'message' => 'Tarea creada correctamente',
'data' => $tarea
], 201); // Código 201: Created
}
/**
* Obtener una tarea específica (JSON)
*/
public function show($id)
{
// Buscar la tarea
$tarea = Tarea::find($id);
// Si no existe, devolver error
if (!$tarea) {
return response()->json([
'success' => false,
'message' => 'Tarea no encontrada'
], 404); // Código 404: Not Found
}
return response()->json([
'success' => true,
'message' => 'Tarea obtenida correctamente',
'data' => $tarea
]);
}
/**
* Actualizar una tarea existente (JSON)
*/
public function update(Request $request, $id)
{
// Buscar la tarea
$tarea = Tarea::find($id);
// Si no existe, devolver error
if (!$tarea) {
return response()->json([
'success' => false,
'message' => 'Tarea no encontrada'
], 404);
}
// Validar los datos
$request->validate([
'titulo' => 'sometimes|min:3|max:255',
'descripcion' => 'nullable|string',
'completada' => 'boolean'
]);
// Actualizar solo los campos enviados
if ($request->has('titulo')) {
$tarea->titulo = $request->titulo;
}
if ($request->has('descripcion')) {
$tarea->descripcion = $request->descripcion;
}
if ($request->has('completada')) {
$tarea->completada = $request->completada;
}
$tarea->save();
return response()->json([
'success' => true,
'message' => 'Tarea actualizada correctamente',
'data' => $tarea
]);
}
/**
* Eliminar una tarea (JSON)
*/
public function destroy($id)
{
// Buscar la tarea
$tarea = Tarea::find($id);
// Si no existe, devolver error
if (!$tarea) {
return response()->json([
'success' => false,
'message' => 'Tarea no encontrada'
], 404);
}
// Eliminar la tarea
$tarea->delete();
return response()->json([
'success' => true,
'message' => 'Tarea eliminada correctamente'
]);
}
}12. Crear Layout Base
Crear resources/views/layouts/app.blade.php:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@yield('title', 'Gestor de Tareas')</title>
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
<style>
body {
padding-top: 20px;
background-color: #f8f9fa;
}
.navbar {
margin-bottom: 20px;
}
.card {
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
</style>
</head>
<body>
<div class="container">
<!-- Barra de navegación -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary rounded">
<div class="container-fluid">
<a class="navbar-brand" href="{{ route('tareas.index') }}">
<i class="bi bi-check2-circle"></i> Gestor de Tareas
</a>
<div class="navbar-nav">
<a class="nav-link text-white" href="{{ route('tareas.index') }}">
<i class="bi bi-list"></i> Lista
</a>
<a class="nav-link text-white" href="{{ route('tareas.create') }}">
<i class="bi bi-plus-circle"></i> Nueva
</a>
</div>
</div>
</nav>
<!-- Mensajes de sesión -->
@if(session('success'))
<div class="alert alert-success alert-dismissible fade show mt-3" role="alert">
<i class="bi bi-check-circle"></i> {{ session('success') }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
@endif
@if(session('error'))
<div class="alert alert-danger alert-dismissible fade show mt-3" role="alert">
<i class="bi bi-exclamation-triangle"></i> {{ session('error') }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
@endif
<!-- Contenido principal -->
<div class="mt-4">
@yield('content')
</div>
<!-- Información API -->
<div class="card mt-5">
<div class="card-header bg-info text-white">
<i class="bi bi-code-slash"></i> Información de la API
</div>
<div class="card-body">
<p class="mb-1"><strong>URL Base API:</strong> <code>http://localhost:8000/api/tareas</code></p>
<p class="mb-1"><strong>Métodos disponibles:</strong></p>
<ul class="mb-0">
<li><code>GET /api/tareas</code> - Listar tareas</li>
<li><code>POST /api/tareas</code> - Crear tarea</li>
<li><code>GET /api/tareas/{id}</code> - Ver tarea</li>
<li><code>PUT /api/tareas/{id}</code> - Actualizar tarea</li>
<li><code>DELETE /api/tareas/{id}</code> - Eliminar tarea</li>
</ul>
</div>
</div>
</div>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- Scripts adicionales -->
@stack('scripts')
</body>
</html>13. Crear Vistas
Vista Index (resources/views/tareas/index.blade.php):
@extends('layouts.app')
@section('title', 'Lista de Tareas')
@section('content')
<div class="card">
<div class="card-header bg-dark text-white">
<h4 class="mb-0">
<i class="bi bi-list-task"></i> Lista de Tareas
</h4>
</div>
<div class="card-body">
@if($tareas->isEmpty())
<div class="alert alert-info">
<i class="bi bi-info-circle"></i> No hay tareas registradas.
<a href="{{ route('tareas.create') }}" class="alert-link">Crea tu primera tarea</a>
</div>
@else
<div class="table-responsive">
<table class="table table-hover table-striped">
<thead class="table-light">
<tr>
<th>ID</th>
<th>Título</th>
<th>Estado</th>
<th>Creado</th>
<th class="text-center">Acciones</th>
</tr>
</thead>
<tbody>
@foreach($tareas as $tarea)
<tr>
<td>{{ $tarea->id }}</td>
<td>
<strong>{{ $tarea->titulo }}</strong>
@if($tarea->descripcion)
<br>
<small class="text-muted">{{ Str::limit($tarea->descripcion, 50) }}</small>
@endif
</td>
<td>
@if($tarea->completada)
<span class="badge bg-success">
<i class="bi bi-check-circle"></i> Completada
</span>
@else
<span class="badge bg-warning">
<i class="bi bi-clock"></i> Pendiente
</span>
@endif
</td>
<td>{{ $tarea->created_at->format('d/m/Y') }}</td>
<td>
<div class="btn-group" role="group">
<!-- Ver -->
<a href="{{ route('tareas.show', $tarea->id) }}"
class="btn btn-sm btn-outline-info"
title="Ver detalles">
<i class="bi bi-eye"></i>
</a>
<!-- Editar -->
<a href="{{ route('tareas.edit', $tarea->id) }}"
class="btn btn-sm btn-outline-warning"
title="Editar">
<i class="bi bi-pencil"></i>
</a>
<!-- Eliminar -->
<form action="{{ route('tareas.destroy', $tarea->id) }}"
method="POST"
class="d-inline"
onsubmit="return confirm('¿Estás seguro de eliminar esta tarea?')">
@csrf
@method('DELETE')
<button type="submit"
class="btn btn-sm btn-outline-danger"
title="Eliminar">
<i class="bi bi-trash"></i>
</button>
</form>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
<!-- Botón para crear nueva tarea -->
<div class="mt-4 text-center">
<a href="{{ route('tareas.create') }}" class="btn btn-primary btn-lg">
<i class="bi bi-plus-circle"></i> Crear Nueva Tarea
</a>
</div>
</div>
</div>
@endsectionVista Create (resources/views/tareas/create.blade.php):
@extends('layouts.app')
@section('title', 'Crear Nueva Tarea')
@section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header bg-success text-white">
<h4 class="mb-0">
<i class="bi bi-plus-circle"></i> Crear Nueva Tarea
</h4>
</div>
<div class="card-body">
<!-- Mostrar errores de validación -->
@if($errors->any())
<div class="alert alert-danger">
<h6>Por favor corrige los siguientes errores:</h6>
<ul class="mb-0">
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- Formulario -->
<form action="{{ route('tareas.store') }}" method="POST">
@csrf
<div class="mb-3">
<label for="titulo" class="form-label">
<strong>Título *</strong>
</label>
<input type="text"
class="form-control @error('titulo') is-invalid @enderror"
id="titulo"
name="titulo"
value="{{ old('titulo') }}"
placeholder="Ej: Comprar víveres"
required>
@error('titulo')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
<div class="form-text">El título es obligatorio (3-255 caracteres).</div>
</div>
<div class="mb-3">
<label for="descripcion" class="form-label">
<strong>Descripción</strong>
</label>
<textarea class="form-control @error('descripcion') is-invalid @enderror"
id="descripcion"
name="descripcion"
rows="4"
placeholder="Ej: Comprar leche, pan, huevos...">{{ old('descripcion') }}</textarea>
@error('descripcion')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3 form-check">
<input type="checkbox"
class="form-check-input"
id="completada"
name="completada"
value="1">
<label class="form-check-label" for="completada">
<strong>¿Tarea completada?</strong>
</label>
<div class="form-text">Marca esta casilla si la tarea ya está terminada.</div>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<a href="{{ route('tareas.index') }}" class="btn btn-secondary me-md-2">
<i class="bi bi-arrow-left"></i> Volver al Listado
</a>
<button type="submit" class="btn btn-success">
<i class="bi bi-save"></i> Guardar Tarea
</button>
</div>
</form>
</div>
</div>
</div>
</div>
@endsectionVista Show (resources/views/tareas/show.blade.php):
@extends('layouts.app')
@section('title', 'Detalles de Tarea')
@section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header bg-info text-white">
<h4 class="mb-0">
<i class="bi bi-eye"></i> Detalles de Tarea #{{ $tarea->id }}
</h4>
</div>
<div class="card-body">
<!-- Información de la tarea -->
<div class="row mb-3">
<div class="col-md-6">
<h5><strong>ID:</strong></h5>
<p>{{ $tarea->id }}</p>
</div>
<div class="col-md-6">
<h5><strong>Estado:</strong></h5>
@if($tarea->completada)
<span class="badge bg-success p-2">
<i class="bi bi-check-circle"></i> COMPLETADA
</span>
@else
<span class="badge bg-warning p-2">
<i class="bi bi-clock"></i> PENDIENTE
</span>
@endif
</div>
</div>
<div class="mb-4">
<h5><strong>Título:</strong></h5>
<p class="fs-5">{{ $tarea->titulo }}</p>
</div>
<div class="mb-4">
<h5><strong>Descripción:</strong></h5>
<div class="border rounded p-3 bg-light">
{{ $tarea->descripcion ?: 'No hay descripción' }}
</div>
</div>
<div class="row">
<div class="col-md-6">
<h5><strong>Creada:</strong></h5>
<p>{{ $tarea->created_at->format('d/m/Y H:i:s') }}</p>
</div>
<div class="col-md-6">
<h5><strong>Actualizada:</strong></h5>
<p>{{ $tarea->updated_at->format('d/m/Y H:i:s') }}</p>
</div>
</div>
<!-- Botones de acción -->
<div class="d-grid gap-2 d-md-flex justify-content-md-center mt-4">
<a href="{{ route('tareas.edit', $tarea->id) }}" class="btn btn-warning me-md-2">
<i class="bi bi-pencil"></i> Editar Tarea
</a>
<form action="{{ route('tareas.destroy', $tarea->id) }}" method="POST" class="d-inline">
@csrf
@method('DELETE')
<button type="submit"
class="btn btn-danger"
onclick="return confirm('¿Estás seguro de eliminar esta tarea?')">
<i class="bi bi-trash"></i> Eliminar Tarea
</button>
</form>
<a href="{{ route('tareas.index') }}" class="btn btn-secondary ms-md-2">
<i class="bi bi-list"></i> Ver Todas
</a>
</div>
</div>
</div>
<!-- Sección JSON para desarrolladores -->
<div class="card mt-4">
<div class="card-header bg-dark text-white">
<i class="bi bi-code"></i> Datos en Formato JSON (API)
</div>
<div class="card-body">
<pre class="bg-light p-3 rounded" style="max-height: 200px; overflow-y: auto;"><code>{
"id": {{ $tarea->id }},
"titulo": "{{ $tarea->titulo }}",
"descripcion": "{{ $tarea->descripcion }}",
"completada": {{ $tarea->completada ? 'true' : 'false' }},
"created_at": "{{ $tarea->created_at }}",
"updated_at": "{{ $tarea->updated_at }}"
}</code></pre>
</div>
</div>
</div>
</div>
@endsectionVista Edit (resources/views/tareas/edit.blade.php):
@extends('layouts.app')
@section('title', 'Editar Tarea')
@section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header bg-warning text-white">
<div class="d-flex justify-content-between align-items-center">
<h4 class="mb-0">
<i class="bi bi-pencil"></i> Editar Tarea #{{ $tarea->id }}
</h4>
<a href="{{ route('tareas.show', $tarea->id) }}" class="btn btn-light btn-sm">
<i class="bi bi-eye"></i> Ver
</a>
</div>
</div>
<div class="card-body">
<!-- Mostrar errores de validación -->
@if($errors->any())
<div class="alert alert-danger">
<h6>Por favor corrige los siguientes errores:</h6>
<ul class="mb-0">
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- Formulario -->
<form action="{{ route('tareas.update', $tarea->id) }}" method="POST">
@csrf
@method('PUT')
<div class="mb-3">
<label for="titulo" class="form-label">
<strong>Título *</strong>
</label>
<input type="text"
class="form-control @error('titulo') is-invalid @enderror"
id="titulo"
name="titulo"
value="{{ old('titulo', $tarea->titulo) }}"
required>
@error('titulo')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="descripcion" class="form-label">
<strong>Descripción</strong>
</label>
<textarea class="form-control @error('descripcion') is-invalid @enderror"
id="descripcion"
name="descripcion"
rows="4">{{ old('descripcion', $tarea->descripcion) }}</textarea>
@error('descripcion')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3 form-check">
<input type="checkbox"
class="form-check-input"
id="completada"
name="completada"
value="1"
{{ $tarea->completada ? 'checked' : '' }}>
<label class="form-check-label" for="completada">
<strong>¿Tarea completada?</strong>
</label>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-between mt-4">
<a href="{{ route('tareas.index') }}" class="btn btn-outline-secondary">
<i class="bi bi-x-circle"></i> Cancelar
</a>
<div>
<button type="submit" class="btn btn-warning me-2">
<i class="bi bi-save"></i> Actualizar
</button>
<a href="{{ route('tareas.show', $tarea->id) }}" class="btn btn-info">
<i class="bi bi-eye"></i> Ver Detalles
</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
@endsection14. Crear Carpeta de Vistas
mkdir -p resources/views/tareas15. Iniciar el Servidor
php artisan serveAcceso a la Aplicación
Interfaz Web:
Lista de tareas: http://localhost:8000/tareas
Crear tarea: http://localhost:8000/tareas/crear
Ver tarea: http://localhost:8000/tareas/1
Editar tarea: http://localhost:8000/tareas/1/editar
API REST:
Listar tareas: GET http://localhost:8000/api/tareas
Crear tarea: POST http://localhost:8000/api/tareas
Ver tarea: GET http://localhost:8000/api/tareas/1
Actualizar tarea: PUT http://localhost:8000/api/tareas/1
Eliminar tarea: DELETE http://localhost:8000/api/tareas/1
Pruebas con curl (API)
# Listar tareas
curl http://localhost:8000/api/tareas
# Crear tarea
curl -X POST http://localhost:8000/api/tareas \
-H "Content-Type: application/json" \
-d '{"titulo":"Mi primera tarea","descripcion":"Descripción de prueba"}'
# Ver tarea específica
curl http://localhost:8000/api/tareas/1
# Actualizar tarea
curl -X PUT http://localhost:8000/api/tareas/1 \
-H "Content-Type: application/json" \
-d '{"titulo":"Título actualizado","completada":true}'
# Eliminar tarea
curl -X DELETE http://localhost:8000/api/tareas/1Resumen de Archivos Creados
Rutas:
routes/web.php- Rutas web normalesroutes/api.php- Rutas API normales
Controladores:
app/Http/Controllers/Web/TareaController.php- Controlador webapp/Http/Controllers/Api/TareaController.php- Controlador API
Modelo:
app/Models/Tarea.php- Modelo de tarea
Vistas:
resources/views/layouts/app.blade.php- Layout baseresources/views/tareas/index.blade.php- Lista de tareasresources/views/tareas/create.blade.php- Crear tarearesources/views/tareas/show.blade.php- Ver tarearesources/views/tareas/edit.blade.php- Editar tarea
Este tutorial está completamente detallado y usa rutas normales en lugar de resource, haciéndolo más comprensible para principiantes. Cada paso está explicado y el código está bien comentado.
Comentarios
Publicar un comentario