Oracle to Salesforce Integration: Handling Inbound REST API

 

Introduction

This blog extends our previous guide on Salesforce-to-Oracle outbound integration by focusing on an inbound REST API integration where Oracle sends customer data (including Orders and Addresses) to Salesforce to create or update records. We’ll provide a detailed Apex REST service with comprehensive comments to explain the @RestResource and @HttpPost annotations and their purpose. Additionally, we’ll clarify when and how to use a Named Credential in inbound integrations, particularly for scenarios requiring outbound callbacks to Oracle. This guide is beginner-friendly, assuming basic Salesforce admin/developer knowledge and familiarity with the objects from the outbound integration.

Use Case

When a customer record is updated in Oracle (e.g., status changes or new orders are added), Oracle sends a REST API request to Salesforce to:

  • Update or create a Customer__c record and its related Order__c and Address__c records.

  • Log the request and response in Integration_Log__c for tracking.

  • Return a success or failure message to Oracle.

  • Optional Callback: Salesforce may call Oracle to validate data or confirm receipt, using a Named Credential for secure authentication.




Example Scenario: Oracle sends a JSON payload with customer details, orders, and addresses. Salesforce updates the records, logs the transaction, and optionally calls Oracle to confirm processing.

Why Oracle-to-Salesforce Integration?

  • Data Consistency: Sync Oracle’s operational data with Salesforce’s customer data.

  • Automation: Reflect Oracle updates in Salesforce without manual intervention.

  • Auditability: Log all requests and responses for debugging and compliance.

  • Flexibility: Support callbacks to Oracle for validation or confirmation using Named Credentials.


Salesforce-Side Prerequisites

The prerequisites remain the same as in the previous blog, with additions for Named Credentials:

  1. Custom Objects:

    • Customer__c: Standard object with fields like Name, Status__c, Email__c, and Oracle_Customer_ID__c (External ID, Unique).

    • Order__c: Child of Customer__c with fields like Order_Date__c, Amount__c, and Oracle_Order_ID__c (External ID, Unique).

    • Address__c: Child of Customer__c with fields like Street__c, City__c, State__c, Zip_Code__c, Country__c.

    • Integration_Log__c: Stores integration details with fields:

      • Customer__c (Lookup to Customer__c)

      • Request_Body__c (Long Text Area)

      • Response_Body__c (Long Text Area)

      • Status_Code__c (Text)

      • Timestamp__c (DateTime)

      • Success__c (Checkbox)

      • Error_Message__c (Long Text Area)

  2. Integration User:

    • Use a Salesforce Integration User with the Minimum Access – API Only Integrations profile.

    • Assign a permission set with read/write access to Customer__c, Order__c, Address__c, Integration_Log__c, and API access.

    • Generate a security token for OAuth or username/password authentication.

  3. Connected App:

    • Create a Connected App (Setup > Apps > App Manager > New Connected App) for Oracle to authenticate via OAuth 2.0.

    • Set scopes: api, id, refresh_token.

    • Share the Client ID, Client Secret, and login URL (e.g., https://login.salesforce.com) with the Oracle team.

  4. Named Credential (For Callbacks):

  • When Needed: If Salesforce needs to make an outbound call to Oracle (e.g., to validate the customer ID or send a confirmation), use a Named Credential to securely store Oracle’s API endpoint and authentication details.

  • Setup:

  • Go to Setup > Security > Named Credentials > New.

Name: Oracle_Callback

  • URL: Oracle’s API endpoint (e.g., https://oracle-erp.com/api).

  • Identity Type: Named Principal.

  • Authentication Protocol: OAuth 2.0 or Password Authentication.

  • Details: Provide Oracle’s Client ID, Client Secret, or username/password (consult Oracle team).

  • Allow Merge Fields in HTTP Body: Enable for dynamic payloads.

  • Usage: In Apex, use callout:Oracle_Callback to make secure HTTP requests without hardcoding credentials.

  1. Sandbox Environment:

    • Test in a sandbox to avoid impacting production data.

    • Create test records for Customer__c, Order__c, and Address__c.

  2. API Access:

    • Ensure Enterprise or higher edition with REST API access.

    • Verify the integration user has API permissions.


Step-by-Step Implementation

Step 1: Get API Details from Oracle Team

  • Salesforce Endpoint: You’ll provide the REST endpoint URL after creating the Apex REST service (e.g., https://yourInstance.salesforce.com/services/apexrest/oracle/customer/update/).

  • Authentication: Share the Connected App’s Client ID, Client Secret, and login URL for OAuth 2.0.

  • JSON Payload: Request a sample JSON from Oracle, e.g.:

    {
      "oracleCustomerId": "CUST123",
      "name": "John Smith",
      "email": "john@example.com",
      "status": "Completed",
      "orders": [
        { "orderId": "ORD001", "orderDate": "2024-04-01", "amount": 100 },
        { "orderId": "ORD002", "orderDate": "2024-04-02", "amount": 150 }
      ],
      "addresses": [
        { "street": "Main St", "city": "Mumbai", "state": "MH", "zipCode": "400001", "country": "India" }
      ]
    }
  • Callback Endpoint (If Needed): Ask Oracle for their API endpoint, authentication details (e.g., OAuth or API key), and expected payload for callbacks.

Step 2: Verify Custom Objects

  • Confirm Customer__c, Order__c, Address__c, and Integration_Log__c are set up.

  • Ensure Oracle_Customer_ID__c (Customer__c) and Oracle_Order_ID__c (Order__c) are External ID fields for upsert operations.

Step 3: Set Up Named Credential (For Callbacks)

  • Scenario: Salesforce calls Oracle to validate the oracleCustomerId before processing or to confirm successful processing.

  • Steps:

    • Go to Setup > Security > Named Credentials > New.

    • Label: Oracle_Callback

    • Name: Oracle_Callback

    • URL: Oracle’s API endpoint (e.g., https://oracle-erp.com/api/validate).

    • Identity Type: Named Principal.

    • Authentication Protocol: Choose based on Oracle’s requirements (e.g., OAuth 2.0 or Password Authentication).

    • Authentication Details: Enter Client ID, Client Secret, or username/password provided by Oracle.

    • Allow Merge Fields in HTTP Body: Enable for dynamic JSON payloads.

  • Why Use Named Credential?:

    • Securely stores Oracle’s endpoint and credentials, avoiding hardcoding.

    • Simplifies Apex callouts using callout:Oracle_Callback.

    • Supports OAuth or password authentication, reducing manual token management.

  • When Not Needed: If Salesforce only receives and processes Oracle’s data without calling Oracle, skip this step.

Step 4: Create Apex REST Service

Below is the updated Apex REST service with detailed comments explaining @RestResource, @HttpPost, and Named Credential usage. The code includes a callback to Oracle using a Named Credential to validate the customer ID.

// @RestResource annotation exposes this Apex class as a REST endpoint
// urlMapping defines the URL path for the endpoint (e.g., /services/apexrest/oracle/customer/update/)
// This allows external systems like Oracle to send HTTP requests to Salesforce
@RestResource(urlMapping='/oracle/customer/update/*')
global with sharing class OracleCustomerReceiver {

    // @HttpPost annotation indicates this method handles HTTP POST requests
    // POST is used because Oracle is sending data to create/update records
    // The method processes the incoming JSON, updates Salesforce records, and returns a response
    @HttpPost
    global static void handleCustomerUpdate() {
        // Get the REST request and response objects
        RestRequest req = RestContext.request;
        RestResponse res = RestContext.response;
       
        // Initialize log record to store request/response details
        Integration_Log__c log = new Integration_Log__c();

        try {
            // Step 1: Capture request details
            String requestBody = req.requestBody.toString();
            log.Request_Body__c = requestBody;
            log.Timestamp__c = System.now();

            // Step 2: Parse JSON payload
            Map<String, Object> payload = (Map<String, Object>) JSON.deserializeUntyped(requestBody);
            String oracleCustomerId = (String) payload.get('oracleCustomerId');
            String name = (String) payload.get('name');
            String email = (String) payload.get('email');
            String status = (String) payload.get('status');
            List<Object> orders = (List<Object>) payload.get('orders');
            List<Object> addresses = (List<Object>) payload.get('addresses');

            // Step 3: Validate payload
            if (String.isBlank(oracleCustomerId) || String.isBlank(name)) {
                throw new CustomException('Missing required fields: oracleCustomerId or name');
            }

            // Step 4: Validate customer ID with Oracle using Named Credential
            // Named Credential (Oracle_Callback) securely stores Oracle's endpoint and credentials
            // This callout checks if the oracleCustomerId exists in Oracle
            HttpRequest validateReq = new HttpRequest();
            validateReq.setEndpoint('callout:Oracle_Callback/validateCustomer?customerId=' + EncodingUtil.urlEncode(oracleCustomerId, 'UTF-8'));
            validateReq.setMethod('GET');
            validateReq.setHeader('Content-Type', 'application/json');
            Http http = new Http();
            HttpResponse validateRes = http.send(validateReq);

            if (validateRes.getStatusCode() != 200) {
                throw new CustomException('Invalid customer ID: ' + validateRes.getBody());
            }

            // Step 5: Upsert Customer__c
            // Uses Oracle_Customer_ID__c as External ID to update existing record or create new
            Customer__c customer = new Customer__c(
                Oracle_Customer_ID__c = oracleCustomerId,
                Name = name,
                Email__c = email,
                Status__c = status
            );
            upsert customer Oracle_Customer_ID__c;
            log.Customer__c = customer.Id;

            // Step 6: Upsert Orders
            List<Order__c> ordersToUpsert = new List<Order__c>();
            for (Object ord : orders) {
                Map<String, Object> orderData = (Map<String, Object>) ord;
                ordersToUpsert.add(new Order__c(
                    Customer__c = customer.Id,
                    Oracle_Order_ID__c = (String) orderData.get('orderId'),
                    Order_Date__c = Date.valueOf((String) orderData.get('orderDate')),
                    Amount__c = (Decimal) orderData.get('amount')
                ));
            }
            if (!ordersToUpsert.isEmpty()) {
                upsert ordersToUpsert Oracle_Order_ID__c;
            }

            // Step 7: Upsert Addresses
            // Note: Addresses lack an External ID, so deduplication logic may be needed
            List<Address__c> addressesToUpsert = new List<Address__c>();
            for (Object addr : addresses) {
                Map<String, Object> addrData = (Map<String, Object>) addr;
                addressesToUpsert.add(new Address__c(
                    Customer__c = customer.Id,
                    Street__c = (String) addrData.get('street'),
                    City__c = (String) addrData.get('city'),
                    State__c = (String) addrData.get('state'),
                    Zip_Code__c = (String) addrData.get('zipCode'),
                    Country__c = (String) addrData.get('country')
                ));
            }
            if (!addressesToUpsert.isEmpty()) {
                upsert addressesToUpsert;
            }

            // Step 8: Send confirmation callback to Oracle using Named Credential
            // This notifies Oracle that the data was processed successfully
            HttpRequest confirmReq = new HttpRequest();
            confirmReq.setEndpoint('callout:Oracle_Callback/confirm');
            confirmReq.setMethod('POST');
            confirmReq.setHeader('Content-Type', 'application/json');
            confirmReq.setBody('{"customerId": "' + oracleCustomerId + '", "status": "Processed"}');
            HttpResponse confirmRes = http.send(confirmReq);
            // Log callback response (optional)
            log.Response_Body__c = 'Customer updated; Confirmation sent: ' + confirmRes.getBody();

            // Step 9: Log success
            log.Status_Code__c = '200';
            log.Success__c = true;
            insert log;

            // Step 10: Return success response to Oracle
            res.statusCode = 200;
            res.responseBody = Blob.valueOf('{"message": "Customer updated successfully"}');

        } catch (Exception ex) {
            // Log error details
            log.Response_Body__c = ex.getMessage();
            log.Status_Code__c = '500';
            log.Success__c = false;
            log.Error_Message__c = ex.getMessage();
            insert log;

            // Return error response to Oracle
            res.statusCode = 500;
            res.responseBody = Blob.valueOf('{"error": "' + ex.getMessage() + '"}');
        }
    }

    // Custom exception class for throwing specific errors
    public class CustomException extends Exception {}
}

Key Comments Explained:

  • @RestResource: Marks the class as a REST endpoint, making it accessible via a URL (e.g., /services/apexrest/oracle/customer/update/). The urlMapping parameter defines the endpoint path.

  • @HttpPost: Specifies that the handleCustomerUpdate method handles HTTP POST requests, which is appropriate for Oracle sending data to create/update records.

  • Named Credential: Used in the validateReq and confirmReq callouts to securely call Oracle’s API. The callout:Oracle_Callback syntax references the Named Credential, eliminating the need to hardcode endpoints or credentials.

Step 5: Configure Named Credential

  • When to Use: In this inbound integration, a Named Credential is used for outbound callouts from Salesforce to Oracle, such as:

    • Validating the oracleCustomerId before processing the request.

    • Sending a confirmation to Oracle after processing.

  • Setup Steps:

    • Go to Setup > Security > Named Credentials > New.

    • Label: Oracle_Callback

    • Name: Oracle_Callback

    • URL: Oracle’s base API endpoint (e.g., https://oracle-erp.com/api).

    • Identity Type: Named Principal.

    • Authentication Protocol: OAuth 2.0 (preferred) or Password Authentication.

    • Details: Enter Client ID, Client Secret, or username/password (provided by Oracle).

    • Allow Merge Fields in HTTP Body: Enable for dynamic payloads.

  • In Apex: Reference the Named Credential with callout:Oracle_Callback, as shown in the code (e.g., callout:Oracle_Callback/validateCustomer).

  • When Not Needed: If Salesforce only processes Oracle’s incoming request without calling Oracle, skip the Named Credential.

Step 6: Expose the REST Endpoint

  • Endpoint URL: https://yourInstance.salesforce.com/services/apexrest/oracle/customer/update/

  • Authentication: Oracle must use OAuth 2.0 (preferred) or username/password with security token.

    • OAuth Example:

      POST /services/oauth2/token
      Host: login.salesforce.com
      Content-Type: application/x-www-form-urlencoded
      grant_type=client_credentials&client_id=<Client_ID>&client_secret=<Client_Secret>
    • Response provides an access_token for the Authorization header.

  • Share the endpoint URL, Client ID, Client Secret, and authentication instructions with the Oracle team.

Step 7: Test the Integration

  1. Prepare Test Data:

    • Create a Customer__c record with Oracle_Customer_ID__c = "CUST123".

    • Add sample Order__c and Address__c records.

  2. Simulate Oracle’s Request:

    • Use Postman to send a POST request:

      POST /services/apexrest/oracle/customer/update/
      Host: yourInstance.salesforce.com
      Authorization: Bearer <access_token>
      Content-Type: application/json

      {
        "oracleCustomerId": "CUST123",
        "name": "John Smith",
        "email": "john@example.com",
        "status": "Completed",
        "orders": [
          { "orderId": "ORD001", "orderDate": "2024-04-01", "amount": 100 },
          { "orderId": "ORD002", "orderDate": "2024-04-02", "amount": 150 }
        ],
        "addresses": [
          { "street": "Main St", "city": "Mumbai", "state": "MH", "zipCode": "400001", "country": "India" }
        ]
      }
  3. Verify Results:

    • Confirm Customer__c, Order__c, and Address__c records are updated.

    • Check Integration_Log__c for:

      • Request_Body__c: JSON from Oracle.

      • Response_Body__c: Success or error message, including callback response.

      • Status_Code__c: 200 or 500.

      • Success__c: True or False.

    • Verify the callback to Oracle (check Oracle logs or ask the Oracle team).

  4. Test Edge Cases:

    • Send invalid JSON (e.g., missing oracleCustomerId).

    • Simulate a failed callback response from Oracle.

Step 8: Monitor and Debug

  • Integration_Log__c: Review logs for errors or failed requests.

  • Debug Logs: Enable for the integration user to troubleshoot Apex issues.

  • API Usage: Monitor via Setup > Integrations > API Usage to stay within limits.


Best Practices

  1. Clear Comments: Use detailed comments in Apex to explain annotations like @RestResource and @HttpPost, making the code self-documenting.

  2. Secure Callouts: Use Named Credentials for all outbound calls to Oracle to avoid hardcoding credentials.

  3. Error Handling: Log all errors in Integration_Log__c and return meaningful responses to Oracle.

  4. Data Validation: Validate incoming JSON and use External IDs to prevent duplicates.

  5. Testing: Test in a sandbox with various scenarios (valid/invalid data, callback failures).

  6. Compliance: Ensure data handling complies with GDPR, CCPA, or other regulations.


JSON Payload Explained

Oracle’s JSON payload:

{
  "oracleCustomerId": "CUST123",
  "name": "John Smith",
  "email": "john@example.com",
  "status": "Completed",
  "orders": [
    { "orderId": "ORD001", "orderDate": "2024-04-01", "amount": 100 },
    { "orderId": "ORD002", "orderDate": "2024-04-02", "amount": 150 }
  ],
  "addresses": [
    { "street": "Main St", "city": "Mumbai", "state": "MH", "zipCode": "400001",
"country": "India" }
  ]
}

Conclusion

This Oracle-to-Salesforce inbound REST API integration enables Oracle to update Salesforce records seamlessly. The Apex REST service, with clear comments on @RestResource and @HttpPost, processes incoming data and logs transactions. Named Credentials simplify secure outbound callouts to Oracle for validation or confirmation. Test thoroughly in a sandbox and collaborate with the Oracle team to ensure smooth integration.

Explore Salesforce REST API Documentation and Oracle REST API Documentation for more details. Try deploying the Apex service and share your results!


Thank you for exploring 

I hope this guide provided valuable insights into real-time inbound REST API integration connections.
For a better experience, I recommend viewing this blog on a desktop, as the mobile version is still being optimized.
Your feedback and thoughts mean a lot—please share your comments below.

Happy integrating!

Blog by Yeshwanth


Comments

Popular posts from this blog

๐ŸŒ Real-Time Salesforce to Oracle REST API Integration – Beginner Guide with JSON and Logging

Salesforce Integration Basic Details