Skip to content

Example API Integration

Jean-Marc Strauven edited this page Aug 6, 2025 · 1 revision

🌐 Example: API Integration

A comprehensive real-world example showing how to use Laravel Arc DTOs in modern API controllers with behavioral traits and validation.

Complete API Controller Example

This example is based on the actual code from examples/modern-api-controller-example.php:

<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api;

use App\DTO\UserDTO;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;

final class UserController extends Controller
{
    /**
     * Display a listing of users with DTO transformation
     */
    public function index(Request $request): JsonResponse
    {
        $users = User::query()
            ->when($request->search, function ($query, $search) {
                $query->where('name', 'like', "%{$search}%")
                    ->orWhere('email', 'like', "%{$search}%");
            })
            ->when($request->status, function ($query, $status) {
                $query->where('status', $status);
            })
            ->paginate($request->per_page ?? 15);

        // Transform to DTOs with behavioral traits
        $userDtos = $users->getCollection()->map(function ($user) {
            return UserDTO::fromModel($user);
        });

        return response()->json([
            'data' => $userDtos,
            'pagination' => [
                'current_page' => $users->currentPage(),
                'last_page' => $users->lastPage(),
                'per_page' => $users->perPage(),
                'total' => $users->total(),
            ],
        ]);
    }

    /**
     * Store a newly created user with comprehensive validation
     */
    public function store(Request $request): JsonResponse
    {
        // Use ValidatesData trait for validation
        if (UserDTO::fails($request->all())) {
            return response()->json([
                'message' => 'Validation failed',
                'errors' => UserDTO::validator($request->all())->errors(),
            ], 422);
        }

        // Create user with validated data
        $validated = UserDTO::validate($request->all());
        $user = User::create($validated);

        // Convert to DTO and demonstrate behavioral traits
        $userDto = UserDTO::fromModel($user);

        // Use HasTagging trait if available
        if (method_exists($userDto, 'addTag')) {
            $userDto = $userDto->addTag('new_user');
        }

        // Use HasAuditing trait if available
        if (method_exists($userDto, 'setCreator')) {
            $userDto = $userDto->setCreator(auth()->id());
        }

        return response()->json([
            'message' => 'User created successfully',
            'user' => $userDto->toArray(),
        ], 201);
    }

    /**
     * Display the specified user
     */
    public function show(User $user): JsonResponse
    {
        $userDto = UserDTO::fromModel($user);

        return response()->json([
            'user' => $userDto->toArray(),
        ]);
    }

    /**
     * Update the specified user
     */
    public function update(Request $request, User $user): JsonResponse
    {
        // Validate with DTO
        $validated = UserDTO::validate($request->all());
        
        // Update model
        $user->update($validated);
        
        // Convert to DTO
        $userDto = UserDTO::fromModel($user->fresh());
        
        // Use HasTimestamps trait
        if (method_exists($userDto, 'touch')) {
            $userDto->touch(); // Updates updated_at
        }

        return response()->json([
            'message' => 'User updated successfully',
            'user' => $userDto->toArray(),
        ]);
    }

    /**
     * Remove the specified user (soft delete)
     */
    public function destroy(User $user): JsonResponse
    {
        $userDto = UserDTO::fromModel($user);
        
        // Soft delete the user
        $user->delete();
        
        return response()->json([
            'message' => 'User deleted successfully',
            'user' => $userDto->toArray(),
        ]);
    }
}

YAML Definition for API Example

The corresponding YAML definition (examples/user.yaml):

# API User DTO with behavioral traits
header:
  dto: UserDTO
  table: users
  model: App\Models\User
  namespace: App\DTO
  traits:
    - HasUuid
    - HasTimestamps
    - ValidatesData
    - ConvertsData
  use:
    - App\DTO\ProfileDTO

fields:
  name:
    type: string
    required: true
    validation: [required, string, min:2, max:100]
    transformers: [trim, title_case]
  
  email:
    type: string
    required: true
    validation: [required, email, unique:users]
    transformers: [trim, lowercase]
  
  email_verified_at:
    type: datetime
    required: false
    validation: [nullable, date]
  
  status:
    type: string
    required: false
    validation: [nullable, in:active,inactive,pending]
    default: "active"
  
  # Profile as nested DTO
  profile:
    type: dto
    dto: ProfileDTO
    required: false

relations:
  posts:
    type: hasMany
    target: App\Models\Post
  
  roles:
    type: belongsToMany
    target: App\Models\Role

Key Benefits in API Controllers

1. Automatic Validation

// Instead of manual validation rules
$request->validate([
    'name' => 'required|string|min:2|max:100',
    'email' => 'required|email|unique:users',
]);

// Use DTO validation
if (UserDTO::fails($request->all())) {
    return response()->json([
        'errors' => UserDTO::validator($request->all())->errors(),
    ], 422);
}

2. Consistent Data Transformation

// DTOs ensure consistent output format
return response()->json([
    'user' => $userDto->toArray(), // Always consistent structure
]);

3. Type Safety

// Type-safe property access
$userName = $userDto->name;      // string
$userEmail = $userDto->email;    // string
$verified = $userDto->email_verified_at; // ?DateTime

4. Behavioral Traits Usage

// Use behavioral traits methods
if (method_exists($userDto, 'wasRecentlyCreated')) {
    $isNew = $userDto->wasRecentlyCreated(); // boolean
}

if (method_exists($userDto, 'touch')) {
    $userDto->touch(); // Updates timestamp
}

Advanced API Patterns

Bulk Operations

public function bulkStore(Request $request): JsonResponse
{
    $users = collect($request->users)->map(function ($userData) {
        // Validate each user
        $validated = UserDTO::validate($userData);
        $user = User::create($validated);
        return UserDTO::fromModel($user);
    });

    return response()->json([
        'message' => 'Users created successfully',
        'users' => $users->toArray(),
        'count' => $users->count(),
    ], 201);
}

Search and Filtering

public function search(Request $request): JsonResponse
{
    $users = User::query()
        ->when($request->name, fn($q, $name) => 
            $q->where('name', 'like', "%{$name}%"))
        ->when($request->email, fn($q, $email) => 
            $q->where('email', 'like', "%{$email}%"))
        ->when($request->status, fn($q, $status) => 
            $q->where('status', $status))
        ->get();

    $userDtos = $users->map(fn($user) => UserDTO::fromModel($user));

    return response()->json([
        'users' => $userDtos->toArray(),
        'total' => $userDtos->count(),
    ]);
}

Export Functionality

public function export(Request $request): JsonResponse
{
    $users = User::all();
    $userDtos = $users->map(fn($user) => UserDTO::fromModel($user));

    // Use DTO export capabilities
    $format = $request->format ?? 'json';
    
    switch ($format) {
        case 'csv':
            $content = $userDtos->toCsv();
            break;
        case 'xml':
            $content = $userDtos->toXml();
            break;
        default:
            $content = $userDtos->toJson();
    }

    return response($content)
        ->header('Content-Type', "application/{$format}")
        ->header('Content-Disposition', "attachment; filename=users.{$format}");
}

Routes Configuration

// routes/api.php
Route::apiResource('users', UserController::class);
Route::post('users/bulk', [UserController::class, 'bulkStore']);
Route::get('users/search', [UserController::class, 'search']);
Route::get('users/export', [UserController::class, 'export']);

Testing the API

Using the API

# Create user
curl -X POST /api/users \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Doe",
    "email": "[email protected]",
    "status": "active"
  }'

# Get user
curl -X GET /api/users/1

# Search users
curl -X GET "/api/users/search?name=John&status=active"

# Export users as CSV
curl -X GET "/api/users/export?format=csv"

Expected Response Format

{
  "user": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "name": "John Doe",
    "email": "[email protected]",
    "email_verified_at": null,
    "status": "active",
    "created_at": "2024-01-15T10:30:00Z",
    "updated_at": "2024-01-15T10:30:00Z",
    "profile": null
  }
}

Error Handling

public function store(Request $request): JsonResponse
{
    try {
        // Validate with DTO
        $validated = UserDTO::validate($request->all());
        
        // Create user
        $user = User::create($validated);
        $userDto = UserDTO::fromModel($user);
        
        return response()->json([
            'message' => 'User created successfully',
            'user' => $userDto->toArray(),
        ], 201);
        
    } catch (ValidationException $e) {
        return response()->json([
            'message' => 'Validation failed',
            'errors' => $e->errors(),
        ], 422);
        
    } catch (\Exception $e) {
        return response()->json([
            'message' => 'Server error',
            'error' => $e->getMessage(),
        ], 500);
    }
}

What's Next?

This example shows Laravel Arc in a real API context. Explore more:


This real-world example demonstrates how Laravel Arc DTOs provide type safety, validation, and consistency in modern API development. 🌐

πŸš€ Laravel Arc Wiki

🏠 Home

πŸš€ Getting Started

πŸ“š Core Concepts

πŸ—οΈ Advanced Features

βš™οΈ Configuration & CLI

🌐 Real-World Examples


🎯 Key Concepts

YAML β†’ DTO β†’ Type-Safe Code

Laravel Arc transforms your YAML definitions into powerful PHP DTOs with automatic validation, field transformers, and behavioral traits.

πŸ”— Quick Links

Clone this wiki locally