npm package: @jsstudio/development-api-interceptor
Description: development-api-interceptor
Author: Srijan Technologies Pvt Ltd
Latest version: 1.0.1

# Development API Interceptor

Software is an agile process where waiting for an actual API endpoint to be develop is not an option, So Development API Interceptor package creates a mock RESTful API backend without having to create an actual HTTP server, it also generates an IndexedDB database in the browser from the provided JSON representation which in turn helps to speed up the development process.

## Getting Started

The below instructions will help you in installing the package into the Client application. See **Usage** for notes on how to use the basic functionalities of the package.

### Installation and Setup

### **Step 1**

Create a db-v1.json file based on the below JSON Schema and JSON Representation Example.

### **JSON Schema**

```javascript
{
    "database": "[Database Name]",
    "tables": [
        {
            "table_name": "[Table name]",
            "columns": [
                {
                    "entity_name": "[Column name]",
                    "type": "[string, integer, boolean, date, json, float, decimal]",
                    "constraints": {
                        "PRIMARY_KEY": boolean, //One column must be a primary key
                        "AUTO_INCREMENT": boolean, //Only primary key column must have auto increment key
                        MAX_LENGTH: [NUMBER],
                        NOT_NULL: [BOOLEAN],
                    }
                },
            ],
            "relationships": [
                {
                   "associated_table": "[Related table name]",
                   "associated_column": "[Related table primary column]",
                   "foreign_key_column": "[Foreign key column]"
                }
             ]
        }
}
```

#### **JSON Representation Example**

```javascript
{
    "database": "db-v1",
    "tables": [
        {
            "table_name": "employees",
            "columns": [
                {
                    "entity_name": "id",
                    "type": "integer",
                    "constraints": {
                        "NOT_NULL": false,
                        "PRIMARY_KEY": true,
                        "AUTO_INCREMENT": true

                    }
                },
                {
                    "entity_name": "name",
                    "type": "string",
                    "constraints": {
                        "MAX_LENGTH": 5,
                        "NOT_NULL": true
                    }
                },
                {
                    "entity_name": "designation",
                    "type": "string",
                    "constraints": {
                        "MAX_LENGTH": 20,
                        "NOT_NULL": true
                    },
                {
                    "entity_name": "details",
                    "type": "json",
                },
                {
                    "entity_name": "project_id",
                    "type": "integer",
                    "constraints": {
                       "NOT_NULL": true,
                       "FOREIGN_KEY": true
                    }
                 }
            ],
            "relationships": [
                {
                   "associated_table": "projects",
                   "associated_column": "id",
                   "foreign_key_column": "project_id"
                }
             ]
        },
        {
            "table_name": "projects",
            "columns": [
                {
                    "entity_name": "project_name",
                    "type": "string",
                    "constraints": {
                        "MAX_LENGTH": 32,
                        "NOT_NULL": true
                    }
                },
                {
                    "entity_name": "id",
                    "type": "integer",
                    "constraints": {
                        "NOT_NULL": true,
                        "PRIMARY_KEY": true,
                        "AUTO_INCREMENT":true
                    }
                }
            ]
        }

    ]
}

```

### **Note:**

* Each table must have a primary key. If there is no PRIMARY_KEY and AUTO_INCREMENT column, the user would get an error - 'Primary key is not present in schema' on subsequent interceptor operations.
* The primary key constraint NOT_NULL must be true if auto_increment is false.
* The auto_increment can be only set to true for the column that is a primary key and is of type number else auto Increment feature would not work.
* The primary key constraint NOT_NULL can be false if auto_increment is true.
* Type in foreign key must be equal to the type of column it is referring to.
* If the type of entity is an json, it won't require any constraints.
* If the schema is to be changed in the future, it must be accompanied by a change in database key. For eg.- If there is any change in employees table in the future, then the database name needs to be changed in the JSON and it could be "database": "db-v2".

### **Step 2**

#### **Installation**

Run the following command in your project's root directory

```js
npm install @jsstudio/development-api-interceptor --save-dev
```

### **Usage**

### **Angular application**

#### **Step 1**. Execute the init command of the Mock Service Worker CLI in the root of angular app

```js
npx msw init ./src
```

**Note**: Add newly created file path to the assets of the angular.json file

#### **Step 2**. Place the created json schema file in src folder

#### **Step 3**. Usage example(Place the below code inside app.module.ts)

```js
import MockApi from '@jsstudio/development-api-interceptor'
import json from '../schema.json';
const mockApi = new MockApi(json);
mockApi.initialize()
```

### **React application(CRA)**

#### **Step 1**. Execute the init command of the Mock Service Worker CLI in the root of react app

```js
npx msw init ./public
```

#### **Step 2**. Place the created json schema file in src folder of react app

#### **Step 3**. Usage example (Place the below code inside App.js)

```js
import MockApi from '@jsstudio/development-api-interceptor'
import json from '../schema.json';
const mockApi = new MockApi(json);
 mockApi.initialize()
```

### **Vue application**

Similar steps as react application can be followed for vue app.

**Output :**
Below indexedDB database will be created using example json representation.

<img src="assets/images/Database_image.png" raw=true alt="Database Image" width="400px"/>

### **Routes**

Once you start the application after completion of above steps, package will expose the following set of api endpoints.

```js
GET    /api/{tableName}
GET    /api/{tableName}/{id}
POST   /api/{tableName}
PUT    /api/{tableName}/{id}
DELETE /api/{tableName}/{id}
```

### **Usage(React/Vue application)**

#### **Using Axios**

```js
// get all request
const response = await axios.get('/api/employees');
console.log(response.data);
//{data: Array(3), message: "Data fetched successfully", status: 200, success: true}
```

```js
// get by id request
const response = await axios.get('/api/employees/1');
console.log(response.data)
//{data: {id:1...}, message: "Data fetched successfully", status: 200, success: true}
 ```

 ```js
// post request
const response = await axios.post('/api/employees', { name: 'John Doe', designation: 'Software Developer' })
console.log(response.data)
//{data: 1, message: "Data created successfully", status: 200, success: true}
```

#### **Note: In case of AUTO_INCREMENT false, pass primary key in request body.**

```js
// post request
const response = await axios.post('/api/employees', { id:1, name: 'John Doe', designation: 'Software Developer' })
console.log(response.data)
//{data: 1, message: "Data created successfully", status: 200, success: true}
```

```js
// put request
const response = await axios.post('/api/employees/1', { name: 'Elvis', designation: 'Software Developer' })
console.log(response.data)
//{data: 1, message: "Data updated successfully", status: 200, success: true}
```

#### **Using Fetch**

**Always pass the config while using fetch api. Below is the sample code.**

```js
// get all request
 const getOptions = {
      method: 'GET',
      headers: { 'Content-Type': 'application/json' },
  };
  const result = await fetch('/api/employees', getOptions)
  const data = await result.json()
  //{data: Array(3), message: "Data fetched successfully", status: 200, success: true}
```

```js
// get by id request
 const getOptions = {
      method: 'GET',
      headers: { 'Content-Type': 'application/json' },
  };
  const result = await fetch('/api/employees/1', getOptions)
  const data = await result.json()
  //{data: {id:1...}, message: "Data fetched successfully", status: 200, success: true}
```

```js
// post request
const postOptions = {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(
      { name:'Mohit', details: { mobile: 1231231, dob: '01-01-1970', project :true }, designation: 'dev' }
    )
};
var response = await fetch('/api/employees', postOptions);
var data = await response.json();
//{data: 1, message: "Data created successfully", status: 200, success: true}
```

#### **Note: In case of AUTO_INCREMENT false, pass primary key in request body**

```js
// put request
const postOptions = {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(
      { name:'Alex', details: { mobile: 1231231, dob: '01-01-1970', project :true }, designation: 'dev' }
    )
};
var response = await fetch('/api/employees/1', postOptions);
var data = await response.json();
//{data: 1, message: "Data updated successfully", status: 200, success: true}
```

### **Usage(Angular application)**

 ```js
// get request
 const response = this.http.get(`api/employees/1`);
 ```

 ```js
 // get all request
 const response = this.http.put(`api/employees`);
 ```

```js
// post request
 const body = {
      name: 'Alex',
      details: JSON.stringify({
        mobile: 12312312,
        dob: 10/10/1991,
        project: 'internal'
      }),
      designation: 'developer'
    };
  const response = this.http.post('api/employees', body);
 ```

#### **Note: In case of AUTO_INCREMENT false, pass primary key in request body**

 ```js
 // put
  const body = {
      name: 'Elvis',
      details: JSON.stringify({
        mobile: 12312312,
        dob: 10/10/1991,
        project: 'internal'
      }),
      designation: 'developer'
    };
 const response = this.http.put(`api/employees/1`);
 ```

### **Package Import Suggestion**

Since it is a dev package, you can create ```src/config/environment/development.js``` and paste the below code  in that file and import it in the entry point file of your app.

```js
import MockApi from '@jsstudio/development-api-interceptor'
import json from '../schema.json';
const mockApi = new MockApi(json);
 mockApi.initialize()
```

## Features

* Creating mock api endpoints without actually creating a HTTP server.
* Generating version based indexedDB database.
* Intercepting API request using service worker.
* Performing RESTful API functions using browser IndexedDB.

## Technologies Used

* **Languages** : Typescript
* **Database**: IndexedDB
* **Client** : React, Vue, Angular
* **Validation Library**: Ajv
* **Logger Library** : Logger
* **Interceptor Library** : MSW(Mock Service Worker)
* **Unit Test Cases** : Mocha and Chai

## Author

👤 **srijanone**

* Website: <http://www.srijan.net>
* Github: [@srijanone](https://github.com/srijanone)

## Show your support

Give a ⭐️ if this project helped you!

## License

(c) Copyright JSSTUDIO Inc. 2020