DEV Community

Esto Triramdani N
Esto Triramdani N

Posted on

Build a REST API of History of Conflicts Using Express.js

Hi everyone! Welcome to my really first post in DEV.
A week ago, I found an interesting dataset that contains list of conflicts in Kaggle (History of Conflicts). That dataset shows conflicts happened in the world. It contains 900+ rows. Whether the data is valid or not, we can use this dataset to learn.
I have transformed the data to JSON. You can just copy here. I splitted the data every 20 item into a new array. So the form of JSON I provided will be an array of array of object.
If you want to see the final result [which has been integrate with frontend app], you can visit this link. Of course we will deploy our app after the app is completely built.

Initialize the Node.js project, then install the dependencies: express, cors, and dotenv. I also install nodemon as devDependencies.

mkdir history-of-conflicts-backend
cd history-of-conflicts-backend
npm init -y
npm i express cors dotenv --save
npm i nodemon --save-dev
Enter fullscreen mode Exit fullscreen mode

In package.json, edit the scripts.

"scripts": {
   "dev": "nodemon index.js",
   "start": "node index.js"
 },
Enter fullscreen mode Exit fullscreen mode

Create index.js on project root directory as we defined that ./index.js is our entry point.
Create an express server in ./index.js and make sure our web server is working fine.

const express = require('express');
const cors = require('cors');
const app = express();
const PORT = process.env.PORT || 4000;

app.use(cors());

app.get('/', (req, res) => {
  res.json({
    message: 'Hello',
  });
});

app.listen(PORT, () => console.log(`Server is running on port ${PORT}`));
Enter fullscreen mode Exit fullscreen mode

Run npm run dev and hit http://localhost:4000 in Postman (or something like that).
Did you find json response with "message": "Hello"? If you did, let's move to the next step!
Create a .json file called transformed-data.json and place it under /data directory.

data
  - transformed-data.json
Enter fullscreen mode Exit fullscreen mode

Now we need a controller to serve sections of part. 'part' that I mean is a group of rows. We have 47 parts in case. First 46 parts has 20 rows, while the last parts has 6 rows.
So we have to create a pagination-like endpoint. We call the group of parts as section.

Create a file ./controllers/index.js. At the top of line, import transformed-data.json.

const transformedData = require('../data/transformed-data.json');

Since I didn't provide the transformed data (the file that has been splitted parts into sections), we need to do it manually. To do that, create function called startEndIndexFinder under the line which transformed-data.json is imported.

function startEndIndexFinder({ currentSection, itemsPerSection }) {
  const section = +currentSection < 0 ? 1 : +currentSection;
  const startIndex = (section - 1) * itemsPerSection;
  const endIndex = section * itemsPerSection - 1;
  return { section, startIndex, endIndex };
}
Enter fullscreen mode Exit fullscreen mode

The function receive object as parameter which contains currentSection and itemsPerSection. Make sure currentSection is greater than 0. Then find the first index and the last index of current section. Finally return an object which contains section, start index, and end index.

Use startEndIndexFinder to our /parts controller.

const partsController = async (req, res) => {
  const currentSection = req.query.section || '1';
  const itemsPerSection =
    +req.query.itemsPerSection || transformedData.length + 1;
  const { endIndex, section, startIndex } = startEndIndexFinder({
    currentSection,
    itemsPerSection,
  });
  const maxSection = Math.ceil(transformedData.length / itemsPerSection);
  if (+currentSection > maxSection) {
    res.status(404).json({
      status: false,
      message: 'No more sections',
      data: {
        itemsPerSection,
        maxSection,
      },
    });
  }
  const data = transformedData
    .map((item, index) => {
      if (index >= startIndex && index <= endIndex) {
        return {
          id: index + 1,
          name: `Part ${index + 1}`,
          from: item[0].Date,
          to: item[item.length - 1].Date,
          link: `/api/parts/${index + 1}`,
        };
      }
    })
    .filter((item) => item);
  res.status(200).json({
    status: true,
    message: 'Sections of parts were successfully fetched',
    data: {
      itemsPerSection,
      section,
      startIndex,
      endIndex,
      maxSection,
      data,
    },
  });
};

module.exports = { partsController };
Enter fullscreen mode Exit fullscreen mode

We received current section and itemsPerSection from request. ItemsPerSection is being validated at this controller because there are possibilities client sends a different amount of itemsPerSection in every requests. So we need to execute this const maxSection = Math.ceil(transformedData.length / itemsPerSection);

Of course you can write a cleaner code than mine :)

After our first controller created, let's use it.

const { partsController } = require('./controllers');
// ...
app.get('/api/parts', partsController);
app.listen(PORT, () => console.log(`Server is running on port ${PORT}`));
Enter fullscreen mode Exit fullscreen mode

Test. Is it working? If yes, let's jump to another step.

The second controller is to serve the detail of a part. It is more easier than the previous one.

// ...
const partController = async (req, res) => {
  const { params } = req;
  let part = params.part ? +params.part - 1 : 1;
  part = part < 0 ? 0 : part;
  part = part > transformedData.length - 1 ? transformedData.length - 1 : part;
  res.status(200).json({
    status: true,
    message: 'List of parts was successfully fetched',
    data: transformedData[part],
  });
};
module.exports = { partsController, partController };
Enter fullscreen mode Exit fullscreen mode

Then use it in ./index.js.

const { partsController, partController } = require('./controllers');
// ...
app.get('/api/parts/:part', partController);
Enter fullscreen mode Exit fullscreen mode

Test it again. If you successful, our API is already done.

By far, our folder structure looks like this.

/controllers
  - index.js
/data
  - transformed-data.json
/node_modules
  ........
index.js
package.json
Enter fullscreen mode Exit fullscreen mode

Next step, we will deploy this app to Vercel.

GitHub repository
See you!

Top comments (0)