Data Source Switching

By default in oeCloud.io, all data of models resides in common database (mostly ‘db’). oeCloud.io ensures that tenant doesn’t see each other’s data. However as a oeCloud.io developer, you can specifiy if tenant wants separate database for tenant’s one ore more models. In this docuement we will learn how ‘Product’ models

In this example, we will demonstrate

  • how ‘Product’ model’s data for icici tenant goes to ‘icicidb’ while that of citi goes to ‘citidb’ data source
  • how Product model’s data for both the tenants can be shared in same data base.

What you will build

  • You will create two data sources
  • You will map data source to tenant for a model
  • You will post and retrieve data by activing as different tenant.
  • You will verify data and ensure that data is not mixed

What you’ll need

  • You should have Node and NPM installed.
  • mod headers extension installed on google chrome.You can get it here

How to start with this guide

You can start from scratch and complete each step, or you can bypass basic setup steps that are already familiar to you.

To start from the scratch go to Getting Started

Getting Started ( Seperate data source for a model for seperate Tenant )

In this example, you will see that Product model’s data will be stored in icicidb when user is from icici tenant while Product model’s data will be stored in citidb when user is from citi tenant. Model’s data will be stored in default database when user is from tenant other than icici and citi.

1. Prepare data

Product Model

  • We will be using given model comes up with application which is Product model.

Product Model

{
    "name": "Product",
    "base": "BaseEntity",
    "strict": false,
    "plural": "Products",
    "idInjection": true,
    "options": {
        "validateUpsert": true
    },
    "properties": {
        "code": {
            "type": "string",
            "source": "code",
            "required": true
        },
        "name": {
            "type": "string",
            "source": "name",
            "required": true
        },
        "category": {
            "type": "string",
            "source": "category"
        }
        ... other properties
    }
    ...
}

Tenants and Users

  • By default, user’s tenant information is taken from logged in user.
  • Once application is started, login to application with user name/password as admin/admin.
  • Create two tenants. One is icici and other is citi.

Switch Tenant

  • This is functionality only accessible to super user(ie admin user). With this functionality, admin user can behaves like tenant user of specific tenant.

Creating Tenant User

Please refer to (Multitenancy)[/guide/multitenancy] for more details

  • In swagger UI explorer (or any other method), POST /BaseUsers/switch-tenant and set tenantId to icici while posting.
  • Create icici user.
  • Post following data to BaseUser model to create icici user.

Icici user creation

{
"username":"iciciuser",
"password":"icici",
"email":"iciciuser@icici.com"
}
  • In swagger UI explorer (or any other method), POST /BaseUsers/switch-tenant and set tenantId to citi while posting.
  • Create citi user.
  • Post following data to BaseUser model to create citi user.

citi user creation

{
"username":"citiuser",
"password":"citi",
"email":"citiuser@citi.com"
}
  • Now we will create two data sources. icicidb and citidb. icicidb will store product’s model data for ‘icici’ tenant while citidb will store that of ‘citi’ tenant.
  • Let us first create two data sources. icicidb and citidb.
  • To do that, you need to post following data one by one to DataSourceDefinition model. DataSourceDefinition model will automatically create loopback data source when record is posted to that model. It may happen that only admin user will have such privileges for such operation.
  • Login as admin user. IMPORTANT

DataSourceDefinition Data to post for icicidb using swagger UI (POST /api/DataSourceDefinitions)

{
    "name": "icicidb",
    "connector": "evmongodb",
    "host": "127.0.0.1",
    "port": 27017,
    "url": "mongodb://127.0.0.1:27017/icicidb",
    "database": "icicidb",
    "user": "admin",
    "password": "admin",
    "connectionTimeout": 50000
  }

DataSourceDefinition Data to post for citidb

{
    "name": "citidb",
    "connector": "evmongodb",
    "host": "127.0.0.1",
    "port": 27017,
    "url": "mongodb://127.0.0.1:27017/citidb",
    "database": "citidb",
    "user": "admin",
    "password": "admin",
    "connectionTimeout": 50000
  }
  • Ensure that both responses are 200 OK.
  • Now you want to map these data sources for tenant. To do that, you need to post mapping data to a model called DataSourceMapping. This model maintains the map between model and data source with scope. Scope field contains tenant information in this case. But it can also contains any context information (tenant is one of it) like user, device, location, role etc.
  • login as iciciuser and post following data to DataSourceMapping. This will create mapping between icicidb and Product model - for icici tenant.

DataSourceMapping data for icici (POST /api/DataSourceMappings)

{
    "modelName": "Product",
    "dataSourceName": "icicidb"
}
  • login as citiuser and post following data to DataSourceMapping. This will create mapping between citidb and Product model - for citi tenant.

DataSourceMapping data for citi (POST /api/DataSourceMappings)

{
    "modelName": "Product",
    "dataSourceName": "citidb"
}
  • Both above entries tells us that, when model is Product and operation is being carried out by icici tenant, always use icicidb as database. While in case of citi, use citidb as database.

2. DataSource switching in action

  • Now since data is papared, we will post data to Product table as icici tenant and then citi tenant.
  • login as icici user Or Set tenant_id to icici in request header of your browser. Please open this guide in new tab.
  • Post following data to Product model using swagger
{
    "code": "M001",
    "name": "Samsung Galaxy S7",
    "category": "Mobiles",
    "price": 46000,
    "offeredSince": "2016-05-01",
    "active": true,
    "description": "Samsung Galaxy S7 Android mobile phone by ICICI",
    "id" : 1   
}
  • Using swagger, locate ‘Product’ model and perform Get Operation while tenant_id is still set to icici.
  • You should able to see following data. Note the description where phone by ICICI is present.
{
    "code": "M001",
    "name": "Samsung Galaxy S7",
    "category": "Mobiles",
    "price": 46000,
    "offeredSince": "2016-05-01",
    "active": true,
    "description": "Samsung Galaxy S7 Android mobile phone by ICICI",
    "id" : 1   
}
  • login as citi user OR Change tenant_id to citi in browser request header. Please open this guide in new tab.
  • Using swagger, locate ‘Product’ model and perform Get Operation while tenant_id is set to citi. You should not able to see any data.
  • Post following data to Product model using swagger while tenant_id is set to ‘citi’.
{
    "code": "M002",
    "name": "Samsung Galaxy S8",
    "category": "Mobiles",
    "price": 47000,
    "offeredSince": "2016-06-01",
    "active": true,
    "description": "Samsung Galaxy S8 Android mobile phone by CITI",
    "id" : 2
}
  • Perform ‘Get’ operation on product model again. You should see same data you just posted for citi. You will not see data posted when tenant_id was ICICI.
{
    "code": "M002",
    "name": "Samsung Galaxy S8",
    "category": "Mobiles",
    "price": 47000,
    "offeredSince": "2016-06-01",
    "active": true,
    "description": "Samsung Galaxy S8 Android mobile phone by CITI",
    "id" : 2
}
  • Switch back to icici user by login as icici user.
  • Perform Get Operation on Product model and you will see data you posted when tenant_id was set to icici. you will NOT see data of citi product

Getting Started ( Same database for a model for seperate Tenant )

1. Prepare data

  • Continuing from above step, stop the application, delete Data Source mapping (DataSourceMapping) entries you have created and start application again. OR
  • You can start from scratch.
  • If you choose above option, you need to create two users on for icici and one for citi tenant as described in previous section.
  • Assume that two users(one for icici and other for citi) are created and application is running.
  • Create Data source by posting following data to DataSourceDefinition as admin user.
{
    "name": "common_product_db",
    "connector": "evmongodb",
    "host": "127.0.0.1",
    "port": 27017,
    "url": "mongodb://127.0.0.1:27017/common_product_db",
    "database": "common_product_db",
    "user": "admin",
    "password": "admin",
    "connectionTimeout": 50000
  }
  • Now you want to map these data sources for tenant. To do that, you need to post mapping data to a model called DataSourceMapping.
  • login as iciciuser and post following data to DataSourceMapping. This will create mapping between common_product_db and Product model - for icici tenant.

DataSourceMapping data for icici

{
    "modelName": "Product",
    "dataSourceName": "common_product_db"
}
  • login as citiuser and post following data to DataSourceMapping. This will create mapping between common_product_db and Product model - for citi tenant.

DataSourceMapping data for citi

{
    "modelName": "Product",
    "dataSourceName": "common_product_db"
}

2. Data Source switching in action

  • Both above entries tells us that, when model is Product is used by either icici or citi user, it will always refer to common_product_db database.
  • Now post the Product Data as you did in previous steps login as iciciuser and then citiuser and repeat the process
  • Go back to mongo db and you should see common_product_db data base should be created and it should have product collection.

Summary

  • As tenant is accessing Product model, ev-foundation run time decides which data source to connect based on tenant.
  • This is called data source switching. This is transparent to end user. it happens based on context. Tenant Id is one of context parameter.
  • This context information is stored in DataSourceMapping model. This way, user can choose which data source should be used by which model and for what scope.
  • we also saw how same feature can be used when you want to share database for the model between tenant. Remember while fetching data, tenant doesn’t see each other data regardless of how it is stored.