tutorials/T2ip4xzTE8GWSDdmMqmN7zFxWhItvUGbGuPOuPZP.png

Cómo montar una API en tu proyecto Laravel 12 existente (y crear un CRUD de clientes) — Guía en 5 minutos

Prerrequisitos rápidos

  • PHP 8.2+ y Composer.

  • Proyecto Laravel 12 ya funcionando.

  • DB configurada en

    .env
    .

Si estas trabajando con una versióno de laravel mayor a la 10 es necesario ejecutar esta linea

php artisan install:api
ya que las versiones posteriores de laravel no incluyen el módulo

Recuerda revisar este link, para descargar el Modelo, la Migración y el .CSV de clientes

1) Instala y configura Sanctum (opcional pero muy recomendado)

composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

En

app/Http/Kernel.php
agrega el middleware para API si no está:

protected $middlewareGroups = [
    'api' => [
        \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

En

config/sanctum.php
, si tu frontend vive en otro dominio, añade su URL en
stateful
.

Tokens personales: para pruebas, puedes generar un token:

// En un tinker o seeder:
$user = \App\Models\User::first();
$token = $user->createToken('api-token')->plainTextToken;
// Usa "Authorization: Bearer $token" en tus requests

2) Crea la migración y el modelo de clientes

2.1 Migración

php artisan make:model Cliente -m

Edita

database/migrations/xxxx_xx_xx_create_clientes_table.php
:

public function up(): void
{
    Schema::create('clientes', function (Blueprint $table) {
        $table->id();
        $table->string('nombre', 120);
        $table->string('apellido_paterno', 120)->nullable();
        $table->string('apellido_materno', 120)->nullable();
        $table->string('email')->unique();
        $table->string('telefono', 20)->nullable();
        $table->timestamps();
        $table->softDeletes();
    });
}

2.2 Modelo

En

app/Models/Cliente.php
:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Cliente extends Model
{
    use SoftDeletes;

    protected $fillable = [
        'nombre', 'apellido_paterno', 'apellido_materno', 'email', 'telefono'
    ];

    protected $appends = ['nombre_completo'];

    public function getNombreCompletoAttribute(): string
    {
        return trim($this->nombre.' '.$this->apellido_paterno.' '.$this->apellido_materno);
    }
}

Aplica migraciones:

php artisan migrate

3) (BONUS) Respuestas consistentes para tu API

Crea

app/Http/Responses/ApiResponse.php
:

namespace App\Http\Responses;

class ApiResponse
{
    public static function success($data = null, string $message = null, int $code = 200)
    {
        return response()->json([
            'success' => true,
            'message' => $message,
            'data'    => $data,
            'errors'  => null,
        ], $code);
    }

    public static function error(string $message, $errors = null, int $code = 422)
    {
        return response()->json([
            'success' => false,
            'message' => $message,
            'data'    => null,
            'errors'  => $errors,
        ], $code);
    }
}

4) Requests de validación

php artisan make:request StoreClienteRequest
php artisan make:request UpdateClienteRequest

app/Http/Requests/StoreClienteRequest.php
:

public function rules(): array
{
    return [
        'nombre'            => ['required','string','max:120'],
        'apellido_paterno'  => ['nullable','string','max:120'],
        'apellido_materno'  => ['nullable','string','max:120'],
        'email'             => ['required','email','unique:clientes,email'],
        'telefono'          => ['nullable','string','max:20'],
    ];
}

app/Http/Requests/UpdateClienteRequest.php
:

public function rules(): array
{
    $id = $this->route('cliente'); // viene del binding
    return [
        'nombre'            => ['sometimes','string','max:120'],
        'apellido_paterno'  => ['sometimes','nullable','string','max:120'],
        'apellido_materno'  => ['sometimes','nullable','string','max:120'],
        'email'             => ['sometimes','email',"unique:clientes,email,{$id}"],
        'telefono'          => ['sometimes','nullable','string','max:20'],
    ];
}

5) Controlador API (CRUD)

php artisan make:controller Api/ClienteController --api

app/Http/Controllers/Api/ClienteController.php
:

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\StoreClienteRequest;
use App\Http\Requests\UpdateClienteRequest;
use App\Http\Responses\ApiResponse;
use App\Models\Cliente;
use Illuminate\Http\Request;

class ClienteController extends Controller
{
    public function index(Request $request)
    {
        $q = $request->get('q');
        $clientes = Cliente::query()
            ->when($q, fn($qq) =>
                $qq->where('nombre', 'like', "%$q%")
                   ->orWhere('apellido_paterno','like',"%$q%")
                   ->orWhere('apellido_materno','like',"%$q%")
                   ->orWhere('email','like',"%$q%")
            )
            ->latest()
            ->paginate(10);

        return ApiResponse::success($clientes);
    }

    public function store(StoreClienteRequest $request)
    {
        $cliente = Cliente::create($request->validated());
        return ApiResponse::success($cliente, 'Cliente creado', 201);
    }

    public function show(Cliente $cliente)
    {
        return ApiResponse::success($cliente);
    }

    public function update(UpdateClienteRequest $request, Cliente $cliente)
    {
        $cliente->update($request->validated());
        return ApiResponse::success($cliente, 'Cliente actualizado');
    }

    public function destroy(Cliente $cliente)
    {
        $cliente->delete();
        return ApiResponse::success(null, 'Cliente eliminado', 204);
    }
}

Route Model Binding: al tipar

Cliente $cliente
, Laravel resuelve el ID automáticamente.

6) Rutas de la API

En

routes/api.php
:

use App\Http\Controllers\Api\ClienteController;

Route::middleware(['auth:sanctum'])->group(function () {
    Route::apiResource('clientes', ClienteController::class);
});

Para pruebas sin auth, elimina el middleware (no recomendado en producción).

7) Probar rápido (curl / Postman)

Crear

curl -X POST https://tudominio.test/api/clientes \
 -H "Authorization: Bearer TU_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
   "nombre":"Manuel",
   "apellido_paterno":"Bravo",
   "email":"manuel@example.com",
   "telefono":"771-000-0000"
 }'

Listar con búsqueda y paginación

curl -H "Authorization: Bearer TU_TOKEN" \
 "https://tudominio.test/api/clientes?q=manu&page=1"

Ver detalle

curl -H "Authorization: Bearer TU_TOKEN" \
 "https://tudominio.test/api/clientes/1"

Actualizar

curl -X PUT https://tudominio.test/api/clientes/1 \
 -H "Authorization: Bearer TU_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{"telefono":"771-123-4567"}'

Eliminar

curl -X DELETE https://tudominio.test/api/clientes/1 \
 -H "Authorization: Bearer TU_TOKEN"

8) Buenas prácticas rápidas

  • Versiona tus rutas (

    /api/v1/clientes
    ) para cambios futuros.

  • Capa de presentación: usa Resources si necesitas transformar campos:

    php artisan make:resource ClienteResource
    
  • Logs y excepciones: centraliza errores con

    App\Exceptions\Handler
    .

  • CORS: configura

    config/cors.php
    si consumirás desde otro dominio.

  • Rate limiting: ajusta límites en

    RouteServiceProvider
    si hace falta.

9) Checklist de producción

  • ✅ HTTPS habilitado

  • ✅ Tokens rotados y revocados cuando corresponda

  • ✅ Backups de DB

  • ✅ Monitoreo (Laravel Telescope opcional en entornos controlados)

  • ✅ Documentación de endpoints (OpenAPI/Swagger con darkaonline/l5-swagger, opcional)

Share:

0 comentarios

Dejar un comentario