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

Ankur Bawiskar
Tera Patron
Tera Patron

Hi,

please find my points below

APIs are only used to retrieve the data from the instance. It will not download the attachment directly, using API you can get the url of the attachment and when you clicked on the URL it will download the file once you give the credentials.

Otherwise use the binary code returned by the API to convert into the attachment file and download into the system from where this API has been called.

Regards
Ankur

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

Hi Ankur,

Thanks for the response.

From where will i get the binary code ? Do i need to encode the attachment file from sys_attachment table in scripted rest api and return the encoded data back?

Also, in first point how can I retrieve the url of the attachment ? Because when i click on any record in sys_attachment table the file gets auto downloaded.

@Rj27 

just checked the docs but didn't find any such API.

I believe it is not possible to get binary data from attachments in ServiceNow directly.

You can only get a string that represents binary, but not actual binary object.

The scripted rest api approach can be considered: Not tested though

1) the scripted REST API will accept example INC number

2) it would then query sys attachment and get the binary data

3) then send the binary data in the API response

Regards
Ankur

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

Hi Ankur,

Tried this way bit it's not working. Can you let me know if anything needs to be added.

(function process( /*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
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 StringUtil = new GlideStringUtil();
var gsais = GlideSysAttachmentInputStream(attachsysid.toString());
var byteArray = new Packages.java.io.ByteArrayOutputStream();
gsais.writeTo(byteArray );
var byteArray1= new Packages.java.io.ByteArrayOutputStream();
var base64EncodedData = StringUtil.base64Encode(byteArray1.toByteArray());
return base64EncodedData;
// writer.writeStream(base64EncodedData);

 

}
}

})(request, response);