[go: up one dir, main page]

Skip to content

Aims making it easier to organize internal handling of incoming webhooks.

License

Notifications You must be signed in to change notification settings

m-shule/laravel-pipes

Repository files navigation

laravel-pipes

Software License Build Status codecov Total Downloads

Handling notifications from API's is simple when they only require to handle one type of notification, but if you have to handle multiple requests e.g. from an SMS API it can get messy. Similar to Botman's hear() method, this package provides a slightly different approach which could be used as part of another Botman like implementation. This package offers a similar API as you are used to from the Laravel Routes.

Install

composer require mshule/laravel-pipes

The incoming web request will be handled by your_app_domain + whatever you put in the pipes.incoming_request_path config. By default, the path will result in your_app_domain/handle-notification.

Optional: Create a separate route file for your pipes.

  1. add a new file routes/pipes.php
  2. set the pipes.load_routes_file to true

Usage

To get an overview of all functionalities this package offers, you can check the tests/PipeRequestTest.php.

Handling Pipes

Pipes are matched by the keys and values of the request's data attributes.

// define pipe match for `foo` => `bar`
// key, value, action
Pipe::match('foo', 'bar', function () {
  return 'matched';
});

// same as
Pipe::match('foo:bar', function () {
  return 'matched';
})

$this->pipe(['foo' => 'bar'])
  ->assertSee('matched'); // true

Attributes can be bound dynamically to the pipe-request.

Pipe::match('foo:{bar}', function ($bar) {
  return $bar;
});

$this->pipe(['foo' => 'bar'])
  ->assertSee('bar'); // true

$this->pipe(['foo' => 'other'])
  ->assertSee('other'); // true

Instead of handling all pipe requests inside a callback, you can also redirect to a controller action.

Pipe::match('foo:{bar}', 'SomeController@index');

If you want to handle multiple requests with different attribute keys you can use the Pipe::any() method.

Pipe::any('{bar}', 'SomeController@index');

Other Options

alias() Sometimes the user might have a typo in their message or you simply want to have different cues available to trigger a Pipe.

Pipe::any('bar', 'FooBarController')
  ->alias(['ba', 'b-r', 'bas']);

The FooBarController will now be called upon ba, b-r, bas or as originally intended on bar.

namespace() As you have probably noted the routes/pipes.php file is bound to a namespace configurable in the config/pipes.php. If you want to define a group with a different namespace, you can use the namespace() method:

Pipe::middleware('pipe')
  ->namespace(config('pipes.namespace'))
  ->group(function () {
    // define your namespaced pipes here
  });

key() Like demonstrated in the first section of the Handling Pipes documentation, you can define Pipe routes in man different ways.

Pipe::match('foo', 'bar', function () {});

// same as
Pipe::match('foo:bar', function () {});

There is a third option to specify the key of a Pipe by using the key() method.

Pipe::key('foo')->match('bar', function () {});

The key method is handy if you have got several pipe routes which react to the same key.

Pipe::key('text')
  ->group(function () {
    // all pipe definitions within here will check for the `text` as key in the incoming request
    Pipe::match('some-text', function () {});
  });

where() To further specify which request should be sent to a specific handler you can define conditions on each pipe like you are used to with Laravel routes.

Pipe::any('{foo}', function ($foo) {
  return $foo;
})->where('foo', 'bar');

Pipe::any('{foo}', function ($foo) {
  return $foo;
})->where('foo', '[a-z]+');

Understanding Pipe Life Cycle

The laravel-pipes lifecycle starts with a post request which is sent to the pipes.incoming_request_path. The ExecutePipeRequest Job is dispatched and an HTTP response returned - this is important since the pipe request is handled asynchronously if you have another queue driver than sync. In the Job, the $request is passed to the Pipe-Kernel's handle() method where it is passed through the global pipe-middlewares. The request is matched with the registered pipes and if a match is found the response is returned, otherwise a NotFoundPipeException is thrown.

Define the queue

As explained in the section above, a job is triggered to start the pipe-lifecycle. With the pipes.queue option you can define a seperate queue to run the pipe job on.

Testing Pipes

This package provides a simple trait to perform pipe requests. The MakesPipeRequests Trait provides a pipe() method to perform a pipe-request. The method fires a post request to the specified endpoint in pipes.incoming_request_path, but it is much easier to write $this->pipe(...) than $this->post(config('pipes.incoming_request_path), [...]).

Since the pipe request is executed through a job, you have to use the Pipe::fake() method to get access to your responses.

Pipe::fake();

$this->pipe(...);

Pipe::assertResponded(function ($response) {
  $response->assertOk()
    ->assertSee(...);
});

Behind the scenes the Pipe::fake() method simply triggers the Event::fake() with the IncomingPipeRequest and IncomingPipeResonse events.

Testing

Run the tests with:

vendor/bin/phpunit

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security-related issues, please email DummyAuthorEmail instead of using the issue tracker.

License

The MIT License (MIT). Please see License File for more information.