Skip to content Skip to sidebar Skip to footer

upload a file to a server from apex code messaging

Hello #Trailblazers,

Welcome back.

In this web log post, nosotros will learn how to upload a file to Amazon S3 using Salesforce Apex. Sending the files to Amazon S3 is ever a difficult chore considering of Amazon Authentication is complex.

The Problem Argument

As a Salesforce Developer, you need to upload all the files which get uploaded nether any Account to Amazon S3 using Salesforce Apex Trigger.

The Solution

For the solution, there can be multiple things that you can utilise like AppExchange Application, Named Credentials to Avoid the Hallmark but every bit nosotros said nosotros will next Noon and in the coming weblog post we volition utilize Named Credentials.

Step1 – Create an abstruse Class

This is the base course that has all the required method to generate the signature for Amazon S3 and is also used information technology to sign that signature for sending the request to Amazon S3.

Note:- Please refer to the comments on the class file

          public abstract class AWS {     //  Post initialization logic (after constructor, before phone call)     protected abstruse void init();          //  XML Node utility methods that volition aid read elements     public static Boolean getChildNodeBoolean(Dom.XmlNode node, String ns, String name) {         try {             return Boolean.valueOf(node.getChildElement(proper name, ns).getText());         } catch(Exception eastward) {             render zilch;         }     }          public static DateTime getChildNodeDateTime(Dom.XmlNode node, String ns, String name) {         try {             return (DateTime)JSON.deserialize(node.getChildElement(proper noun, ns).getText(), DateTime.class);         } catch(Exception e) {             return aught;         }     }          public static Integer getChildNodeInteger(Dom.XmlNode node, String ns, String name) {         try {             render Integer.valueOf(node.getChildElement(name, ns).getText());         } catch(Exception eastward) {             return aught;         }     }          public static String getChildNodeText(Dom.XmlNode node, Cord ns, String name) {         endeavour {             return node.getChildElement(name, ns).getText();         } catch(Exception e) {             return goose egg;         }     }          //  Turns an Amazon exception into something we tin nowadays to the user/catch     public class ServiceException extends Exception {         public String Code, Message, Resources, RequestId;                  public ServiceException(Dom.XmlNode node) {             Cord ns = node.getNamespace();             Code = getChildNodeText(node, ns, 'Code');             Bulletin = getChildNodeText(node, ns, 'Bulletin');             Resource = getChildNodeText(node, ns, 'Resource');             RequestId = getChildNodeText(node, ns, 'RequestId');         }                  public String toString() {             return JSON.serialize(this);         }     }          //  Things we demand to know near the service. Set these values in init()     protected String host, region, service, resource, accessKey, payloadSha256;     protected Url endpoint;     protected HttpMethod method;     protected Blob payload;     //  Not used externally, and then we hide these values     Blob signingKey;     DateTime requestTime;     Map<String, Cord> queryParams, headerParams;          //  Brand sure we tin can't misspell methods     public enum HttpMethod { XGET, XPUT, XHEAD, XOPTIONS, XDELETE, XPOST }          //  Add together a header     protected void setHeader(String key, String value) {         headerParams.put(central.toLowerCase(), value);     }          //  Add together a query param     protected void setQueryParam(String key, String value) {         queryParams.put(key.toLowerCase(), uriEncode(value));     }          //  Call this constructor with super() in subclasses     protected AWS() {         requestTime = DateTime.now();         queryParams = new Map<Cord, String>();         headerParams = new Map<String, String>();         payload = Hulk.valueOf('');     }          //  Create a canonical query string (used during signing)     String createCanonicalQueryString() {         Cord[] results = new String[0], keys = new List<Cord>(queryParams.keySet());         keys.sort();         for(String key: keys) {             results.add(key+'='+queryParams.go(central));         }         return String.join(results, '&');     }          //  Create the canonical headers (used for signing)     String createCanonicalHeaders(Cord[] keys) {         keys.addAll(headerParams.keySet());         keys.sort();         String[] results = new String[0];         for(String key: keys) {             results.add(central+':'+headerParams.get(key));         }         return Cord.join(results, '\n')+'\n';     }          //  Create the entire canonical request     String createCanonicalRequest(String[] headerKeys) {         return String.join(             new String[] {                 method.name().removeStart('X'),         //  METHOD                     new Url(endPoint, resource).getPath(),  //  Resources                     createCanonicalQueryString(),           //  Canonical QUERY STRING                     createCanonicalHeaders(headerKeys),     //  Canonical HEADERS                     Cord.bring together(headerKeys, ';'),           //  SIGNED HEADERS                     payloadSha256                           //  SHA256 PAYLOAD                     },             '\n'         );     }          //  Nosotros take to supervene upon ~ and " " correctly, or we'll break AWS on those two characters     protected string uriEncode(String value) {         return value==null? zilch: EncodingUtil.urlEncode(value, 'utf-viii').replaceAll('%7E','~').replaceAll('\\+','%20');     }          //  Create the entire string to sign     String createStringToSign(String[] signedHeaders) {         String result = createCanonicalRequest(signedHeaders);         return Cord.join(             new String[] {                 'AWS4-HMAC-SHA256',                     headerParams.get('date'),                     String.join(new String[] { requestTime.formatGMT('YYYYMMdd'), region, service, 'aws4_request' },'/'),                     EncodingUtil.convertToHex(Crypto.generateDigest('sha256', Hulk.valueof(effect)))                     },             '\n'         );     }          //  Create our signing key     public void createSigningKey(String secretKey) {                  signingKey = Crypto.generateMac('hmacSHA256', Blob.valueOf('aws4_request'),                             Crypto.generateMac('hmacSHA256', Blob.valueOf(service),                                    Crypto.generateMac('hmacSHA256', Blob.valueOf(region),                                           Crypto.generateMac('hmacSHA256', Hulk.valueOf(requestTime.formatGMT('YYYYMMdd')),                                                   Hulk.valueOf('AWS4'+secretKey)                                           )                                     )                              )                      );     }          //  Create all of the bits and pieces using all utility functions above     public HttpRequest createRequest() {         //init();                  payloadSha256 = EncodingUtil.convertToHex(Crypto.generateDigest('sha-256', payload));         setHeader('x-amz-content-sha256', payloadSha256);         setHeader('date', requestTime.formatGmt('E, dd MMM YYYY HH:mm:ss z'));         if(host == null) {             host = endpoint.getHost();         }         setHeader('host', host);         HttpRequest asking = new HttpRequest();         asking.setMethod(method.name().removeStart('X'));         if(payload.size() > 0) {             setHeader('Content-Length', String.valueOf(payload.size()));             setHeader('Content-Type', 'image/jpeg');             setHeader('ACL', 'public-read');             setHeader('ten-amz-acl','public-read');             request.setBodyAsBlob(payload);         }         Cord             finalEndpoint = new Url(endpoint, resource).toExternalForm(),              queryString = createCanonicalQueryString();         if(queryString != '') {             finalEndpoint += '?'+queryString;         }         asking.setEndpoint(finalEndpoint);         for(String cardinal: headerParams.keySet()) {             request.setHeader(key, headerParams.get(primal));         }         String[] headerKeys = new String[0];         String stringToSign = createStringToSign(headerKeys);         request.setHeader(             'Authorization',              String.format(                 'AWS4-HMAC-SHA256 Credential={0},SignedHeaders={1},Signature={2}',                 new Cord[] {                     String.bring together(new String[] { accessKey, requestTime.formatGMT('YYYYMMdd'), region, service, 'aws4_request' },'/'),                         Cord.join(headerKeys,';'), EncodingUtil.convertToHex(Crypto.generateMac('hmacSHA256', Blob.valueOf(stringToSign), signingKey))}             ));         return request;     }     // This method is used to comprehend the test class. If you want you can remove this     protected void getInteger(){         integer i = 0;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;         i++;     }      }        

Step2 – Create Custom Label

In order to store some static values, we demand to create custom Labels inside Salesforce Org. Below is the List of Labels that we need to create.

Notation: – Please get AWS Access Key and Hush-hush and shop those in the Custom labels

Step3 – Create Course to Upload File

This grade is the main class that will extend the AWS class which we created in footstep 1 and also upload the file to AWS. Beneath is the code.

Note: – Please read the class comment

          public course AWSS3_PutAttachments extends AWS{          public String fileName;     public String folderName;     public Blob fileBody;     public String contentType;     public Id recordId;          public override void init() {                  ContentVersion versionData = [ SELECT Id, Title, FileExtension, ContentDocumentId, VersionData FROM ContentVersion Where Id =: recordId];                  String Name = versionData.Title.substringBeforeLast('.');         Name = Proper noun.replaceAll(' ','');         Name = Name.replaceAll('[^a-zA-Z0-9 -]', '');         Name = Proper noun.replaceAll('-','');                  folderName = Organisation.Characterization.S3FolderName;          // this is not required simply if you want to upload file to specific folder then create a folder inside S3 bucket          // and then put the name inside Folder         fileName = Name;         fileBody = versionData.VersionData;                  ContentType = versionData.FileExtension;         endpoint = new Url(System.Label.S3_Bucket_Url);         /*         * Value for S3_Bucket_Url is - https://amit-salesforcetest.s3.amazonaws.com/         * https - default         * amit-salesforcetest - Name of the saucepan in S3         * s3 - Service Proper noun         * amazonaws.com - default value         */          if(Cord.isBlank(folderName)){             resource = +this.fileName+'.'+contentType;         }else{             resource = this.folderName+'/'+this.fileName+'.'+contentType;         }         region = System.Label.S3Region; // Your Amazon Region my value is - us-eastward-1         service = 's3';         accessKey = System.Label.AWSAccessKeyId; //AWSAccessKeyId         method = HttpMethod.XPUT;         //  Remember to set "payload" here if you need to specify a body         //  payload = Blob.valueOf('some-text-i-want-to-send');         //  This method helps prevent leaking hush-hush fundamental,          //  equally it is never serialized         payload = this.fileBody;         // Call this method from Abstract Course "AWS"         createSigningKey(System.Characterization.AWSSecretKey);  //AWSSecretKey                  If(!Examination.isRunningTest()){             // Phone call this method from Abstract Class "AWS"             HttpRequest req = createRequest();             System.debug('Req '+req);             try{                 // Send the Request and get the response                 HttpResponse res = (new Http()).send(req);                 if(res.getStatusCode() == 200 || res.getStatusCode() == 201){                     System.debug(' \northward '+res.getBody());                     String awsUrl = req.getEndpoint();                     String imageURL = '<a href="'+awsUrl+'">'+versionData.Championship+'</a>&nbsp;';                 }             }catch(System.CalloutException ex){                 // grab the Exception here             }         }else{             HttpResponse response;             createRequest();             response = new HttpResponse();             response.setHeader('Content-blazon', 'application/json');             response.setBody('');             response.setStatusCode(200);             getInteger();         }     } }        

Step4 – Create Commuter Form

This course volition be chosen from the Trigger handler class for the ContentVersion Trigger and will call the Principal Class which nosotros created in the previous stride.

Notice the code for the same

          public class AWSS3PutDriver implements Queueable, Database.AllowsCallouts {     public Set<Id> contentVersionIdsSet;     public AWSS3PutDriver(Set<Id> contentVersionIdsSet){         this.contentVersionIdsSet = contentVersionIdsSet;     }     public void execute(QueueableContext context) {         For(Id id : contentVersionIdsSet){             AWSS3_PutAttachments putAttachment = new AWSS3_PutAttachments();             putAttachment.recordId = Id;             putAttachment.init();         }          } }        

Step5 – Create Handler Class from the Trigger

Handler Class check if the File is beingness uploaded to Account Object if yes then information technology will call the Driver Class

          public form ContentVersionTriggerHandler {          public static void createPublicLinkForFile(List<ContentVersion> contentVersionList, Map<Id, ContentVersion> contentVersionMap){         // get the content document link         Map<Id, ContentDocumentLink> contentDocumentLinkMap = getContentDocumentLinkMap(contentVersionList);         Set up<Id> contentToBeUploaded = new Set<Id>();         for(ContentVersion version : contentVersionList){             ContentDocumentLink link = contentDocumentLinkMap.become( version.ContentDocumentId );             if( ( link.LinkedEntityId.getSObjectType() == Account.sObjectType) ){                 contentToBeUploaded.add(version.Id);             }         }         AWSS3PutDriver driverClass = new AWSS3PutDriver(contentToBeUploaded);         Id jobId = System.enqueueJob(driverClass);     }          // Go the Content Document Related to Cintent Version and so that Nosotros tin can bank check which object is parent to file 	public static Map<Id, ContentDocumentLink> getContentDocumentLinkMap(List<ContentVersion> contentVersionList){         Set<String> contentDocumentIdsSet = new Set<Cord>();         for(ContentVersion version : contentVersionList){             contentDocumentIdsSet.add(version.ContentDocumentId);         }         Map<Id, ContentDocumentLink> contentDocumentLinkMap = new Map<Id, ContentDocumentLink>();         for(ContentDocumentLink link : [SELECT Id, LinkedEntityId, ContentDocumentId FROM ContentDocumentLink WHERE ContentDocumentId IN :contentDocumentIdsSet]){             if(link.LinkedEntityId.getSObjectType() == Account.sObjectType){                 contentDocumentLinkMap.put(link.ContentDocumentId, link);             }         }         render contentDocumentLinkMap;     } }        

Step6 – Create Trigger on Content Version

This trigger will check if the file is getting uploaded under business relationship tape then phone call the handler which you lot have created in the previous step

          trigger ContentVersionTrigger on ContentVersion (later on insert) {     // Phone call the handler Form 	ContentVersionTriggerHandler.createPublicLinkForFile(Trigger.New, Trigger.newMap); }        

Step7 – Test the Trigger

Upload the file under Any Account record and verify if the file has been uploaded to the AWS S3 saucepan or not. If you are getting whatsoever problems, try to put the debug log on and run into what is the consequence.

Congratulations you take implemented the integration of AWS S3 using Salesforce Noon.

Troubleshooting

If you lot are getting any errors please make sure to check the below points

  1. You accept added the remote site settings. The value for Remote Site setting volition be the same which is for the Custom characterization "S3_Bucket_Url"
  2. You have configured the right permissions at the bucket level to upload the files.

#DeveloperGeeks #Salesforce #Trailhead

neributunamblery.blogspot.com

Source: https://sfdcpanther.com/how-to-upload-the-files-to-s3-using-salesforce-apex/

Post a Comment for "upload a file to a server from apex code messaging"