December 9, 2020
AWS S3 Cloud Storage with ColdFusion 2021
Comments
(2)
December 9, 2020
AWS S3 Cloud Storage with ColdFusion 2021
Newbie 2 posts
Followers: 1 people
(2)

Hello Everyone,

I am delighted to tell that now various cloud services are part of the new version of ColdFusion, the 2021 release. Now if you want to use these cloud services, you don’t have to look for their SDKs and think about using these in ColdFusion.

In this blog, I will cover integrating AWS S3 with ColdFusion.

Pre-requisites for AWS S3 with ColdFusion:

  • AWS Account
  • AWS Security Credentials (Access Key ID and Security Access Key)
  • Choosing AWS Regions
  • Installing awss3 package

Introduction

Amazon S3 (Amazon Simple Storage Service) is a storage service using which you can store any object with AWS S3 Cloud. This feature was not part of the earlier tag-based s3 support. The new feature is supported only in cfscript.

Core Concept

Below are core concepts /terminologies that are required to understand:

Term Description
Bucket

A bucket is a container for objects stored in Amazon S3. Every object is contained in a bucket. Every bucket name is unique across AWS S3, i.e., bucket name is a namespace in AWS S3.

If a user creates a new bucket with name ‘xyzBucket’, no one else can create bucket with same name.

Object Object is the entity that you store in the bucket. You can upload any number of objects to a bucket.
Key A key is a name that you assign to an object. You specify the key name while uploading an object.
Region The buckets will be stored in the AWS region that you specify.
Version Versioning can be used to keep multiple versions of an object in a bucket.
ACL Access control list enable you to manage access to buckets and objects. It defines which AWS account or groups are granted access and type of access. By default, the resource owner has the full control over the resource.

Getting Started

Creating S3Service object using credentials and region:

<cfscript>
// Credential object has credentials for the cloud vendor. In this example AWS is the vendor

credential  = {
               "vendorName" : "AWS",
               "region" : "us-east-2",
               "secretAccessKey" : "xxxx",
               "accessKeyId" : "yyyy"
}

// configuration object tells to create service object for S3.
// many other things can be passed with in struct for s3 but lets keep it simple for this blog
configuration  = {
               "serviceName" : "S3"
}

//getCloudService method gives service handle for AWS's S3, 
s3Service = getCloudService(credential, configuration)
</cfscript>

 

Create a bucket

You can think of a bucket as a directory or root directory where you can put any object (file) against a key(filename). A bucket cannot have another bucket it will contain objects only. A bucket name stays unique until the owner deletes the bucket. Let’s see how we can create bucket using the s3Service obtained in the previous step.

<cfscript>
               bucketName = "first-bucket" & now().getTime() //now().getTime() is appended to make bucketName unique
               newbucketRequest = { 

                              "bucket" : bucketName
               }

               bucketObj = s3Service.createBucket(newBucketRequest);


// for already existing bucket->
// bucketObj = s3Service.bucket(bucketName);

</cfscript>

 

List all buckets

To list all the buckets created in an account “listAll” method of s3Service object will be used.

<cfscript>
               s3Service = getCloudService(credential, configuration)
               bucketList=s3Service.writeDump(bucketList)
</cfscript>

 

Delete a bucket

To delete a bucket in an account, the “delete” method of s3Service object will be used. If the bucket is not empty, add ‘”forcedDelete”: true’ to deleteBucket example in request.

<cfscript>
               s3Service = getCloudService(credential, configuration)
               deleteBucket = {
                     "bucket": bucketName
                  }
               s3Service.delete(deleteBucket)
/* //If bucket is not empty
deleteBucket = {
          "bucket": bucketName,
          "forcedDelete" : true
}*/
</cfscript>

 

Upload a file to a bucket

Now let’s upload a file to the bucket using uploadFile” method of s3Service object. We can pass attributes for object acl, tags, server-side encryption etc. But let’s keep it simple in the example.

<cfscript>
               fileToBeUploaded = "xyz.txt";
               key= "xyz";
               uploadRequest =
                    "srcFile": fileToBeUploaded,
                    "key": key
               }
               uploadResponse = bucketObj.uploadFile(uploadRequest);
</cfscript>

 

Downloading an S3 object to a file

We have already uploaded a file to the bucket, now let’s download it using ‘downloadToFile’.

<cfscript>
               downloadedFile = "downloaded-xyx.txt";
               downloadRequest =  {
                     "destinationFIle": downloadedFile,
                     "key": key
               }
               downloadResponse = bucketObj.downloadToFile(downloadRequest);
</cfscript>

 

Store different versions of an object

To store versions of an object you must first enable versioning on a bucket. When you upload an object, it will be uploaded with a version id.

<cfscript>
               bucketObj.enableVersioning();
</cfscript>

You can list all the versions of the object using ‘listAllVersions’

<cfscript>
               objectList=bucketObj.listAllVersions();
               writedump(objectList);
</cfscript>

 

Add ACL to bucket and objects

You can add Bucket ACL while creating the bucket or by using ‘putBucketAcl’.
<cfscript>
               bucketAclRequest={
                              "acl" : "PUBLIC_READ"
               }
               bucketObj.putBucketAcl(bucketAclRequest);
               writedump(bucketObj.getBucketAcl());
</cfscript>

Similarly, you can add Object ACL while uploading an object or by using ‘putObjectAcl’

<cfscript>
               objectAclRequest={
                              "key" : key,
                              "acl" : "PUBLIC_READ"
               }
               bucketObj.putObjectAcl(objectAclRequest);
               writedump(bucketObj.getObjectAcl(key));
</cfscript>

 

Upload an object in parallel

An object can be uploaded in parts parallelly. The part can be from 5 MB to 5 TB in size.

<cfscript>
               fileToBeUploaded = "xyz.txt";
               key= "xyz";
               uploadRequest =  {
                              "srcFile"
: fileToBeUploaded,
                              "key": key,
                              "chunkLengthInBytes" : "6e+6"
               }
               uploadResponse = bucketObj.parallelUploadFile(uploadRequest);
</cfscript>

 

Download an object in parallel

We have already uploaded a object in parallel, now let’s download that object in parallel.

<cfscript>
               downloadedFile = "downloaded-xyx.txt";
               downloadRequest =  {
                              "destinationFIle": downloadedFile ,
                              "key": key,
                              "chunkLengthInBytes" : "6e+6"
               }
               downloadResponse = bucketObj.parallelDownloadFile(downloadRequest);
</cfscript>

 

Upload files in bulk

You can upload a directory to the bucket using ‘uploadDirectory’

<cfscript>
               directoryToBeUploaded = "abc_directory";
               prefix= "abc";
               uploadRequest =  {
                                "sourceDirectory": directoryToBeUploaded,
                                "prefix": prefix,        // prefix that will be added to the object key.
                              "uploadNestedDirectory" : "true"
}
               uploadResponse = bucketObj.uploadDirectory(uploadRequest);
</cfscript>

Upload an object

ColdFusion Objects such as array, list, string etc can be uploaded to a bucket using ‘uploadObject’

<cfscript>
               key = "xyz";
               array1=[1,2,3,4];
               uploadRequestsstruct ={
                              "object" : array1,
                              "key" : key,
                              "type" :"json"
               }
               uploadResponse = bucketObj.uploadObject(uploadRequest);
</cfscript>

Download an object

You can also download an object that was uploaded using ‘downloadObject’

<cfscript>
               key = "xyz";
               downloadRequestsstruct ={
                              "key" : key,
                              "type" :"json”
               }
               downloadResponse = bucketObj.downloadObject(downloadRequestsstruct);
</cfscript>

Object locking

The concept of locking an object from deletion is Object locking. Object can be locked by 2 ways that is Legal hold, Retention lock. Methods such as ‘putObjectLockConfiguration’, ‘acquireLegalHold’, ‘acquireRetentionLock’ can be used.

<cfscript>
               putObjectLockRequest = {
                              “key” : key,
                              "objectLockConfiguration" : {
                                             "objectLockEnabled" : "ENABLED",
                                             "defaultRetention" : {
                                                            "mode" : "GOVERNANCE",
                                                            "days" : 31
                                             }
                              }
               }
               bucketObj.putObjectLockConfiguration(putObjectLockRequest);
               objectLockResponse=bucketObj.getObjectLockConfiguration();
               writeDump(objectLockResponse);
</cfscript>

 

Presigned URL

A presigned URL is a URL that you can provide to your users to grant temporary access to a specific S3 object. Using the URL, a user can either GET the object or PUT an Object

The URL generated using generateputPresignedUrl’ can be used to upload the object.

<cfscript>
               putPresignedReq = {
                              "duration": "1d",     //The URL will expire in 1 day.
                              "key" : key
               }
               putPresignedUrlResp = bucketObj.generatePutPresignedUrl(putPresignedReq);
               writedump(putPresignedUrlResp)
</cfscript>

The URL generated using generateGetPresignedUrl’ can be directly opened using the browser.

<cfscript>
               getPresignedReq = {
                              "duration": "1d",     //The URL will expire in 1 day.
                              "key" : key
               }
               getPresignedUrlResp = bucketObj.generateGetPresignedUrl(getPresignedReq);
               writedump(getPresignedUrlResp)
</cfscript>

2 Comments
2023-08-10 02:20:39
2023-08-10 02:20:39

Hannah, can you offer how one would delete an object within a bucket?

Like
(1)
>
Charlie Arehart
's comment
2023-08-10 21:41:52
2023-08-10 21:41:52
>
Charlie Arehart
's comment

I can offer a solution to my problem. The next day, Paul M shared how to do it in a comment on a CF community forum discussion thread on this matter. See his comment and sample code here.

And I hope first that Adobe will update their docs to clarify it (it does not, which is why I came here to ask), and let’s hope Hannah might update her page here to also mention it.

FWIW, I’ll add that some people will more likely find this post (and have that question) here in 2023 (rather than since this post at the outset of CF2021), because it turns out that CF2023 for now has a bug (to be fixed soon) where it fails to run old CFML code for managing S3 (from before the addition of these new features in 2021).

As such, people on CF2023 using S3 are HAVING to find how to handle it differently (at least until the bug is fixed, scheduled for an update 5, from a tracker ticket about the matter.) I figured I’d add this info here, before they make their way here and would want to ask. 🙂 For more, especially as we for now have only CF2023 update 3, see my comment in that tracker ticket.

Like
Add Comment