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

Commit

Permalink
Add backward compatibility with REST-style webhook topics (e.g. "orde…
Browse files Browse the repository at this point in the history
…rs/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
  • Loading branch information
squatto authored Jul 8, 2021
1 parent 8f8653d commit 320ea52
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 17 deletions.
28 changes: 14 additions & 14 deletions src/ShopifyApp/Console/WebhookJobMakeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Foundation\Console\JobMakeCommand;
use Illuminate\Support\Str;
use Osiset\ShopifyApp\Util;
use Symfony\Component\Console\Input\InputArgument;

class WebhookJobMakeCommand extends JobMakeCommand
Expand Down Expand Up @@ -54,13 +55,18 @@ public function handle()
{
$result = parent::handle();

$topic = Util::getGraphQLWebhookTopic($this->argument('topic'));

$type = $this->getUrlFromName($this->argument('name'));
$address = route(Util::getShopifyConfig('route_names.webhook'), $type);

// Remind user to enter job into config
$this->info("For non-GDPR webhooks, don't forget to register the webhook in config/shopify-app.php. Example:");
$this->info("
'webhooks' => [
[
'topic' => '{$this->argument('topic')}',
'address' => 'https://your-domain.com/webhook/{$this->getUrlFromName(trim($this->argument('name')))}'
'topic' => '$topic',
'address' => '$address'
]
]
");
Expand All @@ -75,13 +81,7 @@ public function handle()
*/
protected function getNameInput(): string
{
$name = parent::getNameInput();
$suffix = 'Job';
if (! Str::endsWith($name, $suffix)) {
$name .= $suffix;
}

return $name;
return Str::finish(parent::getNameInput(), 'Job');
}

/**
Expand All @@ -93,10 +93,10 @@ protected function getNameInput(): string
*/
protected function getUrlFromName(string $name): string
{
if (Str::endsWith($name, 'Job')) {
$name = substr($name, 0, -3);
}

return strtolower(preg_replace('/(?<!^)[A-Z]/', '-$0', $name));
return Str::of($name)
->trim()
->replaceMatches('/Job$/', '')
->replaceMatches('/(?<!^)[A-Z]/', '-$0')
->lower();
}
}
6 changes: 5 additions & 1 deletion src/ShopifyApp/Services/ApiHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,12 @@ public function createWebhook(array $payload): ResponseAccess
}
';

// change REST-format topics ("resource/event")
// to GraphQL-format topics ("RESOURCE_EVENT") for pre-v17 compatibility
$topic = Util::getGraphQLWebhookTopic($payload['topic']);

$variables = [
'topic' => $payload['topic'],
'topic' => $topic,
'webhookSubscription' => [
'callbackUrl' => $payload['address'],
'format' => 'JSON',
Expand Down
15 changes: 15 additions & 0 deletions src/ShopifyApp/Util.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,19 @@ public static function getShopifyConfig(string $key, $shop = null)

return Arr::get($config, $key);
}

/**
* Convert a REST-format webhook topic ("resource/event")
* to a GraphQL-format webhook topic ("RESOURCE_EVENT").
*
* @param string $topic
*
* @return string
*/
public static function getGraphQLWebhookTopic(string $topic): string
{
return Str::of($topic)
->upper()
->replaceMatches('/[^A-Z_]/', '_');
}
}
7 changes: 5 additions & 2 deletions src/ShopifyApp/resources/config/shopify-app.php
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,11 @@
|--------------------------------------------------------------------------
|
| This option is for defining webhooks.
| Key is for the Shopify webhook event
| Value is for the endpoint to call
| `topic` is the GraphQL value of the Shopify webhook event.
| `address` is the endpoint to call.
|
| Valid values for `topic` can be found here:
| https://shopify.dev/api/admin/graphql/reference/events/webhooksubscriptiontopic
|
*/

Expand Down
23 changes: 23 additions & 0 deletions tests/UtilTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,27 @@ public function testGetShopifyConfig(): void
$this->assertEquals('hello world', $secret);
$this->assertEquals('OFFLINE', $grantMode);
}

public function testGraphQLWebhookTopic(): void
{
// REST-format topics are changed to the GraphQL format
$topics = [
'app/uninstalled' => 'APP_UNINSTALLED',
'orders/partially_fulfilled' => 'ORDERS_PARTIALLY_FULFILLED',
'order_transactions/create' => 'ORDER_TRANSACTIONS_CREATE',
];

foreach ($topics as $restTopic => $graphQLTopic) {
$this->assertEquals(
$graphQLTopic,
Util::getGraphQLWebhookTopic($restTopic)
);
}

// GraphQL-format topics are unchanged
$this->assertEquals(
'ORDERS_PARTIALLY_FULFILLED',
Util::getGraphQLWebhookTopic('ORDERS_PARTIALLY_FULFILLED')
);
}
}

0 comments on commit 320ea52

Please sign in to comment.