Skip to content

Commit 3369d6d

Browse files
committed
Abstract Custom Headers Setup + Add Unit Tests
1 parent c4f7d8c commit 3369d6d

File tree

9 files changed

+209
-21
lines changed

9 files changed

+209
-21
lines changed

src/Client/SugarApi.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Sugarcrm\REST\Endpoint\MLPackage;
1515
use Sugarcrm\REST\Endpoint\ModuleLoader;
1616
use Sugarcrm\REST\Endpoint\Ping;
17+
use Sugarcrm\REST\Endpoint\Rest;
1718
use Sugarcrm\REST\Endpoint\Smart;
1819
use Sugarcrm\REST\Endpoint\SugarBean;
1920
use Sugarcrm\REST\Endpoint\ModuleFilter;
@@ -48,6 +49,7 @@
4849
* @method ModuleLoader moduleLoader() -
4950
* @method MLPackage mlp(string $id = null)
5051
* @method Integrate integrate(string $module = '', string $id = '')
52+
* @method Rest rest(string $endpoint = '')
5153
*/
5254
class SugarApi extends AbstractClient implements PlatformAwareInterface
5355
{

src/Endpoint/Abstracts/AbstractSmartSugarEndpoint.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66

77
namespace Sugarcrm\REST\Endpoint\Abstracts;
88

9+
use GuzzleHttp\Psr7\Request;
910
use MRussell\REST\Endpoint\Data\ValidatedEndpointData;
1011
use MRussell\REST\Endpoint\SmartEndpoint;
1112
use MRussell\REST\Traits\PsrLoggerTrait;
1213
use Sugarcrm\REST\Endpoint\SugarEndpointInterface;
1314
use Sugarcrm\REST\Endpoint\Traits\CompileRequestTrait;
15+
use Sugarcrm\REST\Endpoint\Traits\CustomHeadersTrait;
1416

1517
/**
1618
* Provide a smarter interface for Endpoints, to better manage passed in data
@@ -20,6 +22,12 @@ abstract class AbstractSmartSugarEndpoint extends SmartEndpoint implements Sugar
2022
{
2123
use CompileRequestTrait;
2224
use PsrLoggerTrait;
25+
use CustomHeadersTrait;
2326

2427
protected string $_dataInterface = ValidatedEndpointData::class;
28+
29+
protected function configureRequest(Request $request, $data): Request
30+
{
31+
return parent::configureRequest($this->addCustomHeadersToRequest($request), $data);
32+
}
2533
}

src/Endpoint/Abstracts/AbstractSugarBeanCollectionEndpoint.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66

77
namespace Sugarcrm\REST\Endpoint\Abstracts;
88

9+
use GuzzleHttp\Psr7\Request;
910
use Sugarcrm\REST\Endpoint\SugarBean;
1011
use MRussell\REST\Endpoint\Abstracts\AbstractModelEndpoint;
12+
use Sugarcrm\REST\Endpoint\Traits\CustomHeadersTrait;
1113
use Sugarcrm\REST\Endpoint\Traits\FieldsDataTrait;
1214
use Sugarcrm\REST\Endpoint\Traits\ModuleAwareTrait;
1315

@@ -22,6 +24,7 @@ abstract class AbstractSugarBeanCollectionEndpoint extends AbstractSugarCollecti
2224
{
2325
use FieldsDataTrait;
2426
use ModuleAwareTrait;
27+
use CustomHeadersTrait;
2528

2629
public const SUGAR_ORDERBY_DATA_PROPERTY = 'order_by';
2730

@@ -97,6 +100,11 @@ protected function configurePayload(): mixed
97100
return $this->configureFieldsDataProps($data);
98101
}
99102

103+
protected function configureRequest(Request $request, $data): Request
104+
{
105+
return parent::configureRequest($this->addCustomHeadersToRequest($request), $data);
106+
}
107+
100108
/**
101109
* Add module to url options
102110
* @inheritdoc

src/Endpoint/Abstracts/AbstractSugarBeanEndpoint.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Sugarcrm\REST\Endpoint\Integrate;
2323
use Sugarcrm\REST\Endpoint\SugarEndpointInterface;
2424
use Sugarcrm\REST\Endpoint\Traits\CompileRequestTrait;
25+
use Sugarcrm\REST\Endpoint\Traits\CustomHeadersTrait;
2526
use Sugarcrm\REST\Endpoint\Traits\FieldsDataTrait;
2627
use Sugarcrm\REST\Endpoint\Traits\IntegrateSyncKeyTrait;
2728
use Sugarcrm\REST\Endpoint\Traits\ModuleAwareTrait;
@@ -53,6 +54,7 @@ abstract class AbstractSugarBeanEndpoint extends ModelEndpoint implements SugarE
5354
use FieldsDataTrait;
5455
use FileUploadsTrait;
5556
use IntegrateSyncKeyTrait;
57+
use CustomHeadersTrait;
5658

5759
public const MODEL_ACTION_VAR = 'action';
5860

@@ -173,7 +175,7 @@ protected function configureRequest(Request $request, $data): Request
173175
$data = $this->configureFieldsDataProps($data);
174176
}
175177

176-
return parent::configureRequest($request, $data);
178+
return parent::configureRequest($this->addCustomHeadersToRequest($request), $data);
177179
}
178180

179181
/**

src/Endpoint/Abstracts/AbstractSugarCollectionEndpoint.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66

77
namespace Sugarcrm\REST\Endpoint\Abstracts;
88

9+
use GuzzleHttp\Psr7\Request;
910
use MRussell\REST\Exception\Endpoint\InvalidRequest;
1011
use GuzzleHttp\Psr7\Response;
1112
use MRussell\REST\Endpoint\Data\AbstractEndpointData;
1213
use MRussell\REST\Endpoint\CollectionEndpoint;
1314
use MRussell\REST\Traits\PsrLoggerTrait;
1415
use Sugarcrm\REST\Endpoint\SugarEndpointInterface;
1516
use Sugarcrm\REST\Endpoint\Traits\CompileRequestTrait;
17+
use Sugarcrm\REST\Endpoint\Traits\CustomHeadersTrait;
1618

1719
/**
1820
* Provides access to a multi-bean collection retrieved from Sugar 7 REST Api
@@ -23,6 +25,7 @@ abstract class AbstractSugarCollectionEndpoint extends CollectionEndpoint implem
2325
{
2426
use CompileRequestTrait;
2527
use PsrLoggerTrait;
28+
use CustomHeadersTrait;
2629

2730
public const SUGAR_OFFSET_PROPERTY = 'offset';
2831

@@ -82,6 +85,11 @@ protected function configurePayload(): mixed
8285
return $data;
8386
}
8487

88+
protected function configureRequest(Request $request, $data): Request
89+
{
90+
return parent::configureRequest($this->addCustomHeadersToRequest($request), $data);
91+
}
92+
8593
/**
8694
* Get the configured offset
8795
*/

src/Endpoint/Abstracts/AbstractSugarEndpoint.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66

77
namespace Sugarcrm\REST\Endpoint\Abstracts;
88

9+
use GuzzleHttp\Psr7\Request;
910
use MRussell\REST\Endpoint\Endpoint;
1011
use MRussell\REST\Traits\PsrLoggerTrait;
1112
use Sugarcrm\REST\Endpoint\SugarEndpointInterface;
1213
use Sugarcrm\REST\Endpoint\Traits\CompileRequestTrait;
14+
use Sugarcrm\REST\Endpoint\Traits\CustomHeadersTrait;
1315

1416
/**
1517
* Base Sugar API Endpoint for the simplest of REST functionality
@@ -19,4 +21,10 @@ abstract class AbstractSugarEndpoint extends Endpoint implements SugarEndpointIn
1921
{
2022
use CompileRequestTrait;
2123
use PsrLoggerTrait;
24+
use CustomHeadersTrait;
25+
26+
protected function configureRequest(Request $request, $data): Request
27+
{
28+
return parent::configureRequest($this->addCustomHeadersToRequest($request), $data);
29+
}
2230
}

src/Endpoint/Rest.php

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,26 +29,6 @@ class Rest extends Generic
2929
self::PROPERTY_HTTP_METHOD => "GET",
3030
];
3131

32-
protected array $headers = [];
33-
34-
public function withHeaders(array $headers)
35-
{
36-
$this->headers = $headers;
37-
return $this;
38-
}
39-
40-
protected function configureRequest(Request $request, $data): Request
41-
{
42-
$request = parent::configureRequest($request, $data);
43-
44-
if (!empty($this->headers)) {
45-
foreach ($this->headers as $header => $value) {
46-
$request = $request->withHeader($header, $value);
47-
}
48-
}
49-
return $request;
50-
}
51-
5232
public function get(mixed $data = null): static
5333
{
5434
$this->setProperty(self::PROPERTY_HTTP_METHOD, 'GET');
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace Sugarcrm\REST\Endpoint\Traits;
4+
5+
use GuzzleHttp\Psr7\Request;
6+
7+
trait CustomHeadersTrait
8+
{
9+
protected array $customHeaders = [];
10+
11+
/**
12+
* Set a custom header to be sent with the request
13+
* @param string $name
14+
* @param string $value
15+
* @return $this
16+
*/
17+
public function addCustomHeader(string $name, string $value): static
18+
{
19+
$normalized = strtolower($name);
20+
$this->customHeaders[$normalized] = [$name, $value];
21+
return $this;
22+
}
23+
24+
/**
25+
* Remove a custom header from the request
26+
* @param string $name
27+
* @return $this
28+
*/
29+
public function removeCustomHeader(string $name): static
30+
{
31+
$normalized = strtolower($name);
32+
if (isset($this->customHeaders[$normalized])) {
33+
unset($this->customHeaders[$normalized]);
34+
}
35+
return $this;
36+
}
37+
38+
protected function addCustomHeadersToRequest(Request $request): Request
39+
{
40+
if (!empty($this->customHeaders)) {
41+
foreach ($this->customHeaders as $headerNormalized => $values) {
42+
$request = $request->withHeader($values[0], $values[1]);
43+
}
44+
}
45+
return $request;
46+
}
47+
}

tests/Endpoint/RestTest.php

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
<?php
2+
3+
namespace Sugarcrm\REST\Tests\Endpoint;
4+
5+
use PHPUnit\Framework\TestCase;
6+
use GuzzleHttp\Psr7\Response;
7+
use GuzzleHttp\Psr7\Request;
8+
use Sugarcrm\REST\Endpoint\Rest;
9+
use Sugarcrm\REST\Tests\Stubs\Client\Client;
10+
11+
class RestTest extends TestCase
12+
{
13+
protected Client $client;
14+
15+
protected function setUp(): void
16+
{
17+
$this->client = new Client();
18+
parent::setUp();
19+
}
20+
21+
public function testGetRequestToCustomEndpoint()
22+
{
23+
$this->client->mockResponses->append(new Response(200, [], 'OK'));
24+
$rest = $this->client->rest('custom/endpoint');
25+
$rest->setBaseUrl('http://localhost/rest/v11');
26+
$rest->get(['foo' => 'bar']);
27+
$request = $this->client->mockResponses->getLastRequest();
28+
$this->assertEquals('GET', $request->getMethod());
29+
$this->assertEquals('http://localhost/rest/v11/custom/endpoint?foo=bar', (string) $request->getUri());
30+
$this->assertStringContainsString('foo=bar', (string) $request->getUri()->getQuery());
31+
}
32+
33+
public function testPostRequestWithData()
34+
{
35+
$this->client->mockResponses->append(new Response(200, [], 'OK'));
36+
$rest = new Rest([], ['custom/endpoint']);
37+
$rest->setClient($this->client);
38+
$rest->setBaseUrl('http://localhost/rest/v11');
39+
$data = ['foo' => 'bar', 'baz' => 'qux'];
40+
$rest->post($data);
41+
$request = $this->client->mockResponses->getLastRequest();
42+
$this->assertEquals('POST', $request->getMethod());
43+
$this->assertEquals('http://localhost/rest/v11/custom/endpoint', (string) $request->getUri());
44+
$body = json_decode($request->getBody()->getContents(), true);
45+
$this->assertEquals($data, $body);
46+
}
47+
48+
public function testPutRequestWithData()
49+
{
50+
$this->client->mockResponses->append(new Response(200, [], 'OK'));
51+
$rest = new Rest([], ['custom/endpoint']);
52+
$rest->setClient($this->client);
53+
$rest->setBaseUrl('http://localhost/rest/v11');
54+
$data = ['foo' => 'bar'];
55+
$rest->put($data);
56+
$request = $this->client->mockResponses->getLastRequest();
57+
$this->assertEquals('PUT', $request->getMethod());
58+
$body = json_decode($request->getBody()->getContents(), true);
59+
$this->assertEquals($data, $body);
60+
}
61+
62+
public function testPatchRequestWithData()
63+
{
64+
$this->client->mockResponses->append(new Response(200, [], 'OK'));
65+
$rest = new Rest([], ['custom/endpoint']);
66+
$rest->setClient($this->client);
67+
$rest->setBaseUrl('http://localhost/rest/v11');
68+
$data = ['foo' => 'bar'];
69+
$rest->patch($data);
70+
$request = $this->client->mockResponses->getLastRequest();
71+
$this->assertEquals('PATCH', $request->getMethod());
72+
$body = json_decode($request->getBody()->getContents(), true);
73+
$this->assertEquals($data, $body);
74+
}
75+
76+
public function testDeleteRequest()
77+
{
78+
$this->client->mockResponses->append(new Response(200, [], 'OK'));
79+
$rest = $this->client->rest('custom/endpoint');
80+
$rest->setBaseUrl('http://localhost/rest/v11');
81+
$rest->delete();
82+
$request = $this->client->mockResponses->getLastRequest();
83+
$this->assertEquals('DELETE', $request->getMethod());
84+
$this->assertEquals('http://localhost/rest/v11/custom/endpoint', (string) $request->getUri());
85+
}
86+
87+
public function testAddCustomHeader()
88+
{
89+
$this->client->mockResponses->append(new Response(200, [], 'OK'));
90+
$rest = $this->client->rest('custom/endpoint');
91+
$rest->setBaseUrl('http://localhost/rest/v11');
92+
$rest->addCustomHeader('X-Test-Header', 'value1');
93+
$rest->get();
94+
$request = $this->client->mockResponses->getLastRequest();
95+
$this->assertTrue($request->hasHeader('X-Test-Header'));
96+
$this->assertEquals(['value1'], $request->getHeader('X-Test-Header'));
97+
}
98+
99+
public function testRemoveCustomHeader()
100+
{
101+
$this->client->mockResponses->append(new Response(200, [], 'OK'));
102+
$rest = $this->client->rest('custom/endpoint');
103+
$rest->setBaseUrl('http://localhost/rest/v11');
104+
$rest->addCustomHeader('X-Test-Header', 'value1');
105+
$rest->removeCustomHeader('X-Test-Header');
106+
$rest->get();
107+
$request = $this->client->mockResponses->getLastRequest();
108+
$this->assertFalse($request->hasHeader('X-Test-Header'));
109+
}
110+
111+
public function testMultipleCustomHeaders()
112+
{
113+
$this->client->mockResponses->append(new Response(200, [], 'OK'));
114+
$rest = $this->client->rest('custom/endpoint');
115+
$rest->setBaseUrl('http://localhost/rest/v11');
116+
$rest->addCustomHeader('X-Test-Header', 'value1');
117+
$rest->addCustomHeader('Another-Header', 'value2');
118+
$rest->get();
119+
$request = $this->client->mockResponses->getLastRequest();
120+
$this->assertTrue($request->hasHeader('X-Test-Header'));
121+
$this->assertEquals(['value1'], $request->getHeader('X-Test-Header'));
122+
$this->assertTrue($request->hasHeader('Another-Header'));
123+
$this->assertEquals(['value2'], $request->getHeader('Another-Header'));
124+
}
125+
}

0 commit comments

Comments
 (0)