Skip to content
This repository was archived by the owner on Nov 30, 2022. It is now read-only.

Commit 320ea52

Browse files
authored
Add backward compatibility with REST-style webhook topics (e.g. "orders/create") (#868)
* Add utility to convert REST webhook topic to GraphQL topic. Add test. * Convert webhook topic to GraphQL topic before creating the webhook * Show the GraphQL topic and actual webhook address in the output * Add more info to the `webhooks` config section comment * Only replace "Job" at the end of the job name
1 parent 8f8653d commit 320ea52

File tree

5 files changed

+62
-17
lines changed

5 files changed

+62
-17
lines changed

src/ShopifyApp/Console/WebhookJobMakeCommand.php

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Foundation\Console\JobMakeCommand;
66
use Illuminate\Support\Str;
7+
use Osiset\ShopifyApp\Util;
78
use Symfony\Component\Console\Input\InputArgument;
89

910
class WebhookJobMakeCommand extends JobMakeCommand
@@ -54,13 +55,18 @@ public function handle()
5455
{
5556
$result = parent::handle();
5657

58+
$topic = Util::getGraphQLWebhookTopic($this->argument('topic'));
59+
60+
$type = $this->getUrlFromName($this->argument('name'));
61+
$address = route(Util::getShopifyConfig('route_names.webhook'), $type);
62+
5763
// Remind user to enter job into config
5864
$this->info("For non-GDPR webhooks, don't forget to register the webhook in config/shopify-app.php. Example:");
5965
$this->info("
6066
'webhooks' => [
6167
[
62-
'topic' => '{$this->argument('topic')}',
63-
'address' => 'https://your-domain.com/webhook/{$this->getUrlFromName(trim($this->argument('name')))}'
68+
'topic' => '$topic',
69+
'address' => '$address'
6470
]
6571
]
6672
");
@@ -75,13 +81,7 @@ public function handle()
7581
*/
7682
protected function getNameInput(): string
7783
{
78-
$name = parent::getNameInput();
79-
$suffix = 'Job';
80-
if (! Str::endsWith($name, $suffix)) {
81-
$name .= $suffix;
82-
}
83-
84-
return $name;
84+
return Str::finish(parent::getNameInput(), 'Job');
8585
}
8686

8787
/**
@@ -93,10 +93,10 @@ protected function getNameInput(): string
9393
*/
9494
protected function getUrlFromName(string $name): string
9595
{
96-
if (Str::endsWith($name, 'Job')) {
97-
$name = substr($name, 0, -3);
98-
}
99-
100-
return strtolower(preg_replace('/(?<!^)[A-Z]/', '-$0', $name));
96+
return Str::of($name)
97+
->trim()
98+
->replaceMatches('/Job$/', '')
99+
->replaceMatches('/(?<!^)[A-Z]/', '-$0')
100+
->lower();
101101
}
102102
}

src/ShopifyApp/Services/ApiHelper.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,12 @@ public function createWebhook(array $payload): ResponseAccess
384384
}
385385
';
386386

387+
// change REST-format topics ("resource/event")
388+
// to GraphQL-format topics ("RESOURCE_EVENT") for pre-v17 compatibility
389+
$topic = Util::getGraphQLWebhookTopic($payload['topic']);
390+
387391
$variables = [
388-
'topic' => $payload['topic'],
392+
'topic' => $topic,
389393
'webhookSubscription' => [
390394
'callbackUrl' => $payload['address'],
391395
'format' => 'JSON',

src/ShopifyApp/Util.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,19 @@ public static function getShopifyConfig(string $key, $shop = null)
194194

195195
return Arr::get($config, $key);
196196
}
197+
198+
/**
199+
* Convert a REST-format webhook topic ("resource/event")
200+
* to a GraphQL-format webhook topic ("RESOURCE_EVENT").
201+
*
202+
* @param string $topic
203+
*
204+
* @return string
205+
*/
206+
public static function getGraphQLWebhookTopic(string $topic): string
207+
{
208+
return Str::of($topic)
209+
->upper()
210+
->replaceMatches('/[^A-Z_]/', '_');
211+
}
197212
}

src/ShopifyApp/resources/config/shopify-app.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,11 @@
310310
|--------------------------------------------------------------------------
311311
|
312312
| This option is for defining webhooks.
313-
| Key is for the Shopify webhook event
314-
| Value is for the endpoint to call
313+
| `topic` is the GraphQL value of the Shopify webhook event.
314+
| `address` is the endpoint to call.
315+
|
316+
| Valid values for `topic` can be found here:
317+
| https://shopify.dev/api/admin/graphql/reference/events/webhooksubscriptiontopic
315318
|
316319
*/
317320

tests/UtilTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,27 @@ public function testGetShopifyConfig(): void
8282
$this->assertEquals('hello world', $secret);
8383
$this->assertEquals('OFFLINE', $grantMode);
8484
}
85+
86+
public function testGraphQLWebhookTopic(): void
87+
{
88+
// REST-format topics are changed to the GraphQL format
89+
$topics = [
90+
'app/uninstalled' => 'APP_UNINSTALLED',
91+
'orders/partially_fulfilled' => 'ORDERS_PARTIALLY_FULFILLED',
92+
'order_transactions/create' => 'ORDER_TRANSACTIONS_CREATE',
93+
];
94+
95+
foreach ($topics as $restTopic => $graphQLTopic) {
96+
$this->assertEquals(
97+
$graphQLTopic,
98+
Util::getGraphQLWebhookTopic($restTopic)
99+
);
100+
}
101+
102+
// GraphQL-format topics are unchanged
103+
$this->assertEquals(
104+
'ORDERS_PARTIALLY_FULFILLED',
105+
Util::getGraphQLWebhookTopic('ORDERS_PARTIALLY_FULFILLED')
106+
);
107+
}
85108
}

0 commit comments

Comments
 (0)