Skip to content
This page View Markdown Open in ChatGPT Open in Claude

System APIs

Encrypt data

g.sys.system.encrypt calls the encrypt data system API from your code, whatever the settings of that API say about HTTP callers.

Encrypt System API

Get encrypted data using global object 'g'.

let encryptedData = await g.sys.system.encrypt({
    "data": {
        "name": "Bob"
    }
});

Decrypt data

g.sys.system.decrypt calls the decrypt data system API from your code, whatever the settings of that API say about HTTP callers.

Decrypt System API

Get decrypted data using global object 'g'.

let decryptedData = await g.sys.system.decrypt("U2FsdGVkX191c+lmyM80ctf4QV18dZ/x17yDh/fRxs4=");

Hash data

g.sys.system.hash calls the hash data system API from your code, whatever the settings of that API say about HTTP callers.

Hash System API

Get hash of the given data using the global object 'g'.

let hashData = await g.sys.system.hash({ "Name": "Alice" });

Get token

g.sys.system.getToken calls the get token system API from your code, whatever the settings of that API say about HTTP callers.

Get token using global object 'g'.

  • Token of an API Maker API user: no name.
1
2
3
4
await g.sys.system.getToken({
    "u": "USER_NAME",
    "p": "USER_PASSWORD"
});
  • Token of a database user (application user): the name of its token generator.
1
2
3
4
5
await g.sys.system.getToken({
    "name": "TOKEN_GENERATOR_NAME",
    "u": "USER_NAME",
    "p": "PASSWORD"
});
  • Both at once: an array in, an array of tokens out.
1
2
3
4
5
const [apiUser, databaseUser] = await g.sys.system.getToken([
    { "u": "USER_NAME", "p": "USER_PASSWORD" },
    { "name": "TOKEN_GENERATOR_NAME", "u": "USER_NAME", "p": "PASSWORD" }
]);
// apiUser.token goes in x-am-authorization, databaseUser.token in x-am-user-authorization

Execute query

g.sys.system.executeQuery calls the execute plain query system API from your code, whatever the settings of that API say about HTTP callers.

Execute query System API

Execute database query using global object 'g'.

1
2
3
4
5
6
await g.sys.system.executeQuery({
    instance: 'INSTANCE_NAME',
    database: 'DATABASE_NAME',
    collection: 'COLLECTION_NAME',
    query: "select * from DATABASE_NAME.COLLECTION_NAME"
});
  • If the database is Mongodb API Maker supports all the commands listed in below.
  • https://www.mongodb.com/docs/drivers/node/current/usage-examples/command/
  • https://www.mongodb.com/docs/v6.0/reference/command/
1
2
3
4
5
6
7
await g.sys.system.executeQuery({
    instance: 'INSTANCE_NAME',
    database: 'DATABASE_NAME',
    query: {
        dbStats: 1,
    }
});

How we use Native Query in API Maker.

Native query using secret management

  • Set Database constrain in Secret management.

    import * as T from 'types';
    
    let Secret: T.ISecretType | any = {
    // Place your keys here in json format.
        common: <T.ISecretTypeCommon>{
            dbConstrain: {
                instance: 'mysql',
                database: 'inventory',
                collection: ''
            }
        }
    };
    module.exports = Secret;
    

  • Get Database constrain from Secret management.

    1
    2
    3
    4
    let dbConstrain = await g.sys.system.getSecret('common.dbConstrain');
    let instance = dbConstrain.instance || 'mysql';
    let database = dbConstrain.database || 'inventory';
    let collection = dbConstrain.collection || 'employees';
    

  • Create table

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: `${instance}`,
        query: `CREATE TABLE ${database}.${collection}(emp_id int AUTO_INCREMENT PRIMARY KEY);`
    });
    

Various types of Database & It`s Native Query In API Maker

  • MySQL | TiDB | Percona XtraDB

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "SELECT * FROM inventory.employees;"
    });
    

  • MariaDB

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mariadb",
        query: "SELECT * FROM inventory.employees;"
    });
    

  • Microsoft SQL Server

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "sqlserver",
        query: "SELECT * FROM inventory.dbo.employees;"
    });
    

  • MongoDB

    1
    2
    3
    4
    5
    6
    7
    await g.sys.system.executeQuery({
        instance: 'mongodb',
        database: 'inventory',
        query: {
            dbStats: 1,
        }
    });
    

  • PostgreSQL

    await g.sys.system.executeQuery({
        instance: "postgresql",
        query: `drop database if exists e_commerce;`
    });
    
    await g.sys.system.executeQuery({
        instance: "postgresql",
        query: `create database e_commerce;`
    });
    
    await g.sys.system.executeQuery({
        instance: "postgresql",
        database: "e_commerce", // 👈 Need to provide db name
        query: `
    DROP TABLE IF EXISTS "public"."customers";
    CREATE TABLE "public"."customers"
    (
        "customer_id" int2                                       NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 MINVALUE 1 MAXVALUE 32767 START 1 ),
        "first_name"  varchar(45) COLLATE "pg_catalog"."default" NOT NULL,
        "last_name"   varchar(45) COLLATE "pg_catalog"."default" NOT NULL,
        "phone"       int8                                       NOT NULL,
        "last_update" timestamp(6)                               NOT NULL,
        "pincode" int NOT NULL,
        "shipping_id" int NULL,
        CONSTRAINT "customers_pkey" PRIMARY KEY ("customer_id")
    );
    CREATE INDEX "idx_actor_last_name" ON "public"."customers" USING btree ("last_name" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST);
    
    INSERT INTO "public"."customers" ("first_name", "last_name", "phone", "last_update", "pincode", "shipping_id") VALUES ('PENELOPE', 'GUINESS', 123456789, '2006-02-15 04:34:33', 100050, 1);
    INSERT INTO "public"."customers" ("first_name", "last_name", "phone", "last_update", "pincode", "shipping_id") VALUES ('NICK', 'WAHLBERG', 1123456789, '2006-02-15 04:34:33', 111111, 2);
    INSERT INTO "public"."customers" ("first_name", "last_name", "phone", "last_update", "pincode", "shipping_id") VALUES ('ED', 'CHASE', 2123456789, '2006-02-15 04:34:33', 222222, 3);
            `
    });
    

  • Oracle

Please follow these rules when writing a query or statement:

  • Use backticks (`) to enclose your query or statement.
  • Do not add a semicolon (;) at the end of your query.
1
2
3
4
await g.sys.system.executeQuery({
    instance: "oracle",
    query: `SELECT * FROM "INVENTORY"."employees"`
});

DDL Operation in API Maker

  • CREATE TABLE

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "CREATE TABLE inventory.employees(id int AUTO_INCREMENT PRIMARY KEY);"
    })
    

  • ALTER TABLE

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "ALTER TABLE inventory.employees ADD COLUMN emp_name VARCHAR(30) NOT NULL;"
    })
    

  • RENAME TABLE

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "ALTER TABLE inventory.employees RENAME COLUMN id TO emp_id;"
    })
    

  • TRUNCATE TABLE

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "TRUNCATE TABLE inventory.employees;"
    })
    

  • DROP TABLE

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "DROP TABLE IF EXISTS inventory.employees;"
    })
    

DML Operation in API Maker

API Maker allows us to perform various DML operations, such as the following examples.

  • INSERT

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "INSERT into inventory.employees Values(101, 'Bob', 'M');"
    })
    

  • DELETE

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "DELETE FROM inventory.employees WHERE emp_Id = '101';"
    })
    

  • UPDATE

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "UPDATE inventory.employees SET emp_Name = 'Alice' WHERE emp_Id = '101';"
    })
    

DQL Operation in API Maker

API Maker allows us to perform various DQL operations, such as the following examples.

  • SELECT

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "SELECT * FROM inventory.employees;"
    })
    

  • DISTINCT

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "SELECT DISTINCT emp_Name FROM inventory.employees;"
    })
    

  • ORDER BY

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "SELECT * FROM inventory.employees order by emp_Gen,emp_Name;"
    })
    

Aggregated Function in API Maker

API Maker allows us to perform various Aggregated Function, such as the following examples.

  • SUM

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "SELECT SUM(emp_Sal) as Total_Salary FROM inventory.employees;"
    })
    

  • AVG

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "SELECT AVG(emp_Sal) as Average_Salary FROM inventory.employees;"
    })
    

Joins in API Maker

API Maker allows us to perform Joins, such as the following examples.

  • INNER JOIN

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "SELECT * FROM inventory.employees INNER JOIN inventory.attandance ON inventory.employees.emp_Id = inventory.attandance.emp_id;"
    })
    

  • LEFT JOIN

    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "mysql",
        query: "SELECT * FROM inventory.employees LEFT JOIN inventory.attandance ON inventory.employees.emp_Id = inventory.attandance.emp_id;"
    })
    

How to call SQL Server Store Procedure

  • Just replace your procedure name with below "procedureName".
    1
    2
    3
    4
    await g.sys.system.executeQuery({
        instance: "sql_server",
        query: "USE inventory; exec dbo.procedureName;"
    });
    

How to create index in Mongodb

import * as T from 'types';
import * as db from 'db-interfaces';
import * as C from 'iot/Constants';

const createIndexList: IIndexObj[] = [{
    collectionName: "collectionName",
    indexName: 'indexName',
    isUnique: true,
    fields: {
        "category": 1,
        "productName": 1,
    },
}];

async function main(g: T.IAMGlobal) {
    const colMap = {};
    for (const iObj of createIndexList) {
        await dropIndexListOfCollection(g, iObj.collectionName, iObj.indexName);
        await createIndexOnCollection(g, iObj.collectionName, iObj.fields, iObj.indexName, iObj.isUnique);
        colMap[iObj.collectionName] = 1;
    }

    for (const colName in colMap) {
        const indexList = await getIndexListOfCollection(g, C.col.configuration_transactions);
        colMap[colName] = indexList;
    }

    return { hello: 'world', colMap };
};
module.exports = main;


async function getIndexListOfCollection(
    g: T.IAMGlobal,
    collectionName: string,
) {
    const listIndexResp = await g.sys.system.executeQuery({
        instance: C.insDB.instance,
        database: C.insDB.database,
        query: {
            listIndexes: collectionName,
        }
    });

    const indexList = [];
    for (const item of listIndexResp?.cursor?.firstBatch || []) {
        indexList.push(item.name);
    }

    return indexList;
}

async function createIndexOnCollection(
    g: T.IAMGlobal,
    collectionName: string,
    fields: any,
    indexName: string,
    isUnique: boolean,
) {
    const createIndexResp = await g.sys.system.executeQuery({
        instance: C.insDB.instance,
        database: C.insDB.database,
        query: {
            createIndexes: collectionName,
            indexes: [
                {
                    key: fields,
                    name: indexName,
                    unique: isUnique,
                },
            ],
        }
    });

    const indexList = [];
    for (const item of createIndexResp?.cursor?.firstBatch || []) {
        indexList.push(item.name);
    }

    return indexList;
}

async function dropIndexListOfCollection(
    g: T.IAMGlobal,
    collectionName: string,
    indexName: string,
) {
    try {
        const dropResp = await g.sys.system.executeQuery({
            instance: C.insDB.instance,
            database: C.insDB.database,
            query: {
                dropIndexes: collectionName,
                index: indexName,
            }
        });
        return dropResp;
    } catch (e) {
    }
}


interface IIndexObj {
    indexName: string;
    collectionName: string;
    fields: any;
    isUnique: boolean;
}

Multi-tenant

  • instance: "crm::acme" runs the query in the database of the tenant acme of the multi-tenant instance crm.
  • In a custom API called for a tenant, instance: "crm" runs it in the database of that tenant: the x-am-tenant-username header is passed on. Without a tenant, it runs in the structure database.
// The database of acme.
const ordersOfAcme = await g.sys.system.executeQuery({
    instance: 'crm::acme',
    database: 'crm',
    query: "select status, count(*) as orders from orders group by status"
});

// The database of the tenant of the request.
const customers = await g.sys.system.executeQuery({
    instance: 'crm',
    database: 'crm',
    query: "select count(*) as customers from customers"
});

Call external API

g.sys.system.callExternalApi calls the call external API system API from your code, whatever the settings of that API say about HTTP callers.

Call external API using global object 'g'.

Simple call external apis

1
2
3
4
5
6
7
8
9
await g.sys.system.callExternalApi([
    {
        "url": `your_url`,
        "method": "GET",
        "timeout": 5000,
        "queryParams": { "select": "first_name" },
        "headers": { "x-am-authorization": "TOKEN" },
    }
]);

Parallel type

  • If the type is 'parallel' the external APIs are executed in parallel.
await g.sys.system.callExternalApi([
    {
        url: "FULL_URL",
        method: "POST",
        body: [
            {
                first_name: "James",
                last_name: "Bond"
            }
        ],
        id: "saveApi",
        postProcess: [
            {
                from: "saveApi.output.body.data.first_name",
                to: "setApi.body.first_name"
            }
        ],
        queryParams: {
            deep: JSON.stringify([{
                s_key: "SOURCE_COLLECTION_COLUMN_NAME",
                t_key: "TARGET_COLLECTION_COLUMN_NAME",
                t_col: "TARGET_COLLECTION_NAME",
                select: "COLUMN_NAMES"
            }]),
            select: "COLUMN_NAMES",
            limit: 2,
            sort: "COLUMN_NAMES"
        },
        timeout: 1000,
        headers: { "x-am-authorization": "TOKEN" },
    },
    {
        type: 'parallel',
        data: [
            {
                url: "FULL_URL",
                method: 'PUT',
                body: {},
                id: "setApi",
                headers: { "x-am-authorization": "TOKEN" }
            },
            {
                url: "FULL_URL",
                method: 'GET',
                headers: { "x-am-authorization": "TOKEN" }
            }
        ]
    }
]);

Sequential type

  • If the type is 'sequential' the API calls execute one by one.
await g.sys.system.callExternalApi([
    {
        url: "your_url",
        method: "GET",
        timeout: 5000,
        queryParams: { "select": "first_name" },
        headers: { "x-am-meta": true },
        id: "getData",
        output: "any"
    },
    {
        type: "sequential",
        data: [
            {
                url: "your_url",
                method: "POST",
                body: {},
                id: "addData",
                preProcess: [
                    {
                        from: "getData.output.body.data",
                        to: "addData.body"
                    }
                ],
                headers: { "x-am-authorization": "TOKEN", "x-am-response-case": "capitalCase" }
            },
            {
                url: "your_url",
                method: "GET",
                headers: { "x-am-response-case": "capitalCase" }
            }
        ]
    }
]);

Get secret key/keys

g.sys.system.getSecret calls the get secret system API from your code, whatever the settings of that API say about HTTP callers.

Get secret System API

Get secret using global object 'g'.

  • Get only one secret key value.
await g.sys.system.getSecret("common.secret");
  • Get multiple secret keys values.
await g.sys.system.getSecret(["common.secret","common.secret"]);

Get table metadata

g.sys.system.getTableMeta calls the get table meta system API from your code, whatever the settings of that API say about HTTP callers.

Get table metadata System API

Get table metadata using global object 'g'.

1
2
3
4
5
await g.sys.system.getTableMeta({
    instance: 'INSTANCE_NAME',
    database: 'DATABASE_NAME',
    collection: 'COLLECTION_NAME'
});

Multi-tenant

  • instance: "crm::acme" reads the table in the database of the tenant acme of the multi-tenant instance crm. In a custom API called for a tenant, instance: "crm" reads it in the database of that tenant.
1
2
3
4
5
await g.sys.system.getTableMeta({
    instance: 'crm::acme',
    database: 'crm',
    collection: 'customers'
});

Create indexes

g.sys.system.createIndexes calls the create indexes system API from your code, whatever the settings of that API say about HTTP callers.

Create indexes System API

Create indexes using global object 'g'. The same request works on MongoDB, MySQL, MariaDB, SQL Server, PostgreSQL and Oracle ; an index which exists already is left alone (EXISTS), a field the database can not index is SKIPPED with the reason, a refusal of the database is FAILED with its message.

const results = await g.sys.system.createIndexes({
    indexes: [
        {
            instance: 'mysql8',
            database: 'inventory',
            table: 'orders',
            fields: [{ name: 'customer_id' }, { name: 'status', order: 'DESC' }],
        },
        {
            instance: 'mongodb',
            database: 'inventory',
            collection: 'products',
            name: 'ux_products_sku',
            unique: true,
            fields: [{ name: 'sku' }],
        },
    ],
    ifNotExists: true,      // default : nothing is created twice
    continueOnError: true,  // default : one refused index does not stop the others
    skipUnindexable: true,  // default : TEXT, json, CLOB... are skipped before the database is asked
});
// results[0] : { status: 'CREATED', name: 'am_ix_orders_customer_id_status_3f9a1c', fields: ['customer_id', 'status'], ... }
// results[1] : { status: 'EXISTS', message: 'The index "ux_products_sku" exists already.', ... }
  • Without a name, the index is called am_ix_<table>_<fields>_<hash> (am_ixu_ when unique), the same in every environment, cut to the limit of the database (30 characters on Oracle).
  • order : ASC, DESC, HASHED and TEXT (MongoDB) ; nullsFirst: true on PostgreSQL. type : FULLTEXT or SPATIAL (MySQL), CLUSTERED, XML, SPATIAL (SQL Server), hash, gin, gist, spgist, brin (PostgreSQL). method : BTREE, HASH, RTREE (MySQL).
  • This is the call the migration script am_index_maker of Index Maker makes on deploy : a migration script of your own can do the same.

Multi-tenant

  • instance: "crm::acme" creates the index in the database of the tenant acme of the multi-tenant instance crm. In a custom API called for a tenant, instance: "crm" creates it in the database of that tenant.
1
2
3
await g.sys.system.createIndexes({
    indexes: [{ instance: 'crm::acme', database: 'crm', collection: 'customers', fields: [{ name: 'email' }], unique: true }],
});

Drop indexes

g.sys.system.dropIndexes calls the drop indexes system API from your code, whatever the settings of that API say about HTTP callers.

Drop indexes System API

Drop indexes of a table by name using global object 'g'. A name the table does not have is NOT_FOUND, not an error, so the call can run again.

const results = await g.sys.system.dropIndexes({
    instance: 'mysql8',
    database: 'inventory',
    table: 'orders',
    indexes: ['am_ix_orders_customer_id_status_3f9a1c', 'old_idx_status'],
    ifExists: true,         // default : a missing index is NOT_FOUND
    continueOnError: true,  // default : one refused drop does not stop the others
});
// results[0] : { status: 'DROPPED', fields: ['customer_id', 'status'], ... }
// results[1] : { status: 'NOT_FOUND', message: 'The index "old_idx_status" does not exist.', ... }
  • Several tables at once : give a list of such objects, the results come back in one flat list.
  • instance: "crm::acme" drops in the database of the tenant acme of the multi-tenant instance crm.

Get indexes

g.sys.system.getIndexes calls the get indexes system API from your code, whatever the settings of that API say about HTTP callers.

Get indexes System API

List the indexes of a table using global object 'g', in the same format for every database.

1
2
3
4
5
6
7
8
9
const indexes = await g.sys.system.getIndexes({
    instance: 'mysql8',
    database: 'inventory',
    table: 'orders',
});
// [
//     { name: 'PRIMARY', key: { id: 1 }, unique: true },
//     { name: 'am_ix_orders_customer_id_status_3f9a1c', key: { customer_id: 1, status: -1 }, unique: false, method: 'BTREE' },
// ]
  • key holds the fields in order with their direction : 1 ascending, -1 descending, hashed or text on MongoDB.
  • Several tables at once : give a list of such objects, the answer is a list of lists in the same order.
  • instance: "crm::acme" reads the table in the database of the tenant acme of the multi-tenant instance crm.

Emit event

g.sys.system.emitEvent calls the emit event system API from your code, whatever the settings of that API say about HTTP callers.

Emit event System API

Emit event using global object 'g'.

await g.sys.system.emitEvent("EVENT_NAME", "EVENT_DATA", ["LISTENERS_NAME"]);

Emit event websocket

g.sys.system.emitEventWS calls the emit WebSocket event system API from your code, whatever the settings of that API say about HTTP callers.

Emit event web-socket System API

Emit event of websocket using global object 'g'.

await g.sys.system.emitEventWS("EVENT_NAME", "EVENT_DATA");
1
2
3
4
await g.sys.system.emitEventWS(
    "myEvent", 
    { "name": "Bob" }
);

Is valid data for table/collection

g.sys.system.isValidDataForTable calls the is valid data for table system API from your code, whatever the settings of that API say about HTTP callers.

Validate table data

Test data valid or not using global object 'g'.

1
2
3
4
5
6
7
await g.sys.system.isValidDataForTable({
    instance: "INSTANCE_NAME", database: 'DB_NAME', collection: "COLLECTION_NAME",
    data: {
        "field": "fieldValue",
        "field": "fieldValue"
    }
});
await g.sys.system.isValidDataForTable({
    instance: "mongoDB",
    database: "db_inventory",
    collection: "tbl_customers",
    data: {
        "customer_id": 1,
        "first_name": "Bob",
        "last_name": "Lin",
        "last_update": "2006-02-14T23:04:33.000Z",
        "pincode": 382330,
        "isActive": 1
    }
});

Is valid data for custom API

g.sys.system.isValidDataForCustomAPI calls the is valid data for custom API system API from your code, whatever the settings of that API say about HTTP callers.

Validate custom API body object

Test custom API data valid or not using global object 'g'.

1
2
3
4
5
6
7
8
await g.sys.system.isValidDataForCustomAPI({
    name: "custom_api_name",
    data: {
        "some": "data",
        "some": "data"
    },
    type: "BODY" // BODY | QUERY_PARAMS
});

Is valid data for third party API

g.sys.system.isValidDataForThirdPartyAPI calls the is valid data for third party API system API from your code, whatever the settings of that API say about HTTP callers.

Validate third party request body

Test the data is valid for Third party API, using global object 'g'.

await g.sys.system.isValidDataForThirdPartyAPI({
    apiBundleName: "bundle_name",
    apiVersionName: "api_version",
    name: "api_name",
    type: "BODY", // BODY | QUERY_PARAMS
    data: {
        name: 'hello'
    },
    isArray: false
});

Multi tenant instance updated

g.sys.system.multiTenantInstanceUpdated calls the multi tenant instance updated system API from your code, whatever the settings of that API say about HTTP callers.

Multi tenant instance updated System API

After the connection string of a tenant of a multi-tenant instance changed in the tenants table, tell API Maker. Every server drops the connection pools of that tenant, and the next request of the tenant connects with the new connection string.

await g.sys.system.multiTenantInstanceUpdated({ instanceName: 'crm', username: 'acme' });

Several instances or tenants at once, each item answered on its own:

1
2
3
4
5
const output = await g.sys.system.multiTenantInstanceUpdated([
    { instanceName: 'crm', username: 'acme' },
    { instanceName: 'billing', username: 'acme' },
]);
// [{ success: true, data: true }, { success: false, data: false, error: { code: 404, message: "..." } }]