Skip to content

Commit

Permalink
Made the SDK Client immutable
Browse files Browse the repository at this point in the history
  • Loading branch information
evgeek committed Dec 10, 2021
1 parent 57874f5 commit 8ffb3c2
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 202 deletions.
76 changes: 24 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,6 @@ require '/path/to/you/vendor/autoload.php';
//Create and configure a new SDK client
$sdk = new Client('YOU_TOKEN');

//Setup ScraperAPI parameters according to the documentation
$sdk
->setCountryCode('us')
->setDeviceType('desktop')
->setKeepHeaders(true)
->addHeader('Accept', 'application/json');

//Send request
$response = $sdk->get('https://example.com');

Expand All @@ -43,6 +36,8 @@ echo $response->getBody()->getContents();
The client is configured through the constructor parameters:

* ```$apiKey``` (required) - your API key from [ScraperAPI dashboard](https://dashboard.scraperapi.com/dashboard).
* ```$defaultApiParams``` - default API parameters for requests
* ```$defaultHeaders``` - default HTTP headers
* ```$timeout``` (default ```60```) - request timeout.
* ```$tries``` (default ```3```) - number of request attempts.
* ```$delayMultiplier``` (default ```1```) - delay multiplier before new request attempt in seconds. Multiplier 3 means
Expand All @@ -61,67 +56,44 @@ The client is configured through the constructor parameters:
### API parameters

Configuring default API functionality according to [ScraperAPI documentation](https://www.scraperapi.com/documentation/)
. The default settings apply to all requests, unless they are overridden at the request level. All parameters are set
using fluent setters:
. The default settings apply to all requests, unless they are overridden at the request level. You can set the default
options only from constructor (SDK client is immutable), using the second parameter:

```php
$sdk
->setCountryCode('us') //activate country geotargetting
->setRender(true) //activate javascript rendering
->setPremium(false) //activate premium residential and mobile IPs
->setSessionNumber(123) //reuse the same proxy
->setKeepHeaders(true) //use your own custom headers
->setDeviceType('mobile') //set mobile or desktop user agents
->setAutoparse(false); //activate auto parsing for select websites
```

Or you can set all parameters in single ```setParams()``` method using an array. This method erases all previously set
parameters.

```php
$sdk->setParams([
'country_code' => 'us',
'render' => true,
'premium' => false,
'session_number' => 123,
'keep_headers' => true,
'device_type' => 'mobile',
'autoparse' => 'false',
]);
$defaultApiParams = [
'country_code' => 'us', //activate country geotargetting
'render' => true, //activate javascript rendering
'premium' => false, //activate premium residential and mobile IPs
'session_number' => 123, //reuse the same proxy
'keep_headers' => true, //use your own custom headers
'device_type' => 'mobile', //set mobile or desktop user agents
'autoparse' => 'false', //activate auto parsing for select websites
];
$sdk = new Client('YOU_TOKEN', $defaultApiParams);
```

### Headers

You can add default headers by ```addHeader()``` method. Don't forget to enable ```keep_headers``` to allow your headers
to be used!
You can add default headers with the third parameter of the constructor. Don't forget to enable ```keep_headers``` to
allow your headers to be used!

```php
$sdk
->setKeepHeaders(true)
->addHeader('Referer', 'https://example.com/')
->addHeader('Accept', 'application/json');
```

Or set headers in one step by ```setHeaders()``` method. This method erases all previously set headers.

```php
$sdk
->setKeepHeaders(true)
->setHeaders([
'Referer' => 'https://example.com/',
'Accept' => 'application/json',
]);
$defaultHeaders = [
'Referer' => 'https://example.com/',
'Accept' => 'application/json',
];
$sdk = new Client('YOU_TOKEN', ['keep_headers' => true], $defaultHeaders);
```

## Requests

SDK supports ```GET```, ```POST``` and ```PUT``` HTTP methods. Standard parameters of each request methods:

1. ```$url``` (required) - url of scrapped resource.
2. ```$apiParams``` (default ```null```) - to set the API settings for the request. They will override the defaults set
in the SDK Client object (only those that overlap).
2. ```$apiParams``` (default ```null```) - to set the API settings for the request. They will override the defaults from
the SDK Client (only those that overlap).
3. ```$headers``` (default ```null```) - to set headers for the request. Just like ```$apiParams```, they will override
the defaults set in the SDK Client object (only those that overlap).
the defaults from the SDK Client (only those that overlap).

### Synchronous

Expand Down
180 changes: 30 additions & 150 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,59 +18,43 @@

/**
* ScraperAPI documentation - https://www.scraperapi.com/documentation/
*
* @method Client setCountryCode($value) Activate country geotargetting ('us' for example)
* @method Client setRender($value) Activate javascript rendering (true/false)
* @method Client setPremium($value) Activate premium residential and mobile IPs (true/false)
* @method Client setSessionNumber($value) Reuse the same proxy (123 for example)
* @method Client setKeepHeaders($value) Use your own custom headers (true/false)
* @method Client setDeviceType($value) Set your requests to use mobile or desktop user agents (desktop/mobile)
* @method Client setAutoparse($value) Activate auto parsing for select websites (true/false)
*/
class Client
{
/**
* ScraperAPI endpoint url
*/
private const API = 'https://api.scraperapi.com';

/**
* ScraperAPI available query params
*/
private const PARAMS_LIST = [
'country_code',
'render',
'premium',
'session_number',
'keep_headers',
'device_type',
'autoparse'
];

/**
* ScraperAPI API key
* @var string
*/
private $apiKey;

/**
* ScraperAPI default request params
* @var array
*/
private $defaultApiParams;
/**
* Default headers
* @var array
*/
private $defaultHeaders;
/**
* If true, debug statement sent to the output. Useful for debugging async requests
* @var bool
*/
private $printDebugInfo;

/**
* If false, API key in debug statement will be replaced by 'API_KEY' string
* @var bool
*/
private $showApiKey;

/**
* Guzzle client
* @var Guzzle
*/
private $guzzle;

/**
* Optional PSR-3 logger for debug
* @var LoggerInterface|null
Expand All @@ -81,19 +65,6 @@ class Client
* @var mixed
*/
private $logLevel;

/**
* ScraperAPI default request params
* @var array
*/
private $params = [];

/**
* Default headers
* @var array
*/
private $headers = [];

/**
* Total promises in a bunch (for debug statements)
* @var int
Expand All @@ -105,13 +76,12 @@ class Client
*/
private $fulfilledPromises = 0;

/** @var array */
private $paramsList;

/**
* ScraperAPI documentation - https://www.scraperapi.com/documentation/
*
* @param string $apiKey ScraperAPI API key
* @param array|null $defaultApiParams Default api parameters for requests
* @param array|null $defaultHeaders Default headers for requests
* @param int $timeout Request timeout
* @param int $tries Number of request attempts
* @param int $delayMultiplier Delay multiplier before new request attempt in seconds
Expand All @@ -123,6 +93,8 @@ class Client
*/
public function __construct(
string $apiKey,
?array $defaultApiParams = [],
?array $defaultHeaders = [],
int $timeout = 60,
int $tries = 3,
int $delayMultiplier = 1,
Expand All @@ -134,13 +106,25 @@ public function __construct(
)
{
$this->apiKey = $apiKey;
$this->defaultApiParams = $defaultApiParams ?? [];
$this->defaultHeaders = $defaultHeaders ?? [];
$this->printDebugInfo = $printDebugInfo;
$this->showApiKey = $showApiKey;
$this->logger = $logger;
$this->logLevel = $logLevel;

$this->paramsList = array_flip(static::PARAMS_LIST);
$this->guzzle = $this->createGuzzleClient($timeout, $tries, $delayMultiplier, $maxExceptionsLength);
}

/**
* @param int $timeout
* @param int $tries
* @param int $delayMultiplier
* @param int $maxExceptionsLength
* @return Guzzle
*/
private function createGuzzleClient(int $timeout, int $tries, int $delayMultiplier, int $maxExceptionsLength): Guzzle
{
$handlerStack = HandlerStack::create();
$handlerStack->push(Middleware::retry(
function (
Expand Down Expand Up @@ -176,113 +160,9 @@ function ($try) use ($delayMultiplier) {
));
$handlerStack->push(Middleware::httpErrors(new BodySummarizer($maxExceptionsLength)), 'http_errors');

$this->guzzle = new Guzzle(['base_uri' => static::API, 'timeout' => $timeout, 'handler' => $handlerStack]);
}


/**
* Caller for Client default query params setters
*
* @param string $name
* @param array $arguments
* @return $this
* @throws Exception
*/
public function __call(string $name, array $arguments)
{

if (strpos($name, 'set') === 0) {
$this->setter($name, $arguments);
return $this;
}

throw new Exception("Unknown method '$name'.");
return new Guzzle(['base_uri' => static::API, 'timeout' => $timeout, 'handler' => $handlerStack]);
}

/**
* @param string $name
* @param array $arguments
*/
private function setter(string $name, array $arguments): void
{
$paramName = $this->parseParamName($name);
if (array_key_exists($paramName, $this->paramsList)) {
$this->setParam($paramName, $arguments);
}
}

/**
* @param string $name
* @param array $arguments
*/
private function setParam(string $name, array $arguments): void
{
$paramValue = $arguments[0] ?? null;
if ((!is_string($paramValue) && !is_bool($paramValue))) {
$paramValue = (string)$paramValue;
}
if (is_bool($paramValue)) {
$paramValue = $paramValue ? 'true' : 'false';
}
$this->params[$name] = $paramValue;
}

/**
* @param string $name
* @return string
*/
private function parseParamName(string $name): string
{
$words = preg_split('/(?=[A-Z])/', substr($name, 3));
if (!$words) {
return '';
}

return (string)array_reduce($words, static function ($carry, $item) {
if ($item === '') {
return $carry;
}
return ($carry === '' || $carry === null) ? strtolower($item) : "{$carry}_" . strtolower($item);
});

}

/**
* Set Client default query params in one step from array, replacing existing ones
*
* @param array $params
* @return Client
*/
public function setParams(array $params): Client
{
$this->params = $params;
return $this;
}

/**
* Add default header to Client
* @param string $header
* @param array|string $value
* @return $this
*/
public function addHeader(string $header, $value): Client
{
$this->headers[$header] = $value;
return $this;
}

/**
* Set default Client headers in one step from array, replacing existing ones
* @param array $headers
* @return $this
*/
public function setHeaders(array $headers): Client
{
$this->headers = $headers;
return $this;
}


/**
* Get info about ScraperAPI account
*
Expand Down Expand Up @@ -415,14 +295,14 @@ private function prepareQueryParams(
?array $json
): array
{
$params = $this->params;
$params = $this->defaultApiParams;
if (is_array($apiParams)) {
foreach ($apiParams as $param => $value) {
$params[$param] = $value;
}
}

$resultHeaders = $this->headers;
$resultHeaders = $this->defaultHeaders;
if (is_array($headers)) {
foreach ($headers as $param => $value) {
$resultHeaders[$param] = $value;
Expand Down

0 comments on commit 8ffb3c2

Please sign in to comment.