# JavaScript CRUD REST API using Node.js, Express, HarperDB, Docker

Prerequisites:
- Docker installed on the machine
- Node.js and npm installed on the machine
- A tool to test APIs (like Postman)
- HarperDB Studio Account (free)

You can create a free HarperDB Studio Account here: https://studio.harperdb.io/sign-up 

CRUD is simply an acronym used to refer to four basic operations that can be performed on database applications: 

- Create
- Read
- Update
- Delete

___
In this article, we will set CRUD API using:

- Node.js (JavaScript Runtime Engine)
- Express
- HarperDB
- Docker


### NODE.js

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1610518922566/jNlJ0QU14.png)

Node.js is a back-end JavaScript runtime environment, which means briefly that can execute JavaScript code on a computer, for example, yours or the one where Node.js is installed. The good thing is that, by having Docker, you DON't actually need to install it, because we will use the Node.js image, and so we can also avoid versioning between my version of Node.js installed on my machine and yours 

### EXPRESS

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621543171688/L6oouQ0lj.png)

Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.

### HarperDB

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621543249800/0OIpkQ-lE.png)

HarperDB is a full-featured data management platform that runs from edge to cloud, and anywhere in between.

You can create a free account here https://studio.harperdb.io/sign-up 

The good news is that you don't need to pay to test it, but I suggest you try it out if you need more resources


### DOCKER

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1610521677853/SGKWuYsvU.png)

Docker is a platform to build run and share applications using the idea of containers. If you want a brief introduction, here is a short video

[![IMAGE ALT TEXT HERE](https://cdn.hashnode.com/res/hashnode/image/upload/v1610522007247/lu2KkUl9j.png)](https://www.youtube.com/watch?v=eN_O4zd4D9o)
# STEP by Step guide


## HarperDB

HarperDB is a scalable database that's improving app performance and development with solutions like Hybrid Cloud, using a single endpoint!

Its' SQL & NoSQL in one powerful tool, enabling SQL queries on JSON data

It uses a very Intuitive REST API

It removes the need for an ORM by returning the results as JSON arrays

First of all, we need to create our FREE instance of HarperDB, using HarperDB Studio.

It has a simple UI which makes everything easy

Click on "Create new HarperDB Cloud Instance"

![harper1.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621921393309/l72nvqkqH.png)

And then on the Create HarperDB Cloud Instance on the left.


![harper2.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621921583593/Nja-ds42v.png)

Add username, password, and a name for this instance

![harper3.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621921646659/AQzSzWnZr.png)

Leave the default FREE values and change Region if you want

![harper4.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621921697879/WC70EqGR0.png)


Agree with privacy policy and Terms of Service and finally on "Add Instance"

![harper5.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621921775096/Mx-rgiaZL.png)

wait a couple of minutes while your instance is created...


![harper6.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621921864073/uppWDBTMo.png)


![harper7.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621921898044/iG4X4iv_e.png)

When you see "ok", the instance has been created! Nice!


![harper8.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621921930089/xmseKnTSD.png)

Now click on the instance and let's create a schema and a basic table:

First of all the schema **test**

![harper9.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621922012385/mPKxptSg8.png)

And then a table **users** we will use with our application. 
Please note that we don't need to add all the value of the columns here, they will be added automatically when needed!


![harper10.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621922099355/efyW9T2FZ.png)


![harper10b.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621922624988/LSs9ltVmh.png)

## Step by Step guide to create our Node.js Application

0) Create a folder named harperdb-docker and enter into it

```
mkdir harperdb-docker && cd harperdb-docker
```

1) Initialize Node.js application using npm

```bash
npm init -y
```

2) Install the dependencies: express and harperive

Harperive is what we need in order to connect our Node.js application to the HarperDB instance

```bash
npm i express harperive
```

3) Create Structure

```bash
mkdir app && cd app
```

```bash
mkdir controllers
```

```bash
mkdir routes
```

```bash
mkdir util
```

4) Then create an index.js file

```javascript
const express = require('express');

//INITIALIZE APP WITH EXPRESS
const app = express();
app.use(express.json());

//Set proper Headers on Backend
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  next();
});

//ROUTES
app.use('/dev', require('./routes/dev.routes.js'));
app.use('/users', require('./routes/users.routes.js')); //users crud

app.listen(process.env.PORT, () => {
  console.log(`Example app listening at http://localhost:${process.env.PORT}`);
});
```

5) Inside the util folder, let's create the connection for HarperDB, by creating a database.js file

```javascript
const harperive = require('harperive');

const config = {
  harperHost: process.env.INSTANCE_URL,
  username: process.env.INSTANCE_USERNAME,
  password: process.env.INSTANCE_PASSWORD,
  schema: process.env.INSTANCE_SCHEMA,
};

const Client = harperive.Client;
const db = new Client(config);

module.exports = db;
```

6) Create a dev.routes.js file inside routes

This contains just a test endpoint to check if the application is working

```javascript
const controller = require('../controllers/dev.controllers');
const router = require('express').Router();

router.get('/version', controller.getVersion);

module.exports = router;
```


7) Create a users.routes.js file inside routes

It will contain the routes and the references to 5 endpoints, 

```javascript
const controller = require('../controllers/' + 'users' + '.controllers');
const router = require('express').Router();

//CRUD Model-Agnostic.
//Keep them at the end of the route file for url parsing requests
router
  .get('/', controller.getAll)
  .get('/:id', controller.getOne)
  .post('/', controller.createOne)
  .put('/:id', controller.updateOne)
  .delete('/:id', controller.deleteOne);

module.exports = router;
```

At this point, your structure should look like this:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1622798891038/cXDHsZ4FT.png)

### Controllers

8) The dev.controllers.js file inside controllers' folder. This will be used just to test that our application works, even if we have some problems connecting our backend application to the db instance.

```javascript
// [GET] ../dev/version
exports.getVersion = (req, res, next) => {
  return res.status(200).json({ 'HarperDB tutorial version': '1.0.0' });
};
```

9) The users.controllers.js file, located in the controllers folder.

It contains five main methods:

- createOne: To create a new user
- getAll: To Get all the users and return them in an array
- getOne: To get a specific user, by providing id
- updateOne: To update an existing user, providing new values and the id of the user to modify
- deleteUser: to delete an existing user by providing the id

```javascript
const client = require('../util/database');

/**
 * CRUD CONTROLLERS
 */
const SCHEMA = process.env.INSTANCE_SCHEMA;
const TABLE = 'users';

//CREATE-ONE
exports.createOne = async (req, res, next) => {
  console.log('createOne: [POST] /users/');
  try {
    const user = await client.insert({
      table: TABLE,
      records: [
        {
          username: req.body.username,
          password: req.body.password,
          followers: req.body.followers,
        },
      ],
    });
    res.json(user);
  } catch (error) {
    res.json(error);
  }
};

//GET-ALL
exports.getAll = async (req, res, next) => {
  console.log('getAll: [GET] /users/');
  
  try {
    const QUERY = `SELECT * FROM ${SCHEMA}.${TABLE}`
    const users = await client.query(QUERY);
    res.json(users);
  } catch (error) {
    console.log('ERROR in getAll ' + 'USER:', error);
    return res.status(500).json(error);
  }
};

//GET-ONE
exports.getOne = async (req, res, next) => {
  console.log('getOne: [GET] /users/:id');
  
  try {
    const QUERY = `SELECT * FROM ${SCHEMA}.${TABLE} WHERE id="${req.params.id}"`;
    const user = await client.query(QUERY);
    res.json(user);
  } catch (error) {
    console.log('ERROR in getAll ' + 'USER:', error);
    return res.status(500).json(error);
  }
};

//UPDATE-ONE.
exports.updateOne = async (req, res, next) => {
  console.log('updateOne: [PUT] /users/:id');

  try {
    const modUser = await client.update({
      table: TABLE,
      records: [
        {
          id: req.params.id,
          username: req.body.username,
          password: req.body.password,
          followers: req.body.followers,
        },
      ],
    });

    res.json(modUser);
  } catch (error) {
    res.status(500).json(error);
  }
};

//DELETE-ONE
exports.deleteOne = async (req, res, next) => {
  console.log('deleteOne: [DELETE] /users/:id');

  try {
    const QUERY = `DELETE FROM ${SCHEMA}.${TABLE} WHERE id="${req.params.id}"`;
    const deleteUser = await client.query(QUERY);
    res.json(deleteUser);
  } catch (error) {
    res.status(500).json(error);
  }
};
```

That's it! Now we are ready to create a Docker image, based on the application we have just created

___
# DOCKER

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1610519742765/3YdQTSrfX.png)

Now the Docker Part!

In the main folder, create 3 files:

- Dockerfile
- docker-compose.yml
- .dockerignore (it starts with a dot)

the .dockerignore file:

```dockerignore
.git
node_modules
npm-debug.log
```

the Dockerfile:

```bash
FROM node:14

EXPOSE 3000

WORKDIR /src

COPY package*.json ./

RUN npm install

COPY . . 

CMD ["node", "app/index.js"]
```

The docker-compose.yml file:

```yml
version: "3.8"

services: 
  app:
    container_name: hdb_backend
    image: francescoxx/hdb-example:0.0.1
    build:
      context: .
    ports:
      - "3000:3000"
    env_file: 
      .env
```

replace the image "francescoxx/hdb-example:0.0.1" with an image name of your choice (example: mydockerhubuser/harperdb-example:1.0.0)

let's also create the .env file


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621926088330/iiXt0iiGb.png)

To retrieve the instance information you need in order to populate the .env file, visit Harper Studio and click on Config on the top right of the instance

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621922290837/Khd0xd9-I.png)

Then you will see the information you need for your instance

![harper11.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621922358601/Aiviq-9aZ.png)

Please note that a ".env-example" file is attached to the repository for convenience

Set the <PORT> value to 3000.  

```bash
# Replace with your values
INSTANCE_URL=<YOUR_INSTANCE_URL>
INSTANCE_USERNAME=<USERNAME>
INSTANCE_PASSWORD=<PASSWORD>
INSTANCE_SCHEMA=<SCHEMA>
PORT=3000
```
let's build the backend image

On the Terminal, type
```bash
docker-compose build
```

Run the backend service with 

```
docker-compose up
```

___
# POSTMAN / HarperDB UI

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1610520716792/GJbRXRnQT.png)

We will use Postman, but you can use a whenever tool you want


First of all, let's see if the service is up and running, by hitting the http://localhost:3000/dev/version endpoint with a get request:


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621924333782/osGgJekxp.png)

If we get this response, we can start creating our users on our HarperDB cloud instance

Let's start Creating some users using Postman, and sending our data in json format:

This will be a 'POST' Request, and data should be sent in raw json format, as showed in the picture below


![harper12.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621922403243/ccnra1AMV.png)

 
![Harper13.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621922412235/7ccdR5GTb.png)


![harper14.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621922417460/8zMAY1Xfq-.png)

We can check all the users using Postman

![harper15.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621922491501/LqwhSrlFz.png)

But the cool thing is that you can either check the db directly from HarperDB Studio!
I like this feature!

![harper16.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621922499281/IGgCYvzMA.png)

To check a single user, you can make a get request using the id of the user as a query parameter at the end of the URL


![harper17.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621922584199/mgWnfMGT3.png)

To modify an existing user, you can make a PUT request, using the id of the user in the query parameter, and the values you want to update

![harper18.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621922646282/t3uU6K35W.png)


You can check the users in a more convenient way from the HarperDB UI

![harper19.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621923190464/Wt0jXsfsf.png)

Finally, let's delete the user Francesco, with a DELETE request and adding the id as a query parameter at the end of the URL


![harper20.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621923285818/xE74TYAme.png)

As you can see, the user Francesco is no more there

![harper21.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1621923296615/rK-q-QYU0.png)

### Conclusion

This example is to show how simple is to get started using HarperDB cloud instance, monitor the DB entries. The UI can also be used to add/remove/delete values

To create a free HarperDB account, visit: https://studio.harperdb.io/sign-up 

GitHub repository link:
https://github.com/FrancescoXX/harperdb-crud-api
