Creating a full stack web application

Years ago, I created an app that delivered dad jokes. However, as time passed, the supporting services broke down and the app fell into disrepair. Recently, I decided to revamp and revitalize the app, removing the cobwebs and bringing it back to full functionality.

When I decided to build the app, I wanted a good name. I wanted something to inspire curiosity and innovation. I decided to name it Laughter Engine. Here’s how an artificial intelligence bot interprets that name…

Okay I admit it’s creepy as heck, but it does offer a glimpse into the world of AI and how it visually perceives our words. Anyways, I’m digressing. This blog post isn’t about AI! As much as the topic has fascinated me over the past twenty four hours, I’ll save that for another post and potentially a future app built on top of the technology.

For this post, I wanted to share the behind the scenes look of how I built this full stack application and tech decisions I made as I built it.

I’m going to break this post down into several parts:

  1. Tech stack
  2. Data source
  3. Building an API
  4. Database design
  5. Marketing
  6. Things I learned during this process
  7. Future roadmap for improvements

Tech Stack

A tech stack is the combination of technologies a company uses to build and run an application or project.

Don’t they say a picture says a thousand words? Instead of describing it all to you over text, let me give you one of the most prized possessions in the world of software engineering, a diagram.

So what you see here summarizes it, but let me explain a bit of what’s going on. The user visits my website url which, like all domains on the internet, uses a system called DNS to map the domain name to an IP address. The IP address is like a street address for the internet, it tells the internet the address of the resources users will use to access my resources.

In this case since I’m using React JS as my front end, the resource the user gets from making the HTTPS request from their browser is a javascript file. That Javascript file is in charge of generating all the resources the browser needs to display the user the app. Most notably, the javascript generates an HTML file that the browser can interpret into a web page.

From there, the React front end hits a separate API called icanhazdadjoke which conveniently offers free dad jokes to the public that the front end retrieves via a JSON format like so…

$ curl -H "Accept: application/json" https://icanhazdadjoke.com/
{
 "id": "R7UfaahVfFd",
 "joke": "My dog used to chase people on a bike a lot. It got so bad I had to take his bike away.",
 "status": 200
}

From there, the front end sends that joke right over to the user which gives them a chance to rate it…

This is where we hit the internal Laughter Engine custom web server hosted by means of Serverless, a service that makes it easy for developers to run on AWS Lambda computing platform. There’s a lot going on here but in essence what we have is a NodeJS backend that utilizes some special tools provided by amazon to abstract away many of the hairy details with building a web server so I can just focus on writing code and not on scaling resources, etc.

From there, the NodeJS backend interacts with a Postgres DB hosted on Bit.io to store jokes to generate a leaderboard to display back to the user.

Data source

Alright, let’s take a breath a bit after discussing the tech stack. There was a lot going on there, if you don’t understand all of it, don’t worry. Hopefully this section will be a little bit more easygoing.

Years ago when I decided to work on a side project, I approached the project through the sense of a front-end developer. That is, I wanted to build a user interface on top of an existing public API. I figured I’d build something cool on top of something else that already provided some awesome data set exposed via an API.

So I googled, Best public apis to build an app on top of. What I got was a huge amount of responses, but most notably, I found something that struck out to me: The Chuck Norris Jokes API

I’d always loved Chuck Norris jokes and thought it would be cool to build a platform on top of an API that supports them to rate the jokes to find the best ones.

What I’ve learned the hard way through a show and tell with my co-workers is that the API returns some offensive and insensitive jokes that definitely are not safe for work and could be considered hurtful to a variety of folks.

So I switched the API to a much more friendly one… icanhazdadjoke. Admittedly some of the jokes are fairly cheezy, but some aren’t all that bad.

The API is super kind to offer it’s jokes out for free, so the very first step in building my app was simply to fetch the dad jokes and send it back to the user as you’ll see in my architecture diagram

Building an API

I’ve already declared myself as primarily a front end engineer, so why the heck did I concern myself with building an API? That’s backend stuff right? I shouldn’t be concerning myself with it?

Wrong

As much as us software engineers sometimes pigeon hole ourselves as frontend or backend focused, I think there’s something to be said for being versatile and building, able to work with or at least understand both ends of the stack. AKA, it’s good for every software engineer to have a bit of full stack in them.

But why Adriel do you need to concern yourself with the backend of this project?

Ah, I’m glad you asked my friend. So if my sole purpose of that app was to send users a joke from the external joke api and then send them the next one, then you’re right. I wouldn’t need to build a backend. I wouldn’t need a server. I wouldn’t need to deal with Serverless, AWS, and all these other complexities.

However, if all I did was display jokes over from another API then what good value would I actually be providing? Couldn’t I just tell users to go to icanhazdadjoke to find those jokes themselves?

In that spirit, I decided to build on top of what the joke API provided by creating a rating mechanism for the jokes. The idea is that users will rate jokes on a pass/fail basis and those that get the most pass reactions will be surfaced to the top as the best dad jokes of all time.

Now suddenly I’ve changed things around. Instead of simply displaying jokes I’ve built a platform to find the best dad joke of all time. Wow! So much more interesting! I know, right?

In order to save the ratings of the jokes I get from the API, there must be some mechanism to store the jokes across different browsers and users into one shared location.

You may be thinking, why not store this data in something like a google spreadsheet? In a way, that’s exactly what a database is. It’s a glorified google spreadsheet that makes it easy to add, update, manipulate, and delete data.

In my case, data is stored in the form of user ratings.

The API I built has the following endpoints to get, update, and modify this data:

Database design

Again, a picture says a thousand works so let me start with those…

So I’ve got two tables each with four columns. Let’s look at joke_rating.

So joke_rating is really the heart and soul of the laughter engine database. In there, we have the data that will be displayed to the users. As you can see, the main two columns at the end here contain numeric values which keep track of the number of times someone has laughed at a joke. It’s whatever row in the database that has this value as the highest which deems it the funniest dad joke of all time.

So this data in activity is a bit more nuanced. Currently, the app is not displaying any data from this table, writing data to it.

Please, let me explain…

Let’s say we just had the joke_rating table. That would work just fine to keep the app functioning the way it is doing, but it poses some problems if we ever want to change things up in the future. Most notably the problem is that joke_rating had these two columns num_hahas and num_mehs that, while they do a good job for what the app offers right now, would pose a problem if we ever introduced a new reaction. If we introduced a new reaction, we’d have to create another column. Especially if a reaction can be via freeform text, then this problem would get even more hairy.

Instead, what would be better is if there’s another table that has a specific reaction column that can be any string value. THat’s where joke_activity comes into play. Since it has that exact column, now our system is capable of supporting any type of text reaction, so if we ever want to come up with a “sad” reaction, it would be super simple to store it in this table.

Now, if we ever wanted to create a leaderboard of the “saddest” reaction we could do an SQL query on the joke_activity table to group by joke_id where reaction='sad' and sort by joke id’s with the highest count.

In addition to making it more extensible for other reaction types, creating the joke_activity table offers an element that the joke_rating table simply does not: time. There’s no column for time on the joke rating table and we introduce that with joke activity so that if we wanted to find the oldest joke in the system, we can now easily do that.

So joke activity doesn’t offer us any benefits at the moment, but it’s setting ourselves up for future success in case we ever want to build upon the app. Planning for the future is good as failure to plan is planning to fail.

Marketing

What’s the point of an app if nobody uses it? That’s where marketing comes into play. People need to find out about the app. That’s one of the most important elements.

To that spirit I created a share button for mobile so that if you like a joke, you can easily share it with your friends which refers them to the product.

Things I learned

What would be the point of a blog post without discussing some of the major things I learned during the process of revamping this app, or share some of the takeaways if you will.

Sanitize your database inputs

Before doing this project I knew about database input sanitization, but hadn’t ever had to use it in real life since I’m mostly a front end engineer guy.

I learned while building this app that you must sanitize your database inputs or else bad things happen.

For example, one joke had an apostrophe in it Don't you think that... and that single character caused my backend function to crash out of execution since it told me t isn’t a valid character. What happened was that since I didn’t sanitize, it interpreted the ' character as the end of the SQL query since the query starts and ends with ' (i.e. 'SELECT * FROM joke_activity'). By sanitizing, we avoid those problems.

Netlify cares about accessibility, and I respect them more for it

Netlify is the platform that builds my React application and puts it out on the internet, and apparently they care about accessibility.

When I tried to publish the app, I mistakenly was using an image without adding an aria label for screen readers so that blind people could understand what I was trying to convey with the image. Netlify recognized this and failed to build my app and publish it.

When I looked at the logs, Netlify told me the reason for failure. I’m glad this company is putting its money where its mouth is for accessibility and they forced me to make my app more accessible to folks with visual impairments.

Serverless is incredibly easy to use

I have a newfound admiration for serverless. With a simple unix command of serverless, you can literally set up a backend Node server and deploy to AWS. No need to worry about scaling servers, no need to worry about setting up Express, no need to sign up for some expensive service. It’s so simple and easy to use. I intend on using this for future projects where I need to set up a backend layer.

Setting up and connecting to PostgresDB via bit.io is easier to use than MongoDB

When I first built the project, I built it with a service called MongoDB. While it was easy to set up to begin with, over time the company changed hands and the database disappeared. When rebuilding the project, I was going to set it up with the new MongoDB administrator called Atlas, but it was a pain in the neck to set up and believe it would cost me.

Instead I went over to Bit.io, created a new database with a click, and connected to it through the node-postres javascript package. It was easy as heck and I highly recommend using it.

Road map

Yes I built this laughter engine product, but the journey doesn’t end there. There is still lots to be done. Some ideas…

If any of these things may be things you are interested in contributing to, please hit me up.


P.S.

Before I wrote this post I told an AI bot to write it for me. I didn’t end up using it, but to show you the power of AI, this is what I got after telling it to Write me a blog post about building a full stack app that tells users jokes and let's them rate them to contribute to a communal leaderboard to find the best joke:

Creating a full stack web application: Dad Joke Hub

Are you tired of hearing the same old dad jokes over and over again? Look no further than the Dad Joke Hub! Our full stack web application is here to provide you with a never-ending supply of dad jokes, as well as a platform for users to rate and share their favorites.

The front-end of our web application is built using HTML, CSS, and JavaScript. We use a responsive design to ensure that the jokes are easily accessible on any device. Users can navigate through the jokes using a simple and user-friendly interface. Each joke is presented with a rating system, allowing users to rate the joke from 1 to 5.

The back-end of the web application is built using Node.js and MongoDB. Jokes are stored in a MongoDB database, and the application uses a RESTful API to retrieve and update joke data. User ratings are also stored in the database, and a leaderboard is generated to show the most highly-rated jokes.

One of the unique features of our web application is the ability for users to submit their own dad jokes to the database. This allows for a constantly growing collection of jokes, ensuring that there’s always a new and fresh dad joke to enjoy.

The Dad Joke Hub is more than just a collection of dad jokes, it’s a community. Users can share their favorite jokes with friends, and even compete to see who can find the funniest joke. So why wait? Come join the dad joke revolution and check out the Dad Joke Hub today!

Pretty cool right? Who does it better? The robot or me, the human?

Why compete when we can collaborate? My next project and post will likely be related to an AI powered app plan to build next. Stay tuned!