Skip to content

Back End

Lucas Gao edited this page Apr 20, 2021 · 38 revisions

High-level architecture:

  • A Node JS Express server is used as a REST API and acts as a logic tier.

    • API endpoints are located in server/routes/ folder.
    • Currently there are endpoints for signing in (signup.js), logging in (login.js), and CRUD endpoints for To-do list items (todo.js).
  • The server communicates with Google Firebase for reading/writing from the database and for authentication.

    • The Realtime Database in Google Firebase stores user objects (as defined below).
    • Firebase Authentication is used for authenticating users with email and password.
    • Initialization of firebase is done in firebase.js, and a database instance (which can be read and written to) is exported.

File/Folder Structure (most important sections)

server
|--- bin
     |    www
|--- mocks
|--- routes
|--- tests
|--- utils
|   app.js
|   rest_of_files

bin - www

The bin folder stores the www file. This file is essentially the configuration file for the express server, indicating which port it will be listening/run on.

mocks

This folder includes all the mocked data/functions used for testing.

routes

This folder is where the API endpoints sit. Each file in this folder represents a different route, in which different endpoints reside. E.g. todo.js represents /todo.

tests

tests contains all the unit test suite files that will be run when npm test is called. Note that all files must be named ___.test.js so that Jest recognises them as test suites.

utils

This is where all the helper functions should reside.

app.js

This file is the "main" file of the backend server and holds, sets and stores all the routing for the express server and any other express related configurations.

The rest of the files

The rest of the files sitting in the server folder include firebase files e.g. firebase.json, and the npm package files.

Data Model

Data will be stored in a JSON format in the real-time database:

{
	“user_id1” : {
		“email” : ______,
		“todolist” : [
			{
				“entry_id” : ____,
				“title” : ____,
				“date” : ____,
				“time” : ____,
				“description” : ____,
				“ticked” : True/False,
                                   },
			{
				“entry_id” : ____,
				“title” : ____,
				“date” : ____,
				“time” : ____,
				“description” : ____,
				“ticked” : True/False,
                                   },
		]
	},
	“user_id2” : {
		“email” : ______,
		“todolist” : [
			{
				“entry_id” : ____,
				“title” : ____,
				“date” : ____,
				“time” : ____,
				“description” : ____,
				“ticked” : True/False,
                                   },
		]
	},
	.
	.
	.
}

Reading and writing to the database

For information on how to read and write to the Firebase Realtime Database:
https://firebase.google.com/docs/database/web/read-and-write

Authentication

Authentication is done by Google Firebase using email and password. Once a user signups using their email and password, Firebase Authentication will create a user. Each user has a generated user id and token.

e.g:

//signup.js
   firebase
        .auth()
        .createUserWithEmailAndPassword(newUser.email, newUser.password)
        .then((data) => {
            userId = data.user.uid;
            return data.user.getIdToken();
        })

For more information: https://firebase.google.com/docs/auth/web/password-auth

Firebase Authentication can identify the user based on this token and can return the user id.

This is done in the authorise function in server/utils/auth.js:

//auth.js
   admin
            .auth()
            .verifyIdToken(idToken)
            .then((token) => {
                const UUID = token.user_id;
                resolve(UUID);
            })

Thus, this token should be sent in the HTTP Authorization request header for every API endpoint related to a user.

For more information: https://firebase.google.com/docs/auth/admin/verify-id-tokens

API endpoints

Signing up an user

  • Method: POST
  • URI: /signup
  • Request payload: user representation
 {
   email:
   password:
 }
  • Response payload: bearer token for the user
{
   token : xxxx
}
 
  • Response code:
  • 201 if user is able to be created successfully
  • 400 if email or password (must be at least 6 characters) is not in valid form or if a user with this email address already exists.

User Logging in

  • Method: POST
  • URI: /login
  • Request payload: user representation
 {
   email:
   password:
 }
  • Response payload: bearer token for the user
{
   token : xxxx
}
 
  • Response code:
  • 200 if user is able to successfully login
  • 401 if either email/ password does not match whats stored in firebase

Getting to-do list entries

  • Method: GET
  • URI: /todo
  • Query parameter: filter for entries
  • “today” .../todo?timeline=today
  • “upcoming” .../todo?timeline=upcoming
  • Additional parameters:

In the authorization header of the HTTP request, there should be the authentication token sent as a bearer token

  • Response payload: to-do list entries
  • If timeline=today, return all entries due today
[
    {
        "date": [today's date],
        "description": _____,
        "entry_id": _____,
        "ticked": true/false,
        "time": _____AM/PM,
        "title": _____
    }

    ...
]
  • If timeline=upcoming, return upcoming entries excluding today’s (tasks on the same date are grouped together as shown below)
{
    "[after today's date]": [
        {
            "date": [after today's date],
            "description": _____,
            "entry_id": _____,
            "ticked": true/false,
            "time": _____AM/PM,
            "title": _____
        }

        ...
    ],

    "[another after today's date]": [
        {
            "date": [another after today's date],
            "description": _____,
            "entry_id": _____,
            "ticked": true/false,
            "time": _____AM/PM,
            "title": _____
        }

        ...
    ],

    ...
}
  • If no query parameters, return all to-do list entries
[
    {
        "date": _____,
        "description": _____,
        "entry_id": _____,
        "ticked": true/false,
        "time": _____AM/PM,
        "title": _____
    }

    ...
]
  • Response code:
  • 200 if entries are successfully returned
  • 401 if the auth token is invalid

Creating new to-do list entry

  • Method: POST
  • URI: /todo
  • Request payload: new entry fields
 {
   “title” : ____,
   “date” : ____,
   “time” : ____,
   “description” : ____,
 }
  • Additional parameters:

In the authorization header of the HTTP request, there should be the authentication token sent as a bearer token

  • Response action:

New entry written to the database

  • Response code:
  • 200 if entry creation is successful
  • 401 if the auth token is invalid

Updating a to-do list entry

  • Method: PUT
  • URI: /todo
  • Request payload: entry id followed by any updated fields (non-updated fields will not be included in request)
 {
   “entry_id” : ____,
   “title” : ____,
   “date” : ____,
   “time” : ____,
   “description” : ____,
   “ticked” : ____,
 }
  • Additional parameters:

In the authorization header of the HTTP request, there should be the authentication token

  • Response action:

Update the specific entry in the database

  • Response code:
  • 200 if entry update is successful
  • 401 if the auth token is invalid

Deleting a to-do list entry

  • Method: DELETE
  • URI: /todo
  • Request payload: entry id of the to-do list entry to be deleted
 {
   “entry_id” : ____
 }
  • Additional parameters:

In the authorization header of the HTTP request, there should be the authentication token

  • Response action:

Delete the specific entry in the database

  • Response code:
  • 200 if entry deletion is successful
  • 401 if the auth token is invalid

Verifying Login Tokens

  • Method: POST
  • URI: /verifyToken
  • Request header: {authorization: "Bearer token"}
 {
   authorization : "Bearer ___token___"
 }
  • Response code & payload:
  • 200 if the authentication token is valid ​> { validity: true}
  • 401 if the authentication token is invalid ​> { validity: false }
Clone this wiki locally