Salesforce REST API——Send Custom Notifications Using REST API In Trigger

前言

個人需求

當某條記錄被創建後或者修改後,如果裏面當內容不符合要求,那麼爲了增強用戶體驗,需要給用戶發送消息提醒(Custom Notifications ),在salseforce上其實是可以使用Process Builder來發送的,也十分簡單,如果有小夥伴不清楚,可以留言,我會盡快恢復。本文章使用REST API來發送Notifications,雖然代碼量增多些,但是難免以後不會遇到相似的問題,因此留個筆記…

核心代碼

在這之前你需要知道的是怎麼才能數據肯定是以json方式發送過去,那麼customNotifition的數據格式是怎樣的呢?

{
"inputs" :
        [
         {
          "customNotifTypeId" : "0MLB0000000PAwjOAG",
          "recipientIds" : ["005B0000005lewTIAQ"],
          "title" : "opportunity Closed!",
          "body" : "Your Opportunity has been Closed.",
          "targetId" : "006B00000058gHEIAY"
         }
        ]
  }

1、Get Resource From Org Use HttpRequest

/*
 *Get Resource From Org Use HttpRequest
 */
public class OrgREST {// inherited sharing
    
    /*
     *get resource 
     */
    public static String retriveResult(String strResourceName, String strMethod, String strBody) {
        String response;
        String strEndPonitURL = URL.getSalesforceBaseUrl().toExternalForm() + '/services/data/v46.0/' + strResourceName;
        if(String.isNotBlank(strResourceName)) {
            HttpRequest httpRequest = new HttpRequest();  
            httpRequest.setMethod(strMethod);   
            httpRequest.setHeader('Authorization', 'OAuth ' + UserInfo.getSessionId());        
            httpRequest.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID()); 
            
            if(String.isNotBlank(strBody)) {
                httpRequest.setBody(strBody);
                httpRequest.setHeader('Content-Type', 'application/json');
             httpRequest.setHeader('Accept', 'application/json');
            }
            
            httpRequest.setEndpoint(strEndPonitURL); 
            
            try {  
                Http http = new Http();   
                HttpResponse httpResponse = http.send(httpRequest);  
                if (httpResponse.getStatusCode() == 200 ) {  
                    response = httpResponse.getBody();  
                } 
                else {  
                    throw new CalloutException(httpResponse.getBody());  
                }   
            } 
            catch(Exception ex) {  
                throw ex;  
            }  
        } 
        return response;
    }
}

使用該class裏面的retriveResult方法,你可以使用Get方式來獲取你想要的資源,使用POST向服務器發送消息

2、Send CustomNotificationRESTAPI Use Last Code

public class CustomNotificationRESTAPI {//inherited sharing
 
    public static void (String strNotifiTypeDevName, list<sObject> lstObjects, list<Id> lstRecipients) {
        //List<sObject> lstObjects = [select Id from User where Id IN:lstObjectsId];
        System.debug('lstObjects' + lstObjects);
        String strResponse = null;
        System.debug(strNotifiTypeDevName + ':' + strNotifiTypeDevName + ':' + lstRecipients);
        if(String.isNotBlank(strNotifiTypeDevName)) {
            
            // Tooling API query
            String strResourceQuery = 'tooling/query/?q=select+id,customNotifTypeName+from+CustomNotificationType+where+DeveloperName=\''+ strNotifiTypeDevName +'\'';
            
            // OrgREST Custom Class returns the response as string
            strResponse = OrgREST.retriveResult(strResourceQuery, 'GET', null);
            System.debug('strResponse:' + strResponse);
            //get CustomNotificationType
        }
        
        map<String, Object> objData;
        
        if(String.isNotBlank(strResponse)) {
            // Deserializeing the response body
            map<String, Object> mapJsonData = (map<String, Object>)JSON.deserializeUntyped(strResponse);
            
            // Getting records
            list<Object> lstRecordsData = (list<Object>)mapJsonData.get('records');
            
            if(!lstRecordsData.isEmpty()) {
                // Converting each object to readable map to get the data
                objData = (map<String, Object>)lstRecordsData[0];      
            } 
            System.debug('Id ====> '+(String)objData.get('Id'));
        }
       
        /* 
         * Generating JSON body.
         * Below code work for bulk record process.
         * Recipients are User, Owner, Group or Queue Ids
        */
        if(!lstObjects.isEmpty() && !lstRecipients.isEmpty()) {
            JSONGenerator jsGen = JSON.createGenerator(true);
            jsGen.writeStartObject();
            jsGen.writeFieldName('inputs');
            jsGen.writeStartArray();
            
            for(sObject obj : lstObjects) {
                jsGen.writeStartObject();
                // Custom Notification type id
                jsGen.writeStringField('customNotifTypeId', (String)objData.get('Id'));
                jsGen.writeFieldName('recipientIds');
                jsGen.writeStartArray();
                
                // adding mulitiple recipients if any 
                for(Id idRecipient : lstRecipients) {
                    jsGen.writeId(idRecipient);
                }
                
                jsGen.writeEndArray();
                // Notification titile
                jsGen.writeStringField('title','Time Hour Contains Taboo');
                // Notification body
                jsGen.writeStringField('body', 'Your Time Hour Contains Taboo!');
                jsGen.writeStringField('targetId', (String)obj.get('Id'));
                jsGen.writeEndObject();
            }
    
            jsGen.writeEndArray();
            jsGen.writeEndObject();
            
            // Converting JSON as String
            String strJson = jsGen.getAsString();
            System.debug('strJson ====> '+strJson);
            
            // POST URL to send custom notification
            String strPOSTURL = 'actions/standard/customNotificationAction';
            
            // Sending post request to send custom notification
            String strPostResponse = OrgREST.retriveResult(strPOSTURL, 'POST', strJson);
        }
    }
}

這裏相當於就是先通過GET方式去獲取你要的那一個消息提醒(參數strNotifiTypeDevName就是你自定義custom Notification的label name),然後封裝你的POST數據,最後還是調用上一個Class中的方法去發送數據到你的salesfroce服務器

注意事項

1、Tigger不能直接調用REST API

前言也說了,發送消息提醒的話一般是處於某種條件下,所以Process Builder和Trigger就經常會遇到類似的問題。但是如果你直接在你的Trigger裏面調用REST API的話你會遇到:System.CalloutException: Callout from triggers are currently not supported意思就是現在還不支持在Trigger裏面直接調用REST API!!
So,怎麼辦!答案就是你必須將調用REST API的操作放到另一個事務中

trigger TimeHourNotificationTrigger on TimeHour__c (after insert) {
    for(TimeHour__c selfTimeHour : Trigger.New){
        String timeBrief = selfTimeHour.Brief__c;
        //List<Id> lstObjectsId = new List<Id>();
        //lstObjectsId.add(selfTimeHour.User__c);
        List<sObject> lstObjects = new List<sObject>();
        lstObjects.add(selfTimeHour);
        if(timeBrief.containsIgnoreCase('bug') == true || timeBrief.containsIgnoreCase('bugs') == true || timeBrief.containsIgnoreCase('internal') == true){
            System.debug('begin');
            //solution:1 CustomNotificationCallout.sendCustomNotification('Time_Hour_Notification', lstObjectsId, new list<Id>{UserInfo.getUserId()});

            //solution:1 System.enqueueJob(new CustomNotificationCallout('Time_Hour_Notification', lstObjects, new list<Id>{UserInfo.getUserId()}));
            System.debug('end');
        }
    }

solution 1 :在Future裏面調用REST API

但是Future有個很不好的地方就是參數只能是原始類型的不能接受對象,所以你只能傳ID然後再查詢一邊,個人推薦實現Queueable Job

solution 2 : 實現Queueable Job

下面的代碼是使用Queueable來做的,另一種方法被註釋調,如有需要就請自己動手改一改哈。當然別忘了如果用future的話CustomNotificationRESTAPI.sendCustomNotification那個方法的參數和裏面還有以及查詢也要改喲。

public with sharing class CustomNotificationCallout implements Queueable,Database.AllowsCallouts {// 
    
    public String strNotifiTypeDevName;
    //public list<Id> lstObjectsId;
    List<sObject> lstObjects = new List<sObject>();
    public list<Id> lstRecipients;
    
    public CustomNotificationCallout(String strNotifiTypeDevName, List<sObject> lstObjects, list<Id> lstRecipients){
        this.strNotifiTypeDevName = strNotifiTypeDevName;
        //this.lstObjectsId = lstObjectsId;
        this.lstObjects = lstObjects;
        this.lstRecipients = lstRecipients;
        System.debug('constror');
    }
	
    
    
    public void execute(QueueableContext context) { 
        // Awesome processing logic here    
        // Chain this job to next job by submitting the next job
        
        CustomNotificationRESTAPI.sendCustomNotification(strNotifiTypeDevName, lstObjects, lstRecipients);
    }
    
    /*
    @future(callout=true)
    public static void sendCustomNotification(String strNotifiTypeDevName, list<Id> lstObjectsId, list<Id> lstRecipients){
        System.debug('future');
        CustomNotificationRESTAPI.sendCustomNotification(strNotifiTypeDevName, lstObjectsId, lstRecipients);
        System.debug(' end future');
    } */

}

2、使用Queueable必須實現(implement Database.AllowsCallouts)

如果你的classpublic with sharing class CustomNotificationCallout implements Queueable,Database.AllowsCallouts只實現了Queueable的話是代碼、運行都不會報錯,但是是無法發送消息通知的,就像它本身就代表着是否允許Callouts.

PS :如有敘述不清或者錯誤的地方,懇請指正,留言交流,謝謝!

附上外文網站:https://www.salesforcecodecrack.com/2019/06/send-custom-notifications-using-rest-api.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章