This article covers an overview of the community bonding period and the first month of the coding period that I experienced with my project, Journal Policy Tracker Backend under the Open Bioinformatics Foundation organization during the Google Summer of Code 2022.
About the Project
What is Journal Policy Tracker?
The Journal Policy Tracker is going to be a web app where anyone can look up details about the policy of a published journal as well as add policy details of a new journal in our database.
What is the Expected Output of the Project?
This output of this project is supposed to be a fully-fledged backend for the journal policy tracker. Currently, the backend of the journal policy tracker is on Flask and SQLite3. During the timeline of this GSoC project, I will be redoing the backend of the journal policy tracker from scratch by using Express, GraphQL, Apollo Server, and MongoDB.
Meet and Greet
The start of my community bonding period was very exciting as I got to know that I got selected for GSoC this year. Through my mentors, I became aware of the Slack channel for my group called Code Is Science which we use for everyday communication among our team members.
During this community bonding period, I had two meet-and-greet video calls with my mentors. All the mentors in our group were extremely polite and supportive. They answered all the questions and doubts that I had regarding the project during our calls.
The first call was with Pritish Samal who is my immediate mentor for the backend project. The second call was a combined meet and greet with the entire Code Is Science team that consisted of our group Mentor as well as the frontend mentor and mentee.
Discussions
During our meeting, we discussed that we will try to complete the entire backend as soon as possible so once it's done then we can give more time towards integrating the frontend and backend without any hassle. We also decided that we are going to keep track of the timeline and developments of this project in Notion.
Pritish also explained me the concept of Conventional Commits and suggested that we should follow it in our project. Conventional Commits is basically a set of rules/syntax for writing commit messages in git. Using Conventional Commits, the reader can get valuable context about a commit such as whether a commit includes a new feature, bug fixes, refactors, tests etc. Those commit messages will also used for implementing Semantic Versioning in our project.
Researching
During this time, I went through a significant amount of documentation for Express, Apollo Server, GraphQL, mongoose, and MongoDB as well as I went through numerous amounts of YouTube tutorials to better understand the tech stack which is going on to be used in the project.
Boilerplate for our Project
After I had a fair amount of discussion with my mentors and the team, I had a decent idea of what the project is supposed to be at the end. With all that in mind, I started my work on this project. My first pull request was a boilerplate for the project with appropriate folder structure. In that PR, I also created a simple working backend with minimal functions.
Working on the CRUD API for Journals
The first week began with me working on the Journal CRUD API. CRUD stands for Create, Read, Update and Delete.
My goal for this week was to finish the functional part of the CRUD API where we can Create, Read, Update and Delete journal entities from our database.
The journal entity did not yet contain all the fields because we still needed to have some discussions about the contents of a journal before we can finalize the schema.
Later this week we decided upon the final schema for the journal entity. It is supposed to look something like this:
title: String;
url: String;
issn: String;
domainName: String;
policies: title: String;
firstYear: Number;
policyType: String;
isDataAvailabilityStatementPublished: Boolean;
isDataShared: Boolean;
isDataPeerReviewed: Boolean;
enforced: Boolean;
enforcementEvidence: String;
createdAt: Date;
updatedAt: Date;
createdBy: User;
We could have minor changes as we go along the development timeline but it will look similar to this.
This week I also faced a problem while making pull requests. My mentor Pritish helped me with my problem and explained to me the proper workflow that I should be following while making pull requests so I don’t get errors.
At the end after solving the pull request problem, I made a pull request which added a basic journal CRUD API to our project. More work will be done on it in forthcoming pull requests which will be documented later.
Working on the User Authentication System
After putting together a basic working journal CRUD I started working on the User Authentication System of our project.
At first, we decided that we are going to use Passport.js to implement authentication in our project as it was the de-facto library that was used by everyone for this purpose. But as I did more research about it, I realized that it doesn’t go too well together with GraphQL. If we are only using the local strategy (basic username and password stored in a database) and not using Google or Facebook strategies then dropping Passport.js and handling authentication inside the GraphQL resolvers will be the most convenient and easiest to maintain.
So I decided to go forward with that approach and created a simple authentication system with the GraphQL resolvers.
The goal of the user authentication as of now is to create a system where a user can register
a new account, login
into that account, and stay logged in. To keep the user logged in, we decided that we will use the sessions and cookies approach.
Hashing and Salting
I researched a good amount over hashing libraries and ended up choosing bcrypt
because it is currently the most popular library that is used for this purpose and it is very easy to implement. While researching I found this video which was extremely informative that explained the functionality and implementation of bcrypt
in good detail. That helped me a lot.
Error Handling
After the implementation of all the essentials, I implemented error handling. It is supposed to throw up an appropriate error if someone enters the wrong credentials during the register or login process. I implemented them by using simple conditional statements inside the GraphQL resolvers which will throw up an appropriate error message depending upon the error code and error field.
After finishing this, I made a pull request which added a working user authentication system to our project with hashing and salting of passwords.
Sessions
Implementation of Sessions
Implementing sessions was very straightforward in our express app with the use of express-session. I simply followed the express documentation and implemented session like the following:
app.use(
session({
name: COOKIE_NAME,
store: new RedisStore({
client: redis,
disableTouch: true,
}),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 1, // 1 year
httpOnly: true,
sameSite: 'none',
secure: true,
},
saveUninitialized: false,
secret: process.env.SESSION_SECRET,
resave: false,
}),
);
Session data is fetched whenever a particular user executes an action. This is done so that the server knows which user executed what particular action. In this use case, this data is going to be fetched extremely frequently and at a very fast rate. To make sure that the data is always available with the least amount of delay, we are going to use an in-memory database called Redis. Redis stores all it’s data in memory(RAM) so the fetching delay is extremely small which results in really fast experiences for the end user.
Problems While Enabling Cookies
I have almost finished the work of implementing sessions on the backend. While I didn’t face a lot of challenges while implementing sessions itself, I had a few problems while enabling cookies with the Apollo Server.
Enabling cookies in GraphQL Playground was easier but since it has been retired and replaced by Apollo Server, enabling cookies has been comparatively more difficult.
To enable cookies in GraphQL Playground, aside from configuring CORS properly we only had to change one value in settings which was to change the value of request.credentials
to include
.
To enable cookies in Apollo Server, we have to do the following extra steps:
- In cookies settings we set
sameSite
to"none"
andsecure
totrue
- Go to settings in Apollo Studio, turn on “Include Cookies” and add a new shared header with header key as
x-forwarded-proto
and header value ashttps
- Add
app.set("trust proxy", 1)
just above our CORS config.
Dynamic Origin CORS
For the purpose of development, I needed to have multiple origins connect to the backend. One of them will connect to the backend from the Apollo Studio and another will connect from the frontend that I will locally work upon for testing purposes. For that, I used the CORS node package which supported dynamic origins.
To allow multiple origins on my backend, I used the following code:
var whitelist = ['https://studio.apollographql.com', 'http://localhost:3000'];
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
};
After the session PR is merged, I will work towards integrating the user entity and the journal entity so that every journal will contain the ID of the user who created it which we can use to fetch the user details.
FIN
So that was all about my project, the community bonding period, and the first month of my GSOC 2022. I want to thank my mentors and OBF for believing in me to work on this project. In the forthcoming PRs, I will be adding more features and error handling in the journal CRUD API and user authentication API. I will also be adding an authorization middleware and refactoring some code to make it easier to read and understand. I’m excited to complete the work on this project and get it up and running for people to use. I will be writing more articles in the future and documenting the entire process of my project development and completion.