Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guzzle v6 #1062

Merged
merged 12 commits into from May 26, 2015
Merged

Guzzle v6 #1062

merged 12 commits into from May 26, 2015

Conversation

mtdowling
Copy link
Member

Guzzle now uses PSR-7 for HTTP messages.
Due to the fact that these messages are immutable, this prompted a
re-architecting of Guzzle to use a middleware based system rather than an
event system. Any HTTP message interaction (e.g., GuzzleHttp\Message\Request)
need to be updated to work with the new immutable PSR-7 request and response
objects. Any event listeners or subscribers need to be updated to become
middleware functions that wrap handlers (or are injected into a
GuzzleHttp\HandlerStack.

  • Removed GuzzleHttp\BatchResults
  • Removed GuzzleHttp\Collection
  • Removed GuzzleHttp\HasDataTrait
  • Removed GuzzleHttp\ToArrayInterface
  • The guzzlehttp/streams dependency has been removed. Stream functionality
    is now present in the GuzzleHttp\Psr7 namespace provided by the
    guzzlehttp/psr7 package.
  • Guzzle no longer uses ReactPHP promises and now uses the
    guzzlehttp/promises library. We use a custom promise library for three
    significant reasons:
    1. React promises (at the time of writing this) are recursive. Promise
      chaining and promise resolution will eventually blow the stack. Guzzle
      promises are not recursive as they use a sort of trampolining technique.
      Note: there has been movement in the React project to modify promises to
      no longer utilize recursion.
    2. Guzzle needs to have the ability to synchronously block on a promise to
      wait for a result. Guzzle promises allows this functionality.
    3. Because we need to be able to wait on a result, doing so using React
      promises requiring wrapping react promises with RingPHP futures. This
      overhead is no longer needed, reducing stack sizes, reducing complexity,
      and improving performance.
  • GuzzleHttp\Mimetypes has been moved to a function in
    GuzzleHttp\Psr7\mimetype_from_extension and
    GuzzleHttp\Psr7\mimetype_from_filename.
  • GuzzleHttp\Query and GuzzleHttp\QueryParser have been removed. Query
    strings must now be passed into request objects as strings, or provided to
    the query request option when creating requests with clients. The query
    option uses PHP's http_build_query to convert an array to a string. If you
    need a different serialization technique, you will need to pass the query
    string in as a string. There are a couple helper functions that will make
    working with query strings easier: GuzzleHttp\Psr7\parse_query and
    GuzzleHttp\Psr7\build_query.
  • Guzzle no longer has a dependency on RingPHP. Due to the use of a middleware
    system based on PSR-7, using RingPHP and it's middleware system as well adds
    more complexity than the benefits it provides. All HTTP handlers that were
    present in RingPHP have been modified to work directly with PSR-7 messages
    and placed in the GuzzleHttp\Handler namespace. This significantly reduces
    complexity in Guzzle, removes a dependency, and improves performance. RingPHP
    will be maintained for Guzzle 5 support, but will no longer be a part of
    Guzzle 6.
  • As Guzzle now uses a middleware based systems the event system and RingPHP
    integration has been removed. Note: while the event system has been removed,
    if there is sufficient demand, it would be possible that a package could be
    created that adds event support into the middleware system.
    • Removed the Event namespace.
    • Removed the Subscriber namespace.
    • Removed Transaction class
    • Removed RequestFsm
    • Removed RingBridge
    • GuzzleHttp\Subscriber\Cookie is now provided by
      GuzzleHttp\Middleware::cookies
    • GuzzleHttp\Subscriber\HttpError is now provided by
      GuzzleHttp\Middleware::httpError
    • GuzzleHttp\Subscriber\History is now provided by
      GuzzleHttp\Middleware::history
    • GuzzleHttp\Subscriber\Mock is now provided by
      GuzzleHttp\Middleware::mock
    • GuzzleHttp\Subscriber\Prepare is now provided by
      GuzzleHttp\PrepareBodyMiddleware
    • GuzzleHttp\Subscriber\Redirect is now provided by
      GuzzleHttp\RedirectMiddleware
  • Guzzle now uses Psr\Http\Message\UriInterface (implements in
    GuzzleHttp\Psr7\Uri) for URI support. GuzzleHttp\Url is now gone.
  • Static functions in GuzzleHttp\Utils have been moved to namespaced
    functions under the GuzzleHttp namespace. This requires either a Composer
    based autoloader or you to include functions.php.

@jeremeamia
Copy link
Member

Woohoo!!!

@MAXakaWIZARD
Copy link

Nice!

@harikt
Copy link

harikt commented May 20, 2015

Hey,

Good work guys. I have a question / concern.

How are you guys going to help the maintainers of the opensource projects which rely on guzzle.
Eg : I have noticed some are using guzzle3, 4, 5 . It seems when the versions come along there will be conflicts with the higher versions and libraries to use.

Is there any thoughts about it ?

Thank you and good work moving to PSR-7.

@stof
Copy link

stof commented May 20, 2015

@mtdowling what is the reasoning for implementing your own PSR-7 codebase rather than relying on phly/http for instance ?

@mtdowling
Copy link
Member Author

@harikt I think higher level libraries that use Guzzle that don't want to cause conflicts can use a similar strategy that we are using the in the AWS SDK for PHP v3: create your own client interface and use that interface in your project instead of relying on a specific version of Guzzle (or any other library).

  • Guzzle 4 is dead and will no longer be maintained in any capacity. Upgrading from 4 to 5 is trivial and typically just requires an update to your composer.json. Anyone that hasn't done this is probably just unaware that v5 exists. That said, you could probably have a looser dependency on Guzzle 4 or 5 in a higher level project (depending on which features the project relies on).

  • Guzzle 5 will be maintained for a long time (especially if Drupal 8 is locked into v5). Guzzle 5 is perfectly fine to use and maintainable. It's biggest issue is that it suffers from recursive promises. In fact, the reason for Guzzle 6 to start being developed was that we were constantly blowing the stack in the AWS SDK and decided that we would implement our own promise library that didn't use recursion.

    During the process of building the SDK, PSR-7 got closer to becoming a reality, so we decided it was the best way forward for SDK customers (and Guzzle) was to update the SDK and Guzzle to use PSR-7 directly. The change to PSR-7 unfortunately required significant refactoring to Guzzle due to the fact that PSR-7 messages are immutable. Guzzle 5 relied on an event system from plugins. The event system relied on mutability of HTTP messages and side effects in order to work. With immutable messages, you have to change your workflow to become more about either returning a value (e.g., functional middlewares) or setting a value on an object.

    When we realized that the SDK would use PSR-7 directly, we knew that we did not want to preclude Guzzle 5 users from using the SDK. It was then that we decided to abstract away the HTTP layer of the SDK such that you can use Guzzle 5, 6, or any other HTTP client with the SDK. This design decision makes the SDK work with more users and dependency closures, and also simplified the SDK quite a bit. As an example, here are the binding the SDK to different versions of Guzzle: https://github.com/aws/aws-sdk-php/tree/643fb164936a7cfb80f7fe1b64c7227e3177dee8/src/Handler

@stof We considered using phly/http, but ultimately decided not to for a few reasons. Guzzle needs various stream decorators and other abstractions on top of HTTP messages. We also need these abstractions in the AWS SDK for PHP, so I decided that these abstractions that weren't Guzzle specific but PSR7 specific should be in a separate repository that Guzzle could use and the SDK could use. Instead of making something like a guzzlehttp/psr7-helper repo or something and have a dependency on phly/http, I decided to just have a single PSR7 package for Guzzle that provides both the message implementations and some of the more generic high level functionality (stream decorators, multipart bodies, etc). I also feel that there's a lot of heavy handed code in the phly/http package that isn't necessary (e.g., regular expression validation when unnecessary, not allowing custom schemes in the Uri implementation, ...).

@skyzyx
Copy link
Contributor

skyzyx commented May 20, 2015

I have a few concerns about the event system going away. I have a CLI app that queries my company's API, and leverages Log/Retry Subscribers, as well as Before/After Events. Is there any documentation about the migration path for apps which rely on these Guzzle v5 features?

3. Guzzle has a minimum PHP version requirement of PHP 5.4. Pull requests must
not require a PHP version greater than PHP 5.4.
not require a PHP version greater than PHP 5.4 unless the feature is only
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/5.4/5.5/

@harikt
Copy link

harikt commented May 21, 2015

Thank you @mtdowling for the explanations.

@mtdowling
Copy link
Member Author

Hey @skyzyx. I probably should write more docs around this. When using the middleware approach, you need to inject middleware functions into the client's HandlerStack. This should be done when creating a client by injecting a custom HandlerStack into the client using the handler options of the client constructor. If you know that your client uses a GuzzleHttp\HandlerStack as its handler, then you could add and remove middleware from a client's handler after the client is constructed.

leverages Log/Retry Subscribers

Logging and retries were added directly into Guzzle.

// Create a handler stack that adds the default middlewares
// note that you can omit the default middlewares by just creating
// the HandlerStack directly.
$stack = GuzzleHttp\HandlerStack::create();

// Create a log middleware
$logger = create_my_psr_logger(); // implement this function
$formatter = new GuzzleHttp\MessageFormatter();
$middleware = GuzzleHttp\Middleware::log($logger, $formatter);

// Add the log middleware to the stack. You can just push to the end
// or unshift to the front of the stack. You can give middlewares names.
$stack->push($logger, 'my-logger');

// You can add middlewares before or after other middlewares by name
$retry = \GuzzleHttp\Middleware::retry(function ($retries, $request, $response, $exception) {
    return false; // return true or false
});
$stack->before('my-logger', $retry);

// Create the client and use the handler stack you created.
$client = new GuzzleHttp\Client(['handler' => $stack]);

Basically you build up the customizations you'll need when you create the client. If you need specific ad-hoc customizations, you can add a middleware that keys in on custom request options (because each middleware is passed in the request and array of request options). Alternatively, you can specify a custom handler when sending a request by adding a handler into the handler request option.

More documentation on handlers and middleware can be found here: https://github.com/guzzle/guzzle/blob/guzzle-v6/docs/handlers-and-middleware.rst

@mtdowling
Copy link
Member Author

The branch has now been prepped for merging. I will be tagging and releasing Guzzle 6 tomorrow morning.

@kamilsk
Copy link
Contributor

kamilsk commented May 26, 2015

Travis say

PHP Fatal error: Interface 'Psr\Log\LoggerInterface' not found in /home/travis/build/guzzle/guzzle/tests/MiddlewareTest.php on line 196

and I remembered the #1065.

@mtdowling mtdowling merged commit a252cb4 into master May 26, 2015
@mtdowling mtdowling deleted the guzzle-v6 branch May 26, 2015 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants