Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Grpc Client Laravel Package

spiral/grpc-client

Lightweight, extensible PHP gRPC client with a Guzzle-like API. Supports standalone use or Spiral integration, configurable via DTOs, includes interceptors (timeouts, retries), and rich exceptions for error handling. Requires the PHP gRPC extension.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package and PHP gRPC extension:

    composer require spiral/grpc-client -W
    pecl install grpc
    

    Verify the extension is loaded in php.ini or via php -m | grep grpc.

  2. Basic client usage (standalone):

    use Spiral\Grpc\Client\GrpcClient;
    
    $client = GrpcClient::create('localhost:9001');
    $service = $client->service(\GRPC\MyService\MailSenderInterface::class);
    $response = $service->sendMail($ctx, $request);
    
  3. Laravel integration:

    • Register the bootloader in app/Providers/AppServiceProvider.php:
      public function boot(): void
      {
          if (!app()->has(\Spiral\Grpc\Client\Bridge\GrpcClientBootloader::class)) {
              app()->register(\Spiral\Grpc\Client\Bridge\GrpcClientBootloader::class);
          }
      }
      
    • Resolve services via Laravel’s container:
      $mailSender = app()->make(\GRPC\MyService\MailSenderInterface::class);
      

First Use Case: Calling a gRPC Service

  • Generate gRPC stubs (if not already done):
    protoc --php_out=. --grpc_out=. -I=. my_service.proto
    
  • Invoke a method:
    $request = (new \GRPC\MyService\SendMailRequest())
        ->setEmail('user@example.com')
        ->setSubject('Hello')
        ->setMessage('Test');
    
    $response = $mailSender->sendMail(new \Spiral\Grpc\Client\Context([]), $request);
    

Implementation Patterns

1. Configuration via DTOs

Use GrpcClientConfig for centralized setup (e.g., in config/grpc.php):

return [
    'services' => [
        'mail' => new \Spiral\Grpc\Client\Config\ServiceConfig(
            connections: new \Spiral\Grpc\Client\Config\ConnectionConfig('mail-service:9001'),
            interfaces: [\GRPC\MyService\MailSenderInterface::class],
            interceptors: [
                \Spiral\Grpc\Client\Interceptor\SetTimeoutInterceptor::createConfig(5_000),
            ],
        ),
    ],
    'interceptors' => [
        \Spiral\Grpc\Client\Interceptor\RetryInterceptor::createConfig(
            maximumAttempts: 3,
            initialInterval: 100,
        ),
    ],
];

Bind the config to Laravel’s container in a service provider:

$this->app->singleton(\Spiral\Grpc\Client\Config\GrpcClientConfig::class, function ($app) {
    return include __DIR__.'/../config/grpc.php';
});

2. Interceptor Pipeline

Common patterns:

  • Global interceptors (applied to all services):
    $client->withInterceptors([
        SetTimeoutInterceptor::createConfig(10_000),
        RetryInterceptor::createConfig(3),
    ]);
    
  • Service-specific interceptors (via ExecuteServiceInterceptors):
    new GrpcClientConfig(
        interceptors: [ExecuteServiceInterceptors::class],
        services: [
            new ServiceConfig(
                interceptors: [LoggingInterceptor::class],
                // ...
            ),
        ],
    );
    
  • Custom interceptors (e.g., auth, logging):
    final class AuthInterceptor implements InterceptorInterface {
        public function intercept(CallContextInterface $context, HandlerInterface $handler): mixed {
            $metadata = Helper::withMetadata($context);
            $metadata['authorization'] = ['Bearer ' . auth()->token()];
            return $handler->handle(Helper::withMetadata($context, $metadata));
        }
    }
    

3. Connection Management

  • Failover: Use multiple endpoints:
    $client = GrpcClient::create(['primary:9001', 'backup:9001']);
    
  • TLS connections:
    $client = GrpcClient::create(
        new ConnectionConfig('secure-service:9001', tls: new TlsConfig(
            certChain: storage_path('certs/chain.pem'),
            privateKey: storage_path('certs/key.pem'),
        ))
    );
    

4. Laravel-Specific Workflows

  • Dependency Injection:
    class MailService {
        public function __construct(
            private \GRPC\MyService\MailSenderInterface $mailSender,
        ) {}
    }
    
    Register the service in AppServiceProvider:
    $this->app->bind(\GRPC\MyService\MailSenderInterface::class, function ($app) {
        return $app->make(\Spiral\Grpc\Client\ServiceClientProvider::class)
            ->getService(\GRPC\MyService\MailSenderInterface::class);
    });
    
  • Queue jobs for async gRPC calls:
    Dispatch(new SendMailJob($email, $subject, $message));
    
    class SendMailJob implements ShouldQueue {
        public function handle() {
            $mailSender->sendMail($ctx, $request);
        }
    }
    

5. Error Handling

  • Catch gRPC exceptions:
    try {
        $response = $service->sendMail($ctx, $request);
    } catch (\GRPC\RpcException $e) {
        Log::error('gRPC Error: ' . $e->getMessage());
        throw new \RuntimeException('Failed to send mail', 0, $e);
    }
    
  • Custom exceptions:
    throw new \Spiral\Grpc\Client\Exception\GrpcServiceException(
        'Service unavailable',
        $context->getCode(),
        $context->getDetails()
    );
    

Gotchas and Tips

Pitfalls

  1. Missing gRPC Extension:

    • Symptom: Class 'GRPC\ChannelCredentials' not found.
    • Fix: Install the PECL extension (pecl install grpc) and restart PHP.
  2. Protocol Buffer Mismatches:

    • Symptom: Invalid argument: Invalid proto message binary when calling a service.
    • Fix: Ensure the .proto file and generated PHP stubs match the server’s schema. Regenerate stubs if the server’s proto changes:
      protoc --php_out=. --grpc_out=. -I=. updated_service.proto
      
  3. Interceptor Order Matters:

    • Example: Placing RetryInterceptor after SetTimeoutInterceptor overrides the timeout per retry. Reorder interceptors to enforce global timeouts:
      // Correct: Timeout applies to all retries
      $client->withInterceptors([
          SetTimeoutInterceptor::createConfig(10_000),
          RetryInterceptor::createConfig(3),
      ]);
      
  4. Context Leaks:

    • Symptom: Metadata or deadlines set in one interceptor are lost in subsequent calls.
    • Fix: Use Helper::withMetadata() and Helper::withDeadline() to explicitly propagate context:
      $context = Helper::withMetadata($context, ['key' => 'value']);
      
  5. Laravel Container Conflicts:

    • Symptom: BindingResolutionException when resolving gRPC services.
    • Fix: Avoid naming conflicts with Laravel’s built-in bindings. Use explicit aliases:
      $this->app->alias(\GRPC\MyService\MailSenderInterface::class, 'grpc.mail.sender');
      

Debugging Tips

  1. Enable gRPC Logging: Add to php.ini or runtime config:

    grpc.verbose_logging = 1
    grpc.log_level = 3
    

    Logs appear in PHP’s error log or stderr.

  2. Inspect Interceptor Flow: Use a debug interceptor to log context:

    final class DebugInterceptor implements InterceptorInterface {
        public function intercept(CallContextInterface $context, HandlerInterface $handler): mixed {
            Log::debug('Interceptor called', [
                'code' => $context->getCode(),
                'method' => $context->getMethod(),
                'deadline' => $context->getDeadline(),
            ]);
            return $handler->handle($context);
        }
    }
    
  3. Validate Protobuf Messages: Use google/protobuf to validate messages before sending:

    use Google\Protobuf\Internal\Message;
    
    if (!$request->isInitialized()) {
        throw new \InvalidArgumentException('Protobuf message not initialized');
    }
    

Extension Points

  1. Custom Interceptors:
    • Implement InterceptorInterface and add to the pipeline:
      final class CircuitBreakerInterceptor implements InterceptorInterface {
          public
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport