Skip to content

Commit 18fa6f2

Browse files
committed
Start of webhook handler
1 parent 6e7ca6c commit 18fa6f2

File tree

7 files changed

+136
-0
lines changed

7 files changed

+136
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ A Laravel package for aiding in Shopify App development, similar to `shopify_app
3434
- [x] Authentication & installation for shops
3535
- [x] Auto install app webhooks and scripttags thorugh background jobs
3636
- [x] Provide basic ESDK views
37+
- [ ] Handles and processes incoming webhooks
3738

3839
## Requirements
3940

@@ -89,6 +90,8 @@ This package uses jobs to install webhooks and scripttags if any are defined in
8990

9091
If you do however, you can leave the `sync` driver as default. But, it may impact load times for the customer accessing the app. Its recommended to setup Redis or database as your default driver in `config/queue.php`. See [Laravel's docs on setting up queue drivers](https://laravel.com/docs/5.4/queues).
9192

93+
For more information on creating webhooks, see `docs/creating-webhooks.md`.
94+
9295
### Migrations
9396

9497
```bash
@@ -128,6 +131,7 @@ Information on getting started, overriding routes, controllers, is located in th
128131
- [Becoming a Shopify Developer](docs/becoming-a-shopify-developer.md)
129132
- [Process in Authentication](docs/process-in-authentication.md)
130133
- [Developing Locally](docs/developing-locally.md)
134+
- [Creating Webhooks](docs/creating-webhooks.md)
131135
- [Overriding / Extending Package](docs/overriding-and-extending.md)
132136

133137
## Route List

docs/creating-webhooks.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Creating Webhooks
2+
3+
*Coming soon!*
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php namespace OhMyBrew\ShopifyApp\Controllers;
2+
3+
use Illuminate\Routing\Controller;
4+
use OhMyBrew\ShopifyApp\Traits\WebhookControllerTrait;
5+
6+
class WebhookController extends Controller
7+
{
8+
use WebhookControllerTrait;
9+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php namespace OhMyBrew\ShopifyApp\Traits;
2+
3+
use \Exception;
4+
5+
trait WebhookControllerTrait
6+
{
7+
/**
8+
* Handles an incoming webhook
9+
*
10+
* @param string $type The type of webhook
11+
*
12+
* @return \Illuminate\Http\Response
13+
*/
14+
public function handle($type)
15+
{
16+
$classPath = $this->getJobClassFromType($type);
17+
if (!class_exists($classPath)) {
18+
// Can not find a job for this webhook type
19+
abort(500, "Missing webhook job: {$classPath}");
20+
}
21+
22+
// Dispatch
23+
$shopDomain = request()->header('X-Shopify-Shop-Domain');
24+
$data = request()->all();
25+
dispatch(new $classPath($shopDomain, $data));
26+
27+
return response('', 201);
28+
}
29+
30+
/**
31+
* Converts type into a class string
32+
*
33+
* @param string $type The type of webhook
34+
*
35+
* @return string
36+
*/
37+
protected function getJobClassFromType($type)
38+
{
39+
return '\\App\\Jobs\\' . str_replace('-', '', ucwords($type, '-')) . 'Job';
40+
}
41+
}

src/ShopifyApp/resources/routes.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,19 @@
5656
'OhMyBrew\ShopifyApp\Controllers\AuthController@authenticate'
5757
)
5858
->name('authenticate');
59+
60+
/*
61+
|--------------------------------------------------------------------------
62+
| Webhook Handler
63+
|--------------------------------------------------------------------------
64+
|
65+
| Handles incoming webhooks.
66+
|
67+
*/
68+
69+
Route::post(
70+
'/webhook/{type}',
71+
'OhMyBrew\ShopifyApp\Controllers\WebhookController@handle'
72+
)
73+
->name('webhook');
5974
});

tests/OrdersCreateJobStub.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php namespace App\Jobs;
2+
3+
use Illuminate\Bus\Queueable;
4+
use Illuminate\Queue\SerializesModels;
5+
use Illuminate\Queue\InteractsWithQueue;
6+
use Illuminate\Contracts\Queue\ShouldQueue;
7+
use Illuminate\Foundation\Bus\Dispatchable;
8+
9+
class OrdersCreateJob implements ShouldQueue
10+
{
11+
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
12+
13+
public function __construct($shopDomain, $data)
14+
{
15+
}
16+
17+
public function handle()
18+
{
19+
}
20+
}

tests/WebhookControllerTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php namespace OhMyBrew\ShopifyApp\Test;
2+
3+
use \ReflectionMethod;
4+
use Illuminate\Support\Facades\Queue;
5+
6+
require 'OrdersCreateJobStub.php';
7+
8+
class WebhookControllerTest extends TestCase
9+
{
10+
public function testShouldReturn201ResponseOnSuccess()
11+
{
12+
Queue::fake();
13+
14+
$response = $this->call('post', '/webhook/orders-create');
15+
$response->assertStatus(201);
16+
17+
Queue::assertPushed(\App\Jobs\OrdersCreateJob::class);
18+
}
19+
20+
21+
public function testShouldReturnErrorResponseOnFailure()
22+
{
23+
$response = $this->call('post', '/webhook/products-create');
24+
$response->assertStatus(500);
25+
$this->assertEquals('Missing webhook job: \App\Jobs\ProductsCreateJob', $response->exception->getMessage());
26+
}
27+
28+
public function testShouldCaseTypeToClass()
29+
{
30+
$controller = new \OhMyBrew\ShopifyApp\Controllers\WebhookController;
31+
$method = new ReflectionMethod(\OhMyBrew\ShopifyApp\Controllers\WebhookController::class, 'getJobClassFromType');
32+
$method->setAccessible(true);
33+
34+
$types = [
35+
'orders-create' => 'OrdersCreateJob',
36+
'super-duper-order' => 'SuperDuperOrderJob',
37+
'order' => 'OrderJob'
38+
];
39+
40+
foreach ($types as $type => $className) {
41+
$this->assertEquals("\\App\\Jobs\\$className", $method->invoke($controller, $type));
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)