Using REST API with Express

Renzo Regio
17 min readMar 10, 2021

--

TIL 2021.02.24

Day 76: Treehouse Full Stack JavaScript Techdegree

REST API INTRO RECAP:

INTRO TO REST APIs

Traditional Web Applications

  • Handles both server side and client side concerns
  • Example: Favorite Recipes Web App
  • Click on a URL and the browser makes a request to the server and the server responds by finding the recipe data in a database, assembling the data into HTML templates and sending that HTML back to the browser to be displayed.
  • But what if we want to do the same with a mobile app? This is where REST API comes in

When we request information from a RESTful Application, the application only responds with the recipe data — typically in the JSON format. Sending JSON data rather than HTML means that the backend only has to be built once. While any number of front end applications can consume and display the data

If we have a REST API for recipes we could create a recipe website, but we could also use the same data to create a small meal planning app, calorie tracking app, a virtual cookbook and so much more. Making use of the REST API makes everything more flexible in a way that we are only sending out the data.

Another example is the Twitter app on your phone, the twitter’s REST API to get the tweets before you see them — the JSON from twitter’s API is formatted and displayed on your phone. But the Twitter API allows the same tweet data to be accessed and used by a web browser, smart tv, etc.

REST APIs can provide data and content for rich web applications, mobile apps and other server side applications.

Rest API

  • Lets you retrieve data and present that data in any way you want, providing more flexibility.

WHAT IS A REST API?

How information is transferred to the web:

Client (application requesting information from a server)

REST (Representational State Transfer): A set of ideas about how a server should respond to a request from a client — A traditional web application responds with HTML while a REST API responds with data and it is up to the framework on how to display the data from the API

Example: Random User Generator / Employee Directory Built in the Earlier Section of the FSJS

The flexibility of REST API is that once we receive the data — we can do whatever we want from it

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

HTTP METHODS AND CRUD OPERATIONS

Web applications we use everyday like Facebook, instagram, and twitter follow a common pattern: CRUD (Create, Read, Update and Delete)

REST APIs allow a client to manipulate data using actions that map closely to the idea of CRUD — GET POST PUT DELETE which are known as HTTP VERBS OR HTTP METHODS

Information in a REST API is typically organized using nouns that describe what the data represents, nouns like users, posts, movies, score, games — which are Resources

Using HTTP methods and API nouns, a client can tell a REST API what information it wants and what it wants to do with that information.

If a client sends a GET request to the resource/movies, it means that i expects to read or view data representing the collection of movies

POST request means that it wants to create a new movie

PUT means it wants to update an existing movie

DELETE means it wants to delete an existing movie

It takes in requests and response with JSON objects

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

A SIMPLE API

A RESTful API responds with data — most of the time being a JSON object

The express function adds a bunch of methods to Node’s HTTP server to make it easier for us to receive and respond to requests. These methods include GET, POST, PUT and DELETE.

First let’s do a GET method — it takes two arguments, a route as the first argument and a callback function as a second argument (This is the callback function we want to run when this request comes in and how we want to respond.)

The callback function takes two arguments

  • Incoming request from the client (req)
  • Outgoing response from the server (res)

Usually we would do res.render(“template_name”) but we don’t want to do that because we are building a REST API. So inside the callback function we want to send back JSON. And to do that we can use the JSON method available on the response object. We can pass the JSON method an object and it will convert that object into JSON format and send it to the client.

We can see that our API is sending JSON when we make a request.

The browser by default sends a GET request — by visiting /greetings we’re sending a GET request to the route which we’ve programmed in our Express application to send back a JSON object containing a greeting

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

PLANNING OUR REST API

We want the client to be able to send a GET request to /quotes to read a list of quotes

//Send a GET request to /quotes to READ a list of quotes

//Send a GET request to /quotes/:id to READ(View) a Quote

//Send a POST request to /quotes CREATE a new Quote

//Send a PUT request to /quotes/:id UPDATE an existing Quote

//Send a DELETE request to /quotes/:id to DELETE an existing Quote

//Send a GET request to /quotes/quote/random to READ(View) a random Quote

Notice that these endpoints are mostly the same, this is because each endpoint can have multiple HTTP methods — the HTTP method, the action, will tell Express what to do and how to respond to the request

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

GET A QUOTE, GET ALL QUOTES

Now let’s get a single quote

One way to do it:

Or we can use the find method

Using the browser we’re sending a GET request to our Express server with the ID number of the quote we’re looking for

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

MANAGING REST API DATA

Depending on the database you choose, you would likely choose some kind of library known as an ORM (Object Relational Mapping) to facilitate the communication between your Express App and your Database.

An ORM makes it easier to retrieve, manipulate, save and validate the data in your database

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

REFACTOR THE GET ALL ROUTES QUOTE

On records.js

We’re calling records.getQuotes() and saving the result to a variable called quotes — records.getQuotes() reaches into our data store, gets all the quotes and returns them to us. Once we have all those quotes, we send them back to the client as JSON

Note: all the functions in the records.js use asynchronous functions to closely mimic the behavior of an actual database

The getQuotes function returns a promise which uses node’s readFile method to retrieve the data from the data.json file then resolves the promise with that data

We used async await to tell JavaScript to wait until we get all the code or data we need from the getQuotes function then execute the next line of code which is to return the response as a JSON

await tells JavaScript to expect the method to return something, so it should wait until the method to return something to execute the next line of code

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

REFACTOR THE GET ONE QUOTE ROUTE

records.js

routes

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

USING POSTMAN TO TEST ROUTES

Postman is an application that will allow us to send a variety or requests to our API so that we can write endpoints to create, update and delete quotes. And then make sure our application is working as we expect

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

CREATE A NEW QUOTE

Notice that we have the same route /quotes for the get and post request

When the get request is sent, it will execute that code. When a post request is sent, it will execute that code. Even if they have the same route, once called, they perform or render different things.

POST request

And now once we use a get request to get all the quotes, we have what we created from the post request earlier

OR

Similar to how req.params work, express takes information from the client and makes it available to us on the request object on a property called body

Express takes information from the client and makes it available on the request object. But it doesn’t do it automatically

To be able to access values on req.body we would need some middleware.

So on top of the file

When a request comes in, it’ll be sent through this function before it hits any of the routes

This middleware tells express that we’re expecting requests to come in as JSON. That way express can take the JSON we’re sent, via the request body, and make it available to us on the request object on the property called body

On Postman

And once we hit send

And it is now on our data.json

Review:

We are making a POST request containing JSON for a new quote with postman, our client. We are then accessing that information through express with req.body and we’re setting those values to a new object that we’re passing to createQuote() function. Then we are storing our newly created quote to a quote variable and sending it back to the client.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

USING TRY/CATCH WITH ASYNC/AWAIT

We need to find a way to catch any errors that happens in our await function

Let’s throw a fake error

It works, but notice that the status code is still 200

We will tackle this on the next video about status codes

Next let’s add a try/catch block on our get single quote route

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

HTTP STATUS CODES

HTTP status codes gives the client important information about the request and response cycle

200 range: everything went as expected

400 range: something went wrong on the client side — something went wrong with the request, like a missing resource or the wrong information was sent

500 range: something went wrong on the server side — something unexpected happened that prevented the server from fulfilling the request

Common Status Codes

  • 200 — OK (The request was successful)
  • 201 — Created (A new resource has been created)
  • 400 — Bad Request (The request was malformed or missing information)
  • 404 — Not Found (The resource does not exist)
  • 500 — Internal Server Error

Even though there is an error, you can see that the status code is 200 — this means that everything went find, there are no problems — this is the code that express sends by default but we have the power to choose which status codes we send in case of an error or to give consumers of our API useful information about the requests.

We can send a different status code by using the status method

res.status(code)

And now on postman, if we try and make another post request, knowing that there will automatically be an error because of what we set

It now displays the 500 status code for internal server error

Note we can also chain these by doing res.status(500).json()

Also we can send a better status code than 200 if the POST request was successful and that would be the 201 status code for created

And now we will get this

We now have the 201 created status code — or a new resource was created

There is some error handling we could do on our single quote route

We are doing this because if we, for example, try and get a single quote with a fake id parameter, it will return no json as well as a status code of 200 (since this is the default status code express provides). So we are basically handling the error that if the quote exists we will return the json response and if not we will set the status code as well as the json res as an error message.

A status code of 400 means bad request — something is wrong with the syntax of the request, information was missing or some sort of information validation has failed

Without the error handling above, if we request a quote with an id that does not exist — we get back nothing, a blank screen and a 200 status code

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

EDIT A QUOTE

A PUT request indicates to our application that a change is going to be made on an existing resource.

For a PUT request, it is a convention to send a status of 204 — which means no content. This generally means that everything went okay, but there’s nothing to send back.

Also, it is convention not to respond with anything when doing PUT requests.

The datastore simply gets updated and we send back a status code indicating that the update went as expected.

We need another way to end the request, or the server will hang indefinitely. We can end the request with the Express end method — which simply tells express that we’re done.

Let’s edit the quote with the ID of 8721

Prior to updating

We’ll edit it by adding a “jr” to the author’s name

And once we send it

We receive this as a response — a status code of 204 No Content(Per the convention of using the PUT method) and a body of blank which is also a convention when using the PUT request.

And we can now see that it is updated.

So we are finding the quote by ID, taking information the client has sent us and using it to update the quote. Passing the new quote to the updateQuote method to be saved. In a real world situation, we would want to validate the information that was sent to us like has the client sent back data for all the required properties — we do this in ORM

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

DELETE A QUOTE

Similarly to using the PUT route, we will follow the convention of the status 204 and no content for the body

We want to delete the quote with the id 2295

And it is now deleted!

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

WRITING A GLOBAL ERROR HANDLER

There are two types of errors that we’re dealing with

Request Error 404

Or

Server Error 500

For our API we are going to create our own custom error handler so that we can send the error message as a JSON object

Now let’s try and create an error on our delete request

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

REFACTOR WITH EXPRESS MIDDLEWARE

We can use a piece of middleware to prevent using the try/catch block on every single route

We are using an asyncHandler

It takes in a function, wraps it in a try/catch block and passes any errors to the global error handler we wrote

We can use this middleware function in every route instead of using the try/catch block every single time

The asyncHandler will be our callback function, when a request is made, the home route will run the asyncHandler.

We have to wrap this around the asyncHandler function

Inside the asyncHandler function we’ll pass the anonymous function

We don’t have to do the try/catch block anymore since the asyncHandler is the one performing the try/catch block

This is exactly the same code we had before, only the asyncHandler is acting as the middleman here. We passed it the anonymous function containing the code that we want to run when the request is made and it is going to call that function in the try/catch blocks and catch errors for us.

And because we want to await the creation of the record inside of the anonymous function, the anonymous function also needs to be asynchronous

For the PUT request

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

STRUCTURING YOUR REST API

Notice that when we access information through an API, we request information from a /api route.

We can set up our API the same way within an express router. Which is created using a method called express.router

Doing it this way will be beneficial,

We can map each of our routes to an endpoint that starts with /api without having to repeat /api for each route.

It will keep our express files more modular

  1. Create a routes.js file
  • Move all routes except the error handler

2. Require express

  • const express = require(“express”);

3. And back on app.js: recall that we can use app.use to tell express that we want to add a piece of middleware. This time we are going to specify middleware only to be used if the request route starts with a certain path

  • app.use(“/api”, routes);
  • Here we are saying when a request starts with a path /api, use the routes inside of the routes.js file

4. Import routes.js file on app.js

  • const routes = require(“./routes.js”);

5. Back on routes.js we will set up a new router

  • The router method allows us to route everything to /api without having to specify it on every single route
  • const router = express.Router();

6. Replace each route that says app to router

7. Export the router at the bottom of the file

  • module.exports = router;

Created a new module named routes

Moved all our quote routes to it

We’re using the express router method which allows us to map these routes to a specified path, in this case /api

We’re assigning express router to a variable called router and using it handle our various types of requests

Finally, we exported the router through module.exports = router

And on App.js we are importing the file we just made and saying we want to use the routes in that file whenever a request comes in that starts with /api

Now let’s try it out

We get an error if we try to make a GET request to our /quotes route

Let’s add /api at the start

And it works!

This is a standard way to structure and modularize an API in express that will allow our app to easily grow

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

GET RANDOM QUOTE

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

--

--