DEV Community

Cover image for Deploying to Salesforce Prod without the headaches: A step-by-step guide to smooth releases
Bohdan
Bohdan

Posted on

Deploying to Salesforce Prod without the headaches: A step-by-step guide to smooth releases

Apex API programming

Apex is a proprietary, object-oriented programming language used by Salesforce developers to execute flow and transaction control statements on the Salesforce platform. It is a powerful, strongly-typed language that looks and behaves like Java.

🛠️ Setting up your environment

Before you can program or deploy, you need to connect your local development environment (Visual Studio Code) to your Salesforce Org.

Watch: How to Connect VS Code to Salesforce Org This video provides a step-by-step guide on authorizing an org and setting up your project.

How to Connect VS Code to Salesforce Org

💻 Apex API Programming

Apex allows developers to:

  • Implement complex business logic: Custom validations and transaction control.
  • Create custom Web Services: Expose REST or SOAP endpoints.
  • Write Triggers: Execute code on database events (insert, update, delete).

For example, a developer might create a REST service using the @RestResource annotation to enable a web application to retrieve and update a customer's service requests quickly.

🚀 How to deploy updates to the Salesforce Production Environment

Deploying updates involves moving metadata from a lower environment (Sandbox) to Production. While you can deploy an entire project, developers often need to deploy specific files to save time and reduce risk.

Use the following command to deploy specific Apex classes within your project:

sf deploy metadata -m "ApexClass:ContactManager" -m "ApexClass:ContactManagerTest" --test-level RunSpecifiedTests --tests ContactManagerTest
Enter fullscreen mode Exit fullscreen mode

Here is the breakdown of what this command does:

  • sf deploy metadata: This initiates the deployment process focusing on specific metadata components rather than the whole source directory.
  • -m "ApexClass:ContactManager": The -m flag stands for Metadata. This tells the CLI to only deploy the Apex Class file named "ContactManager".
  • -m "ApexClass:ContactManagerTest": We use the flag again to include the corresponding Test Class. It is best practice to always deploy the code and its test together.
  • --test-level RunSpecifiedTests: This is a crucial efficiency flag. By default, production deployments run all local tests. This flag tells Salesforce: "Do not run every test in the system; only run the ones I list."
  • --tests ContactManagerTest: This explicitly lists the test class to execute. If this test passes (and covers enough lines of code), the deployment succeeds.

Why use this? If your organization has thousands of tests that take 2 hours to run, using RunSpecifiedTests allows you to deploy a hotfix in minutes by only validating the relevant code.

📝 Code Examples

Below are examples of the classes referenced in the command above.

  1. The REST Resource Class (ContactManager.cls)

This class uses the @RestResource annotation to define the endpoint URL. It includes a GET method to retrieve data and a POST method to create new records.

@RestResource(urlMapping='/Contacts/*')
global with sharing class ContactManager {

    // HTTP GET: Retrieve a Contact by ID from the URL
    // Endpoint: https://your-instance.salesforce.com/services/apexrest/Contacts/<ContactId>
    @HttpGet
    global static Contact getContactById() {
        RestRequest req = RestContext.request;

        // Grab the contactId from the end of the URL
        String contactId = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);

        Contact result = [SELECT Id, Name, Email, Phone FROM Contact WHERE Id = :contactId];
        return result;
    }

    // HTTP POST: Create a new Contact
    // Endpoint: https://your-instance.salesforce.com/services/apexrest/Contacts/
    @HttpPost
    global static ID createContact(String lastName, String firstName, String email, String phone) {
        Contact thisContact = new Contact(
            LastName = lastName,
            FirstName = firstName,
            Email = email,
            Phone = phone
        );
        insert thisContact;
        return thisContact.Id;
    }
}
Enter fullscreen mode Exit fullscreen mode
  1. The Test Class (ContactManagerTest.cls)

Testing REST services in Apex requires a specific step: mocking the RestContext. You must manually construct the Request and Response objects within the test method so the code has a context to run against.

@isTest
private class ContactManagerTest {

    @testSetup
    static void makeData() {
        Contact c = new Contact(LastName='Test', FirstName='Unit', Email='test@example.com');
        insert c;
    }

    @isTest
    static void testGetContactById() {
        // 1. Query the record created in testSetup
        Contact c = [SELECT Id FROM Contact LIMIT 1];

        // 2. Set up the RestContext
        RestRequest req = new RestRequest(); 
        RestResponse res = new RestResponse();

        // Simulate the URL structure defined in the main class
        req.requestURI = '/services/apexrest/Contacts/' + c.Id;
        req.httpMethod = 'GET';

        // Assign the mock request to the context
        RestContext.request = req;
        RestContext.response = res;

        // 3. Call the method
        Test.startTest();
        Contact result = ContactManager.getContactById();
        Test.stopTest();

        // 4. Assertions
        System.assert(result != null);
        System.assertEquals('Test', result.LastName);
    }

    @isTest
    static void testCreateContact() {
        Test.startTest();
        // Call the POST method directly
        ID thisContactId = ContactManager.createContact('Doe', 'John', 'john.doe@example.com', '555-1234');
        Test.stopTest();

        // Verify record exists
        System.assert(thisContactId != null);
        Contact c = [SELECT LastName FROM Contact WHERE Id = :thisContactId];
        System.assertEquals('Doe', c.LastName);
    }
}
Enter fullscreen mode Exit fullscreen mode

Key Concepts in this Example

  • @RestResource(urlMapping='/Contacts/*'): This exposes the class at the base URL /services/apexrest/Contacts/.
  • global: Methods exposed as Web Services must be defined as global.
  • RestContext: A system class that allows your code to access the incoming HTTP Request (RestContext.request) and the outgoing Response (RestContext.response).
  • Dynamic ID Parsing: In the GET method, we parse the URL to find the ID (substring(req.requestURI.lastIndexOf('/')+1)). This mimics standard REST behavior (e.g., GET /Contacts/003xxxxxxxxxxxx).

Summary

Developing on Salesforce requires a dual mastery: Apex API programming for crafting robust, custom business logic and effective deployment strategies for moving those solutions safely to the Production environment.

Key Takeaways for Success

  • Code Quality is Paramount: Always adhere to Salesforce best practices, especially writing bulkified code to handle large data volumes efficiently.
  • Testing is Non-Negotiable: Deployment hinges on your Apex Test Classes. Achieving the minimum 75% code coverage is mandatory for Production deployment, but striving for 100% ensures stability.
  • Embrace the CLI: Using the Salesforce CLI (sf) for targeted, automated deployments (like using --test-level RunSpecifiedTests) offers speed and reliability far superior to traditional Change Sets.

Top comments (1)

Collapse
 
0ca9 profile image
Gin

Thank you! It was helpful