REST With Node.js
Tags: javascript, tutorial, node, productivity
Published: 2021-12-15 22:07:54

I know, I know… I said I would post more often. In my defense, I moved to another city and it’s exhausting. However, I’m here now and my gift to you before the holidays is finishing up our node.js backend. Let’s dive in.
<figure>
![chappelle rick james gif](https://i.gifer.com/7JiH.gif)
<figcaption>Give it to me baby</figcaption>
</figure>

We’re going to expand our application so that it provides the same RESTful HTTP API as a [json-server](https://github.com/typicode/json-server#routes).

We’re not going to deeply examine Fielding's definition of REST or spend time pondering about what is and isn't RESTful. Instead, we’ll take a [simplified view](https://en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_web_services) and concern ourselves with how RESTful APIs are understood in web applications.

One convention is to create the unique address for resources by combining the name of the resource type with the resource's unique identifier.

Let's assume that the root URL of our service is `example.com/api`.

If we define the resource type of `person` to be `people`, then the address of a person resource with the identifier 10, has the unique address `example.com/api/people/10`.
The URL for the entire collection of all note resources is `example.com/api/people`.

We can execute different operations on resources. The operation to be executed is defined by the `HTTP` verb:

|URL|verb|functionality|
|--- |--- |--- |
|people/10|GET|fetches a single resource|
|people|GET|fetches all resources in the collection|
|people|POST|creates a new resource based on the request data|
|people/10|DELETE|removes the identified resource|
|people/10|PUT|replaces the entire identified resource with the request data|
|people/10|PATCH|replaces a part of the identified resource with the request data|

## Fetching a Single Resource

I know I’ve been rambling about REST for a while, but I swear I wouldn’t do it if it weren’t important. Let’s circle back to our backend application and fetch a single resource.

``` javascript
app.get('/api/people/:id', (request, response) => {
  const id = Number(request.params.id)
  const person = people.find(p => p.id === id)
  

 if (person) {
   response.json(person)
 } else {
   response.status(404).end()
 }
})

```

Lots to unpack here, so I’ll try to break it down.

* `app.get('/api/people/:id', ...)` will handle all HTTP `GET` requests that are of the form `/api/notes/SOMETHING`, where _SOMETHING_ is an arbitrary string.
* The `id` parameter in the route of the request is accessed through the request object.
* The [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) constructor wraps our `id` parameter and turns it into an integer (This is just in case our `id` turns out to be a string, we’re thinking preemptively here).
* Our `if` block leverages the fact that all JavaScript objects are [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), meaning that it will evaluate to true in a comparison operation. However, undefined is [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) meaning that our block will evaluate to false. Thus sending an error status code if no person is found.

## Delete a Resource

Deletion happens by making an `HTTP DELETE` request to the url of the resource. 

<figure>
![Delete](https://media.giphy.com/media/wkKRo7N0T1ONO/giphy.gif)
<figcaption>Looking at you 2021</figcaption>
</figure>

Since we **just** retrieved a single resource, this should be easy.

``` javascript
app.delete('/api/people/:id', (request, response) => {
  const id = Number(request.params.id)
  people = people.filter(p => p.id !== id)

  response.status(204).end()
})
```
Once deletion of the resource is successful, meaning that the person exists and it is removed, we can respond to the request with the status code [204 no content](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5) and return no data with the response.

## POST and Receiving Data

Ok, let's make it possible to add new people to the server. Adding a person happens by making an `HTTP POST` request to the address `localhost:3001/api/people`, and by sending all the information for the new person in the request body in the `JSON` format.

<figure>
![Post-it Malone](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/45q537ttgbphqfxh7vpb.jpeg)
<figcaption>Not that kind of POST</figcaption>
</figure>
To access the data easily, we’ll need the help of the express [json-parser](https://expressjs.com/en/api.html) that is taken to use with command `app.use(express.json())`.

``` javascript
app.use(express.json())

//...


app.post('/api/people', (request, response) => {
 const person = request.body
 console.log(person)
 response.json(person)
})
```

* Here, the event handler function can access the data from the body property of the request object.

* Without the `json-parser`, the body property would be undefined. The `json-parser` functions so that it takes the `JSON` data of a request, transforms it into a JavaScript object and then attaches it to the body property of the request object before the route handler is called.

For the time being, the application does not do anything with the received data besides printing it to the console and sending it back in the response.

Let's return to the application and finalize the handling of the request!

``` javascript
const generateId = () => {
  const maxId = people.length > 0
    ? Math.max(...people.map(p => p.id))
    : 0
  return maxId + 1
}

app.post('/api/people', (request, response) => {
  const body = request.body

  if (!body.name) {
    return response.status(400).json({ 
      error: 'name missing' 
    })
  }

  const person = {
    name: body.name,
    number: body.number,
    id: generateId(),
  }

  people = people.concat(person)

  response.json(person)
})

```
* We need a unique id for each new person so we find out the largest id number in the current list and assign it to the `maxId` variable. The id of the new person is then defined as `maxId + 1`.

* If the received data is missing a value for the _name_ property, the server will respond to the request with the status code [400 bad request](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1)

* Calling `return` is crucial, otherwise the code will execute to the very end and a malformed person object gets saved to the application!

Here's how our backend looks now:

``` javascript
const express = require('express')
const app = express()
app.use(express.json())

let people = [
    {
      name: "Hannah Rickard",
      number: "06-51-99-56-83",
      id: 1
    },
    {
      name: "Hyun Namkoong",
      number: "10987654",
      id: 2
    },
    {
      name: "Courtney Martinez",
      number: "3691215",
      id: 3
    }
  ]

  app.get('/', (request, response) => {
      response.send('<h1>Phonebook</h1>')
  })

  app.get('/api/people', (request, response) => {
      response.json(people)
  })

app.get('/api/people/:id', (request, response) => {
  const id = Number(request.params.id)
  const person = people.find(p => p.id === id)
  

 if (person) {
   response.json(person)
 } else {
   response.status(404).end()
 }
})

app.delete('/api/people/:id', (request, response) => {
  const id = Number(request.params.id)
  people = people.filter(p => p.id !== id)

  response.status(204).end()
})

const generateId = () => {
  const maxId = people.length > 0
    ? Math.max(...people.map(p => p.id))
    : 0
  return maxId + 1
}

app.post('/api/people', (request, response) => {
  const body = request.body

  if (!body.name) {
    return response.status(400).json({ 
      error: 'name missing' 
    })
  }

  const person = {
    name: body.name,
    number: body.number,
    id: generateId(),
  }

  people = people.concat(person)

  response.json(person)
})

  const PORT = 3001
  app.listen(PORT, () => {
      console.log(`Server running on port ${PORT}`)
  })
```

<figure>
![Antonio Banderas Laptop](https://media.giphy.com/media/pHMtogPBHC7Cg/giphy.gif)
<figcaption>You made it!</figcaption>
</figure>

Aaaand we're done! We've managed to `GET` a single resource with the `id`. With that same logic, you were able to `DELETE` a resource. Finally, we received and persisted data with `POST`. 

As we approach the holidays and the end of the year, I want to wish you all the best, and please, if you go shopping, return your shopping cart to its designated spot.

## Resources
[JSON Server](https://github.com/typicode/json-server#routes)
[REST](https://en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_web_services)
[Number Constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)
[HTTP Status Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
[JSON Parser](https://expressjs.com/en/api.html)