// 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

  1. Entra na sua instância ServiceNow como admin
  2. Vai em System Definition > Scripts - Background
  3. Cola o script abaixo inteiro
  4. Clica em Run script
  5. No log (embaixo), procura a linha "URL BASE REAL desta instancia" — copia o valor logo abaixo dela (algo como /api/suaempresa/auraconnect_bridge)
  6. 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).');
})();

← Voltar pra documentação