Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

REST API Custom Error Response

Kiran Patil3
Giga Expert

Hi,

We are trying to add custom response on mandatory variable check-in record producer REST API.

Here is the code for the custom error message:

(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
	
	var recordProducerId = request.pathParams.sys_id;
	var request_body = request.body.nextEntry();
	var noValidation =  (request_body.sysparm_no_validation == 'true');
	
	var catalogUtil = new RestCatalogUtil();
	var isMobile = false;
	
	
	if (request.queryParams.sysparm_view) {
		var viewType = '' + request.queryParams.sysparm_view;
		viewType = viewType.toLowerCase();
		if(viewType == 'mobile')
			isMobile = true;
	}
	
	if(!catalogUtil.isValidItem(recordProducerId, 'sc_cat_item_producer'))
		throw new sn_ws_err.NotFoundError('Record Producer does not exists');
	
	var catalogItem = new sn_sc.CatItem(recordProducerId);
	
	if(!catalogItem.canView(isMobile))
		throw new sn_ws_err.BadRequestError("Security Constraints prevent access to the Item");
	
	var variables = request_body.variables || {};
		
		variables = prePopulateVariables(recordProducerId, variables);
		
		gs.info("Here is the variabbles: " + JSON.stringify(variables));
		
		if (!noValidation) {
			//Mandatory Variables Check
			if(!catalogUtil.checkMandatoryVariables(recordProducerId, variables))
				{
				//	var varInput = [];
				//varInput.push(JSONParser(variables));
				var mandatoryError = new sn_ws_err.ServiceError();
				mandatoryError.setStatus(400);
				mandatoryError.setMessage('Mandatory variables are not filled');
				mandatoryError.setDetail(JSON.stringify(variables));
				throw mandatoryError;
			}
				//throw new sn_ws_err.BadRequestError('One or more mandatory variables are invalid or empty: '+variables);
		}
		
		request_body.sysparm_id = recordProducerId;
		request_body.sysparm_action = 'execute_producer';
		if (!request_body.sysparm_item_guid)
			request_body.sysparm_item_guid = gs.generateGUID('');
		
		return catalogItem.submitProducer(request_body);
		
		
	})(request, response);
	
	
	function prePopulateVariables(itemId, variables) {
		variables = variables || {};
			var varGr = new GlideRecord('item_option_new');
			var qr = varGr.addQuery('cat_item', itemId);
			var variableSet = new sn_sc.CatItem(itemId).getVariableSet();
			if(variableSet.length > 0)
				qr.addOrCondition("variable_set", variableSet);
			varGr.addActiveQuery();
			varGr.query();
			while(varGr.next()) {
				if(varGr.type == 8 && !gs.nil(variables[varGr.getValue('name')])){
					var varValue = variables[varGr.getValue('name')];
					var query = '';
					if(!gs.nil(variables[varGr.getValue('name') + '_lookup_field']))
						{
						query = variables[varGr.getValue('name') + '_lookup_field'] + "=" + varValue;
					} else {
						query = "sys_id=" + varValue;
						query += "^ORuser_name=" + varValue;
						query += "^ORnumber=" + varValue;
						query += "^ORname=" + varValue;
					}
					
					variables[varGr.getValue('name')] = getRecordSysId(varGr.reference, query);
					
				}
				
				if(varGr.type == 21 && !gs.nil(variables[varGr.getValue('name')])){
					var varValue = variables[varGr.getValue('name')];
					var query = '';
					if(!gs.nil(variables[varGr.getValue('name') + '_lookup_field']))
						{
						query = variables[varGr.getValue('name') + '_lookup_field'] + "IN" + varValue;
					} else {
						query = "sys_idIN" + varValue;
						query += "^ORuser_nameIN" + varValue;
						query += "^ORnumberIN" + varValue;
						query += "^ORnameIN" + varValue;
					}
					
					variables[varGr.getValue('name')] = getRecordSysIdList(varGr.list_table, query);
					
				}
			}
			
			return variables;
		}
		
		function getRecordSysId(table_name, encoded_query) {
			gs.info("Here is the encoded_query: " + table_name + ' ' + encoded_query);
			
			var gr = new GlideRecord(table_name);
			gr.addEncodedQuery(encoded_query);
			gr.setLimit(1);
			gr.query();
			
			if(gr.next()){
				return gr.getValue("sys_id");
			}
			else {
				return '';
			}
		}
		
		function getRecordSysIdList(table_name, encoded_query) {
			gs.info("Here is the encoded_query: " + table_name + ' ' + encoded_query);
			
			var sys_id_list = [];
			var gr = new GlideRecord(table_name);
			gr.addEncodedQuery(encoded_query);
			gr.query();
			
			gs.info("Here is the count " + gr.getRowCount());
			
			while(gr.next()){
				
				sys_id_list.push(gr.getValue("sys_id"));
			}
			
			gs.info("Here is the sys_id_list.join(): " + sys_id_list.join());
			
			return sys_id_list.join();
		}
		

Response in postman as follows:

{
    "error": {
        "message": "Mandatory variables are not filled",
        "detail": "{\"username\":\"\",\"disable_account_true\":\"true\",\"justification\":\"Test\",\"opened_by\":\"fdf1dfe71b527fc4d98f3153cd4bwer3\"}"
    },
    "status": "failure"
}

I have added variables back in detail of the response so end-user would know what variables had invalid input or empty value however JSON.stringify would add an extra backslash to response which is annoying. I have tried JSON.parse as well but JSON.parse is not supported in the scoped application, I think.

Please help if anyone has faced a similar kind of issue in the past and fixed it.

Thanks in advance.

~ Kiran

4 REPLIES 4

Tony Chatfield1
Kilo Patron

Hi, I would guess the \ chars are the result of the "char" being escaped;
can you create your object with 'single quotes'

Hi Tony,

Object is return from below (OOB) function

variables = prePopulateVariables(recordProducerId, variables);

this function already returning as JSON object. Not sure how can I stringify JOSN object within another object.

Tony Chatfield1
Kilo Patron
I am not aware of anyway to change the default text identifier. If no one responds with a solution can you run a regex over the string before presenting it to the users?

Yes, regex is my last option 🙂