Què és un Data Transfer Object (DTO)?
Un Data Transfer Object (DTO) és un objecte simple que encapsula dades i les transporta entre processos. Els DTO s'utilitzen per transferir dades entre subsistemes d'aplicacions de programari. No s'espera que continguin cap lògica de negoci, sinó només camps per emmagatzemar dades i getters/setters simples.
Per què utilitzar DTOs en APIs REST de Laravel?
1. Millora de la Llegibilitat i Mantenibilitat del Codi
Els DTO proporcionen un contracte clar per a les estructures de dades, fent que el teu codi sigui més llegible. Definixen exactament quines dades s'esperen, reduint l'ambigüitat i facilitant el manteniment.
2. Desacoblament entre Capes
Mitjançant l'ús de DTOs, desacobles les capes de la teva aplicació (per exemple, Controladors, Serveis, Repositoris). Aquesta separació de responsabilitats permet un codi més flexible que és més fàcil de provar i modificar.
3. Millora de la Validació de Dades
Els DTOs es poden utilitzar per validar dades en el moment de la seva construcció, assegurant que només dades vàlides es desplacin pel sistema. Això condueix a aplicacions més robustes.
4. Beneficis de Seguretat
Els DTOs ajuden a prevenir atacs d'over-posting permetent-te especificar exactament quines propietats poden ser configurades, en comptes d'acceptar tota l'entrada de l'usuari directament als teus models.
Integració de DTOs amb Models a Laravel
A Laravel, els models representen les dades de la teva base de dades. Quan utilitzes DTOs, crees una capa entre els teus models i controladors. Aquí tens com pots relacionar els DTOs amb els models:
- Mapeig de Dades: Mapeja les dades del teu DTO als atributs del teu model.
- Mètodes de Conversió: Implementa mètodes al teu DTO per convertir a i des d'instàncies de models.
- Patró de Repositori: Utilitza repositoris per gestionar operacions de dades, acceptant DTOs com a paràmetres.
Utilitzant Spatie\DataTransferObject
Spatie\DataTransferObject és un paquet que proporciona una forma convenient de crear DTOs en PHP.
Instal·lació
composer require spatie/data-transfer-object
Definint un DTO
use Spatie\DataTransferObject\DataTransferObject;
class UserData extends DataTransferObject
{
public string $name;
public string $email;
public string $password;
}
Utilitzant el DTO en un Controlador
use App\DTOs\UserData;
public function store(Request $request)
{
$userData = new UserData($request->all());
// Pass the DTO to a service or repository
$this->userService->createUser($userData);
return response()->json(['message' => 'User created successfully.']);
}
Relacionant DTOs amb Models
use App\Models\User;
class UserService
{
public function createUser(UserData $userData)
{
$user = new User();
$user->name = $userData->name;
$user->email = $userData->email;
$user->password = bcrypt($userData->password);
$user->save();
return $user;
}
}
Per què l'ús de Models i DTOs no és redundant
Molts desenvolupadors poden pensar que l'ús tant de models com de DTOs és redundant perquè ambdós tracten amb estructures de dades. Tanmateix, compleixen propòsits diferents dins d'una aplicació:
- Models: Representen l'estructura de dades de la teva base de dades i gestionen la persistència de dades, les relacions i la lògica de negoci relacionada amb l'emmagatzematge de dades.
- DTOs: Són objectes simples utilitzats per transferir dades entre les capes de la teva aplicació o a clients externs. Poden incloure camps calculats o dades de serveis externs que poden no formar part de l'esquema de la teva base de dades.
Separant aquestes responsabilitats, aconsegueixes:
- Flexibilitat en la Representació de Dades: Els DTOs poden incloure només les dades necessàries per a una operació específica, incloent camps calculats i dades d'altres serveis.
- Millora de la Mantenibilitat: Els canvis en l'esquema de la teva base de dades no afecten directament als DTOs utilitzats per a les respostes de l'API o la lògica de negoci.
- Millora de la Seguretat i Control de Dades: Els DTOs et permeten especificar exactament quines propietats s'exposen, evitant fuites de dades no intencionades.
Exemple: Entitat de Logística amb Camps Calculats
Escenari:
Suposa que tens un model d'Enviament que representa els enviaments a la teva base de dades amb camps com id, origen, destinació, pes i data de creació. Quan tornes dades als clients o a altres parts de la teva aplicació, necessites incloure informació addicional com:
- Temps Estimat de Lliurament: Un camp calculat basat en l'origen, la destinació i la data actual.
- Estat Actual de l'Enviament: Informació obtinguda d'un servei de seguiment extern.
- Cost d'Enviament: Calculat en funció del pes i la distància.
Implementació de Models i DTOs Junts
1. Model d'Enviament
class Shipment extends Model
{
protected $fillable = ['origin', 'destination', 'weight', 'created_at'];
}
2. ShipmentData DTO
use Spatie\DataTransferObject\DataTransferObject;
class ShipmentData extends DataTransferObject
{
public int $id;
public string $origin;
public string $destination;
public float $weight;
public string $estimated_delivery_time;
public string $current_tracking_status;
public float $shipping_cost;
}
3. Utilitzant el DTO en un Controlador
use App\Models\Shipment;
use App\DTOs\ShipmentData;
use App\Services\ShippingService;
use App\Services\TrackingService;
public function show($id)
{
$shipment = Shipment::findOrFail($id);
// Calculate the estimated delivery time
$estimatedDeliveryTime = ShippingService::calculateEstimatedDeliveryTime(
$shipment->origin,
$shipment->destination
);
// Get the current tracking status from an external service
$currentTrackingStatus = TrackingService::getCurrentStatus($shipment->id);
// Calculate the shipping cost
$shippingCost = ShippingService::calculateShippingCost(
$shipment->weight,
$shipment->origin,
$shipment->destination
);
// Create the DTO
$shipmentData = new ShipmentData([
'id' => $shipment->id,
'origin' => $shipment->origin,
'destination' => $shipment->destination,
'weight' => $shipment->weight,
'estimated_delivery_time' => $estimatedDeliveryTime,
'current_tracking_status' => $currentTrackingStatus,
'shipping_cost' => $shippingCost,
]);
return response()->json($shipmentData);
}
Explicació:
- Model: Gestiona la recuperació de dades i les interaccions amb la base de dades.
- DTO: Combina dades del model, camps calculats i dades de serveis externs en un sol objecte per a la seva transferència.
Beneficis d’aquest Enfocament:
- Separació de Responsabilitats: Els models i els DTOs tenen rols distintius, cosa que condueix a un codi més net.
- Mantenibilitat: Els canvis en la lògica de càlcul o en serveis externs no afecten directament els models de la teva base de dades.
- Control de Dades: Tens control explícit sobre quines dades s'exposen al client.
- Reutilització de Codi: Els DTOs es poden reutilitzar en diferents parts de l'aplicació o punts finals de l'API.
Avantatges d'utilitzar Spatie\DataTransferObject
- Seguretat de Tipus: Garanteix que els tipus de dades de les propietats siguin els esperats.
- Objectes Inmutables: Els DTOs són inmutables per defecte, prevenint efectes secundaris no intencionats.
- Validació Automàtica: Valida les dades en el moment de la creació de l'objecte.
Millors pràctiques
- Mantén els DTOs Simples: Només haurien de contenir propietats i mètodes simples com els getters.
- Utilitza DTOs tant per a Entrada com per a Sortida: Considera utilitzar DTOs separats per a les dades de sol·licitud i les dades de resposta.
- Versiona els Teus DTOs: En crear APIs, versiona els teus DTOs per gestionar canvis al llarg del temps.
Conclusió
Incorporar patrons DTO a la teva API REST de Laravel pot millorar significativament l'estructura i la mantenibilitat de la teva aplicació. Al desacoblar les teves capes i proporcionar contractes de dades clars, fas que la teva base de codi sigui més robusta i fàcil de treballar. Eines com Spatie\DataTransferObject agilitzen aquest procés, oferint beneficis addicionals com la seguretat de tipus i la validació automàtica.
Paraules Clau: Laravel, DTO, Data Transfer Object, REST API, Spatie\DataTransferObject, Estructura de Codi, Mantenibilitat, Models, PHP, Desenvolupament Web
En implementar DTOs als teus projectes de Laravel, no només estàs seguint una millor pràctica, sinó que també estàs preparant la teva aplicació per al èxit futur. Si has trobat útil aquest article, considera compartir-lo amb els teus companys desenvolupadors!