Creating Records (incidents, tasks, etc. ) by external system through an API

Ben Lageson
Tera Contributor

Another team in my company has the need to create records in ServiceNow.  We have done some analysis and decided that a Scripted RestAPI is the correct implementation for this need so that we can do through validation on required fields on the creation of this record.  

 

One consideration that we are struggling with is if we should allow an API user to the be the user that is the creator of the record, or if as part of the payload we ask the user that the API user is working on behalf of. 

 

What does ServiceNow suggest in this situation? Is there a best practice for this? 

1 ACCEPTED SOLUTION

Ankur Bawiskar
Tera Patron
Tera Patron

@Ben Lageson 

whenever you use Scripted REST API you will use GlideRecord to update/create

if you use GlideRecord then ACLs won't be evaluated on that table

if you use GlideRecordSecure then ACLs will be evaluated on that table

If this is integration between 2 systems then better let the record be created with that API user

In this way within the instance you can track how many records got created via API.

If my response helped please mark it correct and close the thread so that it benefits future readers.

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

View solution in original post

3 REPLIES 3

Ankur Bawiskar
Tera Patron
Tera Patron

@Ben Lageson 

whenever you use Scripted REST API you will use GlideRecord to update/create

if you use GlideRecord then ACLs won't be evaluated on that table

if you use GlideRecordSecure then ACLs will be evaluated on that table

If this is integration between 2 systems then better let the record be created with that API user

In this way within the instance you can track how many records got created via API.

If my response helped please mark it correct and close the thread so that it benefits future readers.

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

tej_gill
Tera Contributor

Hello @Ankur Bawiskar ,

 

We are implementing Scripted REST APIs as well, but I am not able to successfully update the record using GlideRecordSecure. I am able to update the same record using standard GlideRecord api. However, when I test my logic in a background script as an admin, I don't have an issue updating using GlideRecordSecure. Is there something I may have missed to understand? Please see my sample code below:

 

Scripted REST API Resource (Please see comments in the code below)

(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {

 	var sysID = request.pathParams.sysID;
	if (!sysID) {
		response.setError(new sn_ws_err.BadRequestError('sysID not provided'));
		response.setStatus(400);
		return;
	}

	var requestBody = request.body.data;
	var state = requestBody.state;
	var closeCode = requestBody.closeCode;
	var closeNotes = requestBody.closeNotes;
	var workNotes = requestBody.workNotes;

	if (!state && !closeCode && !closeNotes && !workNotes) {
		response.setError(new sn_ws_err.BadRequestError('Object contains no or invalid properties'));
		response.setStatus(400);
		return;
	}

	// Query the incident table with the provided sysID
	var incidentTable = 'incident';
	var incidentGr = new GlideRecordSecure(incidentTable);
	incidentGr.addQuery('sys_id', sysID);
	incidentGr.addQuery('active', true);
	incidentGr.query(); 

	// Generate a 404 if no record is found.
	if (!incidentGr.hasNext()) {
		response.setError(new sn_ws_err.NotFoundError('No record found.'));
		response.setStatus(404);
		return;
	}

      // Had to write this logic to catch errors in the event user is not able to update due to ACL
      // Can't seem to find a way to return a custom error message when update fails due to ACL.
	if (!incidentGr.canWrite()) {
		var forbiddenError = new sn_ws_err.ServiceError();
		forbiddenError.setStatus(403);
		forbiddenError.setMessage('Access Denied!');
		forbiddenError.setDetail('The server could not process the request.');
		response.setError(forbiddenError);
		return;
	}

	if (incidentGr.next()) {
		if (state) {incidentGr.state = parseInt(state);}
		if (closeCode) {incidentGr.close_code = closeCode;}
		if (closeNotes) {incidentGr.close_notes = closeNotes;}
		if (workNotes) {incidentGr.work_notes = workNotes;}
		incidentGr.update();  
 
               // the record does not show any updates, but the below response is seen when testing from Postman.
		var responseObj = {
			"sysID": incidentGr.getUniqueValue(),
			"number": incidentGr.getValue('number'),
			"message": "Record successfully updated."
		};
		
		response.setStatus(200);

		response.setBody(responseObj );
	} 

})(request, response);

 

Sample Call from Postman (see attached screenshot)

tej_gill_0-1755287933711.png

 

Please advise if you spot anything wrong with my logic.

 

Thank you

It's not what you asked about,but I have found I get odd results when doing this:

 

response.setBody(responseObj);

If I send back a property with a value of 100 for example, I get "100.0", whci creates havoc if the calling code was expecting an int. So I do this instead:

response.getStreamWriter().writeString(JSON.stringify(responseObj));