Salesforce content management allows users to store information such as documents, images, audio, and video files in their Salesforce org. On occasion, users may require to quickly and easily download certain content items from the Salesforce org using their own custom code.
Node-fetch is a popular Node.js library used by developers to create applications with the help of middleware, through a programming interface. Node-fetch is especially suitable for downloading Salesforce ContentVersion files.
Let’s download a file (ContentVersion) from Salesforce using node-fetch
Queueable interface allows apex developers to run complex, lengthy, and asynchronous processes that normally couldnât be run in synchronous invocations. Queueables are simple to implement and provide several advantages over the old @future annotation, making them a great way to make sure your apex code runs reliably and efficiently.
Async processing is an efficient way to run our algorithms. This mostly involves queues to control how many executions are being processed at a time. Different languages and platforms implement async processing in different ways but the idea is the same. One of the ways (yes, there are more than one) in Salesforce to execute some algorithms that require heavy processing, is the interface Queueable. Another example is the annotation @future but we will put our focus on implementing the interface Queueable in Apex classes.
One of the big challenges for most of the async processing approaches is the absence of order on the execution. This is kind of “Do it when possible”.
In this example we are just inserting a new account. You may think that’s not a heavy operation but what if your org is full of Flows (Process Builder) or triggers that are being executed every time an account is inserted? CPU limit errors will appear soon unless you stay away of the main thread execution.
By using queueable, you will stay away from limits, especially CPU limits.
public class MyQueueable implements Queueable{
private final String myAttribute;
public MyQueueable(String myAttribute){
this.myAttribute = myAttribute;
}
public void execute(QueueableContext context) {
System.debug('executing with: '+myAttribute);
// do some heavy work
Account a = new Account(Name=myAttribute);
insert a;
// enqueue another job if you wish
}
public static void enqueueJob(){
ID jobID = System.enqueueJob(new MyQueueable('my test param'));
System.debug('job id: '+jobID);
}
}
How to enqueue our job
ID jobID = System.enqueueJob(new MyQueueable('my test param'));
Or you can create a method to use it as a shortcut
MyQueueable.enqueueJob();
How to monitor Apex Jobs
You can monitor Apex Jobs from Setup -> Environments -> Jobs -> Apex Jobs. Also you can query your job in case you have to something we them from your code or you just like monitor this way.
SELECT Status,NumberOfErrors, ExtendedStatus
FROM AsyncApexJob
ORDER BY CreatedDate DESC
How to write unit tests for Apex Jobs
@isTest
public class MyQueueableTest {
@isTest
static void myTest() {
String param = 'tes param '+Math.random();
// startTest/stopTest block to force async processes to run in the test.
Test.startTest();
System.enqueueJob(new MyQueueable(param));
Test.stopTest();
// Validate that the job has run by verifying that the record was created.
Account acct = [SELECT Name FROM Account WHERE Name = :param LIMIT 1];
System.assertEquals(param, acct.Name);
}
}
In Salesforce, developers can invoke Apex methods from within the Flow Builder to execute code logic. Apex methods provide the capability of customizing Flows as needed, allowing users to create new features, validate data, and access records or web services. This post will walk you through how to invoke an Apex method from the Flow Builder.
What about Flow Builder
Flow Builder is the replacement for Process Builder in Salesforce. Both of them are useful to automate several kinds of processes but sometimes the out-of-the-box functionality is not enough and we have to go to a custom one such as some lines in an Apex class. Let’s see then how to invoke an Apex method through the Flow Builder.
Salesforce setup – Search Flow Builder
Create Apex class with Invocable method
public class MyFlowClass {
@InvocableMethod(label='My flow method'
description='A cool description about this method'
category='Account')
public static void execute(List<id> accountIds){
System.debug('account ids: '+accountIds);
}
}
</id>
Create the Flow
New Flow – Select typeConfigure FlowConfigure FlowConfigure FlowConfigure Flow
Remember to activate the Flow!
Test the Flow
Our flow will be executed every time we create or modify any account so let’s do that.
First of all open the Developer Console and go to the Logs tab. Open an account, edit any field and save it. After that see the log generated and make sure the debug line is present.
Salesforce and Amazonâs Web Services (AWS) are two powerful software development and cloud computing tools. In this post, weâll discuss how these two tools can be integrated for an optimized and efficient workflow.
The integration of Salesforce and AWS allows businesses to take advantage of the scalability, reliability, and security of both platforms. The integration enables businesses to quickly and efficiently move key data and applications between the cloud platforms and reduces the complexity of integration.
There are many ways to sync up our Salesforce data with third parties in realtime. One option is a mix of Salesforce and AWS services, specifically Change Data Capture from Salesforce and AppFlow from AWS. We are going to build a Cloudformation yml file with all that we need to deploy our integration on any AWS environment. However can be a good option to do it first by point and click through the AWS console and then translate it into a Cloudformation template.
If you are using Heroku and Postgres, Heroku Connect is a good option too
About Salesforce Change Data Capture
Receive near-real-time changes of Salesforce records, and synchronize corresponding records in an external data store.
Change Data Capture
publishes change events, which represent changes to Salesforce records. Changes include creation of a new record, updates to an existing record, deletion of a record, and undeletion of a record.
Important:
Change Data Capture does not support relationships at the time this post was written (08/2021). This means you will only be able to sync up beyond your object unless you implement some tricks using Process Builder and Apex. That’s out of the scope of this post and we are going to see it in a different one because requires some extra steps and knowledge.
To start listening on specific object go to Setup -> Integrations -> Change Data Capture. Move the object you want to the right.
Advantages of using AppFlow approach
Data being transferred securely
Credentials are managed by Oauth process
No coding required unless you want to run some specific logic for every sync up
100% serverless, pay as use
Disadvantages of using AppFlow approach
The connection must exist before deploying the infrastructure. This is a manual step
This approach can take some time to learn and configure, specially if you are already familiar with callouts from Salesforce
Requirements for Salesforce
Your Salesforce account must be enabled for API access. API access is enabled by default for the Enterprise, Unlimited, Developer, and Performance editions.
Your Salesforce account must allow you to install connected apps. If this functionality is disabled, contact your Salesforce administrator. After you create a Salesforce connection in Amazon AppFlow, verify that the connected app named Amazon AppFlow Embedded Login App is installed in your Salesforce account.
The refresh token policy for the Amazon AppFlow Embedded Login App must be set to Refresh token is valid until revoked. Otherwise, your flows will fail when your refresh token expires.
You must enable change data capture in Salesforce to use event-driven flow triggers.
If your Salesforce app enforces IP address restrictions, you must grant access to the addresses used by Amazon AppFlow.
To create private connections using AWS PrivateLink, you must enable both Manager Metadata and Manage External Connections user permissions in your Salesforce account. Private connections are currently available in the us-east-1 and us-west-2 AWS Regions.
Architecture for the solution
Let say we want to listen to changes on Account object. Every time a new Account is created or updated there will be an event to AppFlow through Salesforce Data Capture.
We could add some logic in the Lambda function to decide if we are interested in that change or not.
How to create the Salesforce Oauth Connection
As we said, an Oauth connection must exist before deploying our stack to AWS. This is something we have to create by hand. If we deal with different environments in AWS, we can create as many connection as we want pointing to our different Salesforce instances.
Open your AWS console and go to Amazon App Flow
Go to View Flows and click on Connections
Click on Create Connection. Select production in case you have a dev org. Provide a connection name
Once you click on Continue, a Salesforce popup will be open. Put your Salesforce credentials to login
After that your connection will be created and available to use
It’s important we have a way to troubleshoot in case things go wrong. Since this integration deals with different AWS services, we have to see what we have available in each one.
The first question I asked myself when starting to write unit tests that involve files is: how do I upload files from my tests? Fortunately, dealing with files in Salesforce in a unit test context, is pretty easy.
Creating unit tests in Salesforce is a great way to ensure accurate data and maintain the integrity of Salesforce’s software applications. In this post, we’ll take a look at how to quickly and easily create text files in Salesforce to use them in your unit tests.
We are going to work with the new Salesforce files model and not with the old approach called “Notes and Attachments”.
If you still have Note and Attachments and you want to convert to Salesforce Files I recommend you install Magic Mover for Notes And Attachments to Lightning Experience
Straight to the point
Instantiate a ContentVersion with a name, description and a small content. In this case I will create a TXT file to keep it simple.
After creating the file we want to relate to one or many existing records such as an Account, Opportunity or even a custom object record.
To do that we have to insert a ContentDocumentLink
ContentDocumentLink cdl = new ContentDocumentLink();
cdl.ContentDocumentId = [SELECT Id, ContentDocumentId FROM ContentVersion WHERE Id =: cv.Id].ContentDocumentId;
cdl.LinkedEntityId ='ANY ID'; // <----- put your record id here, example: an account tid
cdl.ShareType = 'V';
insert cdl;
Now go to the associated record and see the file attachment. You will have to add the Files related list to the layout in case you don’t have it yet.
SFDX is the Salesforce command-line interface (CLI) used to deploy and manage your Salesforce applications. Unfortunately, an error can occur when authenticating with an auth code due to the grant type not being supported.
In Salesforce DX, you may experience an error when attempting to authenticate with an authorization code due to the “grant type not supported” error. This error usually occurs when you’re trying to authenticate with wrong instance URL.
For example let’s say you are trying to login to a sandbox
sfdx auth:web:login -a myusername@myorg.sandbox --instanceurl=https://mysandbox-domain.lightning.force.com
And you get this error in console:
ERROR running auth:web:login: Invalid client credentials. Verify the OAuth client secret and ID. Error authenticating with auth code due to: grant type not supported
In your browser you get this
Error authenticating with auth code due to: grant type not supported.
This is most likely not an error with the Salesforce CLI. Please ensure all information is accurate and try again.
Just in case please check the following before going to the solution
Check that your computer’s clock is accurate: Salesforce uses the OAuth protocol for authentication, which relies on accurate timekeeping. If your computer’s clock is off by more than a few minutes, you may encounter authentication errors.
Check your network connection: If your network connection is unstable or slow, you may encounter authentication errors. Make sure you have a stable internet connection.
Check your org’s settings: Make sure that your org is configured to allow API access and that your user account has the necessary permissions to access the API.
Try logging out and logging back in: Sometimes logging out of SFDX and logging back in can help resolve authentication issues.
The solution
The problem is you are using lightning.force.com domain instead of my.salesforce.com
sfdx auth:web:login -a myusername@myorg.sandbox --instanceurl=https://mysandbox-domain.my.salesforce.com
If none of these steps resolve the issue, you may need to reach out to Salesforce support for further assistance.
When you’re developing applications in Salesforce, you may need to retrieve the name of a country based on its ISO code. If this is the case, let’s implement an Apex method that you can use to simplify the process.
The method is called getCountryNameByIsoCode and it takes a string argument that represents the ISO code for a particular country. For example, if you want to retrieve the name of the United States you would use the ISO code US.
The country ISO code for this method is from the standard alpha-2. Example: UY for Uruguay, AR for Argentina, etc
public static String getCountryNameByIsoCode(String isoCode){
if(isoCode == null) return null;
Schema.DescribeFieldResult fieldResult = User.Countrycode.getDescribe();
List<Schema.PicklistEntry> pickListValues = fieldResult.getPicklistValues();
for( Schema.PicklistEntry pickListEntry : pickListValues) {
// pickListEntry.getLabel() returns the country name
// pickListEntry.getValue() returns the country code
if(pickListEntry.getValue().toLowerCase() == isoCode.toLowerCase()) {
return pickListEntry.getLabel();
}
}
return null;
}
When running the command that makes the login against our Sandbox org, it redirects to a localhost URL and then it display an error that doesn’t give us so much information
sfdx auth:web:login -a myuser@abc.com --instanceurl=https://xxxxx--xxxxx.my.salesforce.com
The error
Cannot read properties of undefined (reading ‘id’)
This is most likely not an error with the Salesforce CLI. Please ensure all information is accurate and try again.
Apex is a strongly typed, object-oriented programming language that allows developers to execute flow and transaction control statements on the Salesforce platform. It was developed by Salesforce and runs natively on their platform. Apex can be used to create custom business logic, automate processes and workflows, and integrate with external systems.
In short, Apex is a programming language for Salesforce that enables developers to build custom applications, automate business processes, and perform other tasks not possible with just point-and-click tools. It can be used to build custom triggers, classes, and interfaces to perform various functions on the Salesforce platform.
In Java, we can use Thread.sleep(1000) to delay the execution by one second. In Apex is not that easy since Salesforce is a multi-tenant environment. By Delaying the execution in the main thread we not only impact the users of our organization but also other Salesforce customers đ¤Ż. Thatâs why we donât have that sentence in Apex.
In a multi-tenancy environment, multiple customers share the same application, running on the same operating system, on the same hardware, and with the same data-storage mechanism. The distinction between the customers is achieved during application design, thus customers do not share or see each other’s data.
With some tricks, we can delay the execution without impacting our organizationâs resources. Salesforce provides one mechanism to schedule an algorithm for one time or in a recurrent manner.
global class MyScheduler implements Schedulable {
private final Id recordId;
public MyScheduler(Id recordId){
this.recordId = recordId;
}
global void execute(SchedulableContext sc){
System.debug('**** recordId: '+this.recordId+' date: '+Date.today());
// ****** Do your logic here ******
// abort to execute it only once
System.abortJob(sc.getTriggerId());
}
public static void schedule(){
String hour = String.valueOf(Datetime.now().hour());
String min = String.valueOf(Datetime.now().minute() + 1);
String ss = String.valueOf(Datetime.now().second());
//parse to cron expression
String nextFireTime = ss + ' ' + min + ' ' + hour + ' * * ?';
MyScheduler sc = new MyScheduler('0018F00000ABA3AQBX');
String name = 'Submited at: '+String.valueOf(Datetime.now())+ ' next: '+nextFireTime;
System.debug(name);
System.schedule(name, nextFireTime, sc);
}
}
AWS AppFlow is a fully managed cloud integration solution for moving data between SaaS applications. It enables customers to model and configure flows to synchronize data between applications with just a few clicks. When setting up a flow, customers may encounter an error that says âconflict executing request connector profile is associated with one or more flowsâ.
This error occurs when a connector profile used in a flow is associated to one or more other flows either in the same or another account. While the dependability of the flow connector
Let’s say you have a Salesforce connector (it is valid for any other available) and the token expired. The only way so far is to delete and recreate the connection again. Would be nice to keep the same connection and run the handshake again but it is impossible nowadays.
If we try to delete a connector from the AWS console and it is associated with one or many flows, it will display this error:
Conflict executing request: Connector profile: xxxxxxx is associated with one or more flows. If you still want to delete it, then make delete request with forceDelete flag as true. Some of the associated flows are: [xxxxx, xxxxxx]
The trick is to delete the connector from AWS CLI thus: