The improved HTTP Client in CakePHP 3.0

Many of the web applications I build have to talk to other webservices. Sometimes those services are internal API servers, sometimes they are external. In both situations, I want a simple, easy to use client library. While HttpSocket gets most of the way, it left me wanting a few things:

  • Support for file uploads. The current HttpSocket doesn’t offer it, and its necessary sometimes.
  • Incomplete cookie support. HttpSocket half implements cookie management but is missing a few features, like properly managing the domains.
  • The way scoped client state is managed is fragile and easy to make mistakes with.
  • Handrolled HTTP request generation & response parsing.

The last point doesn’t really bother me when using HttpSocket, but drives me crazy when I have to maintain HttpSocket. I started over with Http\Client for CakePHP 3.0. I took some inspiration from the great python-requests around improving the response object API, and from Aura.Http with regards to implementing PHP’s stream API.

Using the new library should be pretty familiar to people who have used HttpSocket in the past, as most of the end user interface hasn’t changed:

Show Plain Text
  1. <?php
  2. use Cake\Network\Http\Client;
  3.  
  4. $http = new Client();
  5.  
  6. // Simple get
  7. $response = $http->get('http://example.com/test.html');
  8.  
  9. // Simple get with querystring
  10. $response = $http->get('http://example.com/search', ['q' => 'widget']);
  11.  
  12. // Simple get with querystring & additional headers
  13. $response = $http->get('http://example.com/search', ['q' => 'widget'], [
  14.   'headers' => ['X-Requested-With' => 'XMLHttpRequest']
  15. ]);

Doing post and put requests is equally simple::

Show Plain Text
  1. <?php
  2. // Send a POST request with application/x-www-form-urlencoded encoded data
  3. $http = new Client();
  4. $response = $http->post('http://example.com/posts/add', [
  5.   'title' => 'testing',
  6.   'body' => 'content in the post'
  7. ]);
  8.  
  9. // Send a PUT request with application/x-www-form-urlencoded encoded data
  10. $response = $http->put('http://example.com/posts/add', [
  11.   'title' => 'testing',
  12.   'body' => 'content in the post'
  13. ]);

Oauth support added

It always bothered me that using OAuth with HttpSocket was such a painful experience. While there are plugins that provide great support for OAuth1, I don’t think that subclassing should be required to use OAuth. Once you have your OAuth tokens, you can easily do requests to OAuth1 services:

Show Plain Text
  1. <?php
  2. $http = new Client();
  3. $response = $http->get('http://example.com/profile/1', [], [
  4.   'auth' => [
  5.     'type' => 'oauth',
  6.     'consumerKey' => 'bigkey',
  7.     'consumerSecret' => 'secret',
  8.     'token' => '...',
  9.     'tokenSecret' => '...',
  10.     'realm' => 'tickets',
  11.   ]
  12. ]);

Creating scoped clients

Having to re-type the domain name, authentication and proxy settings can become tedious & error prone. The old HttpSocket provided some features for workig with scoped clients, but they only properly worked if you were careful. For the new implementation, I wanted to simplify the creation of scoped clients. Now if you want to create a scoped client you can do so when constructing an instance of Http\Client. The options provided to the constructor are re-used for all the requests made with that client:

Show Plain Text
  1. <?php
  2. // Create a scoped client.
  3. $http = new Client([
  4.   'host' => 'api.example.com',
  5.   'scheme' => 'https',
  6.   'auth' => ['username' => 'mark', 'password' => 'testing']
  7. ]);
  8.  
  9. // Do a request to api.example.com/test.php + basic authentication
  10. $response = $http->get('/test.php');
  11.  
  12. // Make a request to another domain
  13. $response = $http->get('http://other.com/index.html');

Using and managing cookies

Http\Client can also accept cookies when making requests. In addition to accepting cookies, it will also automatically store valid cookies set in
responses. Responses with cookies will be stored in the instance of Http\Client. The cookies stored in a Client instance are
automatically included in future requests to domain + path combinations that match:

Show Plain Text
  1. <?php
  2. $http = new Client([
  3.     'host' => 'cakephp.org'
  4. ]);
  5.  
  6. // Do a request that sets some cookies
  7. $response = $http->get('/');
  8.  
  9. // Cookies from the first request will be included
  10. // by default.
  11. $response2 = $http->get('/changelogs');

Overall I’m pretty happy with how the new HTTP client turned out and hope you find it useful/easier to use once CakePHP 3.0 is released. I think it offers the same simple API it did in the past, but with helpful improvements and a greatly simplified & streamlined implementation.

Comments

You are doing a great job! I hope to test the alpha release soon!

Keep going!

Marco on 2/2/13

Great job! I really like the way how the API works.

Zharfan on 2/2/13

We are waiting, waiting for version 3.0! Please!
Thank you)

Mike on 2/26/13

That’s great it has OAuth support!

Lourenzo Ferreira on 2/28/13

Easily to understand how it should work. Great post!

Porf on 7/14/13

this was actually informative – not like most of what i see online. sharing :)

Zach Smith on 7/18/13

This looks amazing, much more modular compared to cakephp 2. So I should be able to use http client in my own application (not using the cakephp framework)?

Bring on Cake 3, I hope its as good as symfony (and as modular as symfony is)

mini-me on 2/27/14

mini-me: That’s my hope. The HTTP client doesn’t have many dependencies on the rest of the framework so it should eventually be available as a separate package.

mark story on 3/10/14

My ? is
when I am use this techniq $http = new Client([ ‘host’ => ‘api.example.com’, ‘scheme’ => ‘https’, ‘auth’ => [‘username’ => ‘mark’, ‘password’ => ‘testing’]
]);

then how to know that url “api.example.com” someone give you request for login process ??

Means : When I call above function with username and password then how to find username and password in this url “api.example.com” for login process….help me???

jack on 9/12/15

How do I show the request that is created? I need it to send to the API programmer for troubleshooting.

joseph stang on 12/1/15

Comments are not open at this time.