In a recent Salesforce project I am working on there was a need for an unified logging and auditing framework that could be used by Lightning Components and AngularJS applications to create auditing records in Salesforce backend.
An additional need well as there was need of a public api that could be consumed by an external system to archive and monitor the records as needed. This is a perfect case for Platform Events. The diagram below describes the high level architecture of the unified auditing service.
For lightning it is very easy to create a reusable component that can be included in all lightning components that need access to this auditing service. This component can use the unified class that creates the platform events using the information provided. The challenge is to use the same apex class in an angularjs application as an angular service. I will be providing a full Auditing Service Framework in a future blog post .. stay tuned. In this blog post I will focus on how we can expose an apex class through the SOAP api in an angular service that can be reused in angular controllers for creating platform events in the backend.
It all starts with a common apex class for creating the platform events. Notice the @AuraEnabled and webservice keywords. This are needed to expose to Lightning and Javascript (AngularJS) respectively.
global with sharing class TestPlatformEventService {
@AuraEnabled
webservice static String getServiceName() {
return TestPlatformEventService.class.getName();
}
@AuraEnabled
webservice static void createPlatformEvent() {
List<Test_Platform_Event__e> testEvents = new List<Test_Platform_Event__e>();
testEvents.add(new Test_Platform_Event__e(Description__c = 'Test Event ' + Math.random()));
// Call method to publish events
List<Database.SaveResult> results = EventBus.publish(testEvents);
// Inspect publishing result for each event
for (Database.SaveResult sr : results) {
if (sr.isSuccess()) {
System.debug('Successfully published event.');
} else {
for (Database.Error err : sr.getErrors()) {
System.debug('Error returned: ' +
err.getStatusCode() +
' - ' +
err.getMessage());
}
}
}
}
}
|
Next is the AngularJS service that can be used in a AngularJS component or directive to invoke an apex webservice method. The reason we are not using the REST API (directly or through a library like jsforce) is due to CORS (Cross-Origin Resource Sharing) support not enabled on the platform. It is only enabled for the Chatter REST API. Please go ahead and vote for the idea to enable CORS support here.
var serviceModule = angular.module('platformEventServiceModule', []);
serviceModule.service('platformEventService', function() {
var conn;
this.init = function(sessionId) {
sforce.connection.sessionId=sessionId;
};
this.getServiceName = function() {
var result = sforce.apex.execute("TestPlatformEventService", "getServiceName", {});
console.log(JSON.stringify(result));
};
this.createEvent = function() {
var result = sforce.apex.execute("TestPlatformEventService", "createPlatformEvent", {});
};
});
|
Here is a test visualforce page that can be used to test the service.
<apex:page showHeader="false" applyHtmlTag="false" docType="html-5.0">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"/>
<apex:includeScript value="/soap/ajax/28.0/connection.js" />
<apex:includeScript value="/soap/ajax/28.0/apex.js" />
<apex:includeScript value="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.4/angular.min.js"/>
<apex:includeScript value="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js"/>
<apex:includeScript value="{!$Resource.angularTestPlatformEventService}"/>
<script>
var App = angular.module('myApp', ['platformEventServiceModule']);
App.controller('myctrl', function ($scope, platformEventService) {
this.$onInit = function() {
platformEventService.init('{!GETSESSIONID()}');
}
$scope.getServiceName = function () {
$scope.serviceName = platformEventService.getServiceName();
}
$scope.createEvent = function () {
platformEventService.createEvent();
}
});
</script>
</head>
<body ng-app="myApp" class="container" ng-controller="myctrl">
<!--<button ng-click="getServiceName()">Query</button>-->
<button ng-click="createEvent()">Create Event</button>
<div>{{serviceName}}</div>
</body>
</apex:page>
|
For testing the creation of the platform event a simple trigger can be used to create a record everytime
a platform event is created.
trigger TestPlatformEventTrigger on Test_Platform_Event__e (after insert) {
List<TestPlatformEventRecord__c> testPlatformEventRecords = new List<TestPlatformEventRecord__c>();
for(Test_Platform_Event__e evt : Trigger.new) {
System.debug('Creating record for event: ' + evt);
TestPlatformEventRecord__c eventRecord = new TestPlatformEventRecord__c();
eventRecord.User__c = evt.CreatedById;
eventRecord.Description__c = evt.Description__c;
testPlatformEventRecords.add(eventRecord);
}
insert testPlatformEventRecords;
}
|
The entire code with the Platform Event (Test_Platform_Event__e) and Custom Object
(TestPlatformEventRecord__c) can be found on my Github.
Comments