paint-brush
Creating a football pool as an excuse to learn Node JSby@agmezr
1,267 reads
1,267 reads

Creating a football pool as an excuse to learn Node JS

by AlexSeptember 1st, 2018
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

After 4 year of waiting we had another World Cup full of surprises and once again I decided to do a football pool, or quiniela as called in Latin America, to scam all my friends… I mean to learn more. My first experience was on 2014 using PHP and Yii to create it but this time I wanted to learn something new and fresh.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Creating a football pool as an excuse to learn Node JS
Alex HackerNoon profile picture

After 4 year of waiting we had another World Cup full of surprises and once again I decided to do a football pool, or quiniela as called in Latin America, to scam all my friends… I mean to learn more. My first experience was on 2014 using PHP and Yii to create it but this time I wanted to learn something new and fresh.

I want to share my experience with Node and the solution I reached.

Note: This article is about my experience creating one of my first apps with Node and in no way an actual guide for beginners. If you are new to Node there are several guides you find that will help you more, including the official guide . Of course I’m always eager to help in any way I can.

Why Node?

I’ve been using Python for web development for the last years and every time I’m searching for news they are all talking about Node, so I decided to join the cool kid’s club and try it.

Me

Rules

Before starting I needed to set the rules for this year. I don’ think these are the standard rules but on my experience are extremely fun (specially on the last matches when a point or two can make you win):

  • All the users must enter the prediction of a match before starts.
  • If the prediction of a score is an exact match of the final result he earns 3 points.
  • If is not an exact match but have the same winner then he earns 1 point. Example: if user A goes with 3–0 and the actual score is 2–1 then the user gets 1 one point.
  • If the match is a tie and the user also predicts a tie he will earn 1 point. Example: if user B goes 3–3 and the score is 1–1 then the user gets 1 point.
  • The winner is the user with the most points.

Structure

(You can get the complete code here)

The first thing I needed to do was finding an structure that was easy to understand but at the same time scalable. Finally I decided to use an structure somewhat similar to Flask blueprints which I’m more familiar with (baby steps!).














api/|-- config.js|-- controllers| |-- database.js| `-- positions.js|-- matches| |-- index.js| `-- matches.js|-- teams| |-- index.js| `-- teams.js`-- users|-- index.js`-- users.js

This structure groups the functionality of each main feature of the API and views in a directory. Since this is a small project I used only an index file to expose the router and a single file to store the endpoints.

The config file contains the variables used to change the behavior of the app and stores other configuration like for example the id for Oauth

A brief description of each component in the api directory:

Teams

To display the info of all the teams or just a single team by id.

Users

Calculate the total points of each user and update the prediction of each user before a match.

Matches

Contains controllers to view the result of matches, update results, get next match or n last matches.

Controllers

Functions used by any of the other components. Mainly used to handle the connection to the database and queries. Speaking of that…

Database

My second problem was to find a way to store the information of the teams, predictions, dates and results. Although most of the guides I found recommended a different approach (like non relational databases) I opted to use Postgres mainly because that’s what I usually do and didn’t want to add more difficulty as I was on a tight dead line with the first match starting on a couple days (procrastination, hooray!).

The database is simple and contains only four tables:

  • Matches: stores the date and final results of each match.
  • Teams: the name of each team.
  • Predictions: the score predicted by each user.
  • Users: a name used to identify each user and an email for login purposes.

The API

Routing

To create the API I used Express and its powerful router component. With it I can separate the routes the same way I created the structure and use the router to create the endpoint in each module:





// An example of matches.js inside api/matches// obtain routerconst express = require('express'),router = express.Router()...





// example of an endpoint.router.get("/all", (req, res) => {console.log("obtain all matches");// do stuff})

And in the server.js file I import all routes from the other modules:






// require express and import the routes in the api directoryconst express = require('express');matches = require('./api/matches'),teams = require('./api/teams'),users = require('./api/users'),...





// register the routes in the appapp.use('/teams',teams).use('/matches', matches).use('/users', users)... // other routes

Postgres

To manage the database session and the queries I used Node-postgres. With this library you can obtain the database url from the environment (safer and used in some places like Heroku):




const { DATABASE_URL } = process.env;var pool = new Pool({connectionString: DATABASE_URL});

Or create the object and pass it to the Pool:







var pool = new Pool({user: 'username',host: 'localhost',database: 'database_name',password: 'my_password',port: 5432});

With the connections established you can execute queries like this:








// connect pool and query all teams in tablepool.connect().then(client => {return client.query("SELECT * FROM teams").then(data =>{// do stuff with the data...})

With this two components I was able to start coding the endpoints needed for each of the modules and store the data in the database

By the way if you think the code for the query is ugly… you are right! I was descending to hell … callback hell

But that’s a story for another day

If you want to test the app follow the next steps.

Requirements

  • node js(obviously)
  • npm
  • postgres
  • a browser or curl to view the responses

Installing

First clone the project from github:

git clone https://github.com/agmezr/quiniela.git

The project’s structure:

  • api/: controllers, views and responses
  • assets/: contains the script for the database
  • server.js: the file that configure and starts the server
  • packages json: used to install the needed dependencies

Install the dependencies of the project using npm:

npm install

Run the script in assets/database.sql to create the database:

psql <db name | postgres> -f assets/database.sql

After installing the dependencies and db, run the server using:

node server.js

If everything is ok you should see a message like this:

Staring app on 8080

Now open your browser (or use curl) and access localhost:8080/index to see an awesome response:

{"status":"ok"}

If you see that response everything is running. You can play with the other endpoints, for example to view the information of the first team enter to:

http://localhost:8080/teams/1

you will see this response:

[{"id":1,"name":"Russia","grp":"A"}]

Next steps

On next articles I want to share my experience with the use of Oauth to login users using a Google account and creating the views to display the data user friendly and finally deploying it on Heroku.

Conclusion

As one of my fists approaches to Node I want to say it was very pleasant working with it. There are many guides helping the beginners including the official documentation and many more libraries to help you with common task like security, connection to db, etc. Of course there are some things that are hard to understand at first like Promises and the new ES6 syntax but nothing a few hours worth of coding can’t fix.

My advice if you want to try Node JS is create something easy and fun like I did and beware of callback hell!