P
imvdmolen.nl
Blog

Hoe ik API-fouten analyseer en oplos met behulp van Laravel's ingebouwde logging functionaliteiten

Gisteren kreeg ik weer eens een API-timeout in productie. Niets ernstigs, maar het herinnerde me eraan hoe cruciaal goede foutenanalyse is. Na 19 jaar ontwikkelen heb ik geleerd dat API-fouten niet alleen opvangen, maar ook systematisch analyseren het verschil maakt tussen een stabiele applicatie en een nachtmerrie in onderhoud. Laravel biedt hiervoor uitstekende tools, en ik ga je laten zien hoe ik ze gebruik in mijn dagelijkse werk.

Logging configureren voor API-integraties

Laravel gebruikt Monolog als onderliggende logging-engine, wat betekent dat ik veel flexibiliteit heb in hoe ik fouten vastleg. Wat ik altijd eerst doe bij een nieuw project is een dedicated log-channel maken voor API-gerelateerde fouten. Dit houdt mijn logs georganiseerd en maakt het debuggen een stuk eenvoudiger.

// config/logging.php
'channels' => [
    'api' => [
        'driver' => 'single',
        'path' => storage_path('logs/api.log'),
        'level' => env('LOG_LEVEL', 'debug'),
    ],
],

Wanneer ik API-calls maak, wrap ik deze altijd in try-catch blokken met specifieke logging. Hierdoor kan ik later precies terugzien wat er misging en wanneer. Het verschil met generieke error-handling is dat ik context meeneem: welke API, welke parameters, en wat de respons was.

try {
    $response = Http::timeout(30)->get('https://api.example.com/data', [
        'api_key' => config('services.example.key'),
        'limit' => 100
    ]);
    
    Log::channel('api')->info('API call successful', [
        'url' => 'https://api.example.com/data',
        'status' => $response->status(),
        'response_time' => $response->handlerStats()['total_time'] ?? null
    ]);
    
} catch (ConnectionException $e) {
    Log::channel('api')->error('API connection failed', [
        'url' => 'https://api.example.com/data',
        'error' => $e->getMessage(),
        'timeout' => 30
    ]);
} catch (RequestException $e) {
    Log::channel('api')->error('API request failed', [
        'url' => 'https://api.example.com/data',
        'status' => $e->response?->status(),
        'response_body' => $e->response?->body(),
        'error' => $e->getMessage()
    ]);
}

Context is alles bij debugging. Ik neem altijd relevante data mee in mijn log-entries: timestamps, user IDs, request parameters en response codes. Dit scheelt me uren zoeken later wanneer er iets misgaat in productie.

Geavanceerde foutenanalyse implementeren

Exception handlers zijn krachtig, maar ik gebruik ze selectief. Voor API-gerelateerde fouten maak ik vaak een dedicated handler die meer doet dan alleen loggen. Deze handler analyseert het type fout en neemt appropriate actie.

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Client\RequestException;

class ApiExceptionHandler extends ExceptionHandler
{
    public function render($request, Throwable $exception)
    {
        if ($exception instanceof RequestException) {
            $statusCode = $exception->response?->status() ?? 500;
            
            Log::channel('api')->error('API exception caught', [
                'exception' => get_class($exception),
                'message' => $exception->getMessage(),
                'status_code' => $statusCode,
                'url' => $request->url(),
                'user_id' => auth()->id(),
                'trace' => $exception->getTraceAsString()
            ]);
            
            // Return user-friendly response
            if ($statusCode >= 500) {
                return response()->json([
                    'error' => 'Service temporarily unavailable'
                ], 503);
            }
            
            return response()->json([
                'error' => 'Request failed'
            ], $statusCode);
        }
        
        return parent::render($request, $exception);
    }
}

Rate limiting is iets waar ik regelmatig mee te maken heb bij API-integraties. Veel externe services hebben strikte limits, en het herkennen van rate limit errors helpt me om automatische retry-logica te implementeren. Ik log deze specifiek anders dan gewone fouten.

Laravel Telescope gebruik ik veel voor lokale development. Het geeft me een visueel overzicht van alle HTTP-requests, inclusief API-calls, en ik kan precies zien waar dingen misgaan. Voor productie gebruik ik echter liever custom dashboard oplossingen of externe monitoring tools zoals Sentry.

Systematische foutoplossing en testing

Testing van API-integraties doe ik op meerdere niveaus. Unit tests voor de logica, feature tests voor de volledige flow, en mock tests voor scenario's die moeilijk te reproduceren zijn. HTTP fake van Laravel is hiervoor onmisbaar.

use Illuminate\Support\Facades\Http;
use Tests\TestCase;

class ApiIntegrationTest extends TestCase
{
    public function test_handles_api_timeout_gracefully()
    {
        Http::fake([
            'api.example.com/*' => Http::response([], 408) // Timeout
        ]);
        
        $response = $this->postJson('/api/sync-data');
        
        $response->assertStatus(503);
        $response->assertJson(['error' => 'Service temporarily unavailable']);
        
        // Verify logging occurred
        $this->assertDatabaseHas('logs', [
            'level' => 'error',
            'message' => 'API request failed'
        ]);
    }
    
    public function test_retries_failed_api_calls()
    {
        Http::fake([
            'api.example.com/*' => Http::sequence()
                ->push([], 500) // First attempt fails
                ->push(['data' => 'success'], 200) // Second succeeds
        ]);
        
        $result = $this->apiService->fetchData();
        
        $this->assertEquals('success', $result['data']);
    }
}

Retry mechanismen implementeer ik meestal handmatig omdat ik volledige controle wil over wanneer en hoe er opnieuw geprobeerd wordt. Exponential backoff is mijn standaard aanpak: eerste retry na 1 seconde, tweede na 2 seconden, derde na 4 seconden, enzovoort.

Circuit breaker patterns gebruik ik voor kritieke API-integraties. Als een service drie keer op rij faalt, schakel ik over naar een fallback-mechanisme of cached data. Dit voorkomt dat mijn applicatie vastloopt door externe afhankelijkheden.

Monitoring is cruciaal voor productie-omgevingen. Ik stel alerts in voor API-error rates boven bepaalde drempelwaarden. Laravel's scheduler gebruik ik om dagelijks log-statistieken te genereren en te emailen naar het team. Dit geeft ons een proactief overzicht van de gezondheid van onze API-integraties.

Performance monitoring doe ik door response times te loggen en trends bij te houden. Langzame API-responses kunnen wijzen op problemen aan de externe kant, maar ook op netwerk-issues of resource-tekorten aan onze kant. Deze data helpt me om proactief optimalisaties door te voeren voordat gebruikers last krijgen van traagheid.