Creating a Simple REST API - Part 3
Tags: beginners, webdev, node, javascript
Published: 2022-07-14 17:33:22

Hello JuxtaCoders!
Welcome to the third part of the REST API series. I hope the series has been helpful so far. Here, we're going to put everything we've seen so far into a functioning API. If you haven't watched the previous parts ([part 1](https://dev.to/noopur0210/creating-a-simple-rest-api-part-1-45mj) | [part 2](https://dev.to/noopur0210/creating-a-simple-rest-api-part-2-48a)), I highly recommend going through those and then coming back here:)

---

## In this part, we'll build a simple RESTful API using Express.js
First we need to import the express module : 

```jsx
const express = require('express');
const app = express();
```

The another thing we need is the joi module. This is used in validation of the bodies of client requests (like in put and post methods). First we install the joi module from npm and then import it :

```jsx
const Joi = require('joi');
//This returns a class in Joi variable
```

Now we get a middleware of express to parse the various components of the json type client requests : 

```jsx
app.use(express.json());
//This returns a middleware that we are using via the use() method 
```

Now we can create a dummy array of objects as our data set : 

```jsx
const customers = [
    { id: 1, name: 'John', address: 'Highway 71' },
    { id: 2, name: 'Peter', address: 'Lowstreet 4' },
    { id: 3, name: 'Amy', address: 'Apple st 652' },
    { id: 4, name: 'Hannah', address: 'Mountain 21' },
    { id: 5, name: 'Michael', address: 'Valley 345' },
    { id: 6, name: 'Sandy', address: 'Ocean blvd 2' },
    { id: 7, name: 'Betty', address: 'Green Grass 1' },
    { id: 8, name: 'Richard', address: 'Sky st 331' },
    { id: 9, name: 'Susan', address: 'One way 98' },
    { id: 10, name: 'Vicky', address: 'Yellow Garden 2' },
    { id: 11, name: 'Ben', address: 'Park Lane 38' },
    { id: 12, name: 'William', address: 'Central st 954' },
    { id: 13, name: 'Chuck', address: 'Main Road 989' },
    { id: 14, name: 'Viola', address: 'Sideway 1633' }
];
```

---

Now we can start defining the route handlers. 

Let the first route handle be for the homepage : 

```jsx
app.get('/', (req, res) => {
    res.send('Hello World!!');
});
```

Now we can define route handlers for our actual GET requests : 

The first one is to get the details of all customers in our dataset. In the second type of request the client defines for what id they want to see the details.

For the second type of request we want to parse the id out of the url, and find if it even exists in the dataset. Only when it exists can we send the details, otherwise we send an error.

First we parse the id from the request. Using the **req.params.id** object returns a string, so we need to parse it into an integer. For this we use the parseInt() method. 

Now to find if the data for this id exists in our dataset, we need to use the find() method on our array of objects. We check if the id of any of the array elements match the id that the user requested. If it doesn't we produce a 404 status code (meaning not found). Otherwise we respond with the object.

```jsx
app.get('/api/customers', (req, res) => {
    res.send(customers);
});

app.get('/api/customers/:id', (req, res) => {
    const customer = customers.find(c => c.id === parseInt(req.params.id));
		if (!customer) return res.status(404).send("Customer with given ID not found");
		res.send(customer);
});
```

---

Now let's create route handler for our POST request :

First we assume that he client makes a proper request with both the necessary properties in our customer object, fulfilling the requirement of a min number of characters. 

In such case our goal is to simply take the values from the client, push the details into our array, and display the added object : 

```jsx
app.post('/api/customers', (req, res) => {
	const customer = {
        id: customers.length + 1,
        name: req.body.name,
        address: req.body.address
    }

  customers.push(customer);
  res.send(customer);
});
```

But majority of the time we assume that the client will not put the right request. In such case we need to validate the body of the request, matching it with an ideal schema. If there is some issue, we need to show the error with a 400 status code (meaning bad request). Otherwise, we respond with the object added :

```jsx
app.post('/api/customers', (req, res) => {
	const schema = Joi.object({
	    name: Joi.string().min(3).required(),
	    address: Joi.string().min(5).required()
	});
	
/*	const result = schema.validate(req.body);
Or we can use the destructuring technique to directly read the error 
out of the validate method
*/
	const { error } = schema.validate(req.body);
	
	if (error) return res.status(400).send(error);
	
	const customer = {
	    id: customers.length + 1,
	    name: req.body.name,
	    address: req.body.address
	}
	
	customers.push(customer);
	res.send(customer);
});
```

Here we first create a schema to define the requirements of the properties that need to be included in the body of the request. This is done by creating an object using the object() method of the Joi class. Next we use the validate() method to see if req.body is valid with respect to the schema. 

The validate() method returns an object containing two properties —> **error** and **value**. In case there is an error, the property 'value' gets a null value, otherwise the 'error' property gets a null value.

Either we can retrieve this object in 'result' variable and then use its 'error' property, or we can use the concept of destructuring to just take the error value out of the object.

Then we check if the value of error is null or not. If it is not null, we send the value of error, otherwise we create a variable to hold the values of the object and push it into the array and show it to the client.

---

---

Now we create a route handler for the PUT request : 

The client will provide an id for which they want to update the data. So our goal is to first look up the id in our dataset. If it doesn't exist we respond with a 404 status code. If it exists, we check the validity of the request body. If the body is valid, we show the updated object, otherwise we respond with a 400 status code.

Now let's start with finding the id in our dataset : 

```jsx
app.put('/api/customers/:id', (req, res) => {
	//Finding
	const customer = customers.find(c => c.id === parseInt(req.params.id));
  if (!customer) return res.status(404).send("Customer with given ID not found");

	//Validating
  const schema = Joi.object({
      name: Joi.string().min(3).required(),
      address: Joi.string().min(5).required()
  });

	//Using destructuring
  const { error } = schema.validate(req.body);
  if (error) return res.status(400).send(error);

	//Updating
  customer.name = req.body.name;
  customer.address = req.body.address;

  res.send(customer);
});
```

---

Now in the above two route handlers we can the the code for validation is repeated. We can reduce it by creating a method that takes the body as parameter, creates a schema and validates. This method returns the error : 

```jsx
function validation(user) {
	const schema = Joi.object({
      name: Joi.string().min(3).required(),
      address: Joi.string().min(5).required()
  });
	
	return schema.validate(user);
}
```

Now the value we pass this function will be : 

```jsx
const { error } = validation(req.body);
```

Everything else remains the same.

So, now both the route handlers look like this : 

```jsx
//POST
app.post('/api/customers', (req, res) => {

	const { error } = validation(req.body);
	if (error) return res.status(400).send(error);
	
	const customer = {
	    id: customers.length + 1,
	    name: req.body.name,
	    address: req.body.address
	}
	
	customers.push(customer);
	res.send(customer);
});

//PUT
app.put('/api/customers/:id', (req, res) => {
	//Finding
	const customer = customers.find(c => c.id === parseInt(req.params.id));
  if (!customer) return res.status(404).send("Customer with given ID not found");

  const { error } = validation(req.body);
  if (error) return res.status(400).send(error);

	//Updating
  customer.name = req.body.name;
  customer.address = req.body.address;

  res.send(customer);
});
```

---

Now finally we need the DELETE route handler : 

Here we first find if the dataset exists which the client wants to delete, via the id. If it exists, we get the index of the object through its id and we use the splice() method on our dataset array to remove the object. If the id is not found, we show a 404 status code, otherwise we show the deleted object as response.

```jsx
app.delete('/api/customers/:id', (req, res) => {
    //Finding
    const customer = customers.find(c => c.id === parseInt(req.params.id));
    if (!customer) return res.status(404).send("Customer with given ID not found");

    //Delete
    const index = customers.indexOf(customer);
    customers.splice(index , 1);

    res.send(customer);
});
```

---

We end our server by creating a listening port : 

```jsx
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}`));
```

---

This is the final code ———>

```jsx
const Joi = require('joi');
const express = require('express');
const app = express();

app.use(express.json());

const customers = [
    { id: 1, name: 'John', address: 'Highway 71' },
    { id: 2, name: 'Peter', address: 'Lowstreet 4' },
    { id: 3, name: 'Amy', address: 'Apple st 652' },
    { id: 4, name: 'Hannah', address: 'Mountain 21' },
    { id: 5, name: 'Michael', address: 'Valley 345' },
    { id: 6, name: 'Sandy', address: 'Ocean blvd 2' },
    { id: 7, name: 'Betty', address: 'Green Grass 1' },
    { id: 8, name: 'Richard', address: 'Sky st 331' },
    { id: 9, name: 'Susan', address: 'One way 98' },
    { id: 10, name: 'Vicky', address: 'Yellow Garden 2' },
    { id: 11, name: 'Ben', address: 'Park Lane 38' },
    { id: 12, name: 'William', address: 'Central st 954' },
    { id: 13, name: 'Chuck', address: 'Main Road 989' },
    { id: 14, name: 'Viola', address: 'Sideway 1633' }
];

app.get('/', (req, res) => {
    res.send('Hello World!!');
});

app.get('/api/customers', (req, res) => {
    res.send(customers);
});

app.get('/api/customers/:id', (req, res) => {

    const customer = customers.find(c => c.id === parseInt(req.params.id));

    if (!customer) return res.status(404).send("Customer with given ID not found");

    res.send(customer);
});

function validation(user) {
    const schema = Joi.object({
        name: Joi.string().min(3).required(),
        address: Joi.string().min(5).required()
    });

    return schema.validate(user);
}

app.post('/api/customers', (req, res) => {

    const { error } = validation(req.body);
    if (error) return res.status(400).send(error);

    const customer = {
        id: customers.length + 1,
        name: req.body.name,
        address: req.body.address
    }

    customers.push(customer);
    res.send(customer);
});

app.put('/api/customers/:id', (req, res) => {
    //Finding
    const customer = customers.find(c => c.id === parseInt(req.params.id));
    if (!customer) return res.status(404).send("Customer with given ID not found");

    const { error } = validation(req.body);
    if (error) return res.status(400).send(error);

    //Updating
    customer.name = req.body.name;
    customer.address = req.body.address;

    res.send(customer);
});

app.delete('/api/customers/:id', (req, res) => {
    //Look up the customer
    //If not existing, return 404
    const customer = customers.find(c => c.id === parseInt(req.params.id));

    if (!customer) return res.status(404).send("Customer with given ID not found");

    //Delete
    const index = customers.indexOf(customer);
    customers.splice(index, 1);

    //Return the same customer
    res.send(customer);
});

const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}`));
```

---
That's all for now!! I hope this was helpful. Now, you can use this knowledge to make more complex APIs for more diverse databases. But remember, the key is to taking it slow and not to loose momentum. Keep making projects and gradually gain more skills!

If there are any suggestions, feel free to share:)

Until next time... Happy Coding!