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

Command Laravel Package

guzzlehttp/command

Build higher-level web service clients on top of Guzzle by modeling operations as Commands and responses as Results. Includes a generic ServiceClient plus command middleware to map commands to PSR-7 requests and responses to structured results.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require guzzlehttp/command
    
  2. Basic Client Initialization:

    use GuzzleHttp\Client;
    use GuzzleHttp\Command\ServiceClient;
    
    $httpClient = new Client(['base_uri' => 'https://api.example.com']);
    $serviceClient = new ServiceClient(
        $httpClient,
        fn($command) => new Request('GET', '/api/' . $command->getName()),
        fn($response) => new Result(json_decode($response->getBody(), true))
    );
    
  3. First Use Case: Execute a command with magic methods:

    $result = $serviceClient->users(['limit' => 10]);
    // Access result data via array syntax
    $users = $result['data'];
    

Implementation Patterns

Core Workflow

  1. Command Creation & Execution:

    // Explicit command
    $command = $client->getCommand('users', ['limit' => 10]);
    $result = $client->execute($command);
    
    // Magic method shortcut
    $result = $client->users(['limit' => 10]);
    
  2. Request Customization: Use @http for per-command Guzzle options:

    $result = $client->users([
        'limit' => 10,
        '@http' => ['timeout' => 5.0]
    ]);
    
  3. Asynchronous Execution:

    $promise = $client->usersAsync(['limit' => 10]);
    $promise->then(fn($result) => $this->handleResult($result));
    

Integration Tips

  • Dependency Injection: Bind ServiceClient in Laravel's container:

    $this->app->bind(ServiceClient::class, fn() => new ServiceClient(
        new Client(['base_uri' => config('services.api.base_uri')]),
        // ... transformers
    ));
    
  • API Resource Mapping: Create a facade or service class:

    class UserService {
        public function __construct(private ServiceClient $client) {}
    
        public function fetch(int $limit): array {
            return $this->client->users(['limit' => $limit])['data'];
        }
    }
    
  • Middleware Stack: Add command-level middleware:

    $client->getHandlerStack()->push(function($handler) {
        return function($command) use ($handler) {
            $command['@metadata']['timestamp'] = now();
            return $handler($command);
        };
    });
    

Gotchas and Tips

Common Pitfalls

  1. Reserved @http Key:

    • Never expose user input directly to command arguments if it could contain @http.
    • Validate input strictly:
      if (array_key_exists('@http', $input)) {
          throw new \InvalidArgumentException('Forbidden key: @http');
      }
      
  2. Concurrency Limits:

    • Default concurrency (25) may overwhelm APIs. Adjust via:
      $results = $client->executeAll($commands, ['concurrency' => 5]);
      
  3. Result Parsing:

    • Ensure response transformers handle malformed JSON:
      function($response) {
          $body = (string)$response->getBody();
          return new Result(json_decode($body, true) ?: []);
      }
      

Debugging Tips

  • Enable Guzzle Debugging:

    $client = new Client(['debug' => true]);
    

    Inspect $response->getHeaders() for raw HTTP details.

  • Middleware Debugging: Use tap() for debugging middleware:

    $client->getHandlerStack()->push(function($handler) {
        return function($command) use ($handler) {
            tap($command, fn($c) => logger()->debug('Command:', $c->toArray()));
            return $handler($command);
        };
    });
    

Extension Points

  1. Custom Results: Extend GuzzleHttp\Command\Result for typed responses:

    class UserResult extends Result {
        public function __construct(array $data) {
            parent::__construct($data);
        }
    
        public function getIds(): array {
            return array_column($this->toArray(), 'id');
        }
    }
    
  2. Dynamic Command Mapping: Use Laravel's macro to add dynamic methods:

    ServiceClient::macro('fetchUser', function($id) {
        return $this->users(['filter' => ['id' => $id]]);
    });
    
  3. Error Handling: Catch specific exceptions:

    try {
        $result = $client->users();
    } catch (\GuzzleHttp\Command\Exception\CommandClientException $e) {
        // Handle 4xx errors
    } catch (\GuzzleHttp\Command\Exception\CommandServerException $e) {
        // Handle 5xx errors
    }
    

Laravel-Specific Quirks

  • Config Integration: Store API base URI in config/services.php:

    'api' => [
        'base_uri' => env('API_BASE_URI'),
    ],
    

    Then inject via:

    new Client(['base_uri' => config('services.api.base_uri')])
    
  • Exception Handling: Use Laravel's exception handler to convert CommandException to HTTP responses:

    public function render($request, CommandException $exception) {
        return response()->json(['error' => $exception->getMessage()], 400);
    }
    
  • Rate Limiting: Combine with spatie/laravel-rate-limiting:

    RateLimiter::for('api')->byRequest()->allow(100)->every(60);
    
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.
craftcms/url-validator
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony