Sails Tutorial — Chapter 3

Jun 21, 2024

This is the third article in the series. You can read the second one at this link.

Note: To follow this article, you need to install an API client to test the routes that we are going to create in this article. Try Postman or Insomnia if you haven’t one.

In this article, we are going to create the APIs for the Contact resource. If you are building an MVC web app, then you need to create seven routes whereas if you are creating an API, you need to create five routes.

To start with, let’s add a route that returns all the contacts as GET /contacts. When this route is requested, the server should run the index action of ContactsController in the config/routes.js file.

module.exports.routes = {
  "GET /": "HomeController.index",

  // Contacts
  "GET /contacts": "ContactsController.index",
};

We don’t have this ContactsController.js file yet! Let’s create one in the api/controllers folder.

touch api/controllers/ContactsController.js

Open this ContactsController.js file and write the following code.

module.exports = {
  index: (req, res) => {
    res.json({ message: "All contacts" });
  },
};

Open the http://localhost:1337/contacts in the browser and you should see this JSON response.

Now, we need to add a route for a specific contact as GET /contacts/:id. When this route is requested, the server should run the show action of ContactsController in routes.js file.

module.exports.routes = {
  "GET /": "HomeController.index",

  // Contacts
  "GET /contacts": "ContactsController.index",
  "GET /contacts/:id": "ContactsController.show",
};

Let’s define this show action within ContactsController.js file and also print the passed id value using req.params.id.

module.exports = {
  index: (req, res) => {
    res.json({ message: "All contacts" });
  },

  show: (req, res) => {
    console.log(`contact id is ${req.params.id}`);
    res.json({ message: "Single contact" });
  },
};

Open the http://localhost:1337/contacts/1 in the browser and you should see this JSON response. You should also see the console message as contact id is 1 in the terminal.

Next, we need to add a route that creates a new contact by passing first name and last name as firstName and lastName respectively. We can define this route as POST /contacts and map against the create action of ContactsController.

module.exports.routes = {
  "GET /": "HomeController.index",

  // Contacts
  "GET /contacts": "ContactsController.index",
  "GET /contacts/:id": "ContactsController.show",
  "POST /contacts": "ContactsController.create",
};

Let’s define this create action within ContactsController.js file and also print the passed firstName and lastName values using req.body.firstName and req.body.lastName (you can destructure in single line, if you want).

module.exports = {
  index: (req, res) => {
    res.json({ message: "All contacts" });
  },

  show: (req, res) => {
    console.log(`contact id is ${req.params.id}`);
    res.json({ message: "Single contact" });
  },

  create: (req, res) => {
    console.log(`first name is ${req.body.firstName}`);
    console.log(`last name is ${req.body.lastName}`);
    res.json({ message: "Creating contact" });
  },
};

To test this route, we need to do a POST api call in Insomnia (or any other API client you are using). You should get the above JSON response when calling this route and first name & last name should be consoled in the terminal.

Before we go further and add route for updating a resource, let’s do a status code modification in create route as 201 should be the status code when creating a resource. We know how to do it as we’re going to use Express’s .status() method.

module.exports = {
  index: (req, res) => {
    res.json({ message: "All contacts" });
  },

  show: (req, res) => {
    console.log(`contact id is ${req.params.id}`);
    res.json({ message: "Single contact" });
  },

  create: (req, res) => {
    console.log(`first name is ${req.body.firstName}`);
    console.log(`last name is ${req.body.lastName}`);
    res.status(201);
    res.json({ message: "Creating contact" });
  },
};

Much better! Just confirm in Insomnia that you should get 201 status code in response (You can chain .status() and .json() methods in single line, if you want).

Let’s define a route to update a specific contact as PUT /contacts/:id. When this route is requested, the server should run the update action of ContactsController.

module.exports.routes = {
  "GET /": "HomeController.index",

  // Contacts
  "GET /contacts": "ContactsController.index",
  "GET /contacts/:id": "ContactsController.show",
  "POST /contacts": "ContactsController.create",
  "PUT /contacts/:id": "ContactsController.update",
};

Let’s define this update action within the ContactsController.js file. Let’s also print the id as req.params.id and passed firstName & lastName values as req.body.firstName and req.body.lastName (you can also destructure, if you want).

module.exports = {
  index: (req, res) => {
    res.json({ message: "All contacts" });
  },

  show: (req, res) => {
    console.log(`contact id is ${req.params.id}`);
    res.json({ message: "Single contact" });
  },

  create: (req, res) => {
    console.log(`first name is ${req.body.firstName}`);
    console.log(`last name is ${req.body.lastName}`);
    res.status(201);
    res.json({ message: "Creating contact" });
  },

  update: (req, res) => {
    console.log(`contact id is ${req.params.id}`);
    console.log(`first name is ${req.body.firstName}`);
    console.log(`last name is ${req.body.lastName}`);
    res.json({ message: "Updating contact" });
  },
};

We need to test this route in Insomnia. You should get the above JSON response when calling this route and id, firstName & lastName should be consoled in the terminal.

Finally, we need to add a route that deletes a specific contact as DELETE /contacts/:id and should run the destroy action of ContactsController. delete is a reserved keyword in JavaScript. Due to this, we choose destroy as function name.

module.exports.routes = {
  "GET /": "HomeController.index",

  // Contacts
  "GET /contacts": "ContactsController.index",
  "GET /contacts/:id": "ContactsController.show",
  "POST /contacts": "ContactsController.create",
  "PUT /contacts/:id": "ContactsController.update",
  "DELETE /contacts/:id": "ContactsController.destroy",
};

Let’s define this destroy action within ContactsController.js file and also print the id as req.params.id.

module.exports = {
  index: (req, res) => {
    res.json({ message: "All contacts" });
  },

  show: (req, res) => {
    console.log(`contact id is ${req.params.id}`);
    res.json({ message: "Single contact" });
  },

  create: (req, res) => {
    console.log(`first name is ${req.body.firstName}`);
    console.log(`last name is ${req.body.lastName}`);
    res.status(201);
    res.json({ message: "Creating contact" });
  },

  update: (req, res) => {
    console.log(`contact id is ${req.params.id}`);
    console.log(`first name is ${req.body.firstName}`);
    console.log(`last name is ${req.body.lastName}`);
    res.json({ message: "Updating contact" });
  },

  destroy: (req, res) => {
    console.log(`contact id is ${req.params.id}`);
    res.json({ message: "Deleting contact" });
  },
};

And now we have the stub end-points for the given resource e.g. Contact with best practice to create REST APIs.

Tags: sails