S-Drive 3.6 Documentation

initializeUpload


First step in building a custom (non-S-Drive-UI) file upload. For each file you want to upload, this method validates it, creates a "Work In Progress" (WIP) Salesforce record for it, and returns a signed policy your code then uses to upload the actual file bytes directly to the storage bucket (S3/GCS).

This does not upload any file bytes itself. You (or your client-side code) still have to send the file to storage, and then call completeUpload to mark it finished.

This is one piece of a multi-step process — see Uploading a file end-to-end for how this fits together with the rest.

How to call this method

global static List<UploadRequestInfo> initializeUpload(String objectId, List<SObject> attachments, Map<String,String> policyMap)

global static List<UploadRequestInfo> initializeUpload(String objectId, List<SObject> attachments, List<Map<String,String>> policyMapList)

global static List<UploadRequestInfo> initializeUpload(String objectId, List<SObject> attachments, List<Map<String,String>> policyMapList, List<String> idToUploadNewVersionList)


All three do the same underlying work; pick based on how much control you need:

  • The first, if every file in this batch should share the same extra storage-policy conditions (or you don't need any).

  • The second, if each file needs its own policy conditions.

  • The third, if you're uploading new versions of files that already exist, rather than brand-new files.

Parameters

Parameter

Type

Required

Description

objectId

String

Usually yes

The Id of the parent record these files belong to — e.g. an Account, Case. Leave blank for SDrive Tab (cg__S3Object__c) files.

attachments

List<SObject>

Yes

One not-yet-inserted record per file, all of the same SObject type (e.g. all cg__CaseFile__c). Before calling, set at least the file name field (…File_Name__c) and file size field (…File_Size_in_Bytes__c) on each, plus whatever parent/folder lookup field that object type uses. Don't set the content-type or "is latest version" fields yourself — this method sets those. This method performs the DML insert for you; don't insert these records yourself first.

policyMap / policyMapList

Map<String,String> / List<Map<String,String>>

No

Extra conditions to add to the storage-service upload policy for each file (e.g. custom form fields your bucket's policy requires). Pass null if you don't need any.

idToUploadNewVersionList

List<String>

No

One existing file record Id per entry in attachments, in the same order, when this call is uploading a new version of an already-existing file rather than a brand-new one. Pass null for ordinary new uploads.

Return value

Returns List<UploadRequestInfo>, one entry per item in attachments, in the same order. The fields you'll use:

Field

Description

wipFileId

The Id of the WIP Salesforce record this method just inserted — save it, you'll need it for completeUpload.

fileLocation

The storage key (path) this file will live at once uploaded.

fileName / fileSize / fileType

Echoed back from what you provided.

bucketName / s3Endpoint / awsRegion

Where to send the upload request.

policy / signature / timeStamp / awsCredential

The signed values you include as form fields when uploading directly to the bucket.

storageService

's3' or 'gcs' — which backend this org is configured to use.

maxPartCount

The maximum number of parts allowed if you use the multipart flow for this file (10,000 for S3 — see initializeMultiPartUpload for how this differs on GCS).

isVersioned

Whether the bucket this file is going into has versioning enabled.

isS3TransferAccelerationEnabled

Whether to use the accelerated S3 endpoint.


Common errors

All of these come back as SDriveException.

Cause

Fix

The file name or file size field on one of your attachments records is null or empty.

Set both fields on every record before calling.

The file name starts with a space or a dot, or contains any of `\ / : * ? " < > |

Rename the file so it doesn't start with a space/dot and avoids those characters.

The file size is 0.

Only upload files with a size greater than 0.

The file exceeds this org's configured maximum file size.

Upload a smaller file, or raise the MAX_FILE_SIZE setting on the S-Drive Configuration page.

A non-WIP file already has this name in the destination folder — or another user has a WIP (in-progress) upload with this same name started in the last 12 hours. (Error code 409, "A file with the same name already exists in the target folder.") Your own stale WIP records with this name don't trigger this — it's meant to stop two people colliding, not to block you from retrying your own upload.

Use a different file name, or delete/finish the conflicting file first.

The name conflict is with a folder, not a file. (Error code 409, "There is a folder with the same name... overwriting the file onto a folder is not possible.")

Rename the file, or the folder.

objectId isn't a valid 15- or 18-character Salesforce Id. ("Invalid parent id specified.")

Pass a well-formed Id.

You're uploading multiple files in one call, and their parent lookup fields don't all match. (Error code 400, "Parent Folder IDs must be the same for all file records that are being uploaded.")

Every record in attachments must point at the same parent.

The running user doesn't have create access to the file object.

Grant create permission on the object, or run as a user who has it.

Setting a custom Content-Disposition (or other) policy condition

The signed policy initializeUpload builds only allows the form fields it explicitly sets — that's why, for example, sending a Content-Disposition field when you upload (see the form-fields table on Uploading a file end-to-end) requires you to add a matching condition yourself via policyMap:

​```apex Map<String,String> policyMap = new Map<String,String>{ '$Content-Disposition' => 'attachment; filename' };

List<UploadRequestInfo> uploadInfos = SDriveTools.initializeUpload(caseId, attachments, policyMap); ​```

A key starting with $ becomes a "starts-with" condition in the signed policy — it allows any Content-Disposition value beginning with attachment; filename (so you can append the actual file name when you send the form field), rather than requiring an exact match. A key without the $ prefix requires an exact match instead.

Before you call this

  • This does not upload any bytes. After calling it, your code — typically client-side JavaScript, since Apex callouts have size and time limits unsuitable for large files — must send the actual file content to the bucket using the returned policy/signature/etc., and only then call completeUpload.

  • For small files, one direct request to bucketName/s3Endpoint using the returned policy is enough. For larger files, use the multipart flow instead — see initializeMultiPartUpload.

  • Throws SDriveException if: the file name is invalid, the file size is 0, the file exceeds the org's configured maximum file size, a file with the same name already exists in the destination folder (error code 409) and duplicates aren't allowed for that object, or the running user doesn't have create access to the file object.

Example

// Build one not-yet-inserted file record per file to upload
cg__CaseFile__c file1 = new cg__CaseFile__c(
    cg__File_Name__c = 'invoice.pdf',
    cg__File_Size_in_Bytes__c = 482913,
    cg__Case__c = caseId,
    cg__Parent_Folder_Id__c = null // null = uploading to the case's root, not a subfolder
);

List<SObject> attachments = new List<SObject>{ file1 };

List<UploadRequestInfo> uploadInfos = SDriveTools.initializeUpload(
    caseId,
    attachments,
    (Map<String,String>) null
);

UploadRequestInfo info = uploadInfos[0];
System.debug('WIP record created: ' + info.wipFileId);
System.debug('Upload the file bytes to: ' + info.s3Endpoint + '/' + info.bucketName);
System.debug('Using storage key: ' + info.fileLocation);

// Next: upload the actual bytes using info.policy / info.signature / etc.,
// then call SDriveTools.completeUpload(new List<Id>{ info.wipFileId }).
// See "Uploading a file end-to-end" for the full request this requires.

If something goes wrong

If the storage upload fails after this method has already created the WIP record, don't leave it stranded — call cancelUpload (documented separately) with the wipFileId to clean it up.