Simplifier l’intégration d’API externes dans Laravel avec les modules de service

24 juin 2025 3 min
Structurer ses appels API dans Laravel, c’est éviter les pièges classiques : duplication de code, logique planquée dans les contrôleurs, tests impossibles… Avec les modules de service, chaque intégration devient claire, testable et réutilisable.

L’intégration de services externes, publics ou privés, via des API est une tâche courante dans le développement Laravel. Si elle paraît simple au départ, cette intégration peut rapidement devenir difficile à maintenir, à tester, et à faire évoluer proprement sans une architecture claire.

Pour remédier à cela, l’approche des modules de service propose une structure modulaire, réutilisable et testable, s’appuyant sur des patterns éprouvés (Repository, Factory, DTO) et des bonnes pratiques Laravel.

Problème courant : une intégration directe dans les contrôleurs

Prenons l’exemple d’un service météo interrogé via une API. Il est fréquent de voir l’appel direct à l’API réalisé dans le contrôleur :


namespace App\\Http\\Controllers;

use Illuminate\\Support\\Facades\\Http;

class WeatherController extends Controller
{
    public function getWeather($city)
    {
        $response = Http::get('<https://api.weatherapi.com/v1/current.json>', [
            'key' => config('services.weatherapi.key'),
            'q' => $city,
        ]);

        if ($response->failed()) {
            return response()->json(['error' => 'Impossible de récupérer les données météo'], 500);
        }

        $weather = $response->json();
        return response()->json([
            'city' => $weather['location']['name'],
            'temperature' => $weather['current']['temp_c'],
            'condition' => $weather['current']['condition']['text']
        ]);
    }
}

Bien que fonctionnelle, cette approche présente plusieurs limites :

  • Duplication de la logique : en cas de réutilisation ailleurs, le code est copié, multipliant les points de rupture possibles.
  • Couplage fort : les contrôleurs dépendent directement de l’API.
  • Tests difficiles : le test unitaire nécessite de simuler l’appel HTTP à chaque fois.
  • Absence d’abstraction : aucune structuration claire des données retournées.
  • Gestion des erreurs dispersée : chaque point d’appel nécessite une logique d’erreur propre.

Étape 1 : structuration du service

La création d’un dossier Services dans app/ permet de regrouper la logique métier liée à un service externe. Chaque service (ex. Weather) peut contenir :

  • Repositories : logique métier et appels externes
  • DTOs : structure des données
  • Facades : points d’entrée simplifiés
  • Providers : injection de dépendances
  • Exceptions : gestion d’erreurs dédiée

Étape 2 : le Repository

Ce composant centralise la logique d’appel à l’API.


namespace App\\Services\\Weather\\Repositories;

use Illuminate\\Support\\Facades\\Http;

class WeatherRepository
{
    public function getCurrentWeather($city)
    {
        $response = Http::get('<https://api.weatherapi.com/v1/current.json>', [
            'key' => config('services.weatherapi.key'),
            'q' => $city,
        ]);

        if ($response->failed()) {
            throw new \\Exception('Impossible de récupérer les données météo');
        }

        return $response->json();
    }
}

Étape 3 : le DTO (Data Transfer Object)

Le DTO permet de manipuler les données de manière structurée.


namespace App\\Services\\Weather\\DTOs;

class WeatherData
{
    public $city;
    public $temperature;
    public $condition;

    public function __construct(array $data)
    {
        $this->city = $data['location']['name'];
        $this->temperature = $data['current']['temp_c'];
        $this->condition = $data['current']['condition']['text'];
    }
}

Étape 4 : l’Exception personnalisé

Permet de centraliser la gestion des erreurs spécifiques à un service.


namespace App\\Services\\Weather\\Exceptions;

use Exception;

class WeatherServiceException extends Exception
{
    //
}

Étape 5 : le Service Provide

Configure l’injection du repository dans le conteneur de services Laravel.


namespace App\\Services\\Weather\\Providers;

use Illuminate\\Support\\ServiceProvider;
use App\\Services\\Weather\\Repositories\\WeatherRepository;

class WeatherServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(WeatherRepository::class, function ($app) {
            return new WeatherRepository();
        });
    }
}

Étape 6 : la Facade

Fournit une interface simple pour accéder au service.


namespace App\\Services\\Weather\\Facades;

use Illuminate\\Support\\Facades\\Facade;

class Weather extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'App\\Services\\Weather\\Repositories\\WeatherRepository';
    }
}

Étape 7 : utilisation dans un contrôleur

Avec tous les composants en place, l’appel dans le contrôleur est propre, simple et testable :


namespace App\\Http\\Controllers;

use App\\Services\\Weather\\Facades\\Weather;
use App\\Services\\Weather\\DTOs\\WeatherData;

class WeatherController extends Controller
{
    public function getWeather($city)
    {
        try {
            $data = Weather::getCurrentWeather($city);
            $weather = new WeatherData($data);

            return response()->json([
                'city' => $weather->city,
                'temperature' => $weather->temperature,
                'condition' => $weather->condition
            ]);
        } catch (\\Exception $e) {
            return response()->json(['error' => 'Impossible de récupérer les données météo'], 500);
        }
    }
}

Pour aller plus loin

Afin d’accélérer la mise en place de cette architecture, un package Laravel est disponible :

bash
CopierModifier
composer require shreifelagamy/laravel-service-modules

Ce package permet de générer automatiquement la structure complète d’un module de service via des commandes Artisan.

Merci de votre lecture 😎

Ecrit par
Alyson Paya

Partager l'article :

Vous avez un projet ?

Un site vitrine ? e-commerce ? une application ?

Contactez-nous

Découvrez les derniers articles

Tout voir