Andy in the Cloud

From BBC Basic to Force.com and beyond…


3 Comments

Lightning Out: Components on Any Platform

This blog is my first video blog! Since Salesforce does not record the Developer Theatre sessions at the Salesforce World Tour events i thought i would do a re-run at home of my session last week and publish it here. As you know i have a love for all things API’s, and while I typically focus in this blog on backend API’s, there is one i’ve been keen to explore for a while…

The Lightning Out API, as any good API should, brings great promise and reality i’m pleased to say, to further integrating and extending the power of the platform and generally simplifying our users lives. In this case boldly going where no Lightning Component has gone before….

You can access the slides and thus the links within via this Slideshare upload.


16 Comments

Introduction to the Platform Action API

shutterstock_159003926.jpg

Actions are Salesforce’s general term for tasks users can perform either through buttons throughout various UI’s on desktop, mobile, tablet etc or in fact via non-UI processes such those built via via Process Builder or Automation Flows.

Actions are about “getting things done” in Salesforce. They encapsulate a piece of logic that allows a user to perform some work, such as sending email. When an action runs, it saves changes in your organization by updating the database. More here.

Over the years we’ve had many terms and ways to define these. Custom Button and Custom Link are perhaps the most obvious ones, which i’ve covered here in the past. Quick Actions (previously Publisher Actions) and more recently we’ve had Action Link‘s, which i covered in a past blog. Then of course the Standard Buttons, Edit, Delete, Follow, Submit for Approval etc provided by the platform. Such actions appear in various places Record layouts, List Views, Related Lists, Chatter and more recently Flexi Pages (aka Lighting Pages).

You might wonder then, if you had the task as developer to build your own UI or tool that wanted to expose some or all of the above actions, it would be quite a challenge to find them all. Indeed in some cases you may have had to resort to URL hacking to invoke some of them. Well worry not no longer, Salesforce’s clever architects now have you covered! Enter a new virtual SObject known as PlatformAction! Before we get onto what exactly virtual means, lets review some Actions and some SOQL queries…

Consider this Account Record detail page in the Classic (or Aloha) UI

PlatformActionAccount.png

Note down your record ID and use it in a query like the one below…

SELECT DeviceFormat, Label, Type, Section,
       ActionTarget, ActionTargetType, ActionListContext
  FROM PlatformAction
  WHERE ActionListContext = 'Record' AND
        SourceEntity = '001B000000D2V0n' AND
        Section = 'Page' AND
        DeviceFormat = 'Aloha'

In Developer Console you should see something like this…

PlatformActionQueryResults1.png

Pretty cool huh!? Check out the ActionTarget field, for the Standard Button records, thats the URL you can place on your UI’s to invoke that action, simple as that! Better still this is a supported way to get it, no more URL hacking! Now lets add a couple of Custom Buttons and re-run the query…

PlatformActionAcount2.png

We now see CustomButton records appear…

PlatformActionQueryResults2.png

This next query reveals actions shown on a List View. I did note Custom List View buttons that require record selection did not appear however. I suspect this is due to them requiring more than a simple HTTP GET URL to invoke.

SELECT DeviceFormat, Label, Type, Section,
       ActionTarget, ActionTargetType, ActionListContext
  FROM PlatformAction
  WHERE ActionListContext = 'ListView' AND
        SourceEntity = 'Account' AND
        Section = 'Page' AND
        DeviceFormat = 'Aloha'

Other observations..

  • Prior to Summer’16 (out in preview as i write this), Apex SOQL was not supported, only REST API SOQL. This is due to a limitation with the internally applied LIMIT keyword. This has now been resolved in Summer’16, so Apex SOQL now works!
  • SourceEntity can also be given an SObject API name, e.g. SourceEntity = ‘Account’, the result here are object level buttons, like New or those you add to the MRU page.
  • DeviceFormat field value matters, if you leave it off, it defaults to Phone. Thus some actions will be missing from those in Desktop (Lightning Experience) or Aloha (Classic). I eventually found Custom Buttons using Visualforce pages that didn’t have the Lightning Supported checkbox set didn’t appear when querying with the Phone device type for example.
  • User context matters, actions returned are user and configuration sensitive, meaning the record itself, record type and associated layout all contribute to the actions returned. Custom Buttons for example need to be on the relevant layout.
  • Label and Icon information, there are also fields that allow you to render appropriate labels and icons for the actions.
  • Related List actions, you can also retrieve actions shown on related lists, search for RelatedList in the help topic here.
  • Describe actions? You will notice some actions have an ActionTargetType of Describe? These are invoked via an API, something i will cover in later blog.

So lets discuss the “virtual SObject” bit!?!

Your probably wondering what a virtual SObject is?

Well my best guess is its an SObject that is not backed by physical data in the Salesforce database. If you check the documentation you’ll see fields just like any other object and it supports SOQL (with some limitations). My thinking is the records for this object are dynamically generated on demand by doing all the heavy lifting internally to scan all the various historic places where actions have been defined.

Thank you Salesforce architects, this is now my #1 coolest Salesforce API!

Whats next?

  • For starters, no more URL hacking of those standard pages, no excuses now!
  • Helper class or Visualforce and/or Lighting component for actions?
  • Explore the Force.com Actions Developer Guide


6 Comments

Monitoring Record Activity via Data Replication API’s

ReplicateAPI.pngYou might be thinking having started to read this blog that the primary use case of Data Replication API’s is to provide replication, well yes and no! No in a sense it won’t replicate your data for you, it actually won’t even return your data. What it will do is tell you what record Id’s have been updated or deleted within a certain time frame. What happens next is up to you, you don’t even have to do any replication if you don’t want to!

As someone who loves to keep things as native as possible, when answering this StackExchange post, i found it quite cool to find that this API is actually available to Apex developers! The API consist of two Database class methods getUpdated and getDeleted. The former returns new and updated records, its up to you to decide if its a new record or existing depending on if you’ve seen the record Id before or not.

Note: The process around these API’s is explained in more detail in the SOAP Developers Guide, so its worth reading this along with the Apex Developers Guide references. The general polling process is described here and limits and considerations here.

The API’s could not be easier to use, the following shows how to pull a list of record Id’s for updates made to records for a given object in the last hour.

Database.GetUpdatedResult r =
  Database.getUpdated(
    'MyObject__c', Datetime.now().addHours(-1), Datetime.now());
LastDateCovered.png

Salesforce documentation relating to the latestDateCovered field

Neither methods appear to consume any query or DML governor limits, though as noted above have some limits of their own. The GetUpdatedResult (described in more detail in the SOAP API documentation) contains a latestDateCovered field. This value should be retained and used in subsequent getUpdated calls.

Its unclear what Salesforce means by safety in the documentation, though the note relating to long running batch processes does make sense. This aspect highlights a key difference between attempting to query whats changed yourself based on the audit fields. The getDeleted method also works in the same way.

Its worth considering these API’s as a possible and lighter alternative to using Apex Triggers or UI’s to invoke custom behaviour when records are manipulated. Unlike Triggers you don’t know the specific changes, though Field Audit information could be queried if needed.

So be it a replication to another cloud via an Apex HTTP Callout or simply monitoring record activity into some org wide stats. Having Apex support allows you to keep things native via an Apex Schedule job to poll this API as often as you wish. With the advent of External Objects aka Lightning Connect other native possibilities start to present themselves…


30 Comments

Setup Audit Trail API in Winter’16

Winter’16 was a bit low on API for me, but one thing i just found hiding in the New Objects section, was this…

SetupAuditTrail, “Represents changes you or other administrators made in your organization’s Setup area.”

WBAuditWow, this is a BIG thing and opens up a lot of tooling and greater compliance support for changes around orgs. Prior to this, folks where so keen to get hold of this information programatically they would resort to web scraping it from the Salesforce Setup menu!  So I set about giving it a spin via Developer Workbench and learning more about the object.
WBAuditResults

There is also much better data export support via tools such as DataLoader.io (and of course other tools)….

AuditDataLoaderIO

So in addition to Salesforce API’s (used by the above tools), it is also available via Apex SOQL! The following selects all audit records relating to users from a certain email domain.

List<SetupAuditTrail> stuffDoneByConsultants = 
    [SELECT Id,
     	Action,
     	CreatedBy.Name,
     	CreatedDate,
     	Display,
     	Section 
     FROM SetupAuditTrail 
     WHERE CreatedBy.Email LIKE '%xyzconsulting.com%'];

So what else can we do with it? Well… not a lot more sadly, doing an Apex Describe shows that its basically only query-able, no triggers, replication API or indeed streaming API, which while not a total surprised would have been very cool!

Age of Records?

Through the long standing CSV download facility under setup, only 6 months worth of data is available. However running queries in my various long standing orgs i’m seeing data going back as far as all time?!? Although there is no documentation to confirm, and i would honestly would not be surprised to see some limit here, perhaps those of you running long standing production orgs can confirm via the comments below?

What are its fields?

AuditFieldsAs you can see the SetupAuditTrail objects fields are not the most ideal to interpret the data, aside from CreatedBy field (which supports relationship walking to the User object). The most interesting are Action, Section and Display, the later is the one that actually contains the object, field, layout or whatever has changed. The challenge here is its embedded in a message and not called out separately, so there is a bit of parsing to be done here.

IMPORTANT NOTE: The only gap i can see so far is the Delegate User (found in the Setup UI and CSV download) appears to be missing from the API at the moment. Yet it is documented as follows… ‘The Login-As user who executed the action in Setup. If a Login-As user didn’t perform the action, this field is blank.’

So what next?

  • Well i see AuditForce is an example of application tool that was created to better report and dashboard on this information, this tool could be enhanced to use this API now and remove the current web scraping hack the developer (Daniel Peter) was forced to utilise back then.
  • With Apex support its also possible to write Apex Scheduled jobs that periodically scan for certain updates and apply your own rules and notifications.
  • I was thinking it might also be useful to have a nice Lighting Component perhaps?
  • The Setup UI does not permit filtering or even sorting, it would probably not require to much coding to get something like the excellent Data Table component show results of queries from this object (as featured in my List View API blog).
  • Finally given this is available from Salesforce REST API, its also feasible to aggregate into a single console audit information from say multiple sandboxes (something Daniel hints at in his AuditForce blog).

 


Leave a comment

Using Action Link Templates to Declaratively call API’s

ActionLinkSetupSalesforce recently introduced a new platform feature which has now become GA called Action Link Templates. Since then its been staring me in the face and bugging me that i didn’t quite understand them until now…

While there is quite a lot of information in the Salesforce documentation, i was still a bit lost as to what even an Action Link was. It turns out that they are a means to define actions that can appear in a Chatter Post to call external or Salesforce web based API’s. Thus allowing users to do more without leaving their feed.

After realising its a means to link user actions with API’s. I could not resist exploring further with one my favourite external API’s, from LittleBits. The LittleBits cloud API can be used with cloud connected devices constructed by snapping together modules.

The following shows a Chatter Post i created with an Action Link button on it that without any code calls the LittleBits API to cause my device to perform an action. You can read more about my past exploits with Littlebits devices and Salesforce here.

ActionLinkPrimary

It appears for now at least, that such Chatter Posts need to be programatically created and as such lend themselves to integration use cases. While it is possible to create Chatter Posts with Action Links in code without using a template, thats more coding, and doesn’t encourage reuse of Action Link definitions which can also be packaged btw. So this blog focuses, as always on the best practice of balancing the best of declarative with minimal of coding to create the post itself. So first of all lets get some terminology out of the way…

  • Action Link, can actually be rendered as a button or a menu option that appears inline in the chatter post or in the overflow menu on the post. The button can either call an API, redirect to another web site or offer to download a file for the user. You have to add a Action Link to an Action Link Group before you can add it to a Chatter post.
  • Action Link Group, is a collection of one or more Action Links. The idea is the group presents a collection of choices you want to give to the user, e.g Accept, Decline. You can define a default choice, though the user can only pick one. Think of it like a group of radio controls or a choices type UI element. As mentioned above you can create both these 100% in code if you desire.
  • Action Link Group Template, is as the name suggests similar to the above, but allows for declarative definition and then programatic application of the buttons to be separated out. Once you start defining Action Links you’ll see they require a bit of knowledge about the underlying API. So in addition to the reuse benefit, a template is a good way to have someone else or package developer do that work for you. In order to make them generic, you can define place holders in Action Links, called bindings, that allow you to vary the information passed to the underlying API being called.

To define an Action Link you need to create the Action Link Group. Because we are using a template, this can be done using point and click. Under the Setup menu, under Create, you’ll find Action Link Templates, click New.

ActionLinkGroup

The Category field allows you to determine where the Action Link appears, in the body of the feed by selecting Primary action (as shown in the screenshot above) or in the overflow menu by selecting Overflow action, as shown in the screenshot below. Note that my example only defines one Action Link, you can define more.

ActionLinkOverflow

Through the Executions Allowed field, you can also determine if the Action Link can be invoked only once (first come first served) or once by each user who can see the chatter post (for example a chatter post to a group). You can read more about these and other fields here.

Your now ready to add an Action Link to the template, first study the documentation of your chosen web API, not that it can in theory be a SOAP based API, though REST is generally simpler. Hopefully, like the LittleBits API there are some samples that you can copy and paste to get you started. The following extract is what the LittleBits API documentation has to say about the API to control (output to) a device

This outputs 10% amplitude for 10 seconds:

curl -XPOST https://api-http.littlebitscloud.cc/devices/a84hf038ierj/output 
-H ‘Authorization: Bearer TOKEN’ 
-H ‘Accept: application/vnd.littlebits.v2+json’ 
–data ‘{“percent”:10,”duration_ms”:10000}’
“OK”

REST API documentation often uses a command line program called curl as an easy way to try out the API without having to write program code. In the screenshot below you can see how the curl parameters used in the extract above have been mapped to the fields when defining an Action Link. Note also that i have used the {!Bindings.var} syntax to define variable aspects, such as the deviceId, accessToken, percent and durationMs.

ActionLinkLittleBits

NOTE: The User Visibility setting is quite flexible and allows you to control who can actually press the button, as apposed to those who can actually see the Chatter Post.

Go back to your Action Link Group Template and check the Published checkbox. This makes it available for use when creating posts, but also has the effect of making certain aspects read only, such as the bindings. Though you can thankfully continue to tweak the API header and body templates defined on the Action Links.

Execute from Developer Console the following and it will create the Chatter Post shown in above. Currently neither Process Builder or Visual Flow are yet to support Action Link Templates when creating Chatter posts, which gives me an idea for a part two to this blog actually! For now please up vote this idea and review the following code.

// Specify values for Action Link bindings
Map<String, String> bindingMap = new Map<String, String>();
bindingMap.put('deviceId', 'yourdeviceid');
bindingMap.put('accessToken', 'youraccesstoken');
bindingMap.put('percent', '50');
bindingMap.put('durationMs', '10000');
List<ConnectApi.ActionLinkTemplateBindingInput> bindingInputs = new List<ConnectApi.ActionLinkTemplateBindingInput>();
for (String key : bindingMap.keySet()) {
    ConnectApi.ActionLinkTemplateBindingInput bindingInput = new ConnectApi.ActionLinkTemplateBindingInput();
    bindingInput.key = key;
    bindingInput.value = bindingMap.get(key);
    bindingInputs.add(bindingInput);
}

// Create an Action Link Group definition based on the template and bindings
ActionLinkGroupTemplate template = [SELECT Id FROM ActionLinkGroupTemplate WHERE DeveloperName='LittleBits'];
ConnectApi.ActionLinkGroupDefinitionInput actionLinkGroupDefinitionInput = new ConnectApi.ActionLinkGroupDefinitionInput();
actionLinkGroupDefinitionInput.templateId = template.id;
actionLinkGroupDefinitionInput.templateBindings = bindingInputs;
ConnectApi.ActionLinkGroupDefinition actionLinkGroupDefinition =
    ConnectApi.ActionLinks.createActionLinkGroupDefinition(Network.getNetworkId(), actionLinkGroupDefinitionInput);
System.debug('Action Link Id is ' + actionLinkGroupDefinition.actionLinks[0].Id);

// Create the post and utilise the Action Link Group created above
ConnectApi.TextSegmentInput textSegmentInput = new ConnectApi.TextSegmentInput();
textSegmentInput.text = 'Click to Send to the Device.';
ConnectApi.FeedItemInput feedItemInput = new ConnectApi.FeedItemInput();
feedItemInput.body = new ConnectApi.MessageBodyInput();
feedItemInput.subjectId = 'me';
feedItemInput.body.messageSegments = new List<ConnectApi.MessageSegmentInput> { textSegmentInput };
feedItemInput.capabilities = new ConnectApi.FeedElementCapabilitiesInput();
feedItemInput.capabilities.associatedActions = new ConnectApi.AssociatedActionsCapabilityInput();
feedItemInput.capabilities.associatedActions.actionLinkGroupIds = new List<String> { actionLinkGroupDefinition.id };

// Post the feed item.
ConnectApi.FeedElement feedElement =
    ConnectApi.ChatterFeeds.postFeedElement(
        Network.getNetworkId(), feedItemInput, null);

If you review the debug log produced the above code will output the Action Link Id. This can be used to retrieve response information from the Web API called. This is especially useful if the Web API callout failed, as only a generic failure message is shown to the end user. Once you have the Action Link Id paste the following code into Developer Console and review the debug log for the Web API response.

ConnectApi.ActionLinkDiagnosticInfo diagInfo =
    ConnectApi.ActionLinks.getActionLinkDiagnosticInfo(
        Network.getNetworkId(), '0AnG0000000Cd3NKAS');
System.debug('Diag output ' + diagInfo.diagnosticInfo);

Summary

Its true that Chatter Actions (formally Publisher Actions) are another means to customise the user experience of Chatter Posts, however these require development of Visualforce pages or Canvas applications. However by using Action Links you can provide a simpler platform driven user experience with much less coding.

By using Action Link Group Templates you can separate the concerns of delivering an integration, between those who know the external API’s and those that are driving the integration with Chatter via chatter posts referencing them. The bindings form the contract between the two.

Its also worth noting the Apex REST API‘s can be used from Action Links as well as other Salesforce API’s, in this case the authentication is handled for you, nice!