Build a REST API of History of Conflicts Using Express.js
Tags: javascript, api, tutorial, express
Published: 2022-03-07 09:54:40

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](https://www.kaggle.com/ramjasmaurya/conflicts-among-nations)). 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](https://github.com/estotriramdani/history-of-conflicts-backend/blob/main/data/transformed-data.json). 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](https://history-of-conflicts.estotriramdani.com/). 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.

```terminal
mkdir history-of-conflicts-backend
cd history-of-conflicts-backend
npm init -y
npm i express cors dotenv --save
npm i nodemon --save-dev
```
In package.json, edit the scripts.
```json
"scripts": {
   "dev": "nodemon index.js",
   "start": "node index.js"
 },
```
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.
```javascript
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}`));
```
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
```  

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. 

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

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.
```javascript
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 };
```

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.
```javascript
const { partsController } = require('./controllers');
// ...
app.get('/api/parts', partsController);
app.listen(PORT, () => console.log(`Server is running on port ${PORT}`));
```
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. 
```javascript
// ...
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 };
```
Then use it in ./index.js.
```javascript
const { partsController, partController } = require('./controllers');
// ...
app.get('/api/parts/:part', partController);
```

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
```

Next step, we will deploy this app to Vercel.

_[GitHub repository](https://github.com/estotriramdani/history-of-conflicts-backend)_
See you!