Category: Week 7

Authorisation for a REST API deployed on Heroku

This week we have been tasked with building a REST API that returns JSON data for our group projects, and my group made one that contains data about books that our cohort has read.

We added user authentication for our POST routes so only logged in users can add resources to the database. We did this with token-based authentication using the jsonwebtoken Node.js npm package.

When a new user signs up to our API they get a JWT that is signed with a secret that we stored as an environment variable in our .env file.

const dotenv = require("dotenv");
const jwt = require("jsonwebtoken");
const secret = process.env.JWT_SECRET;

dotenv.config();

function signUp(req, res) {
  // run database query function that creates a new user
  .then((user) => {
    const access_token = jwt.sign({ user: user.id }, secret, { expiresIn: "1h" });
  user.access_token = access_token;
  // send user object
  }
  // error-handling
};

When the user signs in successfully by making a POST request to the API, we send the access_token property of their user object in the response body. The user can then send this JWT in the authorization headers when making a request to our API that requires authorization.

This was all working great on our local servers, but we were unable to sign up or sign in to our API once deployed on Heroku. We were scratching our heads until it dawned on me as I was biting into my sandwich at lunch: we needed to add our JWT_SECRET variable to our Config Vars on Heroku. Problem solved 🥳!

Operational vs. Programmer Errors

This week we did a research spike on error-handling to prepare us for this week’s Express project, and one of the topics we covered was the difference between operational and programmer errors.

Operational errors in your application are run-time errors that relate to the system’s configuration or network. For example, a failure to connect to the server, or a request timeout.

Programmer errors in your application are bugs that can be avoided by changing the code, often created by spelling mistakes. Examples include: missing or invalid arguments, mistyping a variable name, passing the wrong data type that what was expected, or calling an asynchronous function without a callback. These errors should not be handled because the code is broken so the program should not recover and keep handling requests.

We deployed a programmer error to our REST API today which broke our Heroku server because we forgot to uncomment an unused function that we had imported but not defined in our code. This was a mistake which we’ve learned the following from: always test our server runs before pushing changes to our master branch on GitHub, and learn more about continuous integration!

Faking HTTP requests in Node.js

We can use the nock library for Node.js to mock HTTP requests and receive fake network responses, so we can focus on testing our code rather than getting failing tests caused by poor connection to an API.

After you install the npm package, you can use nock like this to override Node’s http.request function in your server tests:

const nock = require("nock");

nock("https://api.com")
  .get("/path")
  .reply(200, { response object } );

Underscores in front of variables

Today we were learning about building REST APIs in Node using Express. In one of our functions we had to use a try...catch statement for our error handling.

We had to put an underscore in as an argument as catch cannot take an empty argument.

try {
  // try something here
} catch (_) {
  // error handling here
}

Routing in Express JS

Until today we have been using vanilla Node to build our web applications for workshops and projects in the course.

Today we learned how 3 words can make your life so much easier. Those words are: npm install express!

Until now we have been handling routes in our applications using the built-in Node HTTP server functionality, essentially writing long if statements that handle each path and request type:

const http = require("http");

const server = http.createServer((request, response) => {
  const url = request.url;
  if (method === "GET" url === "/") {
    // handling request
  } else if (method === "POST" url === "/submit") {
    // handling request
  }
};

This is made much simpler with the Express server object:

const express = require("express");
const server = express();

server.get("/", (req, res) => {
  // handling request
});

server.post("/submit", (req, res) => {
  // handing request
});