cult3

Adding Slack Slash Commands to a Laravel application

Jan 25, 2016

Table of contents:

  1. Setting up the Slash Command
  2. Adding the route
  3. Defining the Controller
  4. Creating the Slack class
  5. Defining the Command interface
  6. Define the implementations
  7. Conclusion

Slack has exploded in popularity in the last year or so with thousands of companies adopting it as the central communication tool for their team or organisation.

Slack is basically just modern IRC with a better user interface, but Slack has also built a way to allow all types of services to integrate and push data into it as a central information hub.

This is really useful for using third-party services that your company already uses.

But it also makes it very easy to build your own internal integrations for your own application.

For example, instead of adding a page to an internal admin application, you can simply add a Slack slash command that can be used in Slack.

This is really handy for requests that simply need to return a chunk of data from time to time.

In today’s tutorial we’re going to be looking at setting up Slack slash commands in your Laravel application.

Setting up the Slash Command

The first thing we need to do is to set up the Slash Command in Slack.

If you go to your companies integrations and then choose “Slash Commands” you should be presented with a walkthrough for creating a new command.

The important bits are choosing the URL and the token as we will need those two bits of information to build the integration on the Laravel side.

Adding the route

The first thing I’m going to do is to define the route for Slack commands:

use Illuminate\Contracts\Routing\Registrar;

class SlackRoutes
{
    /**
     * Define the routes
     *
     * @param Registrar $router
     * @return void
     */
    public function map(Registrar $router)
    {
        $router->post("slack/{command}", [
            "as" => "slack.commands",
            "uses" => "SlackController@commands",
        ]);
    }
}

Here I’m defining a route that will accept the command name and then pass that as a parameter to the SlackController.

Defining the Controller

Next I will define the Controller that will be accepting the request from Slack:

class SlackController extends Controller
{
    /**
     * Run the Slack command
     *
     * @param string $command
     * @param Request $request
     * @return JsonResponse
     */
    public function commands($command, Request $request)
    {
        $response = Slack::handle($command, $request->all());

        return response()->json($response);
    }
}

As you can see I’m passing the $command and the body of the request to the handle() method on a class called Slack.

This will return a response that I can return from the Controller. At the minute this won’t work as we haven’t created the Slack class.

Creating the Slack class

Next we can create the Slack class:

class Slack
{
    /**
     * @param string $command
     * @param array $data
     */
    public static function handle($command, array $data)
    {
        $command = sprintf("Acme\Slack\Commands\%s", studly_case($command));

        if (class_exists($command)) {
            $command = new $command($data);

            return $command->handle();
        }

        throw new InvalidSlackCommand("invalid_slack_command");
    }
}

As you can see this is just a simple class with a single static method. Alternatively you could create a class and then use a Laravel facade to get that same interface.

First we accept the $command name and turn it into a namespace.

If the class exists, we can instantiate a new instance and then handle it and return the response.

Otherwise we can throw an InvalidSlackCommand Exception which will bubble up to the surface and return the correct HTTP response as we saw in Dealing with Exceptions in a Laravel API application.

Defining the Command interface

Next we need to define the Command interface for each command implementation.

interface Command
{
    /**
     * Handle the command
     *
     * @return array
     */
    public function handle();
}

Define the implementations

Finally we can define each Slash Command implementation:

class Last10Users implements Command
{
    /**
     * Handle the command
     *
     * @return array
     */
    public function handle()
    {
        // Check token
        // Find the last 10 users
        // Return response
    }
}

The array that you return from this method will be sent back to Slack and will be published as the response into the Slack channel.

To make the most of this you should have a read of the Slack Message Formatting documentation.

Now that everything is set up, to add a new Slash Command you simply have to add the command in Slack, and then create a new implementation class in your application.

Conclusion

It’s really great that the software we use can be integrated together through webhooks and API requests.

This is perfect for sending data between the various services you pay for, but it also makes it possible to tie together internal integrations for increasing the productivity of your team.

I love how easy it is to create Slack slash commands. Whenever you receive a common request from your colleagues, you can simply turn it into a slash command that they can right inside of Slack.

This allows you to get on with your work, and makes it really easy for your colleagues to get the data they need without having to authenticate with yet another different service.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.