- Saved searches
- Use saved searches to filter your results more quickly
- License
- pbmengine/php-restclient
- Name already in use
- Sign In Required
- Launching GitHub Desktop
- Launching GitHub Desktop
- Launching Xcode
- Launching Visual Studio Code
- Latest commit
- Git stats
- Files
- README.md
- Building ReST API clients in PHP the easy way
- Composer
- The service definition
- But, wait a minute
- The client
- Using the client
- Writing tests
- Finally
Saved searches
Use saved searches to filter your results more quickly
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
License
pbmengine/php-restclient
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Sign In Required
Please sign in to use Codespaces.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
Generic PHP client to access REST APIs
This publication describes a generic api rest client suitable for all PHP packages.
You can install the package via composer:
composer require pbmengine/php-restclient
use Pbmengine\Restclient\HttpClient; $client = new HttpClient; // or $client = new HttpClient(\GuzzleHttp\Client, 'https://example.com/v1', ['timeout' => 30]); $response = $client->get('users'); $response = $client->jsonPayload(['id' : 1])->post('users');
$client->baseUrl('https://example.com/v1'); $client->options(['http_errors' => false, 'timeout' => 30]); $client->option('http_errors', false); $client->authorizationBearer('token'); $client->authorizationHttp('username', 'password'); $client->authorizationDigest('username', 'password'); $client->headers(['API-KEY' => 30]); $client->header('API-KEY', 30); $client->queryParams(['embed' => 'resource']); $client->queryParam('embed', 'resource'); $client->jsonPayload([]); $client->multipartPayload([]); $client->formParamsPayload([]); $client->getHeaders(); $client->getQueryParams(); $client->getBody(); $client->getRequestUrl('endpoint'); $response = $client->get('users'); $response = $client->post('users'); $response = $client->put('users/12'); $response = $client->delete('users/12'); $response = $client->patch('users/12'); $response = $client->head('users/12');
$response->statusCode(); // 200 $response->headers(); // [] $response->raw(); // ResponseInterface $response->raw()->getHeaders(); // [] $response->isValid(); // true $response->isServerError(); // false $response->isClientError(); // false $response->content(); // StdClass $response->contentAsArray(); // Array $response->contentAsJson(); // Json String $response->contentAsCollection(); // Illuminate Collection
Use Case several requests
$client = (new HttpClient) ->baseUrl('https://example.com') ->authorizationBearer('your token'); // get all users $response = $client ->queryParam('embed', 'client'); ->get('users'); // update user $response = $client ->jsonPayload(['name' => 'John']) ->put('users/' . $response->content()->data->id); // set new Bearer $client->authorizationBearer('another token'); // delete user $response = $client->delete('users/id');
Please see CHANGELOG for more information on what has changed recently.
If you discover any security related issues, please email systems@personal-business-machine.com instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.
Building ReST API clients in PHP the easy way
Like everything else, there is an easy way and there is a hard way to build a ReST client in PHP. The hard way is to comb over an API spec PDF, start implementing each API operation one by one, and dealing with argument handling, request validation and response validation for each call.
ReST API documentation is getting better these days. As more people adopt Swagger 2.0 / OAI, it’s becoming easier to generate user-facing documentation, API clients and even API services. There are many online tools that provide a GUI for building Swagger definitions such as APISpark by RestLet and SwaggerHub. You can even host your own or build locally using swagger-ui.
In this post, I will go over what it takes to build an API consumer client in PHP using Guzzle Services. There are some examples out there of how this is done for earlier versions of Guzzle, but I will focus on Guzzle 6+.
Composer
Like every modern PHP library, we will want to start out with a `composer.json` file. You can use the composer init command to create one for you.
composer init --stability dev --name 'foo-api/foo-php-rest-client' --type library --no-interaction composer require guzzlehttp/guzzle-services:dev-guzzle6
The service definition
The service definition describes the API endpoint you are going to connect to. In previous version of guzzle-services, the service description was a JSON file with a DSL specification. The same description format applies in the 6.x version, but the factory method for loading the service description from a JSON file was removed so we can think of it as a more generalized data structure. The current documentation shows the definition being loaded as an array but it can still be stored in JSON or a YAML file and loaded into an associative array.
< "name": "Foo", "apiVersion": "2012-10-14", "baseUrl": "http://api.foo.com", "description": "Foo is an API that allows you to Baz Bar", "operations": < "GetFoo": < "httpMethod": "GET", "uri": "/foo", "summary": "Gets foo", "responseModel": "FooResponse" >, "CreateFoo": < "httpMethod": "POST", "uri": "/foo", "summary": "Creates new foo", "responseModel": "FooResponse", "parameters": < "name": < "location": "json", "type": "string", "required": true >, "description": < "location": "json", "type": "string", "required": true >> > >, "models": < "BaseResponse": < "type": "object", "properties": < "success": < "type": "string", "required": true >, "errors": < "type": "array", "items": < "type": "object", "properties": < "code": < "type": "string", "description": "The error code." >, "message": < "type": "string", "description": "The detailed message from the server." >> > > >, "additionalProperties": < "location": "json" >>, "FooResponse": < "type": "object", "extends": "BaseResponse", "properties": < "Foo": < "type": "object", "properties": < "id": < "type": "string", "required": true >, "name": < "type": "string", "required": true >, "description": < "type": "string", "required": true >> > > > > >
But, wait a minute
We were talking about Swagger and now we have to deal with a DSL. The service description was inspired by an early version of Swagger, but Swagger has changed. In some ways it’s a good thing the service description hasn’t changed. If you’ve already created a `service.json` file and you want to upgrade Guzzle, you don’t have to re-write the `service.json` file.
If you already have a Swagger file, that’s great. Swizzle is reportedly able to convert your Swagger spec to a service definition but I have yet to try it out.
The client
The Client class will be responsible for loading the service definition. It uses a factory method (`create`) that takes a config array. It will load the service definition from the `service.json` file as the service definition. This client also uses Guzzle default to add Basic Authentication to each request.
$config['base_uri']] + (array) json_decode(file_get_contents(__DIR__ . '/../service.json'), TRUE) ); // Creates the client and sets the default request headers. $client = new Client([ 'headers' => [ 'Content-Type' => 'application/json', 'Accept' => 'application/json', ], 'auth' => [$config['api_user'], $config['api_pass']], ]); return new static($client, $service_description, NULL, NULL, NULL, $config); > >
Using the client
Using the client is quite simple. You just need to instantiate it using the `::create` method and then call operations directly. Operations are available as method calls (supplied via a magic method `__call`) so you can access them directly.
'https://example.com', 'api_user' => 'Foo', 'api_pass' => 'Pass', ]); $result_object = $foo_client->GetFoo(); $result_array = $result_object->toArray();
There is another way to write this without using magic. You may wish to do this because your IDE doesn’t recognize the method `::GetFoo` and shows it as highlighted text. In this case you can use the `::getCommand` method call.
'https://example.com', 'api_user' => 'Foo', 'api_pass' => 'Pass', ]); $command = $foo_client->getCommand('GetFoo'); $result_object = $foo_client->execute($command); $result_array = $result_object->toArray();
Writing tests
Good libraries have tests. By looking at a library’s tests, you get a good idea of the quality of the library, as well as information on how it can be used. Lest’s require phpunit to run our tests.
composer require phpunit/phpunit:~4.0 --dev
With API clients, you don’t usually want to make real calls to an API client. That would be API integration testing. You should be able to assume the service is testing itself. You could use fake versions of your client for testing, but with Guzzle there is an easier way. You can just use the built in Guzzle test server. I won’t go over this in any depth in this article but you can see the basic idea below. For more information on testing please reference the code in the foo-php-frest-client example repository.
); $this->client = FooClient::create([ 'base_uri' => Server::$url, 'api_user' => $_SERVER['FOO_USER'], 'api_pass' => $_SERVER['FOO_PASS'], ]); > public function testGetFoo() < $foo = [ 'id' =>'1', 'name' => 'Foo', 'description' => 'The best ever Foo.', ]; Server::enqueue([new Response(200, [], json_encode(['status' => 'OK','Foo' => $foo], TRUE))]); $response = $this->client->GetFoo(); self::assertInstanceOf(ResultInterface::class, $response); self::assertEquals($foo, $response->toArray()['Foo']); >
Finally
Writing an API client in PHP doesn’t have to be painful. There are libraries for OAuth authentication which is a common way of authenticating API requests. Now that you know how to create an API client, share it with the rest of us so we can include it using Composer. Sharing is caring, as they say.