Find your people. Pick a challenge. Ship something real. The CreatorCon Hackathon is coming to the Community Pavilion for one epic night. Every skill level, every role welcome. Join us on May 5th and learn more here.

Script for a Scripted REST API to create REQ and corresponing RITMs from external systems/agents

ankitbeura
Tera Contributor
This isn't a question instead it's a code suggestion for all those developer who're looking for a agent to do their job of  creation of a REQ/RITM.
 
This Scripted REST API accepts a POST JSON body, reads which catalog item to submit, uses CartJS to submit it, creates REQ + RITM(s), then returns them back in the API response.
 

Script:

(function process( /** @type {RESTAPIRequest} */ request, /** @type {RESTAPIResponse} */ response) {
    try {
        // --- Parse JSON body safely ---
        var bodyStr = request.body ? request.body.dataString : '';
        var data = bodyStr ? new global.JSON().decode(bodyStr) : (request.body && request.body.data) || {};

        // --- Inputs ---
        var itemSysId = (data.item_sys_id || '').trim();
        var itemName = (data.item_name || '').trim();
        var quantity = (data.quantity != null ? String(data.quantity) : '1');
        var variables = data.variables || {};
        var requestedFor = (data.sysparm_requested_for || '').trim(); // sys_user.sys_id (optional)

        if (!itemSysId && !itemName)
            throw new sn_ws_err.BadRequestError('Provide either item_sys_id or item_name');

        if (variables && typeof variables !== 'object')
            throw new sn_ws_err.BadRequestError('variables must be a JSON object keyed by variable names');

        // --- Resolve catalog item sys_id if only name provided ---
        if (!itemSysId && itemName) {
            itemSysId = resolveItemSysIdByName(itemName);
        }

        // --- Build CartJS request map ---
        // CartJS is the recommended server-side API for Service Catalog automation. [1](https://www.servicenow.com/docs/r/api-reference/server-api-reference/c_CartJSScoped.html)
        var cart = new sn_sc.CartJS('cart_' + gs.generateGUID());
        var reqMap = {
            sysparm_id: itemSysId,
            sysparm_quantity: quantity,
            variables: variables
        };
        if (requestedFor) reqMap.sysparm_requested_for = requestedFor;

        // --- Add to cart, then submit the order ---
        cart.addToCart(reqMap); // put the item in the cart
        var submitInfo = cart.submitOrder(reqMap); // submit creates REQ and RITM(s)

        // CartJS submit/checkout typically returns request info (number/id),
        // not the list of RITMs, so we query sc_req_item by the request. [2](https://www.servicenow.com/community/developer-forum/return-the-new-ritm-number-after-cartjs-checkoutcart/m-p/2774955)
        var reqNumber = (submitInfo && (submitInfo.request_number || submitInfo.number)) || '';
        var reqSysId = (submitInfo && submitInfo.request_id) || '';

        var items = [];
        if (reqSysId || reqNumber) {
            var grReq = new GlideRecord('sc_request');
            if (reqSysId) grReq.addQuery('sys_id', reqSysId);
            else grReq.addQuery('number', reqNumber);
            grReq.query();
            if (grReq.next()) {
                var grRitm = new GlideRecord('sc_req_item');
                grRitm.addQuery('request', grReq.getUniqueValue());
                grRitm.orderBy('sys_created_on');
                grRitm.query();
                while (grRitm.next()) {
                    items.push({
                        number: grRitm.getValue('number'),
                        sys_id: grRitm.getUniqueValue(),
                        cat_item: grRitm.getValue('cat_item'),
                        state: grRitm.getValue('state'),
                        stage: grRitm.getValue('stage')
                    });
                }
            }
        }

        // --- Respond ---
        response.setStatus(201);
        return {
            status: 'success',
            request: {
                number: reqNumber,
                sys_id: reqSysId
            },
            items: items
        };

    } catch (e) {
        // Bubble up framework errors; wrap others
        if (e instanceof sn_ws_err.ServiceError) throw e;
        var se = new sn_ws_err.InternalServerError(e.message);
        se.setDetail(e.stack);
        throw se;
    }

    // --- Helper(s) ---
    function resolveItemSysIdByName(name) {
        var gi = new GlideRecord('sc_cat_item');
        gi.addActiveQuery();
        gi.addQuery('name', name);
        gi.query();

        var count = 0,
            sysId = '';
        while (gi.next()) {
            count++;
            sysId = gi.getUniqueValue();
        }
        if (count === 0)
            throw new sn_ws_err.NotFoundError('Catalog item not found: ' + name);
        if (count > 1)
            throw new sn_ws_err.ConflictError('Multiple catalog items named "' + name + '". Use item_sys_id instead.');
        return sysId;
    }
})(request, response);

 

POST URL: https://Your Instance.service-now.com/Resource Path

 

Resource Path:Once ya Scripted REST API is created you could customize your resource path accordingly.

 

Authentication: In this acse I have used api key based authentication, You could go for O-Auth or Basic Auth

 

DEMO request body:

{
"item_sys_id": "SYS_ID of Catalog Item",
"item_name": "CATALOG ITEM NAME(OPTIONAL)",
"quantity": 1,
"sysparm_requested_for": "SYS_ID of requested_for",
"variables": {

"request_type":"create",
"select_action_create":"part_creation",
"requested_for":"6c6a9d5287bcea1066eceb573cbb356a"
}
}

 

Demo Response body:

{
    "result": {
        "status": "success",
        "request": {
            "number": "REQ0489327",
            "sys_id": "c0bc2313876b725066eceb573cbb35d2"
        },
        "items": [
            {
                "number": "RITM0433243",
                "sys_id": "0cbc2313876b725066eceb573cbb35d2",
                "cat_item": "0f67f042c3d13e10526d798dc0013190",
                "state": "1",
                "stage": "request_approved"
            }
        ]
    }
}

 #ServiceCatalog #ScriptedRESTAPI

1 REPLY 1

lauri457
Tera Sage

We have the service catalog api already, why not use it? The oob api does user criteria checks etc. You can even view the resources on-platform.

Service Catalog API | ServiceNow Developers

 

How much of this is is ai generated and can you explain what this catch does?

    } catch (e) {
        // Bubble up framework errors; wrap others
        if (e instanceof sn_ws_err.ServiceError) throw e;
        var se = new sn_ws_err.InternalServerError(e.message);
        se.setDetail(e.stack);
        throw se;
    }

You are manually throwing errors inside your try block and then doing this. Kind of defeats the purpose

 

InternalServerError does not even seem to be a valid error class