"Processors", SRAPIs, and How to Run a Script and Redirect a User From a URL in ServiceNow

Processors in ServiceNow are (were) actually extremely useful things, though they’re surprisingly not very well-known. They give you a URL you can hit (like my_processor.do) and allow you to run a server-side script, then redirect the user to some other page.

Processors are quite useful for situations like generating a record and then redirecting the user to that record just by navigating to one URL, or - by adding some URL parameters (like my_processor.do?some_param=some_value) automating some simple or complex processes with nothing more than a single click of a URL! You can generate that URL dynamically and present it in the UI somewhere (for example, by using gs.addInfoMessage()), or link to the processor in an email. You could even use something like my “Set Catalog Variables from URL Parameters” tool in conjunction with this functionality to dynamically populate and submit RITMs from a single click of a link in a Knowledge Article!

Some pre-existing useful processors are:

  • System cache flush (cache.do)

  • Attachment processor for constructing and viewing attachments (sys_attachment.do)

  • Content search (content_search.do)

  • Customer service chat (CustomerServiceChat.do)

  • Export Wizard (export_wizard.do)

While it’s possible to modify the ACLs on the Processor table to allow you to create them again (for now), that may not be the best idea for long-term support.

So, if we don’t use a processor, how can we accomplish this functionality in our app? The answer is Scripted REST APIs (SRAPIs) plus a little bit of http header magic!

In this article, we’re going to show you how to accomplish (mostly) the same functionality as a processor using an SRAPI, and provide some code you can use to get your pseudo-processor SRAPI up-and-running within minutes! We’ll also provide some best-practice advice for how to use SRAPIs in this way, and outline some specific use-cases for this sort of thing.


There are a few very specific (and in my opinion, unnecessarily arcane) things you’ll need to do to emulate the functionality of Processors via SRAPI, but I’ve wrapped those up in a function that you can copy-and-paste into your own SRAPI code to accomplish this goal. Specifically, that’s the redirectTo() function in the below code:

(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
    
    var redirectLink, incidentShortDesc;
    var grIncident = new GlideRecord('incident');
    var instanceURL = gs.getProperty('glide.servlet.uri', '');
    
    /*
        If the request includes the URI parameter "inc_short_desc", get its value.
        This will be used to set the generated Incident's Short Description.
        If the request doesn't include that param, then just use "Test Incident" as the default.
     */
    incidentShortDesc = request.queryParams.inc_short_desc.toString() || 'Test Incident';
    
    //!!!WARNING!!!
    //If the user is not logged in, DON'T DO ANYTHING. Just return. Don't even generate the INC.
    //Unauthenticated tomfoolery may result if these aren't the first functional lines of code.
    if (!gs.isLoggedIn()) {
        redirectLink = instanceURL + 'nav_to.do?uri=login.do';
        gs.addErrorMessage('Please login and try your request again.');
        //Redirect the user to the login page.
        redirectTo(response, redirectLink);
        return;
    }
    
    grIncident.initialize();
    grIncident.setValue('caller_id', gs.getUserID());
    grIncident.setValue('state', '1'); //1 = "New"
    grIncident.setValue('short_description', incidentShortDesc);
    //...
    grIncident.insert();
    
    redirectLink = instanceURL + 'nav_to.do?uri=' + grIncident.getLink(true);
    gs.addInfoMessage('A new Incident has been generated. You have been redirected to the new Incident record. ');
    redirectTo(response, redirectLink);
    
    /**
     * Set redirect headers necessary to redirect the user to the provided URL.
     * The "response" object will be modified in-place, so returning it is not necessary.
     * DO NOT CALL THIS FUNCTION WITHOUT VERIFYING THAT THE USER IS AUTHENTICATED FIRST,
     *  UNLESS YOU WANT THE USER TO BE REDIRECTED TO THE TARGET REGARDLESS OF AUTHENTICATION.
     * @param  response - The RESTAPIResponse object from the SRAPI to use for
     *  the redirect. The response object will be modified in-place.
     * Docs: https://developer.servicenow.com/dev.do#!/reference/api/orlando/server/sn_ws-namespace/c_RESTAPIResponse?navFilter=rest
     * @param  redirectURL - Must be full URL including http(s)://
     * @example
     redirectTo(response, (gs.getProperty('glide.servlet.uri', '') + 'incident.do?sysparm_query=caller_id=' + gs.getUserID()));
     */
    function redirectTo(response, redirectURL) {
        response.setHeader(
            "Cache-Control",
            "no-cache,no-store,must-revalidate,max-age=-1"
        );
        response.setHeader(
            "Pragma",
            "no-store,no-cache"
        );
        //This doesn't really matter, but the redirect may sometimes fail without this header.
        response.setHeader(
            "Expires",
            "Thu, 01 Jan 1970 00:00:00"
        );
        response.setStatus(301); //301 = Redirect
        response.setLocation(redirectURL);
        
        return true;
    }
    
})(request, response);

There are a few very important things to note about this approach, which I’ll list below. Please do not attempt this in your instance without carefully reading the below points!

  1. The SRAPI method should be GET.

  2. Requires authentication should be set to false.
    Unless you want unauthenticated users to be able to trigger your SRAPI script to run as often as they want (very risky), you must be sure to include gs.isLoggedIn() as a condition for your script running, before it does anything important!
    See my comments and conditional return on lines 14 - 23 in the code above, which prevent unauthenticated users from using this pseudo-processor.

    1. I have not yet found a better way of doing this, which is a little disappointing since Processors just handled it for you (including the redirect after the login). If I come up with anything more friendly, I’ll update this article.
      If you have any ideas, please reply in the comments and you’ll be credited for the suggestion if it works!

  3. The redirect URL (the second argument to the redirectTo() function) must be a full URL, including http(s) or another resource/protocol identifier.

Once you’re done, your SRAPI method should look something like this:

One last tip I’ll mention, is this: In the example above, I’ve actually generated a new record, and then redirected a user to it. However, if you aren’t making any changes to the instance or potentially revealing any sensitive data, you don’t need to worry about whether the user is authenticated or not. In fact, if the thing you’re doing is just generating a template, it may actually be preferable to pre-populate a “new record” form without saving it to the database.
If this is the case, then redirecting the user to that form with URL parameters to pre-populate the fields you want pre-populated can be done without authentication, because the instance itself will determine if the user is authenticated before showing them the form. If they’re not authenticated, it’ll ask them to log in and then bounce them back to the pre-populated form after they’re authenticated!

Redirecting a user to a pre-populated dynamic “new record” form also eliminates the problem of unauthenticated users, because no actual changes are being made to the instance! Instead, for that specific use-case, if you’re okay just redirecting the user to the “new record” form, with the important values pre-populated but not yet saved to the database, you can do so by using the sysparm_query URL parameter!

For example:
https://your_instance.service-now.com/nav_to.do?uri=incident.do?sysparm_query=category=inquiry

Pro-tip: Although you can redirect an unauthenticated user to a new record form that’s pre-populated - if the user is not authenticated, code like gs.getUserID() won’t work as expected. However, you can often get around this by including something like javascript:gs.getUserID() in the URL!
Example: incident.do?sysparm_query=caller_id=javascript:gs.getUserID()
Just be sure to do something like the following to let the user know that they need to click the button to create the record:
gs.addInfoMessage(‘This Incident has been pre-populated. Please be sure to click Submit after filling out any additional details, to save the Incident!’);

That’s about all there is to it!
If you have questions or comments, please let me know in the Comments section below.
If you found this article helpful, chances are someone else will, too! Share what you’ve learned with your network by sending them a link to this article. 😁

This post was inspired by some advice from JarodM from the SNDevs community. Thanks, Jarod!


If you’re looking for help with your ServiceNow implementation, backlog killing, or SN development/architecture staff augmentation, The SN Guys can help! Reach out and schedule a call with us to see what we can do for you.