Guzzle Services

repository·2.0·Indexed 42 days ago

https://github.com/guzzle/guzzle-services

A tool for building SDK-style API clients using service descriptions to map named operations and parameters to HTTP requests and responses. It abstracts manual request serialization and supports custom request/response locations, command handler stacks, and response model parsing. Compatible with PHP >=7.2.5 for version 1.7 and >=7.4 for version 2.0.

Tokens
15.4K
Snippets
34
Records
59
Agent score
53%

What's inside Guzzle Services

  1. Handle Operation HTTP Methods in 2.0

    2.0

    In 2.0, operations without an explicit httpMethod now default to GET. This changes the behavior of getHttpMethod() and toArray(), which will now return 'GET' instead of an empty string.

    Important:

    • Explicit httpMethod values must be non-empty strings. Passing an empty string or non-string value throws InvalidArgumentException.
    • Casing is preserved. Because Guzzle Services 2.0 uses Guzzle PSR-7 3.x, it no longer automatically uppercases methods. If your service expects GET, use uppercase in your service description.
  2. How Guzzle Services works

    2.0

    Guzzle Services allows you to build SDK-style clients by defining a service description. This description maps named operations and parameters to HTTP requests and maps responses into result data. This approach is intended for users building an SDK for an API who want to describe operations in arrays rather than manually writing request serializers.

    If you only need to send direct HTTP requests without service descriptions, use guzzlehttp/guzzle instead.

  3. Return raw PSR-7 responses instead of parsed models

    2.0

    By default, Guzzle Services parses responses according to the operation's responseModel. To return raw binary data or unparsed response bodies, set 'process' => false on the specific operation within your Description object.

    When processing is disabled, the raw PSR-7 response is accessible via the response key in the result array.

    Note: Operation-level process settings override client-level settings. If process is omitted or set to null at the operation level, it inherits the client's configuration.

    $description = new Description([
        'operations' => [
            'getMetadata' => [
                'httpMethod' => 'GET',
                'uri' => '/metadata/{id}',
                'responseModel' => 'metadataResponse',
                'parameters' => [
                    'id' => ['type' => 'string', 'required' => true, 'location' => 'uri'],
                ],
            ],
            'getFile' => [
                'httpMethod' => 'GET',
                'uri' => '/files/{id}',
                'process' => false, // Disables parsing
                'parameters' => [
                    'id' => ['type' => 'string', 'required' => true, 'location' => 'uri'],
                ],
            ],
        ],
    ]);
    
    // Accessing the raw response
    $result = $guzzleClient->getFile(['id' => '123']);
    $response = $result['response'];
  4. Quick Start: Create a service-driven client

    2.0

    To create a client, define a Description object containing your baseUri, operations, and models. Then, instantiate a GuzzleClient by passing a standard GuzzleHttp Client and your Description. You can then call operations by their name and pass parameters as an array.

    use GuzzleHttp\Client;
    use GuzzleHttp\Command\Guzzle\Description;
    use GuzzleHttp\Command\Guzzle\GuzzleClient;
    
    $description = new Description([
        'baseUri' => 'https://api.example.com',
        'operations' => [
            'getUser' => [
                'httpMethod' => 'GET',
                'uri' => '/users/{id}',
                'responseModel' => 'user',
                'parameters' => [
                    'id' => ['type' => 'string', 'location' => 'uri'],
                ],
            ],
        ],
        'models' => [
            'user' => [
                'type' => 'object',
                'additionalProperties' => ['location' => 'json'],
            ],
        ],
    ]);
    
    $client = new GuzzleClient(new Client(), $description);
    $result = $client->getUser(['id' => '123']);
  5. Add client-wide default parameters

    2.0

    Use the defaults option when instantiating a GuzzleClient to provide parameters that should be included in most or all commands (e.g., apiKey, tenantId).

    Explicit arguments passed to a specific command will override these defaults.

    Requirement: Any default parameter must have a corresponding parameter schema in the Description (either in parameters or via additionalParameters) so the client knows how to validate and serialize it.

    use GuzzleHttp//... imports
    
    $guzzleClient = new GuzzleClient(
        $client,
        $description,
        null,
        null,
        null,
        [
            'defaults' => [
                'apiKey' => getenv('EXAMPLE_API_KEY'),
            ],
        ]
    );
    
    // The apiKey will be automatically included in this call
    $result = $guzzleClient->listUsers();
  6. Use Command Handler Stacks for Middleware

    2.0

    The command handler stack is distinct from the underlying Guzzle HTTP handler stack. Command middleware wraps commands before they are transformed into HTTP requests. HTTP middleware should be applied to the underlying GuzzleHttp\\ClientInterface instead.

    Use the special @http command key to pass request options to the underlying HTTP client's sendAsync() call. The base command client consumes this key and passes its contents as options.

    use GuzzleHttp\Command\CommandInterface;
    
    $client->getHandlerStack()->push(function (callable $handler) {
        return function (CommandInterface $command) use ($handler) {
            $command['@http'] = ($command['@http'] ?: []) + [
                'timeout' => 2.0,
            ];
    
            return $handler($command);
        };
    }, 'timeout');
  7. Use URI Templates for dynamic URIs

    2.0

    Operation uri values are expanded using guzzlehttp/uri-template.

    • URI Variables: Only parameters with location: uri are used for template expansion.
    • Query Expansion: Use location: query to append parameters to the query string after expansion, or use URI Template query expressions (like {?filter*}) with location: uri to let the template control the expansion.

    Example of query expansion via template:

    'operations' => [
        'searchUsers' => [
            'httpMethod' => 'GET',
            'uri' => '/users{?filter*,page}',
            'parameters' => [
                'filter' => ['type' => 'object', 'location' => 'uri'],
                'page' => ['type' => 'integer', 'location' => 'uri'],
            ],
        ],
    ]
  8. Change query parameter serialization behavior

    2.0

    By default, Guzzle Services uses RFC 3986 encoding with PHP-style array indexes (e.g., foo%5B0%5D=bar). If your API requires empty brackets for arrays (e.g., foo%5B%5D=bar), you must provide a custom Serializer to the GuzzleClient using a QueryLocation with a specific serializer configuration.

    To remove numeric indexes, pass true to the Rfc3986Serializer constructor.

    use GuzzleHttp//... imports
    
    // Create a QueryLocation that uses Rfc3986Serializer with empty brackets enabled
    $queryLocation = new QueryLocation('query', new Rfc3986Serializer(true));
    
    // Create a Serializer with the custom query location
    $serializer = new Serializer($description, ['query' => $queryLocation]);
    
    // Pass the serializer to the GuzzleClient
    $guzzleClient = new GuzzleClient($client, $description, $serializer);
  9. Migrate from Guzzle Services 0.6 to 1.0

    2.0

    Guzzle Services 1.0 introduced support for Guzzle 6 and PSR-7.

    Key Changes:

    • Dependencies: Requires PHP 5.5+, guzzlehttp/guzzle 6.2+, and guzzlehttp/command 1.x. If you are on Guzzle 5, stay on 0.6.
    • Base URI: Change baseUrl to baseUri in service descriptions.
    • Request Locations:
      • Rename postField to formParam.
      • Rename postFile to multipart.
    • Custom Logic: Subscriber-based response processing and validation hooks were replaced by Guzzle Command handlers. Move custom logic to command handlers.
    // 0.6 to 1.0: Base URI
    // 0.6
    $description = new Description(['baseUrl' => '...']);
    // 1.0
    $description = new Description(['baseUri' => '...']);
    
    // 0.6 to 1.0: Request Locations
    // 0.6
    'location' => 'postField' // becomes
    'location' => 'formParam'
    
    // 0.6
    'location' => 'postFile' // becomes
    'location' => 'multipart'
  10. Upgrade from Guzzle Services 1.x to 2.0

    2.0

    Guzzle Services 2.0 is a major release that introduces strict types, higher PHP requirements, and updated dependencies.

    Key Changes:

    • PHP Version: Requires ^7.4 || ^8.0. If you must support PHP 7.2 or 7.3, stay on 1.x.
    • Dependencies: Requires Guzzle Command 2.x, Guzzle 8.x, Guzzle PSR-7 3.x, and Guzzle URI Template 2.x.
    • Strict Types: The library now uses native PHP type hints. Custom extension points (like parameter filters) must now accept the exact types expected (e.g., a filter expecting a string will throw a TypeError if passed an int).
    • Final Classes: Operation, ValidatedDescriptionHandler, and Rfc3986Serializer are now @final. Do not attempt to subclass them; use service description data or middleware composition instead.
  11. Define Reusable Models

    2.0

    Models are reusable schemas defined in the top-level models map. A response model must have its type set to object or array. You can use extends to inherit from other models, though nested maps like properties are not deep-merged.

    'models' => [
        'baseJsonObject' => [
            'type' => 'object',
            'location' => 'json',
            'additionalProperties' => false,
        ],
        'user' => [
            'extends' => 'baseJsonObject',
            'properties' => [
                'id' => ['type' => 'string'],
                'name' => ['type' => 'string'],
            ],
        ],
    ]