Add Webhooks to your Laravel app, arrr

Related tags

Laravel captainhook
Overview

Captain Hook

# Captain Hook ## Add Webhooks to your Laravel app, arrr

image image codecov.io Scrutinizer Code Quality Build Status StyleCI

Implement multiple webhooks into your Laravel app using the Laravel Event system.

A webhook is a method of altering the behavior of a web application, with custom callbacks.
These callbacks may be managed by third-party users and developers who may not necessarily
be affiliated with the originating application.

Examples

php artisan hook:add http://www.myapp.com/hooks/ '\App\Events\PodcastWasPurchased'
php artisan hook:add http://www.myapp.com/hooks/ 'eloquent.saved: \App\User'
Input::get("url"), "event" => "\\App\\Events\\MyEvent", "tenant_id" => Auth::id() ]); ">
Webhook::create([
    "url" => Input::get("url"),
    "event" => "\\App\\Events\\MyEvent",
    "tenant_id" => Auth::id()
]);

Contents

## Installation

In order to add CaptainHook to your project, just add

"mpociot/captainhook": "~2.0"

to your composer.json's require block. Then run composer install or composer update.

Or run composer require mpociot/captainhook if you prefer that.

Then in your config/app.php add

Mpociot\CaptainHook\CaptainHookServiceProvider::class

to the providers array.

Publish and run the migration to create the "webhooks" table that will hold all installed webhooks.

php artisan vendor:publish --provider="Mpociot\CaptainHook\CaptainHookServiceProvider"

php artisan migrate
## Usage

The CaptainHook service provider listens for any eloquent.* events.

If the package finds a configured webhook for an event, it will make a POST request to the specified URL.

Webhook data is sent as JSON in the POST request body. The full event object is included and can be used directly, after parsing the JSON body.

Example

Let's say you want to have a webhook that gets called every time your User model gets updated.

The event that gets called from Laravel will be:

eloquent.updated: \App\User

So this will be the event you want to listen for.

### Add new webhooks

If you know which event you want to listen to, you can add a new webhook by using the hook:add artisan command.

This command takes two arguments:

  • The webhook URL that will receive the POST requests
  • The event name. This could either be one of the eloquent.* events, or one of your custom events.
php artisan hook:add http://www.myapp.com/hook/ 'eloquent.saved: \App\User'

You can also add multiple webhooks for the same event, as all configured webhooks will get called asynchronously.

### Delete existing webhooks

To remove an existing webhook from the system, use the hook:delete command. This command takes the webhook ID as an argument.

php artisan hook:delete 2
### List all active webhooks

To list all existing webhooks, use the hook:list command.

It will output all configured webhooks in a table.

### Spark

Install this package like stated in the Installation section, then follow the Spark installation instructions.

### Custom event listeners

All listeners are defined in the config file located at config/captain_hook.php.

### Receiving a webhook notification

To receive the event data in your configured webhook, use:

// Retrieve the request's body and parse it as JSON
$input = @file_get_contents("php://input");
$event_json = json_decode($input);

// Do something with $event_json
### Webhook logging

Starting with version 2.0, this package allows you to log the payload and response of the triggered webhooks.

NOTE: A non-blocking queue driver (not sync) is highly recommended. Otherwise your application will need to wait for the webhook execution.

You can configure how many logs will be saved per webhook (Default 50).

This value can be modified in the configuration file config/captain_hook.php.

### Using webhooks with multi tenancy

Sometimes you don't want to use system wide webhooks, but rather want them scoped to a specific "tenant". This could be bound to a user or a team.

The webhook table has a field tenant_id for this purpose. So if you want your users to be able to add their own webhooks, you won't use the artisan commands to add webhooks to the database, but add them on your own.

To add a webhook that is scoped to the current user, you could do for example:

Input::get("url"), "event" => "\\App\\Events\\MyEvent", "tenant_id" => Auth::id() ]); ">
Webhook::create([
    "url" => Input::get("url"),
    "event" => "\\App\\Events\\MyEvent",
    "tenant_id" => Auth::id()
]);

Now when you fire this event, you want to call the webhook only for the currently logged in user.

In order to filter the webhooks, modify the filter configuration value in the config/captain_hook.php file. This filter is a Laravel collection filter.

To return only the webhooks for the currently logged in user, it might look like this:

'filter' => function( $webhook ){
    return $webhook->tenant_id == Auth::id();
},
## License

CaptainHook is free software distributed under the terms of the MIT license.

'Day 02: Table, Lamp & Treasure Map' image licensed under Creative Commons 2.0 - Photo from stevedave

Comments
  • Feature/fixes by pionect

    Feature/fixes by pionect

    Hey,

    I changed the following things:

    • Check if migrations ran in service provider before querying the database. If the package is added by a deploy service, it fails because it tries to fetch webhooks before the migrations are run.
    • Remove dynamic migration dates. This is because I needed to change the migration in an other package in stead of the underlying Laravel project. It's impossible to override a migration in an other package if "vendor:publish" is run by a deploy service and the migration name is unknown. (the files are copied after all the service providers have been triggered, so the check if the migration already exists doesn't work in this case)
    • made tenant_id unsigned This is done so I can set a foreign key to another table.
    • add missing : to eloquent events in README The webhooks weren't triggering because I missed a : in the event name.

    Hope I provided enough info and you accept this pull request! :)

    opened by dducro 6
  • [2.0] Allow logging webhook triggers

    [2.0] Allow logging webhook triggers

    This is a fairly large PR, and it does a few things aside from what the title says:

    • [x] Allow users to enable logging of webhooks (defaults to active with a 50 logs/hook limit)
    • [x] Make code more testable by clearer separation
    • [x] Separate the execution of the event handler out into a separate job
    • [x] New migration system to allow creating multiple migrations, this will make upgrading easier as it just requires publishing the latest files

    Upgrade notes

    This introduces a logger as part of the Job. This means that users need to run the latest migration, by first publishing the latest migration files and calling php artisan migrate.

    • No need for a custom service provider, you now declare your listeners in the config file!
    • Request data is now not automatically JSON encoded, this is instead done by the transformer in config. By default, the function is a simple JSON encode.

    Final comments

    The package is still lacking some structure. However, I did not want to restructure the entire application in this pull request. In the future, a goal should be to get rid of getters and setters only used for testing purposes, and instead resolved out of the IoC container, for a start. Abstracting out Guzzle might also be useful for testing purposes, and same goes for the logging module.

    opened by phroggyy 6
  • Removing webhooks based on response

    Removing webhooks based on response

    We're using this with Zapier, but we'd like to remove the webhooks/subscriptions/zaps that are returning 401 (removed).

    Could we add some code to TriggerWebhooksJob.php around line 72 to the tune of this:

                    }, function ($request, $options, Promise $response) use ($log, $webhook) {
                    $response->then(function (ResponseInterface $response) use ($log, $webhook) {
                        $log->status = $response->getStatusCode();
                        $log->response = $response->getBody()->getContents();
                        $log->response_format = $log->payload_format = isset($response->getHeader('Content-Type')[0]) ? $response->getHeader('Content-Type')[0] : null;
    
                        $log->save();
    
                        // Retry this job if the webhook response didn't give us a HTTP 200 OK
                        if ($response->getStatusCode() != 200) {
                            $this->release(30);
                        }
    
                        // Delete the webhook if the reponse is returning HTTP 410 REMOVED
                        if ($response->getStatusCode() == 410) {
                            $webhook->delete();
                        }
                    });
    
    enhancement 
    opened by stulogy 5
  • [New Feature] - Allow logging of up to X webhook responses

    [New Feature] - Allow logging of up to X webhook responses

    In order to analyze possible webhook errors or to just display the results of the last X webhooks, we need a "webhook_logs" table, that will store that information. It should be configurable how many log entries get stored per webhook.

    enhancement 
    opened by mpociot 2
  • eloquent.saved event for model is not getting fired.

    eloquent.saved event for model is not getting fired.

    Issue description

    I have been trying to get captainhook to work for a model and was not able to do so. I'm not sure where I'm doing a mistake but I assume Laravel is not firing eloquent.saved or any other events. I followed all the exact instructions mentioned in readme.

    Here are my project files that might help resolve the issue:

    Any help is greatly appreciated.

    php artisan hook:list

    +----+-----------+------------------------+----------------------------+
    | id | tenant_id | url                    | event                      |
    +----+-----------+------------------------+----------------------------+
    | 7  |           | http://localhost:10000 | eloquent.saved \App\Vessel |
    +----+-----------+------------------------+----------------------------+
    

    composer.json

    {
      "name": "laravel/laravel",
      "description": "The Laravel Framework.",
      "keywords": [
        "framework",
        "laravel"
      ],
      "license": "MIT",
      "type": "project",
      "require": {
        "laravel/framework": "5.2.39",
        "league/flysystem-aws-s3-v3": "~1.0",
        "venturecraft/revisionable": "1.*",
        "maknz/slack": "^1.7",
        "phpmailer/phpmailer": "^5.2",
        "snowfire/beautymail": "dev-master",
        "mpociot/captainhook": "~2.0",
        "doctrine/dbal": "^2.5",
        "predis/predis": "^1.1",
        "torann/currency": "^0.3.0",
        "yajra/laravel-datatables-oracle": "~6.0"
      },
      "require-dev": {
        "fzaninotto/faker": "~1.4",
        "mockery/mockery": "0.9.*",
        "phpunit/phpunit": "~4.0",
        "symfony/css-selector": "2.8.*|3.0.*",
        "symfony/dom-crawler": "2.8.*|3.0.*"
      },
      "autoload": {
        "classmap": [
          "database",
          "app/Libraries/ImageUploaderPHP"
        ],
        "psr-4": {
          "App\\": "app/"
        },
        "files": [
          "app/Support/helpers.php"
        ]
      },
      "autoload-dev": {
        "classmap": [
          "tests/TestCase.php"
        ]
      },
      "scripts": {
        "post-root-package-install": [
          "php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
          "php artisan key:generate"
        ],
        "post-install-cmd": [
          "Illuminate\\Foundation\\ComposerScripts::postInstall",
          "php artisan optimize"
        ],
        "post-update-cmd": [
          "Illuminate\\Foundation\\ComposerScripts::postUpdate",
          "php artisan optimize"
        ]
      },
      "config": {
        "preferred-install": "dist",
        "process-timeout": 0
      }
    }
    
    

    .env

    APP_ENV=local
    APP_DEBUG=true
    APP_KEY=1yoaL71DDzGvey0BwVy25hySFMdBaEoA
    
    DB_HOST=127.0.0.1
    DB_DATABASE=myfyba
    DB_USERNAME=root
    DB_PASSWORD=
    
    CACHE_DRIVER=redis
    SESSION_DRIVER=redis
    QUEUE_DRIVER=redis
    REDIS_HOST=localhost
    
    ....
    

    config/captain_hook.php

    <?php
    
    /**
     * This file is part of CaptainHook arrrrr.
     *
     * @license MIT
     */
    
    return [
    
        /*
        |--------------------------------------------------------------------------
        | Event listeners
        |--------------------------------------------------------------------------
        |
        | This array allows you to define all events that Captain Hook should
        | listen for in the application. By default, the Captain will just
        | respond to eloquent events, but you may edit this as you like.
        */
        'listeners' => ['eloquent.*'],
    
        /*
        |--------------------------------------------------------------------------
        | Webhook filter closure
        |--------------------------------------------------------------------------
        |
        | If your webhooks are scoped to a tenant_id, you can modify
        | this filter function to return only the webhooks for your
        | tenant. This function is applied as a collection filter.
        | The tenant_id field can be used for verification.
        |
        */
        'filter' => function ($webhook) {
            return true;
        },
    
        /*
        |--------------------------------------------------------------------------
        | Webhook data transformer
        |--------------------------------------------------------------------------
        |
        | The data transformer is a simple function that allows you to take the
        | subject data of an event and convert it to a format that will then
        | be posted to the webhooks. By default, all data is json encoded.
        | The second argument is the Webhook that was triggered in case
        | you want to transform the data in different ways per hook.
        |
        | You can also use the 'Foo\Class@transform' notation if you want.
        |
        */
        'transformer' => function ($eventData, $webhook) {
            return json_encode($eventData);
        },
    
        /*
        |--------------------------------------------------------------------------
        | Webhook response callback
        |--------------------------------------------------------------------------
        |
        | The response callback can be used if you want to trigger
        | certain actions depending on the webhook response.
        | This is unused by default.
        |
        | You can also use the 'Foo\Class@handle' notation if you want.
        |
        */
        'response_callback' => function ($webhook, $response) {
            // Handle custom response status codes, ...
        },
    
        /*
        |--------------------------------------------------------------------------
        | Logging configuration
        |--------------------------------------------------------------------------
        |
        | Captain Hook ships with built-in logging to allow you to store data
        | about the requests that you have made in a certain time interval.
        */
        'log' => [
            'active' => true,
            'storage_quantity' => 50,
        ],
    ];
    
    opened by nullifiedaccount 1
  • Class GuzzleHttp\Middleware doesn't exist in guzzlehttp/guzzle ~5.3

    Class GuzzleHttp\Middleware doesn't exist in guzzlehttp/guzzle ~5.3

    In looking at the source for guzzlehttp/guzzle 5.3 (https://github.com/guzzle/guzzle/tree/5.3/src), there is no Middleware class, so it's no surprise that I'm getting a "Class does not exist" exception.

    This can be resolved by either dropping support for 5.3 in your composer.json file, or refactoring your usage of the Middleware class to be compliant with 5.3 and 6.

    opened by adamgoose 1
  • webhook is not working

    webhook is not working

    I added a webhook by running this -

    php artisan hook:add http://localhost:9999 'eloquent.updated \App\Models\User'

    but when I update my user model I don't get any request in http://localhost:9999

    Am I doing it right? Any help will be appreciated.

    Thanks

    opened by shahriar1 1
  • Adding the ability to assign the tenant_id to the Spark Team

    Adding the ability to assign the tenant_id to the Spark Team

    The new 'tenant_spark_model' option in the config allows you to assign the tenant_id to the Spark Team instead of the User like is happening by default.

    opened by crash13override 1
  • Adding option to enable /api routes and with auth:api middleware

    Adding option to enable /api routes and with auth:api middleware

    With this new config option you can choose to add extra routes that will allow services like Zapier to create,update and delete Webhooks like explained in this website http://resthooks.org/ .

    opened by crash13override 1
  • Sort requires and keywords in composer.json

    Sort requires and keywords in composer.json

    • Sort import in composer.json : this allows to get less noise in commits when adding/updating/deleting an entry
    • Add support for phpunit 5
    • Use new || syntax
    • Stay consistant and use tilde (~) syntax for Mockery
    opened by lucasmichot 1
  • Allow to define custom events in a config file

    Allow to define custom events in a config file

    If we allow users to define custom events in a config file, there will be no need to go through the hassle of extend the SP, which I reckon could be quite handy.

    opened by phroggyy 1
  • [Feature Request] Adding additional headers to outgoing webhook

    [Feature Request] Adding additional headers to outgoing webhook

    So far looks like request post to webhook receiver is anonymous. Can this be a configuration of adding more header options?

    For example: create a captain_hook.request_header callable (like $transformer), then we can use the $webhook object and original $header option, such as

    // @file config/config.php
    'request_header' => function ($webhook, $header = []) {
        return [
            'X-Hub-Signature' => 'sha1=xxxxxxxxxxxxxxxxxxxxx',
        ]
    }
    
    opened by oh-bala 0
  • Can't run

    Can't run "php artisan config:cache" because of Closure in config file

    After I try to run "php artisan config:cache" I get an error that prevents Laravel from running completely (ReflectionException). After some debugging I found that the problem was in this part of the config file of CaptainHook

        'filter'             => function($webhook) {
            return $webhook->tenant_id == Auth::user()->currentTeam->id;
        },
    

    The problem is that Laravel can't cache Closures, so it's throwing an error.

    It would be really nice if we could pass to the filter params also a string with the Class and method to be run ("\App\SomeClass@someMethod"), just like you do for the "transformer" and the "response_callback" field.

    Do you think it would be possible to make?

    and thanks a lot for the amazing libraries you've built!!!

    opened by crash13override 2
  • Fix #43

    Fix #43

    Our take on Laravel 5.4 compatibility.

    By using a wildcard in the event name Laravel will give us the event name in the event listener so we don’t have to retrieve the name from elsewhere.

    opened by phoogkamer 0
  • Laravel 5.1 not supported?

    Laravel 5.1 not supported?

    I'm integrating this module into a Laravel 5.1 application and I found some incompatibilities.

    To get it working, I had to make a change to the migration scripts and revert PR #37 (Removed deprecated Selfhandling contract).

    Is there any plan to continue support for Laravel 5.1 such as a maintenance branch or is there some specific version of this package I should use instead?

    I'm fairly new to Laravel so I might be missing something. Also, great work on the package!

    opened by tiagoalves 0
Releases(3.2.0)
Owner
Marcel Pociot
Marcel Pociot
Laravel Breadcrumbs - An easy way to add breadcrumbs to your @Laravel app.

Introduction Breadcrumbs display a list of links indicating the position of the current page in the whole site hierarchy. For example, breadcrumbs lik

Alexandr Chernyaev 269 Dec 21, 2022
Add tags and taggable behaviour to your Laravel app

Add tags and taggable behaviour to a Laravel app This package offers taggable behaviour for your models. After the package is installed the only thing

Spatie 1.4k Dec 29, 2022
Add variables to the payload of all jobs in a Laravel app

Inject extra info to the payloads of all jobs in a Laravel app This package makes it easy to inject things in every job. Imagine that you want to have

Spatie 62 Dec 9, 2022
Easily add a full Laravel blog (with built in admin panel and public views) to your laravel project with this simple package.

Webdevetc BlogEtc - Complete Laravel Blog Package Quickly add a blog with admin panel to your existing Laravel project. It has everything included (ro

WebDevEtc. 227 Dec 25, 2022
Laravel-tagmanager - An easier way to add Google Tag Manager to your Laravel application.

Laravel TagManager An easier way to add Google Tag Manager to your Laravel application. Including recommended GTM events support. Requirements Laravel

Label84 16 Nov 23, 2022
A simple blog app where a user can signup , login, like a post , delete a post , edit a post. The app is built using laravel , tailwind css and postgres

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Nahom_zd 1 Mar 6, 2022
This package lets you add uuid as primary key in your laravel applications

laravel-model-uuid A Laravel package to add uuid to models Table of contents Installation Configuration Model Uuid Publishing files / configurations I

salman zafar 10 May 17, 2022
A Laravel package helps you add a complete real-time messaging system to your new / existing application with only one command.

A Laravel package helps you add a complete real-time messaging system to your new / existing application with only one command.

Munaf Aqeel Mahdi 1.7k Jan 5, 2023
Add Server-Timing header information from within your Laravel apps.

Laravel Server Timings Add Server-Timing header information from within your Laravel apps. Installation You can install the package via composer: comp

Beyond Code 498 Dec 15, 2022
`dd` is a helper method in Laravel. This package will add the `dd` to your application.

dd dd is a helper method in Laravel. This package will add the dd to your application. Install Run composer require larapack/dd 1.* For Laravel Larave

Larapack 109 Dec 26, 2022
Add Active Campaign API v3 to your Laravel application.

Laravel ActiveCampaign (WIP) This package provides a simple interface to the ActiveCampaign API v3. Currently the packages only supports the endpoints

Label84 10 Nov 28, 2022
Easily add all the 58 Algerian Wilayas and its Dairas to your cool Laravel project (Migrations, Seeders and Models).

Laravel-Algereography Laravel-Algereography allows you to add Migrations, Seeders and Models of Algerian Wilayas and Dairas to your existing or new co

Hocine Saad 48 Nov 25, 2022
Laravel-OvalFi helps you Set up, test, and manage your OvalFi integration directly in your Laravel App.

OvalFi Laravel Package Laravel-OvalFi helps you Set up, test, and manage your OvalFi integration directly in your Laravel App. Installation You can in

Paul Adams 2 Sep 8, 2022
A web app for detecting backend technologies used in a web app, Based on wappalyzer node module

About Techdetector This a web fingerprinting application, it detects back end technologies of a given domain by using the node module wappalyzer. And

Shobi 17 Dec 30, 2022
CV-Resumes-App is helped us to build resume .. you can help me to improve this app...

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Eng Hasan Hajjar 2 Sep 30, 2022
This package helps you to add user based follow system to your model.

Laravel Follow User follow unfollow system for Laravel. Related projects: Like: overtrue/laravel-like Favorite: overtrue/laravel-favorite Subscribe: o

安正超 1k Dec 31, 2022
An easy way to add colors in your CLI scripts.

COLORS Here is a preview of what you can achieve with the library: Installation Installation via composer is highly recommended. { "require": {

Kevin Le Brun 335 Dec 4, 2022
Add internal link to your published assets.

WORK IN PROGRESS, some functionalities may be changed in the future. Add internal link to your published assets. Installation You can install the pack

Kaqaz Studio 1 Aug 9, 2022
Custom Blade components to add sortable/drag-and-drop HTML elements in your apps.

Laravel Blade Sortable Demo Repo Installation You can install the package via composer: composer require asantibanez/laravel-blade-sortable After the

Andrés Santibáñez 370 Dec 23, 2022