How We Used Slack, Scala and Play to Automate Our Lunch Order

Automate all the things! Slack slash commands to the rescue

Every day at noon, lunch orders are launched. All the places we order our food from support online orders BUT there’s this one spot we like that only accepts orders by phone or email. A local homemade food restaurant with a menu that changes every week. At some point we grew tired of collecting everyone’s orders manually, so we decided to automate this process through Slack with a spontaneous hackathon. In this post we’ll share how we came across Slack’s slash commands, and how they can be customized to do anything you want.

So what are Slack slash commands?

Slash commands let you connect to other services and make your Slack resemble a command line. Or an IRC client if you’re into that. Any message that starts with a “/” can execute a preconfigured command. In addition, Slash commands carry data about the context that they’re sent from and can also include extra text. For example, if you’re using the Giphy integration, writing /giphy feed me will send a request containing that message to Giphy’s server, which will search for a random related GIF, and return it in its response.

/giphy feed me
Another nice pre-built command that comes out-of-the-box is /shrug ¯\_(ツ)_/¯

Java developers?
Get new posts directly to your inbox

How can you customize it?

In a nutshell, all we had to do is configure a new command through Slack’s settings page. Which is super easy. This is enough to make it send an HTTP request to a predefined external URL whenever the command is typed in the app. We then built a new backend that’s responsible for getting those HTTP requests and responding to them. Here’s the longer story, not necessarily in the actual order of events 🙂

Step #1: Name your command through the configurations page

Step #1: Choose a name for your Slack slash command
Talu is the name of that restaurant that we like

Step #2: Customize the command

On the next screen you’ll need to set up the URL of the backend, and give your slash command a custom name, custom icon, and description:

Step #2: Customize the command

Here we also received all the info about the payload that Slack sends with each request:

Slack Slash Command Payload

Step #3: Build the backend for the slash command

This step is a bit longer than, say… naming your command! Since we really like Scala here at Takipi we’ve decided to go with the Play Framework through Typesafe’s Activator. To get started we created a new play-scala project by typing activator new. A full description of the new project structure can be found in the Play Documentation – All we had to do essentially is change two files:

  1. The conf/routes file is responsible for mapping incoming HTTP requests to actions in the backend controller. We added the following line:
    POST    /talu                      controllers.Application.talu
  2. app/controllers/Application.scala is the place to define the actual actions.

Here’s how we defined the supported commands:


class Application extends Controller {

...

val slashCommandForm = Form(
tuple(
"command" - > text,
"text" - > text
)
)

def talu = Action {
implicit request =>
val(command, text) = slashCommandForm.bindFromRequest.get

val subCommand = text.split(" ")(0)
val param = text.substring(text.indexOf(" ") + 1)

subCommand match {
case "add" => Ok(add param)
case "remove" => Ok(remove param)
case "clear" => Ok(clear)
case "list" => Ok(list)
case "send" => Ok(send)
case _ => Ok("Bad Request :[")
}
}

....

}

And here’s how we handle adding a dish to the order:

def add(dish: String): String = {
val count = globals.orders getOrElseUpdate(dish, 0)
globals.orders += (dish - > (count + 1))

return (dish + " added.")
}

Step #4: Wrap it up

Create a Play application distribution by running: activator dist. The new distribution is created under target/universal

Step #5: Deploy!

We’ve decided to deploy using a free account of Boxfuse which was perfect for this need. A super quick deployment of a Play application to an AWS instance (also requires an AWS account of course). Without the overhead of all the usual setup and configuration. If you’d like to get a closer look at how your application behaves in production, you can also hook it up with Takipi’s agent to eliminate any guesswork when exceptions or log errors occur.

And here are the results

/talu add tom yum soup :ramen:
Slack slash command results

 

/talu list

Slack slash command results
/talu send
Slack slash command results

Final Thoughts

Taking a break from your day to day coding is always fun and refreshing. It also lets you put your hands on technologies you wouldn’t experience otherwise. If you’re into writing your own slash command, here’s a fun idea that we’d like to use ourselves: a command that acts as an English to Emoji translator, replacing words with the closest available emoji in meaning.

Wrote a cool slash command? We’d love to hear about it!
Feel free to share it in the comments below

Tzofia is a full-stack team lead in Takipi. She's a big Scala fan and currently studies towards her masters degree in Computer Science at Bar Ilan University.
  • skyahead

    Care to share the source?

  • Mich

    What about synchronization in this part of code?

    Is getOrElseUpdate safe in this case?

    def add(dish : String) : String = {
    val count = globals.orders getOrElseUpdate (dish, 0)
    globals.orders += (dish -> (count+1))

    return (dish + ” added.”)
    }

    • Tzofia Shiftan

      Hi Mich! Thanks for the comment, makes perfect sense. We will add that to the code.

  • Andres Perez

    Hey! Your post inspired me to write my own slash command that returns a listing of the nearest available food trucks. I wrote it in Scala and used the Play framework and Heroku for deployment. I also open-sourced it on GitHub so people can use it for themselves or add to it: https://github.com/andy327/slack-foodtrucks

    • Tzofia Shiftan

      Hi Andres! Wow, cool idea! We’re happy that the post inspired you to build your own slash command. I’ll add a link to your project as part of the post.

  • Guy Fighel

    What’s the external API you are using to order meals? I was looking for one and couldn’t find. 🙂
    Cool idea!

    • Tzofia Shiftan

      Hi Guy! Sorry for the late reply. We defined the API ourselves and used Play framework for the implementation. Since this place only accepts orders by email, the “send” command simply sends an email containing the order details. No special external API 🙂