Readme
API Client Service
Objetivo: Crear una API Client Service con relación NM. Características:
- Relacionamos los dos modelos
- Usaremos Middleware mediante grupo
- Usaremos apiResource en rutas en lugar de resource (No añade create/update)
-
Opcional: Documentación con Swagger
-
composer create-project laravel/laravel client/service
- Instalar API:
php artisan install:api
- Crear AuthController:
php artisan make:controller AuthController
api.php
Dejamos el archivo de rutas:
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
use App\Http\Controllers\ClientController;
use App\Http\Controllers\ServiceController;
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
Route::middleware('auth:sanctum')->group(function () {
Route::post('/logout', [AuthController::class, 'logout']);
Route::apiResource('clients', ClientController::class);
Route::apiResource('services', ServiceController::class);
});
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
API Rutas para probar sin autenticación
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
use App\Http\Controllers\ClientController;
use App\Http\Controllers\ServiceController;
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
/*
Route::middleware('auth:sanctum')->group(function () {
Route::post('/logout', [AuthController::class, 'logout']);
Route::apiResource('clients', ClientController::class);
Route::apiResource('services', ServiceController::class);
});
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
*/
Route::apiResource('clients', ClientController::class);
Route::apiResource('services', ServiceController::class);
//rutas para introducir un servicio a un cliente
//de uno en uno
Route::post('/clients/{client}/services/{service}', [ClientController::class, 'addService']);
//de varios a la vez
Route::post('/clients/{client}/services', [ClientController::class, 'attachServices']);
classAuthController
<?php
// AuthController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Auth;
use Laravel\Sanctum\Sanctum;
class AuthController extends Controller {
public function register(Request $request) {
$request->validate([
'name' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required|min:6',
]);
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
return response()->json(['token' => $user->createToken('api-token')->plainTextToken, 'user' => $user]);
}
public function login(Request $request) {
if (!Auth::attempt($request->only('email', 'password'))) {
return response()->json(['message' => 'Unauthorized'], 401);
}
return response()->json(['token' => Auth::user()->createToken('api-token')->plainTextToken, 'user' => Auth::user()]);
}
public function logout(Request $request) {
$request->user()->tokens()->delete();
return response()->json(['message' => 'Logged out']);
}
}
Al poner el anterior código, nos falla el modelo User al no tener el ApiToken, lo incorporamos:
Modelo User
Incluimos librería y HasApiToken
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasApiTokens, HasFactory, Notifiable;
... RESTO IGUAL
Modelo Client
Creamos el modelo cliente con migración, modelo y controlador
php artisan make:model Client -mcr
Modelo Service
Creamos el modelo Service conmigración, modelo y controlador
php artisan make:model Service -mcr
Migraciones
Create_client_service_table
php artisan make:migration create_client_service_table
public function up(): void
{
Schema::create('client_service', function (Blueprint $table) {
$table->id();
$table->foreignId('client_id')->constrained()->onDelete('cascade');
$table->foreignId('service_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
}
Migración Client
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up() {
Schema::create('clients', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->string('phone');
$table->timestamps();
});
}
public function down() {
Schema::dropIfExists('clients');
}
};
a
Migración Service
// Migration for services table
return new class extends Migration {
public function up() {
Schema::create('services', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description');
$table->decimal('price', 10, 2);
$table->timestamps();
});
}
public function down() {
Schema::dropIfExists('services');
}
};
Migramos todo.
php artisan migrate
OPCIONAL Poblamos
Si se construye el seeder
php artisan db:seed
RouteList
Peticiones API Cliente
A continuación dejo el verbo, la ruta y el contenido del body para la solicitud
Client Index
GET
http://localhost:8000/api/clients
Client Store
POST
http://localhost:8000/api/clients
{
"name": "name...",
"email": "test@test.com",
"phone": "123456789"
}
Service Store
post
http://localhost:8000/api/services
{
"name": "Analyst",
"description": "Analyst",
"price": "100"
}
Tabla Pivote (2 opciones)
Client-Services-STORE (Tabla Pivote con varios servicios a la vez)
POST http://localhost:8000/api/clients/1/services
{
"services": [1, 2]
}
Client-1Service-STORE (Tabla Pivote con un servicio en cada petición)
POST http://localhost:8000/api/clients/1/services/2
Nada en el body, va en la ruta.
Mejora.
Ampliarlo y probarlo con la autenticación y el login a través de Sanctum
Referencias
Más videos sobre esta temática que pueden ayudar:
- El rincón del ISMA 1 Como CONSTRUIR una REST API con LARAVEL: PHP Curso Completo
- El Rincón del ISMA 2: Cómo construir API desde 0 (clientes / servicios)
- La idea de este proyecto parte de este video 2, pero es un poco lioso y falla en algunas partes.