Skip to content

yousifelhady/flask-sms-notifications-app

Repository files navigation

flask-sms-notifications-app

Flask based backend application that implements endpoints that can send SMSs (needs to be integrated with real service provider) and can send notifications via FCM (Firebase Cloud Messaging) to registered users. The application integrates with a postgres database that keep records of the sent messages and notifications for tracking and history purposes.
The whole project can run and execute using Docker-Compose.

Docker-Compose Setup

  1. Download Docker at your machine in order to be able to execute docker commands.
  2. Clone the project repo.
  3. Run CMD terminal from the project's directory and execute:
docker-compose up
  1. Docker will setup the project's environement, install all the dependencies and handle the database connection.
  2. Skip the following headers and Jump to "API Documentation" section to start using and testing the endpoints.

Pre-requisites to run the project

  1. Install Python latest version
  2. Install Postgres software according to your OS
  3. Clone the project's repo and you are ready!
Key Dependencies
  • Flask is a lightweight backend microservices framework. Flask is required to handle requests and responses.
  • SQLAlchemy is the Python SQL toolkit and ORM we'll use handle the lightweight postgres database.
  • Flask-Migrate is a flask library used to handle db migrations.
  • PyFCM is a python library that wraps the FCM functionalities of Google Firebase

Steps to prepare the project's environment

  1. Navigate to the project's directory and firstly create a virtual python environment to install the project's dependencies.
    Follow the steps of how to configure a virtual environment from here
  2. Activate the virtual environment by running activate.bat from (./env/Scripts)
  3. Install all the project's dependencies by running this command at the CMD/terminal:
pip install -r requirements.txt
  1. Setup the database by creating a local Postgres database Postgres default username/password: postgres/postgres
createdb database_name
  1. Open models.py to configure the following with your inputs:
    • database_name
    • user
    • password
    • localhost (default: localhost)
  2. You can skip (no.5) and configure the values using environment variables corresponding to their names in the models.py file.
  3. Migrate database using database migrations using flask migrate, but first you have to set the flask app in the environment variable "FLASK_APP" as following:
set FLASK_APP=app.py

then run the flask migrate commands as following:

flask db upgrade

hence, database tables shall be created (they will be initially empty).

8. To verify that the database tables have been created, type the following in the CMD terminal:

psql database_name

you will enter the command line mode of postgres database, then type:

\dt

Steps to run the project's app

  1. In CMD/terminal, type the following:
set FLASK_APP=app.py
flask run --reload

Applcation will run on http://127.0.0.1:5000/

or just execute the app file

python app.py

Application will run on the specified url in "app.py" which is http://0.0.0.0:5000/ and to run it, use http://localhost:5000

  1. When you open the localhost root page / an empty HTML page shall be rendered and it will contain the device registration token.
  2. This token shall be used to send notifications to the page, so save it in an external file for later usage.

Important Note:

  • If the root page remained static and no token appeared, you have to run the localhost on "https".
  • You can use a free software ngrok to achieve this, it is pretty simple and neat!

APIs Documentation

Getting Started

In order to execute and test the API endpoints, you can use either Postman or Curl commands.

  • Base URL: At present this app can only be run locally and is not hosted as a base URL.
  • The backend app runs at http://localhost:5000
  • Authentication: This version of the application does not require authentication.

Endpoints Library

POST '/smss'
POST '/notifications/tokens'
POST '/notifications/topic'

POST '/smss'

  • Send SMS to a single contact number, it needs to be integrate with real SMS service provider.
  • It stores the sent message and stores the contact (as a client object) in the database and associate a relation between them using the client's object foreign key.
  • Sending SMS requests are limited per minute and can be configured by "api_limit_per_minute" constant in "config.py", currently (api_limit_per_minute=5).
  • Request Arguments: 'contact', 'subject', 'message'
  • 'contact' have to be correctly formated "[+country_code].*[number]"
  • Returns: JSON Object contains 'success', 'message_id'
  • Curl Sample: curl http://localhost:5000/smss -X POST -H "Content-Type: application/json" -d "{"contact": "+201009129288", "subject": "SMS Subject", "message": "This is a message body"}"
  • Postman Sample:
    {
      "contact": "+201009129288",
      "subject": "SMS Subject",
      "message": "This is a message body"
    }

Result:

Status: 200 OK
    {
      "message_id": 1,
      "success": true
    }

POST '/notifications/tokens'

  • Send notification to subscribed tokens using FCM (Firebase Cloud Messaging) under the hood.
  • It stores the sent notification and stores the tokens in the database and associate a many to many relationship between them in third table (as 1 notification can be sent to multiple tokens, and 1 token can receive multiple notifications with time)
  • Request Arguments: 'tokens', 'title', 'body'
  • 'tokens' is a list of subscribed tokens to which the notification shall be sent, tokens have to be valid and correctly formated.
  • You can retrieve a token by running the root route of the application "http://localhost:5000" on https, then copy and paste the generated token to Postman or Curl as shown in the sample bellow.
  • Returns: JSON Object contains 'success', 'notification_id'
  • Curl Sample: curl http://localhost:5000/notifications/tokens -X POST -H "Content-Type: application/json" -d "{"tokens": ["dyimeAKczeP3UJ8ynvI1I2:APA91bHQFAK2d28Tyfg89zqWVrPynCCEXF9eNnRW705fFxEdDE4klEBsqlVsdWiXl3jkWykCQ503Nh4m6EeL3tNS7iR1mnCB9e_Q7Sw_wDd_N3nENiqwmpTV2e1blahBck03zhR9t4LJ"], "title": "Notification Title", "body": "This is a notification body"}"
  • Postman Sample:
    {
      "tokens": ["dyimeAKczeP3UJ8ynvI1I2:APA91bHQFAK2d28Tyfg89zqWVrPynCCEXF9eNnRW705fFxEdDE4klEBsqlVsdWiXl3jkWykCQ503Nh4m6EeL3tNS7iR1mnCB9e_Q7Sw_wDd_N3nENiqwmpTV2e1blahBck03zhR9t4LJ"],
      "title": "Notification Title",
      "body": "This is a notification body"
    }

Result:

Status: 200 OK
    {
      "notification_id": 1,
      "success": true
    }

POST '/notifications/topic'

  • Send notification to users who are subscribing to a specific topic.
  • The Notification will be sent anyway and users who are subscribing to the topic shall receive it.
  • Request Arguments: 'topic', 'title', 'body'
  • Returns: JSON Object contains 'success'
  • Curl Sample: curl http://localhost:5000/notifications/topic -X POST -H "Content-Type: application/json" -d "{"topic": "news", "title": "Notification Title", "body": "This is a topic notification body"}"
  • Postman Sample:
    {
      "topic": "news",
      "title": "Notification Title",
      "body": "This is a topic notification body"
    }

Result:

Status: 200 OK
    {
      "success": true
    }

Error Handling

HTTP Errors are returned as JSON objects in the following format example:

Status: 404 NOT FOUND
{
    "success": False,
    "error": 404,
    "message": "Not Found"
}

The APIs will handle all types of HTTP errors when requests fail or request data cannot be found or something went wrong for any reason.

Database Schema Design

The project works with Postgres database and uses SQLAlchemy ORM to deal with it, create tables and make transactions.

The implemented database schema consist of 5 tables:

  1. "clients" table with columns (id, contact)
    Used to store received contacts as clients for tracking their data.
  2. "messages" table with columns (id, subject, body, time, client_id as foreign key)
    Used to store sent messages and associate them with the client that the messsage has been sent to.
  3. "tokens" table with columns (id, token)
    Used to store registered tokens.
  4. "notifications" table with columns (id, title, body, time)
    Used to store sent notifications.
  5. "tokennotifications" table with columns (id, token_id, notification_id)
    Used to associate tokens with the notifications they have received, creating a many to many relation between tokens and notifications.
    As 1 notification can be sent to multiple tokens, and 1 token can receive multiple notifications with time.

Testing

The project files contain a file app_test.py, this file contains all the unit tests that test the API endpoints. To run the tests, open CMD terminal and execute the following (make sure that the server is up and running)

python test_app.py

Test cases will be executed and result will be displayed in the CMD terminal incase of success or failure.

Acknowledgement

I would like to acknowledge Software Engineer/ Hussein Khaled for his contribution and help in setting up Docker-compose for the project.

Authors

Software Engineer/ Yousif Elhady

About

Flask based backend application that implement endpoints that can send SMSs and notifications to registered users in Postgres database

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published