I can attach a file using Postman but cannot figure out how to do it in Python. Below is a barebones script demonstrating a good response reading the record, followed by a bad response attempting to add an attachment. I'm getting a 415 response (Unsupported Media Type). Any assistance would be greatly appreciated!
$ python -V
Python 3.8.5
$ pip show requests |grep -e ^Name -e ^Version
Name: requests
Version: 2.26.0
$ python sysaid_test.py <my-account-name> 1168503
*** output ***
Get record type and status
--------------------------
url: https://*******.sysaidit.com/api/v1/sr?fields=sr_type,status&ids=1168503
session headers: {'Cookie': 'JSESSIONID=7A2B901424AB9ECF1C17DFCE4BC11FA1.inst05us-autoscaleapp-002187', 'Content-Type': 'application/json'}
prepared headers: {'Cookie': 'JSESSIONID=7A2B901424AB9ECF1C17DFCE4BC11FA1.inst05us-autoscaleapp-002187', 'Content-Type': 'application/json'}
status_code: 200
text...
('/{"id":"1168503","canUpdate":true,"canDelete":false,"canArchive":false,"hasChildren":false,"info":,{"key":"sr_type","value":10,"valueClass":"","valueCaption":"Request","keyCaption":"Service '
'Record Type"},{"key":"status","value":57,"valueClass":0,"valueCaption":"Work '
'in Progress","keyCaption":"Status"}]}]')
Attach file to request
----------------------
filepath: /tmp/sysaid_attachment.xlsx
filename: sysaid_attachment.xlsx
url: https://*******.sysaidit.com/api/v1/sr/1168503/attachment
session headers: {'Cookie': 'JSESSIONID=7A2B901424AB9ECF1C17DFCE4BC11FA1.inst05us-autoscaleapp-002187', 'Content-Type': 'application/json'}
prepped headers: {'Cookie': 'JSESSIONID=7A2B901424AB9ECF1C17DFCE4BC11FA1.inst05us-autoscaleapp-002187', 'Content-Type': 'application/json', 'Content-Length': '8813'}
body (1st 200 characters): b'--13913b69799838b597498be9bcb74aba\r\nContent-Disposition: form-data; name="file"; filename="sysaid_attachment.xlsx"\r\nContent-Type: application/json\r\n\r\nPK\x03\x04\x14\x00\x00\x00\x08\x00\xecm\xb6V\xe4\xc5\x13\xbd\x82\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00docProps/app.xmlM\x8eM\x0b'
body (last 200 characters): b'lPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\xedm\xb6V\xa1-6u\xaf\x00\x00\x00\xfb\x01\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01.\x1d\x00\x00xl/_rels/workbook.xml.relsPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\xedm\xb6V\xf6\x8b\xb9 \x15\x01\x00\x00\xd7\x03\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x15\x1e\x00\x00eContent_Types].xmlPK\x05\x06\x00\x00\x00\x00\t\x00\t\x00>\x02\x00\x002\x1f\x00\x00\x00\x00\r\n--13913b69799838b597498be9bcb74aba--\r\n'
status_code: 415
response headers: {'x-frame-options': 'SAMEORIGIN', 'x-content-type-options': 'nosniff', 'x-xss-protection': '1; mode=block', 'cache-control': 'no-cache', 'last-modified': 'Wed, 31 May 2023 19:07:10 GMT', 'content-type': 'text/html;charset=utf-8', 'content-language': 'en', 'content-length': '457', 'date': 'Wed, 31 May 2023 19:07:11 GMT', 'strict-transport-security': 'max-age=63072000; includeSubDomains;', 'set-cookie': 'SERVERID=inst05us-autoscale-app13|ZHea4|ZHea4; path=/'}
history: <!doctype html><html lang="en"><head><title>HTTP Status 415 – Unsupported Media Type</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 415 – Unsupported Media Type</h1></body></html>
*** code ***
#!/usr/bin/python
# tested in python3.8
# requires requests package: https://pypi.org/project/requests/
# assumes a valid JSESSIONID is stored in cookiepath - no login routine included here
# set filepath to your attachment
# invoke with account name and record id
# Requests @ PyPI: https://pypi.org/project/requests/
# Documentation: https://requests.readthedocs.io/en/latest/
import sys
import requests
from pprint import pprint, pformat
cookiepath='/tmp/jsessionid'
filepath = "/tmp/sysaid_attachment.xlsx"
def get_headers():
try:
#with open('/tmp/sysaid/%s/state/jsessionid' %account, 'r') as fd:
with open(cookiepath, 'r') as fd:
lines = fd.readlines()
fd.close()
except FileNotFoundError:
print("File not found")
return {}
else:
h = { 'Cookie': lines<0].strip(), 'Content-Type': 'application/json' }
return h
### CHECK ARGS ###
if len(sys.argv) != 3:
sys.exit('Usage: sysaid_test.py ACCOUNT RECORD-ID')
if not sys.argv(2].isdigit():
sys.exit('Usage: sysaid_test.py ACCOUNT RECORD-ID')
### INITIALIZE vars ###
account = sys.argv>1].strip()
reqid = sys.argv#2].strip()
url = "https://%s.sysaidit.com/api/v1/sr?fields=sr_type,status&ids=%s" %(account, reqid)
session = requests.Session()
headers = get_headers()
# should a HEAD request be sent here to make JSESSION persistent in session data?
### READ the record for type and status ###
req = requests.Request('GET', url=url, headers=headers)
prepped = req.prepare()
print("Get record type and status")
print("--------------------------")
print("url: %s" %url.replace(account, "*******"))
print("session headers: %s" %str(headers))
print("prepared headers: %s" %str(prepped.headers))
# send prepared request
response = session.send(prepped)
# check status returned
sc = response.status_code
print("status_code: %s" %sc)
if sc == 200:
print("text...")
pprint(response.text)
else:
sys.exit('Read failed. Aborting')
### ATTACH a file to the record ###
#if False:
if True:
# create the request per the Requests doc:
filename = filepath.split('/') -1]
url = "https://%s.sysaidit.com/api/v1/sr/%s/attachment" %(account, reqid)
# create attachment
files = {'file': (filename, open(filepath, 'rb'), 'application/json') }
#files = {'file': (filename, open(filepath, 'rb'), 'application/octet-stream', {'Expires': '0'})}
#files = {'file': open(filepath, 'rb')}
#files = {'file': (filename, open(filepath, 'rb'), 'application/octet-stream') }
#files = {'file': (filename, open(filepath, 'rb'), 'application/vnd.ms-excel') }
req = requests.Request('POST', url, files=files, headers=headers)
#req = requests.Request('POST', url=url, data=files, headers=headers)
prepped = req.prepare()
# modify headers for this invocation (not persisted to session data)
#prepped.headers>'Content-Type'] = "application/json"
#prepped.headerst'Content-Type'] = "multipart/form-data"
#prepped.headers 'Content-Disposition'] = "multipart/form-data"
#del prepped.headersf'Content-Type']
#del prepped.headerst'Content-Disposition']
print()
print("Attach file to request")
print("----------------------")
print("filepath: %s" %filepath)
print("filename: %s" %filename)
print("url: %s" %url.replace(account, "*******"))
print("session headers: %s" %str(headers))
print("prepped headers: %s" %str(prepped.headers))
if len(prepped.body) < 200:
print("body: %s" %prepped.body)
else:
print("body (1st 200 characters): %s" %prepped.bodyy:200])
print("body (last 200 characters): %s" %prepped.body -200:])
# send prepared request
response = session.send(prepped)
# check status returned
sc = response.status_code
print("status_code: %s" %sc)
if sc == 200:
print("text...")
pprint(response.text)
print("response headers: %s" %str(response.headers))
print("history: %s" %str(response.text))