From b526cdec31993cfa434b788b42d194a8e245446f Mon Sep 17 00:00:00 2001 From: Michael Dennis Date: Tue, 31 Oct 2017 22:23:29 -0700 Subject: [PATCH 1/7] Add docker compose file for a containerized development environment --- .gitignore | 5 ++++- README.md | 41 ++++++++++++++++++++++++++++++++++++++- docker-compose.yml | 19 ++++++++++++++++++ docker/files/default.conf | 23 ++++++++++++++++++++++ 4 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 docker-compose.yml create mode 100644 docker/files/default.conf diff --git a/.gitignore b/.gitignore index b90ffc5..6aad9af 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,7 @@ vendor/ .idea/ # Environment files -.env/*.* \ No newline at end of file +.env/*.* + +# Docker compose env file +.env diff --git a/README.md b/README.md index ffd4d58..910b5c9 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ All updates to this library is documented in our [CHANGELOG](https://github.com/ - [Installation](#installation) - [Quick Start](#quick-start) - [Usage](#usage) +- [Docker](#docker) - [Roadmap](#roadmap) - [How to Contribute](#contribute) - [Thanks](#thanks) @@ -138,7 +139,45 @@ print $response->body(); - [Example Code](https://github.com/sendgrid/php-http-client/tree/master/examples) -## Environment Variables + +# Docker + +This repo comes with a `docker-compose.yml` file to get a development environment up and running quickly. + +## Prerequisites + +- Install [Docker](https://www.docker.com/) on your local machine. + +## Instructions + +Clone this repo to your local machine. + +``` +$ git clone https://github.com/sendgrid/php-http-client.git +``` + +Create a .env file at the root of the repo and add your API key. + +``` +$ cd php-http-client +$ echo "SENDGRID_API_KEY='YOUR_API_KEY'" >> .env +``` + +Create the containers. + +``` +$ docker-compose up -d +``` + +The `examples` directory is now available locally by visiting `localhost:8080`. Run the provided `example.php` file by clicking on the link in the browser or experiment with your own files by adding them to the `examples` folder. + +Destroy the containers. + +``` +$ docker-compose down +``` + +## Environment Variables You can do the following to create a .env file: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d301541 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,19 @@ +version: '3' +services: + nginx: + image: nginx:latest + container_name: php-http-client-nginx + ports: + - "8080:80" + volumes: + - ./:/php-http-client + - ./docker/files/default.conf:/etc/nginx/conf.d/default.conf + links: + - php + php: + image: php:7-fpm + container_name: php-http-client-php-fpm + volumes: + - ./:/php-http-client + environment: + SENDGRID_API_KEY: ${SENDGRID_API_KEY} diff --git a/docker/files/default.conf b/docker/files/default.conf new file mode 100644 index 0000000..c2ea241 --- /dev/null +++ b/docker/files/default.conf @@ -0,0 +1,23 @@ +server { + listen 80; + server_name localhost; + + root /php-http-client/examples; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + location / { + autoindex on; + } + + location ~ \.php$ { + try_files $uri =404; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass php:9000; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + } +} From 1e911113fcfe68fd5783ace6c33c9ae64cf2cacb Mon Sep 17 00:00:00 2001 From: Michael Dennis Date: Sat, 27 Jan 2018 19:31:20 -0800 Subject: [PATCH 2/7] Add missing methods --- lib/Client.php | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/lib/Client.php b/lib/Client.php index 6d31c98..caf3537 100644 --- a/lib/Client.php +++ b/lib/Client.php @@ -239,6 +239,51 @@ private function createCurlMultiHandle($requests) return [$channels, $multiHandle]; } + /** + * Prepare response object + * + * @param resource $curl the curl resource + * + * @return Response object + */ + private function prepareResponse($curl) + { + $response = curl_exec($curl); + + $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE); + + $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); + + $responseBody = substr($response, $headerSize); + + $responseHeaders = substr($response, 0, $headerSize); + $responseHeaders = explode("\n", $responseHeaders); + $responseHeaders = array_map('trim', $responseHeaders); + + $response = new Response($statusCode, $responseBody, $responseHeaders); + + return $response; + } + + /** + * Retry request + * + * @param array $responseHeaders headers from rate limited response + * @param string $method the HTTP verb + * @param string $url the final url to call + * @param array $body request body + * @param array $headers original headers + * + * @return Response response object + */ + private function retryRequest($responseHeaders, $method, $url, $body, $headers) + { + $sleepDurations = $responseHeaders['X-Ratelimit-Reset'] - time(); + sleep($sleepDurations > 0 ? $sleepDurations : 0); + + return $this->makeRequest($method, $url, $body, $headers, false); + } + /** * Make the API call and return the response. This is separated into * it's own function, so we can mock it easily for testing. From 2aebfd9d682b124f571241653541314916d645ce Mon Sep 17 00:00:00 2001 From: Michael Dennis Date: Sat, 27 Jan 2018 19:35:53 -0800 Subject: [PATCH 3/7] Use var_dump to prevent array to string conversion error --- examples/example.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/example.php b/examples/example.php index 107d95a..9e556b5 100644 --- a/examples/example.php +++ b/examples/example.php @@ -15,9 +15,9 @@ $queryParams = ['limit' => 100, 'offset' => 0]; $requestHeaders = ['X-Mock: 200']; $response = $client->api_keys()->get(null, $queryParams, $requestHeaders); -echo $response->statusCode(); -echo $response->body(); -echo $response->headers(); +var_dump($response->statusCode()); +var_dump($response->body()); +var_dump($response->headers()); // GET /v3/api_keys - retrieve all API Keys that belong to the user $queryParams = ['limit' => 100, 'offset' => 0]; From 02aa8f5b2506419477e4f4c215ded378576c5a2d Mon Sep 17 00:00:00 2001 From: Michael Dennis Date: Sun, 28 Jan 2018 18:36:49 -0800 Subject: [PATCH 4/7] Maintain array keys --- lib/Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Client.php b/lib/Client.php index caf3537..116e456 100644 --- a/lib/Client.php +++ b/lib/Client.php @@ -180,7 +180,7 @@ private function buildUrl($queryParams = null) */ private function createCurlOptions($method, $body = null, $headers = null) { - $options = array_merge( + $options = array_replace( [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => 1, From e4ea392a8c029026af7c9907ddc80631b32fac55 Mon Sep 17 00:00:00 2001 From: Michael Dennis Date: Sun, 28 Jan 2018 18:52:39 -0800 Subject: [PATCH 5/7] Fix missing headers --- lib/Client.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/Client.php b/lib/Client.php index 116e456..e4c5f61 100644 --- a/lib/Client.php +++ b/lib/Client.php @@ -191,18 +191,24 @@ private function createCurlOptions($method, $body = null, $headers = null) $this->curlOptions ); + $requestHeaders = ['Content-Type: application/json']; + + // Merge client headers + if (isset($this->headers)) { + $requestHeaders = array_merge($requestHeaders, $this->headers); + } + + // Merge request headers if (isset($headers)) { - $headers = array_merge($this->headers, $headers); - } else { - $headers = []; + $requestHeaders = array_merge($requestHeaders, $headers); } if (isset($body)) { $encodedBody = json_encode($body); $options[CURLOPT_POSTFIELDS] = $encodedBody; - $headers = array_merge($headers, ['Content-Type: application/json']); } - $options[CURLOPT_HTTPHEADER] = $headers; + + $options[CURLOPT_HTTPHEADER] = $requestHeaders; return $options; } @@ -303,8 +309,6 @@ public function makeRequest($method, $url, $body = null, $headers = null, $retry $curlOpts = $this->createCurlOptions($method, $body, $headers); curl_setopt_array($curl, $curlOpts); - curl_setopt($curl, CURLOPT_HTTPHEADER, $this->headers); - $response = $this->prepareResponse($curl); curl_close($curl); From 020163130fff2233242a5706c848e655dba7dd50 Mon Sep 17 00:00:00 2001 From: Michael Dennis Date: Sun, 28 Jan 2018 19:00:47 -0800 Subject: [PATCH 6/7] Update scopes to allow managing API keys --- examples/example.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/examples/example.php b/examples/example.php index 9e556b5..f615670 100644 --- a/examples/example.php +++ b/examples/example.php @@ -29,9 +29,13 @@ $requestBody = [ 'name' => 'My PHP API Key', 'scopes' => [ + 'api_keys.create', + 'api_keys.delete', + 'api_keys.read', + 'api_keys.update', 'mail.send', 'alerts.create', - 'alerts.read' + 'alerts.read', ] ]; $response = $client->api_keys()->post($requestBody); @@ -51,8 +55,10 @@ $requestBody = [ 'name' => 'A New Hope', 'scopes' => [ - 'user.profile.read', - 'user.profile.update' + 'api_keys.create', + 'api_keys.delete', + 'api_keys.read', + 'api_keys.update', ] ]; $response = $client->api_keys()->_($apiKeyId)->put($requestBody); From 6b83002068cc3c7a9e1d0bdf2283e117d85bd39e Mon Sep 17 00:00:00 2001 From: Michael Dennis Date: Sun, 28 Jan 2018 19:13:51 -0800 Subject: [PATCH 7/7] Print results from all example requests --- examples/example.php | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/examples/example.php b/examples/example.php index f615670..849aeb7 100644 --- a/examples/example.php +++ b/examples/example.php @@ -17,13 +17,18 @@ $response = $client->api_keys()->get(null, $queryParams, $requestHeaders); var_dump($response->statusCode()); var_dump($response->body()); -var_dump($response->headers()); +// var_dump($response->headers()); +echo '

'; // GET /v3/api_keys - retrieve all API Keys that belong to the user $queryParams = ['limit' => 100, 'offset' => 0]; $requestHeaders = ['X-Mock: 200']; $retryOnLimit = true; // with auto retry on rate limit $response = $client->api_keys()->get(null, $queryParams, $requestHeaders, $retryOnLimit); +var_dump($response->statusCode()); +var_dump($response->body()); +// var_dump($response->headers()); +echo '

'; // POST /v3/api_keys - create a new user API Key $requestBody = [ @@ -41,15 +46,27 @@ $response = $client->api_keys()->post($requestBody); $responseBody = json_decode($response->body(), true); $apiKeyId = $responseBody['api_key_id']; +var_dump($response->statusCode()); +var_dump($response->body()); +// var_dump($response->headers()); +echo '

'; // GET /v3/api_keys/{api_key_id} - retrieve a single API Key $response = $client->api_keys()->_($apiKeyId)->get(); +var_dump($response->statusCode()); +var_dump($response->body()); +// var_dump($response->headers()); +echo '

'; // PATCH /v3/api_keys/{api_key_id} - update the name of an existing API Key $requestBody = [ 'name' => 'A New Hope' ]; $response = $client->api_keys()->_($apiKeyId)->patch($requestBody); +var_dump($response->statusCode()); +var_dump($response->body()); +// var_dump($response->headers()); +echo '

'; // PUT /v3/api_keys/{api_key_id} - update the name and scopes of a given API Key $requestBody = [ @@ -62,6 +79,14 @@ ] ]; $response = $client->api_keys()->_($apiKeyId)->put($requestBody); +var_dump($response->statusCode()); +var_dump($response->body()); +// var_dump($response->headers()); +echo '

'; // DELETE /v3/api_keys/{api_key_id} - revoke an existing API Key $response = $client->api_keys()->_($apiKeyId)->delete(); +var_dump($response->statusCode()); +var_dump($response->body()); +// var_dump($response->headers()); +echo '

';