Sample code for 30+ languages & platforms
Delphi DLL

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 Delphi DLL Downloads

Delphi DLL
uses
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, BinData, StringBuilder, Rest, Xml;

...

procedure TForm1.Button1Click(Sender: TObject);
var
success: Boolean;
rest: HCkRest;
endPoint: PWideChar;
receiptID: PWideChar;
sbPath: HCkStringBuilder;
numReplaced: Integer;
responseXml: PWideChar;
xml: HCkXml;
numRecords: Integer;
sbSaveFilePath: HCkStringBuilder;
sbAttachmentPath: HCkStringBuilder;
attachmentData: HCkBinData;
i: Integer;
attachmentID: PWideChar;
filename: PWideChar;
statusCode: Integer;
responseBody: PWideChar;

begin
success := False;

// 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.

rest := CkRest_Create();

// 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).

endPoint := 'Receipts';
receiptID := 'c4f40e59-c390-0001-caff-ce731c707d00';

sbPath := CkStringBuilder_Create();
CkStringBuilder_Append(sbPath,'/api.xro/2.0/{Endpoint}/{Guid}/Attachments/');
numReplaced := CkStringBuilder_Replace(sbPath,'{Endpoint}',endPoint);
numReplaced := CkStringBuilder_Replace(sbPath,'{Guid}',receiptID);

responseXml := CkRest__fullRequestNoBody(rest,'GET',CkStringBuilder__getAsString(sbPath));
if (CkRest_getLastMethodSuccess(rest) <> True) then
  begin
    Memo1.Lines.Add(CkRest__lastErrorText(rest));
    Exit;
  end;

// A 200 response is expected for actual success.
if (CkRest_getResponseStatusCode(rest) <> 200) then
  begin
    Memo1.Lines.Add(responseXml);
    Exit;
  end;

// Examine the response.
Memo1.Lines.Add(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>

xml := CkXml_Create();
CkXml_LoadXml(xml,responseXml);

// Iterate over the attachments and download each.
numRecords := CkXml_NumChildrenAt(xml,'Attachments');
Memo1.Lines.Add('Number of Attachments = ' + IntToStr(numRecords));

sbSaveFilePath := CkStringBuilder_Create();
sbAttachmentPath := CkStringBuilder_Create();
attachmentData := CkBinData_Create();
i := 0;
while i < numRecords do
  begin
    CkXml_putI(xml,i);
    attachmentID := CkXml__getChildContent(xml,'Attachments|Attachment[i]|AttachmentID');
    filename := CkXml__getChildContent(xml,'Attachments|Attachment[i]|FileName');

    Memo1.Lines.Add('AttachmentID: ' + attachmentID);
    Memo1.Lines.Add('Filename: ' + filename);
    Memo1.Lines.Add('----');

    // 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.
    success := CkRest_SendReqNoBody(rest,'GET',CkStringBuilder__getAsString(sbAttachmentPath));
    if (success <> True) then
      begin
        Memo1.Lines.Add(CkRest__lastErrorText(rest));
        Exit;
      end;

    // Get the response header.  If it's not a 200 success status code, then the response body does NOT contain
    // the attachment data.
    statusCode := CkRest_ReadResponseHeader(rest);
    if (statusCode = -1) then
      begin
        // We didn't get any response..
        Memo1.Lines.Add(CkRest__lastErrorText(rest));
        Exit;
      end;
    if (statusCode <> 200) then
      begin
        Memo1.Lines.Add('Response Status: ' + IntToStr(statusCode));
        responseBody := CkRest__readRespBodyString(rest);
        if (CkRest_getLastMethodSuccess(rest) <> True) then
          begin
            Memo1.Lines.Add('Failed to read the response body.');
          end
        else
          begin
            Memo1.Lines.Add(responseBody);
          end;
        Memo1.Lines.Add('Failed.');
        Exit;
      end;

    // 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);
    success := CkRest_ReadRespBd(rest,attachmentData);
    if (success <> True) then
      begin
        Memo1.Lines.Add(CkRest__lastErrorText(rest));
        Exit;
      end;

    // Save the data to the file.
    CkStringBuilder_SetString(sbSaveFilePath,'qa_output/');
    CkStringBuilder_Append(sbSaveFilePath,filename);
    success := CkBinData_WriteFile(attachmentData,CkStringBuilder__getAsString(sbSaveFilePath));
    if (success <> True) then
      begin
        Memo1.Lines.Add('Failed to save to output file.');
      end
    else
      begin
        Memo1.Lines.Add('Saved to ' + CkStringBuilder__getAsString(sbSaveFilePath));
      end;

    i := i + 1;
  end;

CkRest_Dispose(rest);
CkStringBuilder_Dispose(sbPath);
CkXml_Dispose(xml);
CkStringBuilder_Dispose(sbSaveFilePath);
CkStringBuilder_Dispose(sbAttachmentPath);
CkBinData_Dispose(attachmentData);

end;