The Zurich release has arrived! Interested in new features and functionalities? Click here for more

Download file using REST API

Rj27
Mega Guru

Hi All,

I need to download files attached to any incident using REST API.

I will be sending incident detail from my postman. 

Already Referred to attachment api reference docs but could'nt find a solution.

NOTE: I don't have the option to use ui action 

Is this doable?

Thanks in Advance!

1 ACCEPTED SOLUTION

I'm executing python script from the command line.

I may be missing some steps below but the general way to install python is as follows.

1. Install python

https://phoenixnap.com/kb/how-to-install-python-3-windows

2. Create subdirectory

mkdir servicenowapis

3. Move to the subdirectory

cd servicenowapis

4. Create a virtualenv

python-m venv venv

5. Activate venv

venv\Scripts\activate.bat

6. Install request module

pip install requests

7. Copy the script I've provided to the directory

8. Copy and paste content of Constants.py over import statements

9. Edit username, password

9. Edit table_api.py to use Incident number

e.g.

get_file_attachment('INC0000002')

10. Execute command

python test_api.py

 

import requests

SERVICENOW_URL = 'https://<instance>.service-now.com'
SERVICENOW_USER = '<username>'
SERVICENOW_PWD = '<password>'

DOWNLOAD_DIR = './downloads/'

REQUEST_HEADER = {"json": {"Content-Type": "application/xml", "Accept": "application/json"},
                  "png": {"Content-Type": "application/xml", "Accept": "application/png"},
                  "xml": {"Content-Type": "application/xml", "Accept": "application/xml"},
                  }

ATTACHMENT_API = '/api/now/attachment'
TABLE_API = '/api/now/table'
# TABLE_NAME = 'kb_knowledge'
TABLE_NAME = 'incident'


def get_table_data(table_name, param):
    url = SERVICENOW_URL + TABLE_API + '/' + table_name + '?' + param
    response = requests.get(url, auth=(SERVICENOW_USER, SERVICENOW_PWD), headers=REQUEST_HEADER.get('json'))
    if response.status_code != 200:  # if error, then exit
        print('Status:', response.status_code, 'Headers:', response.headers, 'Error Response:', response.json())
        exit()
    return response.json()


def get_attachment_info(sys_id):
    url = SERVICENOW_URL + ATTACHMENT_API + '/' + sys_id
    response = requests.get(url, auth=(SERVICENOW_USER, SERVICENOW_PWD), headers=REQUEST_HEADER.get('json'))
    if response.status_code != 200:  # if error, then exit
        print(f'Status:  {response.status_code}, Headers:{response.headers}')
        exit()
    return response.json()


def get_attachment(att_sys_id, file_type, download_dir):
    url = SERVICENOW_URL + '/' + ATTACHMENT_API + '/' + att_sys_id + '/file'
    response = requests.get(url, auth=(SERVICENOW_USER, SERVICENOW_PWD), headers=REQUEST_HEADER.get(file_type))
    if response.status_code != 200:  # if error, then exit
        print('Status:', response.status_code, 'Headers:', response.headers, 'Error Response:', response.json())
        exit()
    with open(download_dir, 'wb') as f:
        for chunk in response:
            f.write(chunk)


def get_file_attachment(record_number):
    param = 'sysparm_query=number=' + record_number + '&sysparam_limit=1'

    file_info = get_table_data(TABLE_NAME, param).get('result')
    if len(file_info) < 1:
        print(f'There is no attachment to sys_id:{record_number}')
        return
    attachment_sys_id = file_info[0].get('sys_id')

    param = 'sysparm_query=table_sys_id=' + attachment_sys_id + '&sysparam_limit=1'
    kb_attachments = get_table_data('sys_attachment', param)
    result = kb_attachments.get('result')
    for attach_file in result:
        attach_sys_id = attach_file.get('sys_id')
        content_type = attach_file.get('content_type').split('/')
        file_ext = content_type[1]
        file_name = attach_file.get('file_name')
        get_attachment(attach_sys_id, file_ext, DOWNLOAD_DIR + file_name)


if __name__ == '__main__':
    # get_file_attachment('KB0010062')  # knowledge base number
    get_file_attachment('INC0000002')

View solution in original post

26 REPLIES 26

Hi,

So you are trying to send the base64Encoded data to the 3rd party once they consume the endpoint and they will send RITM number.

if yes then please check below

For scoped app use this to get base64data

updated script below

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

	// implement resource here

	var arr = [];

	var queryParams = request.queryParams;
	var queryRITM = queryParams.number;

	var gr = new GlideRecord('sc_req_item');
	gr.addQuery('number', queryRITM);
	gr.query();
	while (gr.next()) {

		var ga = new GlideRecord('sys_attachment');
		ga.addQuery('table_sys_id', gr.sys_id);
		ga.query();
		while (ga.next()) {
			var attachsysid = ga.sys_id;
			var filename = ga.file_name;

			var attachmentRec = new GlideRecord('sys_attachment');
			attachmentRec.get(attachsysid);
			var sysAtt = new GlideSysAttachment();
			var base64Data = sysAtt.getContentBase64(attachmentRec);

			var obj = {};
			obj["filename"] = filename;
			obj["attachmentBase64Data"] = base64Data;
			arr.push(obj);
		}
	}

	response.setStatus(200);
	response.setBody(obj);

})(request, response);

your sample json output would look like this

{
  "result": [
    {
      "filename": "sample file.txt",
      "attachmentBase64Data": "base64DataForThisFile"
    },
    {
      "filename": "sample file.docx",
      "attachmentBase64Data": "base64DataForThisFile"
    }
  ]
}

Regards
Ankur

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

Hi Ankur,

The json is just returning me the file name.

My requirement is to download the attached file.


I tried  below script but when i click send and download from postman, file is downloaded with name 'response' and not in the correct format. I am asked to select the format in which i want to open the downloaded response.
Also, if there are multiple attachments, then only one file is downloaded.

SCRIPT::

var queryParams = request.queryParams;
var queryRITM = queryParams.number;

var gr = new GlideRecord('sc_req_item');
gr.addQuery('number', queryRITM);
gr.query();
while (gr.next()) {

var ga = new GlideRecord('sys_attachment');
ga.addQuery('table_sys_id', gr.sys_id);
ga.query();
while (ga.next()) {
var obj = {};
var attachsysid = ga.sys_id;
var filename = ga.file_name;

obj['Content-Type'] = "'" + ga.content_type + "'";
response.setStatus(200);
response.setHeaders(obj);
var writer = response.getStreamWriter();
var attachmentStream = new GlideSysAttachmentInputStream(attachsysid);
writer.writeStream(attachmentStream);

Hi,

I believe as per your script it would download only one.

Usually the attachments are transferred in base64Encoded format when integrated with other 3rd party applications.

Regards
Ankur

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

@Rj27 

Hope you are doing good.

Did you get a chance to check on the comments?

If your query is resolved please mark appropriate response as correct & helpful so that this thread can be closed and others can be benefited by this.

Regards
Ankur

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

Hitoshi Ozawa
Giga Sage
Giga Sage

I haven't done this yet but there's a attachment api with a get method. There's also a curl and python samples. It's going to be necessary to get the sys_ids before calling this API. Will test it out tomorrow during lunch hours. 🙂

https://developer.servicenow.com/dev.do#!/reference/api/orlando/rest/c_AttachmentAPI#r_AttachmentAPI...