A Chatbot for OhDear!
One day, I tried to show one of my posts to a coworker and I realised my website was down. I had nothing to warn me when that happens and it was kind of embarrassing. Solving it was as easy as logging in to DigitalOcean and restart the droplet, but it looked very unprofessional.
For how long was my site down? How many people were unable to read my awesome posts?
That was when I decided I needed some kind of automatic monitor for my website uptime.
The documentation looked awesome so I joined on a free 10-day trial to check if it was useful for me. It turned out to be the perfect solution I needed. Taking a look at the docs and learning how to use it (pretty easy indeed), I saw the API section. It was well-structured and simple. I've worked on building APIs and consuming them for almost 3 years and I wanted to work on something new. That's when this project came to my mind.
A chatbot to interact with this API. To check your website status and receive messages if something is wrong.
I create my bots to interact only with Telegram. I know how it works and it's easy to test the result. This project could work with Facebook Messenger in a future, I'm not discarding that feature 🤔
Once I installed a fresh copy of BotMan and built the app's basic setup, I realised I never tested code that interacts with an API that was not mine. I learned TDD and Unit Testing after learning how to develop APIs. BotMan offers a great Testing Solution to work with. In fact, it's easier to develop a chatbot with tests since you can check the result instantly.
Then I remembered a few lessons in Adam Wathan's course Test Driven Laravel regarding this matter. You create a class that will return the same payload as the API you want to integrate. Usually your
Fake class will extend the current working class to override those methods that perform the actual API call. And that's what I've done for this test suite. This way I was able to develop the entire project without querying OhDear's app.
OhDear offers a PHP Open Source package to interact with their API. I needed to extend a few classes to adapt them into my needs but the rest was pretty easy.
They also have a package to interact with OhDear WebHooks, but this time I was unable to use this package. It works with a secret key saved in a configuration file. My app, on the other hand, is made to interact with multiple users at the same time, and each user has a different secret key. I'm currently storing that information encrypted in the database. When a webhook request is received it contains the username. For example
https://deployedbot.com/freekmurze. I check the payload with the user's secret key in order to proceed or return an authorization error.
I built this project using the Single Action Controllers approach and I'm pretty happy with the result, It's something I'll consider in future projects for sure.
Mostly, there is just one controller per namespace in this project. But the benefit is also visible in the routes file, since it looks neat and you can use your IDE to click on the controllers name and go directly.
When you work on a chatbot that you want to test, you have two options:
- Write the message twice, in controller and tests, and remember to update both if something is modified.
- Store your messages somewhere you can call in your controller and tests.
I decided to go with number 2, and also decided to store the messages in Laravel translations files. This project is not multilingual (for now 😉) but I think that having the messages there makes it easy to:
- Refactor the message.
- Read code, it's easy to see
ohdear.token.storedthan a whole sentence.
- Test that the message is sent to the user.
- Reuse the message in another conversation.
- Translate the whole app in the future, since you have all the texts in a single place.
This bot is currently running and you can talk to it here or by searching
Mr. Dear on Telegram. You can also deploy it on your own server since it is open sourced. You will find instructions how to do that in the README.md.
You may also like: