28 de febrero de 2023

Cómo crear una API REST con Laravel 13: guía completa con Sanctum y API Resources

Foto de Marco Orta Marco Orta | 3 mins de lectura
Compartir
Editor de código mostrando una ruta API de Laravel devolviendo JSON
Tabla de Contenidos

    Construir una API REST con Laravel es una de las habilidades más demandadas en 2026: cualquier app móvil, frontend SPA o agente de IA que se conecte a tu sistema lo hará a través de una API. En esta guía vamos a montar una API REST funcional con Laravel 13, incluyendo rutas, controladores, Form Requests para validación, API Resources para serialización y Sanctum para autenticación por tokens.

    ¿Qué es una API REST?

    Una API REST (Representational State Transfer) es una interfaz que expone recursos accesibles por HTTP, devolviendo casi siempre JSON. Los principios clave: cada recurso tiene una URL única, las operaciones usan los verbos HTTP estándar (GET, POST, PUT/PATCH, DELETE), las respuestas son sin estado y siguen convenciones predecibles.

    1. Crear una nueva aplicación Laravel 13

    Si no tienes el proyecto, revisa primero Cómo instalar Laravel 13. En resumen:

    laravel new mi-api
    cd mi-api
    

    En Laravel 11+, el archivo routes/api.php ya no se crea por defecto. Para habilitarlo, ejecuta:

    php artisan install:api
    

    Este comando crea routes/api.php, registra el prefijo /api automáticamente, e instala Laravel Sanctum para autenticación por tokens.

    2. Configurar la base de datos

    Edita el archivo .env con tus credenciales:

    DB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_PORT=3306
    DB_DATABASE=mi_api
    DB_USERNAME=root
    DB_PASSWORD=
    

    Para empezar rápido, también puedes usar SQLite:

    DB_CONNECTION=sqlite
    

    Luego ejecuta las migraciones:

    php artisan migrate
    

    3. Crear modelo, migración y factory

    Vamos a montar un CRUD de “productos”. Generamos todo en un comando:

    php artisan make:model Product -mfr
    

    Las flags -mfr crean migración, factory y resource controller. Edita la migración generada:

    public function up(): void
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->text('description')->nullable();
            $table->decimal('price', 10, 2);
            $table->integer('stock')->default(0);
            $table->timestamps();
        });
    }
    

    Y en el modelo app/Models/Product.php, declara los $fillable:

    class Product extends Model
    {
        use HasFactory;
    
        protected $fillable = ['name', 'description', 'price', 'stock'];
    }
    

    Ejecuta la migración:

    php artisan migrate
    

    4. Crear el API Resource

    Los API Resources son la forma idiomática de Laravel para controlar exactamente qué campos expone tu API:

    php artisan make:resource ProductResource
    

    Edita app/Http/Resources/ProductResource.php:

    public function toArray(Request $request): array
    {
        return [
            'id'          => $this->id,
            'name'        => $this->name,
            'description' => $this->description,
            'price'       => (float) $this->price,
            'stock'       => $this->stock,
            'created_at'  => $this->created_at->toIso8601String(),
        ];
    }
    

    5. Crear Form Requests para validación

    En lugar de validar dentro del controlador, en 2026 lo idiomático es usar Form Requests dedicados:

    php artisan make:request StoreProductRequest
    php artisan make:request UpdateProductRequest
    

    Edita StoreProductRequest:

    public function authorize(): bool
    {
        return true;
    }
    
    public function rules(): array
    {
        return [
            'name'        => ['required', 'string', 'max:255'],
            'description' => ['nullable', 'string'],
            'price'       => ['required', 'numeric', 'min:0'],
            'stock'       => ['required', 'integer', 'min:0'],
        ];
    }
    

    6. Implementar el controlador

    app/Http/Controllers/ProductController.php ya tiene el esqueleto. Llénalo así:

    use App\Http\Requests\StoreProductRequest;
    use App\Http\Requests\UpdateProductRequest;
    use App\Http\Resources\ProductResource;
    use App\Models\Product;
    
    class ProductController extends Controller
    {
        public function index()
        {
            return ProductResource::collection(Product::latest()->paginate(20));
        }
    
        public function store(StoreProductRequest $request)
        {
            $product = Product::create($request->validated());
            return new ProductResource($product);
        }
    
        public function show(Product $product)
        {
            return new ProductResource($product);
        }
    
        public function update(UpdateProductRequest $request, Product $product)
        {
            $product->update($request->validated());
            return new ProductResource($product);
        }
    
        public function destroy(Product $product)
        {
            $product->delete();
            return response()->noContent();
        }
    }
    

    Fíjate en dos patrones clave de Laravel moderno: route model binding (Product $product ya viene resuelto desde la URL) y response()->noContent() (devuelve 204 No Content correctamente).

    7. Definir las rutas

    Edita routes/api.php:

    use App\Http\Controllers\ProductController;
    use Illuminate\Support\Facades\Route;
    
    Route::apiResource('products', ProductController::class);
    

    Una sola línea registra las cinco rutas REST: GET /api/products, POST /api/products, GET /api/products/{id}, PUT/PATCH /api/products/{id} y DELETE /api/products/{id}.

    Verifica con:

    php artisan route:list --path=api
    

    8. Autenticación con Laravel Sanctum

    Cuando ejecutaste php artisan install:api, Sanctum quedó instalado. Para emitir tokens, añade el trait HasApiTokens a App\Models\User:

    use Laravel\Sanctum\HasApiTokens;
    
    class User extends Authenticatable
    {
        use HasApiTokens, HasFactory, Notifiable;
        // ...
    }
    

    Crea un endpoint de login que devuelva el token:

    use App\Models\User;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Hash;
    
    Route::post('/login', function (Request $request) {
        $request->validate([
            'email'    => ['required', 'email'],
            'password' => ['required'],
        ]);
    
        $user = User::where('email', $request->email)->first();
    
        if (! $user || ! Hash::check($request->password, $user->password)) {
            return response()->json(['message' => 'Credenciales inválidas'], 401);
        }
    
        return response()->json([
            'token' => $user->createToken('api')->plainTextToken,
            'user'  => $user,
        ]);
    });
    

    Y protege las rutas de productos:

    Route::middleware('auth:sanctum')->group(function () {
        Route::apiResource('products', ProductController::class);
    });
    

    Ahora cada petición a /api/products necesita el header:

    Authorization: Bearer {token}
    

    Sanctum emite tokens opacos, pero si tu API usa JSON Web Tokens (JWT) puedes inspeccionar su header y payload y verificar la firma con esta herramienta:

    9. Probar la API

    Usa Bruno, Thunder Client, Postman o curl directamente:

    # Login
    curl -X POST http://localhost:8000/api/login \
      -H "Content-Type: application/json" \
      -d '{"email":"[email protected]","password":"password"}'
    
    # Crear producto (sustituye TOKEN por el devuelto arriba)
    curl -X POST http://localhost:8000/api/products \
      -H "Authorization: Bearer TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"name":"Laptop","price":1500,"stock":10}'
    

    10. Tests con PHPUnit (o Pest)

    Laravel 13 trae Pest integrado por defecto. Un test básico:

    use App\Models\User;
    use Laravel\Sanctum\Sanctum;
    
    it('lista productos para usuarios autenticados', function () {
        Sanctum::actingAs(User::factory()->create());
    
        $this->getJson('/api/products')
            ->assertOk()
            ->assertJsonStructure(['data', 'meta', 'links']);
    });
    
    it('rechaza peticiones sin token', function () {
        $this->getJson('/api/products')->assertStatus(401);
    });
    

    Ejecuta los tests:

    php artisan test
    

    Conclusión

    En 2026 construir una API REST con Laravel es prácticamente “ejecutar install:api, crear un resource controller y listo”. Lo que marca la diferencia entre una API juguete y una API profesional son los detalles: API Resources para serialización limpia, Form Requests para validación, Sanctum para autenticación por tokens, y tests para no romper nada en cada release.

    Una vez que tu API esté en pie, dos siguientes pasos típicos son: optimizar el rendimiento con Cómo optimizar el rendimiento de tu proyecto Laravel y, si quieres exponer tu lógica a agentes de IA, leer Cómo construir un agente de IA con Laravel y MCP.

    Si te ha servido la guía, recuerda compartirla. ¡Saludos!

    Compartir

    Buscar

    Etiquetas

    Tutorial PHP Laravel IA Desarrollo Web JavaScript Buenas Prácticas Laravel 13 Seguridad Herramientas Claude SEO Expresiones Regulares Manipulación de Texto Frontend