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

Powerful, extensible PHP gRPC client with a simple Guzzle-like API. Supports standalone use or Spiral integration, configurable via DTOs, includes common interceptors (timeouts, retries) and dedicated exceptions. 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
    

    Enable the extension in php.ini:

    extension=grpc.so
    
  2. Generate gRPC service interfaces (if not already done): Use protoc with the protoc-gen-php-grpc plugin to generate PHP interfaces from .proto files. Example:

    protoc --php_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_php_plugin` path/to/service.proto
    
  3. 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);
    
  4. Integrate with Spiral Framework: Add the bootloader to Kernel.php:

    protected const LOAD = [
        // ...
        \Spiral\Grpc\Client\Bridge\GrpcClientBootloader::class,
    ];
    

First Use Case: Calling a gRPC Service

  1. Define a request DTO (auto-generated by protoc):

    $request = (new \GRPC\MyService\SendMailRequest())
        ->setEmail('user@example.com')
        ->setSubject('Hello')
        ->setMessage('Test message');
    
  2. Create a context (for metadata/headers):

    use Spiral\Grpc\Client\Interceptor\Helper;
    $ctx = Helper::withMetadata(new \Spiral\RoadRunner\GRPC\Context([]), [
        'x-custom-header' => ['value'],
    ]);
    
  3. Invoke the service method:

    $response = $service->sendMail($ctx, $request);
    
  4. Handle the response:

    if ($response->getSuccess()) {
        // Success logic
    } else {
        // Error handling (e.g., check $response->getError())
    }
    

Implementation Patterns

1. Configuration-Driven Setup

Use GrpcClientConfig for centralized configuration (recommended for Spiral apps):

use Spiral\Grpc\Client\Config\GrpcClientConfig;
use Spiral\Grpc\Client\Config\ServiceConfig;
use Spiral\Grpc\Client\Interceptor\SetTimeoutInterceptor;

$config = new GrpcClientConfig(
    interceptors: [SetTimeoutInterceptor::createConfig(5_000)],
    services: [
        new ServiceConfig(
            connections: ['service1:9001', 'service2:9001'],
            interfaces: [\GRPC\MyService\MailSenderInterface::class],
        ),
    ],
);

Register in Spiral:

// In a bootloader or config file
$container->bind(GrpcClientInterface::class, fn() => new GrpcClient($config));

2. Service Client Provider

For dependency injection (e.g., in Spiral):

use Spiral\Grpc\Client\ServiceClientProvider;

$provider = new ServiceClientProvider($container, $config);
$mailSender = $provider->get(\GRPC\MyService\MailSenderInterface::class);

Usage in a service:

final class MailService {
    public function __construct(
        private \GRPC\MyService\MailSenderInterface $mailSender,
    ) {}

    public function send(string $email): bool {
        $request = (new \GRPC\MyService\SendMailRequest())->setEmail($email);
        return $this->mailSender->sendMail(new \Spiral\RoadRunner\GRPC\Context([]), $request)->getSuccess();
    }
}

3. Interceptors for Cross-Cutting Concerns

Add interceptors for logging, retries, auth, etc.:

$client = GrpcClient::create('localhost:9001')
    ->withInterceptors([
        SetTimeoutInterceptor::createConfig(10_000),
        RetryInterceptor::createConfig(maximumAttempts: 3),
        new AuthInterceptor($authToken), // Custom interceptor
    ]);

Custom Interceptor Example:

use Spiral\Grpc\Client\Interceptor\InterceptorInterface;
use Spiral\Grpc\Client\Interceptor\Helper;

final class AuthInterceptor implements InterceptorInterface {
    public function __construct(private string $token) {}

    public function intercept(CallContextInterface $context, HandlerInterface $handler): mixed {
        $metadata = Helper::withMetadata($context, ['authorization' => [$this->token]]);
        return $handler->handle($metadata);
    }
}

4. TLS/SSL Configuration

Secure connections with TlsConfig:

use Spiral\Grpc\Client\Config\ConnectionConfig;
use Spiral\Grpc\Client\Config\TlsConfig;

$config = new ConnectionConfig(
    'secure-service:9001',
    tls: new TlsConfig(
        certChain: '/path/to/cert.pem',
        privateKey: '/path/to/key.pem',
    ),
);

5. Failover and Load Balancing

Use multiple connections with interceptors like ConnectionsRotationInterceptor:

$client = GrpcClient::create([
    'service1:9001',
    'service2:9001',
])->withInterceptors([
    ConnectionsRotationInterceptor::createConfig(),
]);

6. Streaming RPCs

Handle server/client streaming:

// Client streaming
$stream = $client->service(\GRPC\StreamingService\ClientStreamerInterface::class);
$stream->send($request1);
$stream->send($request2);
$stream->finish();
$response = $stream->recv();

// Server streaming
$responseStream = $service->streamData($ctx, $request);
foreach ($responseStream as $response) {
    // Process each response
}

7. Error Handling

Use gRPC-specific exceptions:

try {
    $response = $service->sendMail($ctx, $request);
} catch (\GRPC\Exception $e) {
    if ($e->getCode() === \GRPC\STATUS_UNAVAILABLE) {
        // Retry or fallback logic
    }
    throw new \RuntimeException('gRPC call failed', 0, $e);
}

Gotchas and Tips

Pitfalls

  1. Missing gRPC Extension:

    • Error: Class 'GRPC\ChannelCredentials' not found.
    • Fix: Install the PECL extension (pecl install grpc) and enable it in php.ini.
  2. Protobuf Generation Issues:

    • Error: Generated interfaces don’t match the service.
    • Fix: Ensure protoc is run with the correct plugins:
      protoc --php_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_php_plugin` service.proto
      
  3. Interceptor Order Matters:

    • Gotcha: Timeouts or retries configured later may override earlier ones.
    • Fix: Place SetTimeoutInterceptor before RetryInterceptor to avoid infinite retries.
  4. Stateful Interceptors:

    • Gotcha: Interceptors are recreated per request; avoid storing state in class properties unless scoped.
    • Fix: Use request-scoped dependencies or pass data via CallContext.
  5. TLS Certificate Paths:

    • Gotcha: Absolute paths in TlsConfig may break in Docker/containerized environments.
    • Fix: Use relative paths or environment variables:
      new TlsConfig(
          certChain: getenv('GRPC_CERT_PATH'),
          privateKey: getenv('GRPC_KEY_PATH'),
      );
      
  6. Context Propagation:

    • Gotcha: Metadata set in one interceptor may be lost if not explicitly passed to HandlerInterface.
    • Fix: Use Helper::withMetadata() to propagate context:
      $handler->handle(Helper::withMetadata($context, $updatedMetadata));
      
  7. Service Interface Mismatch:

    • Gotcha: Using a raw GRPC\Channel instead of the generated interface.
    • Fix: Always use the auto-generated interface (e.g., \GRPC\MyService\MailSenderInterface).

Debugging Tips

  1. Enable gRPC Logging: Add to php.ini:

    grpc.verbose_logging = 1
    

    Or set via code:

    \GRPC\Channel::setDefaultOptions([
        'grpc.default_metadata' => [['grpc-log-level', ['debug']]],
    ]);
    
  2. Inspect Metadata: Use Helper::getMetadata() to debug headers:

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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope