DEV Community

Cover image for Creating a Simple REST API - Part 3
Noopur Sharma
Noopur Sharma

Posted on

Creating a Simple REST API - Part 3

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 | part 2), 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 :

const express = require('express');
const app = express();
Enter fullscreen mode Exit fullscreen mode

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 :

const Joi = require('joi');
//This returns a class in Joi variable
Enter fullscreen mode Exit fullscreen mode

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

app.use(express.json());
//This returns a middleware that we are using via the use() method 
Enter fullscreen mode Exit fullscreen mode

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

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' }
];
Enter fullscreen mode Exit fullscreen mode

Now we can start defining the route handlers.

Let the first route handle be for the homepage :

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

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.

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);
});
Enter fullscreen mode Exit fullscreen mode

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 :

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);
});
Enter fullscreen mode Exit fullscreen mode

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 :

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);
});
Enter fullscreen mode Exit fullscreen mode

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 :

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);
});
Enter fullscreen mode Exit fullscreen mode

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 :

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

    return schema.validate(user);
}
Enter fullscreen mode Exit fullscreen mode

Now the value we pass this function will be :

const { error } = validation(req.body);
Enter fullscreen mode Exit fullscreen mode

Everything else remains the same.

So, now both the route handlers look like this :

//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);
});
Enter fullscreen mode Exit fullscreen mode

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.

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);
});
Enter fullscreen mode Exit fullscreen mode

We end our server by creating a listening port :

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

This is the final code ———>

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}`));
Enter fullscreen mode Exit fullscreen mode

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!

Top comments (0)