Skip to content

BillyDoesDev/notificationd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

$~ notificationd

A system to send notifications to users.


This submission underlines the following (the striked out ones are not covered):

Notification Service:
Objective: Build a system to send notifications to users.

Requirements

  1. API Endpoints:
    • Send a Notification (POST /notifications)
    • Get User Notifications (GET /users/{id}/notifications)
  2. Notification Types:
    • Email, SMS, and in-app notifications.
  3. Bonus Points:
    • Use a queue (e.g., RabbitMQ, Kafka) for processing notifications.
    • Add retries for failed notifications. (unstable)

Deliverables

  1. A Git repository link containing:
    • Source code.
    • README with setup instructions and any assumptions made.
  2. (Optional) Link to the deployed application or API documentation (if implemented).

Sample working demo

image

Setup

  • Make sure you have Docker installed and running on your system.

  • Clone this repository and cd into it:

    git clone https://github.com/BillyDoesDev/notificationd.git
    cd notificationd
  • If you haven't already, create an account on MailGun. This will be used to create and send emails.

    • Follow their welcome guide to set up your account, and obtain your API keys, and configure your test email. Save these for later.
  • Now, create an account on Twilio. This handles SMS notifications.

    • Obtain a virtual phone number and your auth token from their dashboard, and save these for later.
  • Create a .env file in the current directory. Its contents should have the following. Replace the fields as required.

Important

Keep the MONGO_URI as is.

MAILGUN_API_KEY="xxx"
MAILGUN_DOMAIN="xxx.mailgun.org"
REGISTERED_RECEIVER_EMAIL="John Doe <[email protected]>"

TWILIO_SID="xxx"
TWILIO_AUTH_TOKEN="xxx"
TWILIO_PHONE_NUMBER="+1xxx"
RECEIVER_PHONE_NUMBER="xxx"

RABBITMQ_QUEUE="hello"
RABBITMQ_EXCHANGE="notification-exchange"
RABBITMQ_ROUTING_KEY="hello"

The directory structure should look something like this:

.
├── compose.yaml
├── Dockerfile
├── .dockerignore
├── .env
├── .gitignore
├── LICENSE
├── main.py
├── README.md
├── requirements.txt
├── scripts
│   └── notification_worker.py
├── static
│   ├── css
│   └── main.js
└── templates
    └── index.html

Execution and API details

  • Create a python virtual environment, activate it and install the dependencies.

    python -m venv env
    source env/bin/activate
    # env\scripts\activate        # for Windows users
    
    pip install -r requirements.txt
  • Inside the project directory, run:

    docker compose up --build -d
  • This will start the docker container, which manages essential dependencies for the project. Once that's up, start up your python servers, one for the primary API endpoint, and the other for managing the RabbitMQ broker.

    python main.py

    And in a separate terminal:

    python scripts/receive_v2.py
  • The API endpoints are live at http://localhost:5050. You can head over there in your browser to try out a web client for the API.

  • To access a GUI to the database, you can head over to http://localhost:8081 to access the mongo-express dashboard for the MongoDB database.

  • To shut the server down, simply run the following, and kill the python processes:

    docker compose down

Tip

If you do not make any changes to the files, to run this next time, you can simply do:

docker compose up -d

This does not rebuild the containers each time.


API Documentation

The following endpoints are available:

  1. Post a new notification

    Sends a request for a new notification to be sent.

    • URL

      /notifications

    • Method:

      POST

    • URL Params

      Required:

      None

    • Data Params

      {
          "user_id": 4,
          "notification_type": "in-app",
          "content": "hello, world!"
      }

      The user_id key can be any integer, denoting some user id in a real system.
      The notification_type key can be either in-app | sms | email.
      The content key is the message you want to send in your notification.

    • Success Response:

      • Code: 201
        Content:

        {"message": "Notification queued", "id": "6829ce9ed71d22a7cfbf86db"}

        The id key refers to the unique ObjectID of the notification as stored in the MongoDB. Queries on this notification may be performed using this.

    • Error Response:

      • Code: 500
    • Sample Call:

        curl -X POST 'http://localhost:5050/notifications' \
        -H 'Content-Type: application/json' \
        --data-raw '{"user_id":4,"notification_type":"in-app","content":"hello, world!"}'

  2. Get Notifications

    Returns notifications for a certain user id.

    • URL

      /users/:id/notifications

    • Method:

      GET

    • URL Params

      Required:

      id=[integer]

    • Data Params

      None

    • Success Response:

      • Code: 200
        Content:

        {"data": [
            {
                "user_id": 4,
                "notification_type": "email",
                "content": "message content",
                "status": "sent",
                "timestamp": {
                    "$date": "2025-05-18T09:20:09.362Z"
                }
            },
            ...
        ]}

        The status key can have values pending | sent | failed. In case a notification hasn't been sent yet, it will be retried after every 10s.
        The timestamp key shows the UNIX timestamp of the last notification status.

    • Error Response:

      • Code: 400
        Content: {"error": "No notifications for user_id found."}
    • Sample Call:

       curl 'http://localhost:5050/users/4/notifications' 

Tech Stack Details

  • This app runs in a python-flask server, and uses MongoDB to store user notifications. The entire setup is dockerised, to provide a seamless deployment experience, and also to allow room for scalability.
  • In-app updates are managed via websockets, using socket.io, on both the client and the server.
  • SMS and Email updates are handled via RabbitMQ, which serves as a message broker, to deliver notifications gracefully, and handle large workloads.
    • Essentially, when a new POST request is sent, RabbitMQ comes into action, via the scripts/receive_v2.py script, which manages a suitable exchange to deliver messages, along with separate queues, to deal with successful and failed attempts. As of wriring this, the retry feature is a bit unreliable.
  • MailGun and Twilio are used to send email and SMS updates, respectively.

Tip

[Note that this is completely optional] If you prefer having socket.io.js fully offline, you can get it using:

curl -O https://raw.githubusercontent.com/BillyDoesDev/blueberry/refs/heads/main/> static/socket.io.js

And then simply link that to your index.html

Note

Previously, before RabbitMQ was implemented in this project, messages were polled at fixed intervals using apscheduler, by looking at database records. You can browse that version of the project here.

License

This project is open source, under the MIT License.

MIT License

Copyright (c) 2025 BillyDoesDev

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

About

A RESTful API to send notifications to users.

Topics

Resources

License

Stars

Watchers

Forks