Sample code for 30+ languages & platforms
Tcl

Xero Get Attachment (Download a Xero Attachment)

Demonstrates how to get the content of an attachment in Xero.

Note: This example requires Chilkat v9.5.0.64 or greater.

Chilkat Tcl Downloads

Tcl

load ./chilkat.dll

set success 0

# Note: Requires Chilkat v9.5.0.64 or greater.

# This requires the Chilkat API to have been previously unlocked.
# See Global Unlock Sample for sample code.

set rest [new_CkRest]

# Before sending REST API calls, the REST object needs to be
# initialized for OAuth1.
# See Xero 2-Legged OAuth1 Setup for sample code.

# Assuming the REST object's OAuth1 authenticator is setup, and the initial
# connection was made, we may now send REST HTTP requests..

# --------------------------------------------------------------
# First get a list of attachments for a given document (in this case a Receipt).

set endPoint "Receipts"
set receiptID "c4f40e59-c390-0001-caff-ce731c707d00"

set sbPath [new_CkStringBuilder]

CkStringBuilder_Append $sbPath "/api.xro/2.0/{Endpoint}/{Guid}/Attachments/"
set numReplaced [CkStringBuilder_Replace $sbPath "{Endpoint}" $endPoint]
set numReplaced [CkStringBuilder_Replace $sbPath "{Guid}" $receiptID]

set responseXml [CkRest_fullRequestNoBody $rest "GET" [CkStringBuilder_getAsString $sbPath]]
if {[CkRest_get_LastMethodSuccess $rest] != 1} then {
    puts [CkRest_lastErrorText $rest]
    delete_CkRest $rest
    delete_CkStringBuilder $sbPath
    exit
}

# A 200 response is expected for actual success.
if {[CkRest_get_ResponseStatusCode $rest] != 200} then {
    puts "$responseXml"
    delete_CkRest $rest
    delete_CkStringBuilder $sbPath
    exit
}

# Examine the response.
puts "$responseXml"

# A sample response looks like this:

# 	<Response xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
# 	  <Id>b235646f-34ac-4b15-90ce-d63267f7cd33</Id>
# 	  <Status>OK</Status>
# 	  <ProviderName>ChilkatPrivate</ProviderName>
# 	  <DateTimeUTC>2016-11-11T14:32:17.0908971Z</DateTimeUTC>
# 	  <Attachments>
# 	    <Attachment>
# 	      <AttachmentID>0edcddc8-325f-40c7-b950-8c71f14afc7c</AttachmentID>
# 	      <FileName>penguins.jpg</FileName>
# 	      <Url>http://api.xero.com/api.xro/2.0/Receipts/c4f40e59-c390-0001-caff-ce731c707d00/Attachments/penguins.jpg</Url>
# 	      <MimeType>image/jpg</MimeType>
# 	      <ContentLength>777835</ContentLength>
# 	    </Attachment>
# 	    <Attachment>
# 	      <AttachmentID>0adffdc8-325f-65c7-b950-4391f14af908</AttachmentID>
# 	      <FileName>starfish.jpg</FileName>
# 	      <Url>http://api.xero.com/api.xro/2.0/Receipts/c4f40e59-c390-0001-caff-ce731c707d00/Attachments/starfish.jpg</Url>
# 	      <MimeType>image/jpg</MimeType>
# 	      <ContentLength>24537</ContentLength>
# 	    </Attachment>
# 	  </Attachments>
# 	</Response>

set xml [new_CkXml]

CkXml_LoadXml $xml $responseXml

# Iterate over the attachments and download each.
set numRecords [CkXml_NumChildrenAt $xml "Attachments"]
puts "Number of Attachments = $numRecords"

set sbSaveFilePath [new_CkStringBuilder]

set sbAttachmentPath [new_CkStringBuilder]

set attachmentData [new_CkBinData]

set i 0
while {$i < $numRecords} {
    CkXml_put_I $xml $i
    set attachmentID [CkXml_getChildContent $xml "Attachments|Attachment[i]|AttachmentID"]
    set filename [CkXml_getChildContent $xml "Attachments|Attachment[i]|FileName"]

    puts "AttachmentID: $attachmentID"
    puts "Filename: $filename"
    puts "----"

    # Download this attachment.
    # First build the path for this particular attachment by appending the FileName to the path used to get the list of attachments.
    CkStringBuilder_Clear $sbAttachmentPath
    CkStringBuilder_AppendSb $sbAttachmentPath $sbPath
    CkStringBuilder_Append $sbAttachmentPath $filename

    # Send the GET request in one call, and then get the response in the next two.
    set success [CkRest_SendReqNoBody $rest "GET" [CkStringBuilder_getAsString $sbAttachmentPath]]
    if {$success != 1} then {
        puts [CkRest_lastErrorText $rest]
        delete_CkRest $rest
        delete_CkStringBuilder $sbPath
        delete_CkXml $xml
        delete_CkStringBuilder $sbSaveFilePath
        delete_CkStringBuilder $sbAttachmentPath
        delete_CkBinData $attachmentData
        exit
    }

    # Get the response header.  If it's not a 200 success status code, then the response body does NOT contain
    # the attachment data.
    set statusCode [CkRest_ReadResponseHeader $rest]
    if {$statusCode == -1} then {
        # We didn't get any response..
        puts [CkRest_lastErrorText $rest]
        delete_CkRest $rest
        delete_CkStringBuilder $sbPath
        delete_CkXml $xml
        delete_CkStringBuilder $sbSaveFilePath
        delete_CkStringBuilder $sbAttachmentPath
        delete_CkBinData $attachmentData
        exit
    }

    if {$statusCode != 200} then {
        puts "Response Status: $statusCode"
        set responseBody [CkRest_readRespBodyString $rest]
        if {[CkRest_get_LastMethodSuccess $rest] != 1} then {
            puts "Failed to read the response body."
        }         else {
            puts "$responseBody"
        }

        puts "Failed."
        delete_CkRest $rest
        delete_CkStringBuilder $sbPath
        delete_CkXml $xml
        delete_CkStringBuilder $sbSaveFilePath
        delete_CkStringBuilder $sbAttachmentPath
        delete_CkBinData $attachmentData
        exit
    }

    # OK, the response header indicates the attachment content is forthcoming...
    # There are a few ways to get the response body. If it is a very large attachment, it can be streamed directly
    # to a file.  We'll assume it's not, so we'll get the response into a BinData object, and then save it to a file.
    CkBinData_Clear $attachmentData
    set success [CkRest_ReadRespBd $rest $attachmentData]
    if {$success != 1} then {
        puts [CkRest_lastErrorText $rest]
        delete_CkRest $rest
        delete_CkStringBuilder $sbPath
        delete_CkXml $xml
        delete_CkStringBuilder $sbSaveFilePath
        delete_CkStringBuilder $sbAttachmentPath
        delete_CkBinData $attachmentData
        exit
    }

    # Save the data to the file.
    CkStringBuilder_SetString $sbSaveFilePath "qa_output/"
    CkStringBuilder_Append $sbSaveFilePath $filename
    set success [CkBinData_WriteFile $attachmentData [CkStringBuilder_getAsString $sbSaveFilePath]]
    if {$success != 1} then {
        puts "Failed to save to output file."
    }     else {
        puts "Saved to [CkStringBuilder_getAsString $sbSaveFilePath]"
    }

    set i [expr $i + 1]
}

delete_CkRest $rest
delete_CkStringBuilder $sbPath
delete_CkXml $xml
delete_CkStringBuilder $sbSaveFilePath
delete_CkStringBuilder $sbAttachmentPath
delete_CkBinData $attachmentData