loading...
Cover image for Building a water-drinking reminder with Next.js and Quirrel
Quirrel

Building a water-drinking reminder with Next.js and Quirrel

skn0tt profile image Simon Knott ・5 min read

Hi there! Welcome to the first ever post on the Quirrel blog!
Quirrel is an open-source task queueing service that's easy to use and sparks joy.
In this tutorial, we're going to use it to create a water drinking reminder - because if you're anything like me, it's easy to forget sometimes.

Check out the finished version here: water-reminder.quirrel.dev


To follow this tutorial, you should already know a little bit about Next.js.
If you’re totally new to it, check out the Next tutorial first.


Let's get started!

The first thing we're gonna do is to create a new Next.js project.

$ npx create-next-app water-reminder
Enter fullscreen mode Exit fullscreen mode

Open up water-reminder in your favourite editor and run npm run dev to startup the development environment.

Take a look into pages/index.js and replace its content with the following:

// pages/index.js
export default function Home() {
  return (
    <main>
      <h1>
        Water Drinking Reminder
      </h1>

      <p>
        I want to be reminded under the following e-mail:
      </p>

      <form
        onSubmit={(evt) => {
          evt.preventDefault();
          const formData = new FormData(evt.target);
          const email = formData.get("email");
          alert(email);
        }}
      >
        <input
          name="email"
          type="email"
          placeholder="E-Mail"
        />
        <button type="submit">
          Submit
        </button>
      </form>
    </main>
  );
}
Enter fullscreen mode Exit fullscreen mode

It contains some markup and a simple form that lets you submit the e-mail you want to be reminded at.
At the moment, it will just alert the typed email.
In your browser, open up localhost:3000.
It should look similar to this:

Submission Form

Submitting the form to the backend

Setup a new API Route by creating pages/api/setupReminder.js and adding the following code:

// pages/api/setupReminder.js
export default async (req, res) => {
  const email = req.body;
  console.log(`I'll setup the reminder for ${email}.`);
  res.status(200).end();
}
Enter fullscreen mode Exit fullscreen mode

Now instead of alert-ing the form value, let's post it to the newly created API route.
Go back to pages/index.js and replace the following:

// pages/index.js
onSubmit={(evt) => {
  evt.preventDefault();
  const formData = new FormData(evt.target);
  const email = formData.get("email");
- alert(email);
+ fetch("/api/setupReminder", { method: "POST", body: email });
}}
Enter fullscreen mode Exit fullscreen mode

Submitting the form will now cause the e-mail to be printed to your development console:

Screenshot 2020-10-13 at 16.19.35

Now that we've hooked up the form with the API Route, let's get into Quirrel and E-Mail sending.

Setting up Quirrel

Quirrel is a task queueing service.
It takes requests à la "call me back at /api/queue in 10 minutes", stores them and makes sure to call back /api/queue as requested.
What's awesome about Quirrel is that it can run fully locally, for example in a Docker container.
That's what we're gonna setup for testing.

Paste the following into docker-compose.yml:

# docker-compose.yml
version: "3.7"

services:
  quirrel:
    image: ghcr.io/quirrel-dev/quirrel
    environment:
      REDIS_URL: redis://redis
    ports:
      - "9181:9181"

  redis:
    image: redis
Enter fullscreen mode Exit fullscreen mode

Now run docker-compose up to start Quirrel (you need Docker and Docker Compose installed for this to work).

Hooking up your Next.js application to Quirrel works by installing the Next.js client library:

$ npm install @quirrel/next
Enter fullscreen mode Exit fullscreen mode

Now create a new queue by creating pages/api/queues/reminder.js and typing the following:

// pages/api/queues/reminder.js
import { Queue } from "@quirrel/next";

export default Queue(
  "queues/reminder", // because it's reachable
                     // under /api/queues/reminder
  async (recipient) => {
    console.log(`Sending an E-Mail to ${recipient}`);
  }
);
Enter fullscreen mode Exit fullscreen mode

Queue takes two arguments: The first one is it's API location, and the second one is the worker function.
Whenever a job is executed, the worker function is called.

To use our newly created Queue, simply import it from the API Route:

// pages/api/setupReminder.js
+ import reminderQueue from "./queues/reminder";
// 👆 don't forget this

export default async (req, res) => {
  const email = req.body;
- console.log(`I'll setup the reminder for ${email}.`);
+ await reminderQueue.enqueue(
+   email,
+   {
+     id: email,
+     delay: 30 * 60 * 60 * 1000,
+     repeat: {
+       every: 30 * 60 * 60 * 1000, // 30 minutes
+       times: 16, // 16 * 30min = 8h
+     },
+   }
+ );
  res.status(200).end();
};
Enter fullscreen mode Exit fullscreen mode

Calling .enqueue will schedule a new job.
The first argument is the job's payload while the second argument contains some options:

  • id prevents having multiple reminders for the same e-mail address
  • repeat makes the job execute on twice an hour, for a duration of 8 hours
  • delay adds an initial delay of 30 minutes, so the first job isn't executed immediately

To verify that this works, open up the Quirrel Development UI at ui.quirrel.dev.
It will connect to your local Quirrel instance and show all pending jobs in the "Pending" tab:

Quirrel UI

If it doesn't connect, that may be because you're using Safari. Try a different browser instead.

Submitting your email to the form at localhost:3000 will add a new job to the UI, and pressing "Invoke" will execute the job.
You'll now be able to see Sending an E-Mail to XYZ in your development logs.

Because it's a repeated job, it will be re-scheduled immediately, until it's been executed for the 16th time.

Before we proceed with the last part of the tutorial: Stand up, go to the kitchen and grab a glass of water 💧

Let's hook up E-Mail!

Now that the Queue is working, let's hook up the final thing: E-Mail!

Run npm install nodemailer and add your SMTP setup code to your reminder queue:

// pages/api/queues/reminder.js
import { Queue } from "@quirrel/next";
+ import { createTransport } from "nodemailer";

+ const mail = createTransport({
+   host: "smtp.ethereal.email",
+   port: 587,
+   auth: {
+     user: "randall.renner66@ethereal.email",
+     pass: "Dp5pzSVa52BJwypJQm",
+   },
+ });

...
Enter fullscreen mode Exit fullscreen mode

If you don't have any SMTP credentials at hand, you can get some demo ones at ethereal.email.

Then simply switch out the console.log call with a real email dispatch:

...

export default Queue(
  "queues/reminder",
  async (recipient) => {
-   console.log(`Sending an E-Mail to ${recipient}`);
+   await mail.sendMail({
+     to: recipient,
+     from: "waterreminder@quirrel.dev",
+     subject: "Remember to drink some water!",
+     text: "..."
+   })
  }
);
Enter fullscreen mode Exit fullscreen mode

That's it! Now our app is fully working.
It may not be the best water reminder service ever, but it's your very own one.

Here are some ideas to improve it further:

  • Make duration and interval of the reminder configurable
  • Allow users to unsubscribe using a link in the email
  • Add some styles, maybe using Tailwind CSS

Deploying this to production is easy using the managed Quirrel service.
Simply follow this guide: Deploying Quirrel to Vercel

Conclusion

We've built a working water reminder in little under an hour.
You can see the finished project here: quirrel-dev/water-reminder-demo

If you've got experience with well-known task queueing libraries like beanstalkd or SideKiq, you may have noticed how easy-to-use Quirrel is.
The highly integrated client libraries for popular frameworks and the managed solution available, Quirrel is a great choice for JAMStack users.

And if you want to host Quirrel yourself, the MIT License allows you to do so.

Posted on by:

skn0tt profile

Simon Knott

@skn0tt

Currently working on quirrel.dev. Creator of ente.app. Open Sourcerer, studying IT Systems Engineering at HPI.

Quirrel

Quirrel makes job queues simple as cake. MIT-Licensed, Great DX, End-to-End-Encryption, with an easy-to-use managed deployment.

Discussion

pic
Editor guide