The pandemic has affected each and every part of our lifestyle in a major way. Those who have had it especially difficult are the students who are in the final year of their study. While we cannot do anything about the uncertainties whether their exams will be conducted, we identified one problem that we can attempt to solve. Every final year batch gets a grand farewell from their juniors, celebrating their foray into the real world. There’s the yearbook with quotes of each student which will serve as a source of nostalgia years down the line. There’s a Scribble Day where students reminisce the best parts about the journey they have had in these four years. The Class Of 2020 missed it all.
“Developing an application that will facilitate virtual yearbook and scrapbook.” - That’s the simple problem statement we started with. The Yearbook will contain all the students of the #ClassOf2020. Each student will have his/her profile. Each student can post “scraps” on other’s profiles, which the other can choose to display to everyone on his/her profile.
In this section, I will try to elaborate on the process we followed in developing the application. The design plus development took about 45 days, followed by a beta rollout and subsequent bug fixing.
As the purpose of the application is decided, we now move to define the features. Following is the list of features that the application should support.
We planned on having a web app using ReactJS, and an Android app. So, having a central API which both Android client and React WebApp can use made sense. Following is a list of technologies that were used.
In the system, there are two major entities - Users, and the Scraps they post. You can see the diagram below to get a clear idea of the database design.
The posted_by and posted_to attributed in the Scrap table are foreign keys referencing the id attribute in the User table. This simple design with two tables allows us to query any desired data easily.
It was important to have a simple yet effective design system that would be followed everywhere to ensure consistency. We started with developing basic low fidelity wireframes of the App and WebApp. Below are a few images that show the UI UX design process we followed. Credits to Swaraj Thamke for the amazing logo design!
The API was developed using Flask in Python. I have described various stages of developing the API below:
Authentication: Generally, you can implement authentication on the web either using Sessions or using JWT (JSON Web Tokens).
Session-based Authentication: Server creates a session for the user after the user logs in. The sessionID is stored on a cookie in the user’s browser. SessionID is then sent along with every request to the server to verify identity as long as the user is logged in. This method is stateful in the sense the server is responsible for maintaining the client state.
Token-based Authentication: Server creates a JSON Web Token (JWT) for the user when he logs in. The JWT contains the user’s identity. The client includes the JWT as a Authorization header with every request to server to prove identity. This method is stateless in the sense the user state is stored inside the token which resides on the client’s local storage in the browser. Unlike session based auth, the server does not store user state.
Which one to choose between the two? We went with Token Based Authentication because of the following reasons -
One thing to take care of while using JWT is that they are not secure, so we should NOT include any sensitive information in the JWT. Only public information should be included.
We used SwaggerHub to document the API. SwaggerUI provides easy and fast API documentation.
We used Heroku to deploy our app. We use Heroku supported gunicorn web server to deploy the app. I have covered deploying a Flask app on heroku in a separate post here - “Deploying your Flask WebApp to Heroku for the World to see”
Simultaneously, we were developing the WebApp as well. We used Material UI for convenient styling. After the UI design was finalized, actual development work started. We also used React Router DOM for routing.
Implementing user authentication using the API was a little bit tricky. The JWT token received from the API was stored in the browser’s localStorage. Along with the token, we are storing the user’s ID, and some other identity info in the localStorage so that frequently needed public data could be loaded quickly. Based on whether the user is logged in, certain routes were protected. If the user is not logged in, he was directed to the login page.
To decide whether the user is logged in or not, the webapp would check the client’s localStorage. If the user is logged in, the JWT would be present. However, there was a chance that a malicious actor may insert his own JWT just to bypass the login check. So, checking whether the user is logged in purely based on the existence of JWT in localStorage was not a good idea. So, we would also validate the JWT by making a call to the API. And, once the user logs out, all the data from localStorage would be removed.
Other than this, most of the development of the WebApp was developing the user interfaces using the corresponding API endpoints.
Android Client: We have just submitted our Android app to Play Store and it is currently under review by Google Play Store :)Update:: The GradGoggles Android App is now live on the Google Play Store!.
There were countless other minute challenges that we faced but solving them helped us learn many things which can only be learned by getting one’s hands dirty.
That’s it for this post, I hope it was informative. Projects like these really teach a lot. Also, it feels nice when actual users are using and enjoying something you made. I hope you enjoyed reading this (rather long) post. Thank you, and stay safe!