// opcional
Instalar o NowConnectBridge (opcional)
Só necessário se você quiser usar create_table ou add_column — todas as outras 40 ferramentas funcionam sem instalar nada, usando a API REST padrão do ServiceNow.
Por que isso é necessário
A API REST nativa do ServiceNow não expõe criação de tabela/coluna — é uma limitação da própria plataforma, não uma escolha do NowConnect. Esse script cria um Scripted REST API pequeno e isolado que resolve isso. Ele só cria registros novos, não altera nada existente na sua instância.
Como instalar
- Entra na sua instância ServiceNow como admin
- Vai em System Definition > Scripts - Background
- Cola o script abaixo inteiro
- Clica em Run script
- No log (embaixo), procura a linha "URL BASE REAL desta instancia" — copia o valor logo abaixo dela (algo como
/api/suaempresa/auraconnect_bridge) - Volta no painel NowConnect, edita essa instância, e cola esse valor no campo "URL base do bridge"
Esse valor é diferente pra cada cliente/instância — o ServiceNow gera automaticamente com base no código da sua empresa, por isso não dá pra usar um caminho fixo igual pra todo mundo.
// ══════════════════════════════════════════════════════════════
// NowConnect — Scripted REST API: NowConnectBridge
// Execute como Background Script no ServiceNow (perfil admin)
//
// Cria a API que permite create_table e add_column via NowConnect.
// Endpoints: POST /api/x_1961802_auramcp/auraconnect_bridge/execute
// GET /api/x_1961802_auramcp/auraconnect_bridge/health
//
// SEGURO: só cria registros novos, não mexe em nenhuma configuração existente.
// ══════════════════════════════════════════════════════════════
(function() {
gs.info('=== NowConnect Bridge Setup ===');
var apiGR = new GlideRecord('sys_ws_definition');
apiGR.addQuery('name', 'NowConnectBridge');
apiGR.query();
var apiSysId;
if (apiGR.next()) {
apiSysId = apiGR.getUniqueValue();
gs.info('[NowConnect] API ja existe: ' + apiSysId);
} else {
apiGR.initialize();
apiGR.setValue('name', 'NowConnectBridge');
apiGR.setValue('api_id', 'auraconnect_bridge');
// NAO definimos namespace manualmente -- o ServiceNow atribui isso sozinho
// com base no escopo em que este script roda (Global, por padrao, em Background Scripts).
// Cada instancia tera um namespace diferente (baseado no codigo da empresa), entao
// descobrimos e mostramos o valor real no final, em vez de tentar fixar um so pra todo mundo.
apiGR.setValue('short_description', 'NowConnect Bridge - metadata operations');
apiGR.setValue('active', true);
apiSysId = apiGR.insert();
gs.info('[NowConnect] API criada: ' + apiSysId);
}
var execScript = "(function process(request, response) {\n" +
" var body = request.body.data;\n" +
" var op = body.operation, params = body.params || {}, dryRun = body.dry_run === true;\n" +
" var result = {};\n" +
" gs.info('[AURACONNECT] Op: ' + op + ' DryRun: ' + dryRun);\n" +
" try {\n" +
" if (op == 'inspect_table') {\n" +
" var cols = [], gr = new GlideRecord('sys_dictionary');\n" +
" gr.addQuery('name', params.table_name); gr.addNotNullQuery('element'); gr.query();\n" +
" while (gr.next()) cols.push({element:gr.getValue('element'),label:gr.getValue('column_label'),type:gr.getDisplayValue('internal_type'),max_length:gr.getValue('max_length'),mandatory:gr.getValue('mandatory')=='true',reference:gr.getValue('reference')});\n" +
" var ga = new GlideAggregate(params.table_name); ga.addAggregate('COUNT'); ga.query(); var cnt=0; if(ga.next()) cnt=parseInt(ga.getAggregate('COUNT'));\n" +
" result = {table:params.table_name, columns:cols, column_count:cols.length, record_count:cnt};\n" +
" } else if (op == 'create_table') {\n" +
" if (dryRun) { result = {dry_run:true, would_create:params}; }\n" +
" else {\n" +
" var tgr = new GlideRecord('sys_db_object'); tgr.initialize();\n" +
" tgr.setValue('name', params.name); tgr.setValue('label', params.label);\n" +
" if (params['extends']) { var p=new GlideRecord('sys_db_object'); p.addQuery('name',params['extends']); p.query(); if(p.next()) tgr.setValue('super_class',p.getUniqueValue()); }\n" +
" var tid = tgr.insert();\n" +
" if (!tid) throw new Error('Failed to create table');\n" +
" var cc=[];\n" +
" if (params.columns) for (var i=0;i<params.columns.length;i++) {\n" +
" var c=params.columns[i], d=new GlideRecord('sys_dictionary'); d.initialize();\n" +
" d.setValue('name',params.name); d.setValue('element',c.name); d.setValue('column_label',c.label||c.name);\n" +
" d.setValue('internal_type',c.type); d.setValue('max_length',c.max_length||255);\n" +
" if(c.mandatory) d.setValue('mandatory','true'); if(c.reference) d.setValue('reference',c.reference);\n" +
" cc.push({element:c.name, sys_id:d.insert()});\n" +
" }\n" +
" result = {success:true, table_sys_id:tid, table_name:params.name, columns:cc};\n" +
" }\n" +
" } else if (op == 'add_column') {\n" +
" if (dryRun) { result = {dry_run:true, would_add:params}; }\n" +
" else {\n" +
" var d=new GlideRecord('sys_dictionary'); d.initialize();\n" +
" d.setValue('name',params.table_name); d.setValue('element',params.column_name);\n" +
" d.setValue('column_label',params.label); d.setValue('internal_type',params.column_type);\n" +
" d.setValue('max_length',params.max_length||255);\n" +
" if(params.mandatory) d.setValue('mandatory','true');\n" +
" if(params.reference_table) d.setValue('reference',params.reference_table);\n" +
" var cid=d.insert(); if(!cid) throw new Error('Failed to add column');\n" +
" result = {success:true, table:params.table_name, column:params.column_name, sys_id:cid};\n" +
" }\n" +
" } else {\n" +
" response.setStatus(400); result = {error:'Unknown op: '+op};\n" +
" }\n" +
" } catch(e) { response.setStatus(500); result={error:e.message}; gs.error('[AURACONNECT] '+e.message); }\n" +
" response.setBody(result);\n" +
"})(request, response);";
var execGR = new GlideRecord('sys_ws_operation');
execGR.addQuery('web_service_definition', apiSysId);
execGR.addQuery('name', 'execute');
execGR.query();
if (execGR.next()) {
execGR.setValue('operation_script', execScript);
execGR.update();
gs.info('[NowConnect] /execute atualizado');
} else {
execGR.initialize();
execGR.setValue('web_service_definition', apiSysId);
execGR.setValue('name', 'execute');
execGR.setValue('http_method', 'POST');
execGR.setValue('relative_path', '/execute');
execGR.setValue('active', true);
execGR.setValue('operation_script', execScript);
execGR.insert();
gs.info('[NowConnect] /execute criado');
}
var hGR = new GlideRecord('sys_ws_operation');
hGR.addQuery('web_service_definition', apiSysId);
hGR.addQuery('name', 'health');
hGR.query();
if (!hGR.next()) {
hGR.initialize();
hGR.setValue('web_service_definition', apiSysId);
hGR.setValue('name', 'health');
hGR.setValue('http_method', 'GET');
hGR.setValue('relative_path', '/health');
hGR.setValue('active', true);
hGR.setValue('operation_script',
'(function process(request, response) { response.setBody({status:"ok",server:"NowConnectBridge",version:"1.0"}); })(request, response);');
hGR.insert();
gs.info('[NowConnect] /health criado');
}
// Descobre o namespace REAL que o ServiceNow atribuiu (varia por instancia/empresa,
// nao da pra saber de antemao -- por isso lemos de volta em vez de assumir um valor fixo).
var freshApiGR = new GlideRecord('sys_ws_definition');
freshApiGR.get(apiSysId);
// Le o campo base_uri REAL calculado pelo proprio ServiceNow, em vez de tentar
// reconstruir manualmente -- confirmado que o ServiceNow remove underscore do
// api_id ao montar a URL (auraconnect_bridge virou auraconnectbridge na pratica),
// entao qualquer reconstrucao manual e fragil. base_uri e a fonte da verdade.
var baseUrl = freshApiGR.getValue('base_uri');
if (!baseUrl) {
var realNamespace = freshApiGR.getValue('namespace') || 'DESCONHECIDO';
baseUrl = '/api/' + realNamespace + '/auraconnectbridge';
gs.info('[NowConnect] AVISO: campo base_uri vazio, usando fallback reconstruido.');
}
gs.info('');
gs.info('=== NowConnect Bridge Pronto ===');
gs.info('URL BASE REAL desta instancia (copie isso pro painel NowConnect):');
gs.info(baseUrl);
gs.info('');
gs.info('Endpoints completos:');
gs.info('POST ' + baseUrl + '/execute');
gs.info('GET ' + baseUrl + '/health');
gs.info('');
gs.info('PROXIMO PASSO: cole "' + baseUrl + '" no campo "URL base do bridge" ');
gs.info('ao editar essa instancia no painel NowConnect (nowconnect.com.br/dashboard).');
})();