Какова последовательность действий алгоритма для взаимодействия с внешним сервисом через API?

Как правильно организовать взаимодействие с внешним сервисом в мини CRM на Laravel с использованием шаблонов Blade? В данной CRM предусмотрено создание и редактирование заявок от клиентов, изменение их статуса и выполнение множества других функций с учетом различных ролей. 

Нужно наладить отправку данных в сторонний сервис (например, 1С) при изменении или добавлении информации. В какой момент следует отправлять запрос: сразу в контроллере после успешного сохранения данных в локальной базе? Следует ли интегрировать вызов API стороннего сервиса в каждый контроллер для выполнения различных действий? Какова лучшая практика в этом случае?
  • 10 сентября 2024 г. 17:43
Ответы на вопрос 2
Взаимодействие с внешним сервисом через API в вашем случае может быть организовано следующим образом:

### 1. Определение момента для отправки данных
В идеале отправка данных в сторонний сервис (например, 1С) должна происходить в момент, когда данные уже успешно сохранены в локальной базе данных. Это может быть сделано либо в самом контроллере, либо в виде отдельного события, на которое можно подписаться.

### 2. Использование событий и слушателей
Один из лучших способов организации подобной интеграции — использование событий в Laravel. Вы можете создать событие, которое будет триггериться при создании или обновлении заявки, а затем назначить слушателя, который будет выполнять вызов API внешнего сервиса. Это позволит вам отделить логику взаимодействия с API от логики контроллера:

1. **Создание события**: Сначала создайте событие, которое будет содержать информацию о заявке.
   
   ```php
   // app/Events/RequestUpdated.php
   namespace App\Events;

   use App\Models\Request;
   use Illuminate\Foundation\Events\Dispatchable;

   class RequestUpdated
   {
       use Dispatchable;

       public $request;

       public function __construct(Request $request)
       {
           $this->request = $request;
       }
   }
   ```

2. **Создание слушателя**: Теперь создайте слушателя, который будет обрабатывать это событие и выполнять API вызовы.

   ```php
   // app/Listeners/SendRequestToExternalService.php
   namespace App\Listeners;

   use App\Events\RequestUpdated;
   use Illuminate\Support\Facades\Http;

   class SendRequestToExternalService
   {
       public function handle(RequestUpdated $event)
       {
           // Получение данных из модели
           $data = $event->request->toArray();

           // Отправка запроса к внешнему сервису
           Http::post('https://example.com/api/endpoint', $data);
       }
   }
   ```

3. **Регистрация события и слушателя**: Зарегистрируйте событие и слушателя в вашем `EventServiceProvider`.

   ```php
   // app/Providers/EventServiceProvider.php
   namespace App\Providers;

   use App\Events\RequestUpdated;
   use App\Listeners\SendRequestToExternalService;
   use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

   class EventServiceProvider extends ServiceProvider
   {
       protected $listen = [
           RequestUpdated::class => [
               SendRequestToExternalService::class,
           ],
       ];
   }
   ```

### 3. Вызов события в контроллере
Теперь в вашем контроллере вы можете просто вызывать это событие после успешного сохранения данных:

```php
// Controller
use App\Events\RequestUpdated;

public function store(Request $request)
{
    $validatedData = $request->validate([
        // валидация данных
    ]);

    $requestModel = Request::create($validatedData);

    // Вызываем событие
    event(new RequestUpdated($requestModel));

    return redirect()->route('requests.index')->with('success', 'Request created successfully.');
}
```

### 4. Обработка ошибок при взаимодействии с API
Также важно обрабатывать возможные ошибки при отправке данных на внешний сервис. Вы можете использовать блоки `try-catch` в вашем слушателе, а также обрабатывать неуспешные HTTP-запросы (например, логирование или повторные попытки отправки).

### 5. Организация кода
Чтобы избежать дублирования кода, вы можете создать отдельный сервисный класс для взаимодействия с API, который будет использоваться в вашем слушателе, например, `ExternalServiceApi`, который будет инкапсулировать логику взаимодействия с API.

### Резюме
Лучшей практикой для интеграции с внешним API является использование событий и слушателей, что позволяет разделить логику и упростить поддержку кода. Вызывайте события после успешного сохранения данных в базе, чтобы гарантировать, что только корректные данные передаются во внешний сервис.
Все зависит от того, что вам нужно. Если нужно отправлять запрос немедленно, то пихаете отправку запроса везде, где вам нужно что-то отправлять, если когда это произойдет неважно, то везде пихаете постановку отправки в очередь, а обработчик очереди отправит запрос уже потом, когда до него доберется. 
Пихать конечно же надо везде, где это должно происходить: должно в куче контроллеров, значит пихаете нужный вызов в кучу контроллеров, только в одном - пихаете только в него.
Естественно, отправка запроса или постановка в очередь должна быть вызовом нужного метода отдельного класса, а не повторяемой везде последовательности некоторого количества строк, реализующих необходимое действие. Но, если все ваши контроллеры являются потомками одного общего предка, то можно описать этот метод в нем. Для работы с очередями, кстати, в Laravel есть все необходимое.
Похожие вопросы