0

Writing a test class on the helper & apex class we are using for an API call. We are running into

System.JSONException: Unexpected character ('}' (code 125)): was expecting double-quote to start field name at [line:1, column:420] with (System Code) Class.FileFeed.doPost: line 16, column 1 Class.TestFileFeed.testDoPost: line 135, column 1.

The calls that are failing are just the post methods and I seem to be running into a loss as to what the issue might be.

File Feed Apex


@RestResource(urlMapping='/FileFeedV1')
global class FileFeed {
    // public List<Accounts> accounts;

    @HttpGet
    global static string doGet() {
        return 'This is a GET from the FileFeed service.';
    }

    @HttpPost
    global static string doPost() {
        ResponseJSON responseList = new ResponseJSON();
        RestRequest req = RestContext.request;
        List<Object> jsonWrapList = (List<Object>)JSON.deserializeUntyped(req.requestbody.tostring());
        responseList = processFileFeed(jsonWrapList); 
        return 'This is a POST from the FileFeed Service.';
    }

    //Inner class for defining JSON response
    public class ResponseJSON {
        public List<Result> results = new List<Result>();
    }
    //Inner class for storing JSON response properties
    public class Result {
        public String type;
        public string id;
        public String email;
        public String phone;
        public String error;
    }
    //Method to process incoming Web leads from Azure
    public static ResponseJSON processFileFeed(List<Object> inputJSON){
        ResponseJSON sfResponse = new ResponseJSON();
        List<File_Feed__c> changeList = new List<File_Feed__c>();
        List<Account> addList = new List<Account>();
        List<Object> jsonMapped = new List<Object>();
        String recordTypeId = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Employer').getRecordTypeId();
        List<Account> allAccounts = null;
        Map<String, Account> mappedAccounts = new Map<String, Account>();
        List<Account> allEmployerAccounts = null;
        Map<String, Account> mappedEmployerAccounts = new Map<String, Account>();

        for(Object record : inputJSON) {
            Map<String,Object> recordMapped =  FileFeedHelper.GetMappings(record);
            jsonMapped.add((Object) JSON.deserializeUntyped(JSON.serialize(recordMapped)));
            String groupNumber = String.valueOf(recordMapped.get('Group_Number_Form__c'));
            String personEmail = String.valueOf(recordMapped.get('PersonEmail')).toLowerCase();
            String action = '';
            if(recordMapped.containsKey('Action_Type__c')){
                action = String.valueOf(recordMapped.get('Action_Type__c'));
                recordMapped.remove('Action_Type__c');
            } else if(recordMapped.containsKey('Termination_Date')) {
                //check if termed based off 
                if(String.valueOf(recordMapped.get('Termination_Date')) != '') {
                    action = 'Termed';
                }
            }
            if(recordMapped.containsKey('Termination_Date')) {
                recordMapped.remove('Termination_Date');
            }
            if(action.toLowerCase() != 'add' && action.toLowerCase() != 'change') {
                action = 'Termed';
            }
            Boolean hasEffectiveDate = (String.ValueOf(recordMapped.get('Effective_Date__c')) != '' && String.ValueOf(recordMapped.get('Effective_Date__c')) != null);
            if(action.toLowerCase() == 'termed'){
                recordMapped.put('Member_Status__c','Cancelled');
                if(hasEffectiveDate){
                    recordMapped.put('Expiration_Date__c',(Object)String.ValueOf(FileFeedHelper.getEndOfMonth(recordMapped.get('Effective_Date__c'))));
                }
                recordMapped.put('Billing_Notes__c', 'Cancel');
                recordMapped.put('Cancel_Reason__c', 'Removed via File Feed');
            }
            if(hasEffectiveDate){
                recordMapped.put('Effective_Date__c', (Object)date.parse(String.valueOf(recordMapped.get('Effective_Date__c'))));
            }   
            if(allAccounts == null){
                allAccounts = Database.query('SELECT Id, Member_Status__c, Expiration_Date__c, Billing_Notes__c, Cancel_Reason__c, Group_Number_Form__c, ' + FileFeedHelper.getFields(recordMapped) + ' FROM Account WHERE Group_Number_Form__c != NULL');
                for(Account a : allAccounts) {
                    if(a.Group_Number_Form__C != null && a.PersonEmail != null) {
                        mappedAccounts.put(a.Group_Number_Form__c.toLowerCase() + a.PersonEmail.toLowerCase(), a);
                    }
                }
            }
            Account sfAccount = mappedAccounts.get(groupNumber + personEmail);
            if(sfAccount != null){
                for(String key : recordMapped.keySet()) {
                    if(key == 'Group_Number_Form__c'){
                        continue;
                    }
                    Object sfValue = sfAccount.get(key);
                    Object recordValue = recordMapped.get(key);
                    String sfStrVal = String.valueOf(sfValue);
                    String recordStrVal = String.valueOf(recordValue);
                    if( (sfValue == null && recordValue == null) ||
                        (sfvalue == null && recordValue != null && recordStrVal == '') || 
                        (sfvalue != null && recordValue == null && sfStrVal == '') || 
                        (sfValue != null && recordValue != null && sfStrVal.toLowerCase() == recordStrVal.toLowerCase())) {
                        System.debug('KEY MATCH = ' + key);
                    } else {
                        System.debug('KEY MISMATCH = ' + key);
                        System.debug('sf key value : ' + String.valueOf(sfAccount.get(key)) );
                        System.debug('json key value : ' + String.valueOf(recordMapped.get(key)) );
                        //create a FileFeedObject
                        File_Feed__c newChange = new File_Feed__c();
                        newChange.Account__c = sfAccount.Id;
                        newChange.Action_Type__c = String.ValueOf(action);
                        newChange.Field_Updating__c = key;
                        newChange.New_Value__c = String.ValueOf(recordMapped.get(key));
                        newChange.Old_Value__c = String.ValueOf(sfAccount.get(key));
                        changeList.add(newChange);
                    }
                }
            } else {
                System.debug('SF ACCOUNT NOT FOUND');
                System.debug(groupNumber);
                //account does not exist
                // create new account object and add to SF
                if(allEmployerAccounts == null){
                    allEmployerAccounts = Database.query('SELECT Id, Group_Number__c FROM Account WHERE RecordTypeId = :recordTypeId and Group_Status__c = \'Active\'');
                    for(Account a : allEmployerAccounts){
                        mappedEmployerAccounts.put(String.valueOf(a.get('Group_Number__c')), a);
                        System.debug(a.get('Group_Number__c'));
                    }
                }
                Account sfEmployerAccount = mappedEmployerAccounts.get(groupNumber);
                System.debug(sfEmployerAccount.get('Group_Number__c'));
                // if this line fails that means there is no company associated to this group number
                recordMapped.put('Employer__c', String.ValueOf(sfEmployerAccount.get('Id')));
                if(action.toLowerCase() == 'add' || action.toLowerCase() == 'change') {
                    recordMapped.put('Member_Status__c', 'Active');
                    recordMapped.put('Original_Effective_Date__c', recordMapped.get('Effective_Date__c'));
                    recordMapped.put('Expiration_Date__c', (Object)date.parse('12/31/' + Date.today().year()));
                    recordMapped.put('Payment_Schedule__c', 'Monthly');
                    recordMapped.put('Billing_Type__c', 'Payroll Deduct');
                    recordMapped.put('Billing_Notes__c', 'New');                    
                    //generate auto incrementing unique memberid
                    // recordMapped.put('Member_ID__c', '');                    
                    addList.add((Account) JSON.deserialize(JSON.serialize(recordMapped), Account.class));
                } else {
                    //check termed date and see if they are terming in the future                    
                    if(hasEffectiveDate && (Date)recordMapped.get('Effective_Date__c') >= Date.today()) {
                        //set to end of the month
                        addList.add((Account) JSON.deserialize(JSON.serialize(recordMapped), Account.class));
                    }
                }                
            }
        }        
        for(Account a : addList) {
            System.debug(a);
        }
        insert changeList;
        insert addList;
        return sfResponse;
    }
}

File Feed Helper Apex

public with sharing class FileFeedHelper {
    static Map<String,String> jsonToSfoMappings = new Map<String,String>();
    static {
        //Action Mappings;
        jsonToSfoMappings.put('Action','Action_Type__c');
        jsonToSfoMappings.put('/Action','Action_Type__c');
        jsonToSfoMappings.put('TerminationDate','Termination_Date');
        jsonToSfoMappings.put('Termination_Date','Termination_Date');

        //Email Mappings;
        jsonToSfoMappings.put('Email_Address','PersonEmail');
        jsonToSfoMappings.put('E-mail','PersonEmail');
        jsonToSfoMappings.put('Email','PersonEmail');
        jsonToSfoMappings.put('Business Email','PersonEmail');
        jsonToSfoMappings.put('Business_Email','PersonEmail');
        jsonToSfoMappings.put('E-mail Address','PersonEmail');
        jsonToSfoMappings.put('E-mail_Address','PersonEmail');
        jsonToSfoMappings.put('Email Address','PersonEmail');
        jsonToSfoMappings.put('Email_Address','PersonEmail');

        //Group Number Mappings;
        jsonToSfoMappings.put('Group_Number','Group_Number_Form__c');
        jsonToSfoMappings.put('Group Number','Group_Number_Form__c');
        jsonToSfoMappings.put('Group #','Group_Number_Form__c');
        jsonToSfoMappings.put('Group_#','Group_Number_Form__c');
        
        //First Name Mappings;
        jsonToSfoMappings.put('First_Name','FirstName');
        jsonToSfoMappings.put('First Name','FirstName');

        //Last Name Mappings;
        jsonToSfoMappings.put('Last_Name','LastName');
        jsonToSfoMappings.put('Last Name','LastName');

        //Employee ID Mappings;
        jsonToSfoMappings.put('Employee ID','Employee_ID__c');
        jsonToSfoMappings.put('Employee_ID','Employee_ID__c');
        jsonToSfoMappings.put('Member ID','Employee_ID__c');
        jsonToSfoMappings.put('Member_ID','Employee_ID__c');
        jsonToSfoMappings.put('Employee ID Number','Employee_ID__c');
        jsonToSfoMappings.put('Employee_ID_Number','Employee_ID__c');
        jsonToSfoMappings.put('Employee Number','Employee_ID__c');
        jsonToSfoMappings.put('Employee_Number','Employee_ID__c');

        //Middle Initial Mappings;
        // jsonToSfoMappings.put('Middle_Initial','');
        
        //Primary Phone Mappings;
        jsonToSfoMappings.put('Primary Phone','Phone');
        jsonToSfoMappings.put('Primary_Phone','Phone');
        jsonToSfoMappings.put('Personal Phone','Phone');
        jsonToSfoMappings.put('Personal_Phone','Phone');
        jsonToSfoMappings.put('Phone','Phone');
        jsonToSfoMappings.put('Home Phone','Phone');
        jsonToSfoMappings.put('Home_Phone','Phone');

        //Secondary Phone Mappings;
        jsonToSfoMappings.put('Secondary Phone','PersonOtherPhone');
        jsonToSfoMappings.put('Secondary_Phone','PersonOtherPhone');
        jsonToSfoMappings.put('Work Phone','PersonOtherPhone');
        jsonToSfoMappings.put('Work_Phone','PersonOtherPhone');
        jsonToSfoMappings.put('Mobile Phone','PersonOtherPhone');
        jsonToSfoMappings.put('Mobile_Phone','PersonOtherPhone');
        
        //Home Address 1 Mappings;
        jsonToSfoMappings.put('Home Address 1','BillingStreet');
        jsonToSfoMappings.put('Home_Address_1','BillingStreet');
        jsonToSfoMappings.put('Home Address','BillingStreet');
        jsonToSfoMappings.put('Home_Address','BillingStreet');
        jsonToSfoMappings.put('Address1','BillingStreet');
        jsonToSfoMappings.put('Address 1','BillingStreet');
        jsonToSfoMappings.put('Address_1','BillingStreet');
        jsonToSfoMappings.put('Home Address1','BillingStreet');
        jsonToSfoMappings.put('Home_Address1','BillingStreet');
        jsonToSfoMappings.put('Address Line 1','BillingStreet');
        jsonToSfoMappings.put('Address_Line_1','BillingStreet');

        // //Home Address 2 Mappings;
        jsonToSfoMappings.put('Home Address 2','BillingStreet2');
        jsonToSfoMappings.put('Home_Address_2','BillingStreet2');
        jsonToSfoMappings.put('Address2','BillingStreet2');
        jsonToSfoMappings.put('Address 2','BillingStreet2');
        jsonToSfoMappings.put('Address_2','BillingStreet2');
        jsonToSfoMappings.put('Home Address2','BillingStreet2');
        jsonToSfoMappings.put('Home_Address2','BillingStreet2');
        jsonToSfoMappings.put('Address Line 2','BillingStreet2');
        jsonToSfoMappings.put('Address_Line_2','BillingStreet2');

        //City Mappings;
        jsonToSfoMappings.put('City','BillingCity');

        //State Mappings;
        jsonToSfoMappings.put('State','BillingState');
        jsonToSfoMappings.put('State/Province','BillingState');

        //Zip Code Mappings;
        jsonToSfoMappings.put('Zip Code','BillingPostalCode');
        jsonToSfoMappings.put('Zip_Code','BillingPostalCode');
        jsonToSfoMappings.put('Zip','BillingPostalCode');


        //Plan Mappings;
        jsonToSfoMappings.put('Benefit_Program','Plan__c');
        jsonToSfoMappings.put('Program','Plan__c');
        jsonToSfoMappings.put('Plan','Plan__c');
        jsonToSfoMappings.put('Deduction/Benefit (Long)','Plan__c');
        jsonToSfoMappings.put('Deduction/Benefit_(Long)','Plan__c');
        
        //Num of Pets Mappings;
        jsonToSfoMappings.put('Number_of_Pets','Number_of_Pets__c');
        jsonToSfoMappings.put('Coverage','Number_of_Pets__c');
        jsonToSfoMappings.put('Benefit Option Code','Number_of_Pets__c');
        jsonToSfoMappings.put('Benefit_Option_Code','Number_of_Pets__c');
        jsonToSfoMappings.put('Number of Pets','Number_of_Pets__c');

        //Rate Mappings;
        jsonToSfoMappings.put('Rate','Rate__c');
        jsonToSfoMappings.put('Total Rate','Rate__c');
        jsonToSfoMappings.put('Total_Rate','Rate__c');
        jsonToSfoMappings.put('Monthly Employee Rate','Rate__c');
        jsonToSfoMappings.put('Monthly_Employee_Rate','Rate__c');
        jsonToSfoMappings.put('Employee Rate','Rate__c');
        jsonToSfoMappings.put('Employee_Rate','Rate__c');

        //Effective Date Mappings;
        jsonToSfoMappings.put('Effective Date','Effective_Date__c');
        jsonToSfoMappings.put('Effective_Date','Effective_Date__c');
        jsonToSfoMappings.put('Plan Effective Start Date','Effective_Date__c');
        jsonToSfoMappings.put('Plan_Effective_Start_Date','Effective_Date__c');
        jsonToSfoMappings.put('Effective Start Date','Effective_Date__c');
        jsonToSfoMappings.put('Effective_Start_Date','Effective_Date__c');
        jsonToSfoMappings.put('Coverage Start Date','Effective_Date__c');
        jsonToSfoMappings.put('Coverage_Start_Date','Effective_Date__c');

        //Work Location Mappings;
        jsonToSfoMappings.put('Work Location','Work_Location__c');
        jsonToSfoMappings.put('Work_Location','Work_Location__c');
        jsonToSfoMappings.put('Location','Work_Location__c');
        jsonToSfoMappings.put('Division','Work_Location__c');
        jsonToSfoMappings.put('Company','Work_Location__c');

        // //Vet Number Mappings;
        // jsonToSfoMappings.put('Vet_Number','');

        // //Pet Name Mappings;
        // jsonToSfoMappings.put('Pet_Name','');

        // //Pet Type Mappings;
        // jsonToSfoMappings.put('Pet_Type','');

        // //Pet Breed Mappings;
        // jsonToSfoMappings.put('Pet_Breed','');

        // //Pet Age Mappings;
        // jsonToSfoMappings.put('Pet_Age','Pet_Age__c');

        // //Pet Gender Mappings;
        // jsonToSfoMappings.put('Pet_Gender','');
    }

    private static String getMap(String key){
        return jsonToSfoMappings.get(key);
    }

    public static Map<String,Object> getMappings(Object originalRecord) {
        
        Map<String,Object> originalMap = (Map<String,Object>) JSON.deserializeUntyped(JSON.serialize(originalRecord));
        Map<String,Object> newMap = new Map<String,Object>();

        for(String key : originalMap.keySet()) {
            String mappedKey = getMap(key);
            if(mappedKey != '' && mappedKey != null) {
                newMap.put(mappedKey, originalMap.get(key));
            }
        }
        if(newMap.containsKey('BillingStreet2')) {
            String addr1 = String.valueOf(newMap.get('BillingStreet'));
            String addr2 = String.valueOf(newMap.get('BillingStreet2'));
            if(addr2 != '' && addr2 != null){
                newMap.put('BillingStreet', addr1 + ' ' + addr2);
            }
            newMap.remove('BillingStreet2');
        }
        return newMap;
    }

    public static Account convertJsonToAccountObject(String json) {
        Account a = new Account();
        return a;
    }

    public static String getFields(Map<String,Object> mapping) {
        String fields = '';
        for(String key : mapping.keySet()) {
            if(key == 'Action_Type__c' || key == 'Member_Status__c' || key == 'Expiration_Date__c' || key == 'Billing_Notes__c' || key == 'Cancel_Reason__c' || key == 'Group_Number_Form__c'){
                continue;
            }
            if (fields != '') {
                fields += ',' + key;
            }else {
                fields += key;
            }
        }
        return fields;
    }

    public static Date getEndOfMonth(Object dateToParse){
        return Date.parse(String.valueOf(dateToParse)).addMonths(1).toStartOfMonth().addDays(-1);
    }
}

Test Class


@IsTest
public class TestFileFeed  {
   static testMethod void testDoPost(){
       //Create test data 
       Rate_Card__c rc = new Rate_Card__c();
       rc.name = 'File Feed Testing Rate';
       rc.Preferred_1_Monthly__c = 10;
       rc.Preferred_2_Monthly__c = 20;
       rc.Preferred_3_Monthly__c = 30;
       rc.Preferred_4_Monthly__c = 8;
       insert rc; 
       
       Id employerAccountRecordTypeId = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Employer').getRecordTypeId();
       Account a = new Account();
       a.Name = 'Test Employer';
       a.Group_Number__c = '123';
       a.Group_Status__c = 'Active';
       a.Participating_Program__c = 'Choice;Select;Preferred;Basic';
       //a.Effective_Date__c = date.valueOf(01/01/2020);
       a.Rate_Card__c = rc.id;
       insert a;
        
        String JSONMsg = '{'+
        '    \"records\": ['+
        '    {'+
        '       \"Action\": \"Change\",'+
        '       \"Group_Number\": \"932\",'+
        '       \"Employee ID Number\": \"1234\",'+
        '       \"Last Name\": \"Testerson\",'+
        '       \"First Name\": \"test\",'+
        '       \"Middle Initial\": \"s\",'+
        '       \"Primary Phone\": \"1234567890\",'+
        '       \"Home Address1\": \"638 W Nido Ave\",'+
        '       \"City\": \"Mesa\",'+
        '       \"State\": \"Az\",'+
        '       \"Zip Code\": \"85210\",'+
        '       \"Email Address\": \"[email protected]\",'+
        '       \"Program\": \"Preferred\",'+
        '       \"Number of Pets\": \"1\",'+
        '       \"Rate\": \"10.26\",'+
//      '       \"Effective Date\": \"09\/01\/2022\",'+
        '    },'+
        '    {'+
        '       \"Action\": \"Change\",'+
        '       \"Group_Number\": \"932\",'+
        '       \"Employee ID Number\": \"1234\",'+
        '       \"Last Name\": \"Testerson\",'+
        '       \"First Name\": \"test\",'+
        '       \"Middle Initial\": \"s\",'+
        '       \"Primary Phone\": \"1234567890\",'+
        '       \"Home Address1\": \"638 W Nido Ave\",'+
        '       \"City\": \"Mesa\",'+
        '       \"State\": \"Az\",'+
        '       \"Zip Code\": \"85210\",'+
        '       \"Email Address\": \"[email protected]\",'+
        '       \"Program\": \"Preferred\",'+
        '       \"Number of Pets\": \"1\",'+
        '       \"Rate\": \"10.26\",'+
//      '       \"Effective Date\": \"09\/01\/2022\",'+
        '    },'+
        '    {'+
        '       \"Action\": \"Change\",'+
        '       \"Group_Number\": \"932\",'+
        '       \"Employee ID Number\": \"1234\",'+
        '       \"Last Name\": \"Testerson\",'+
        '       \"First Name\": \"test\",'+
        '       \"Middle Initial\": \"s\",'+
        '       \"Primary Phone\": \"1234567890\",'+
        '       \"Home Address1\": \"638 W Nido Ave\",'+
        '       \"City\": \"Mesa\",'+
        '       \"State\": \"Az\",'+
        '       \"Zip Code\": \"85210\",'+
        '       \"Email Address\": \"[email protected]\",'+
        '       \"Program\": \"Preferred\",'+
        '       \"Number of Pets\": \"1\",'+
        '       \"Rate\": \"10.26\",'+
//      '       \"Effective Date\": \"09\/01\/2022\",'+
        '    },'+
        '    {'+
        '       \"Action\": \"Change\",'+
        '       \"Group_Number\": \"932\",'+
        '       \"Employee ID Number\": \"1234\",'+
        '       \"Last Name\": \"Testerson\",'+
        '       \"First Name\": \"test\",'+
        '       \"Middle Initial\": \"s\",'+
        '       \"Primary Phone\": \"1234567890\",'+
        '       \"Home Address1\": \"638 W Nido Ave\",'+
        '       \"City\": \"Mesa\",'+
        '       \"State\": \"Az\",'+
        '       \"Zip Code\": \"85210\",'+
        '       \"Email Address\": \"[email protected]\",'+
        '       \"Program\": \"Preferred\",'+
        '       \"Number of Pets\": \"1\",'+
        '       \"Rate\": \"10.26\",'+
//      '       \"Effective Date\": \"09\/01\/2022\",'+
        '   },'+
        '   {'+
        '       \"Action\": \"Change\",'+
        '       \"Group_Number\": \"932\",'+
        '       \"Employee ID Number\": \"1234\",'+
        '       \"Last Name\": \"Testerson\",'+
        '       \"First Name\": \"test\",'+
        '       \"Middle Initial\": \"s\",'+
        '       \"Primary Phone\": \"1234567890\",'+
        '       \"Home Address1\": \"638 W Nido Ave\",'+
        '       \"City\": \"Mesa\",'+
        '       \"State\": \"Az\",'+
        '       \"Zip Code\": \"85210\",'+
        '       \"Email Address\": \"[email protected]\",'+
        '       \"Program\": \"Preferred\",'+
        '       \"Number of Pets\": \"1\",'+
        '       \"Rate\": \"10.26\",'+
//      '       \"Effective Date\": \"09\/01\/2022\",'+
        '    }]'+
        '}';
        
        //Prepare input 
        RestRequest req = new RestRequest(); 
        RestResponse res = new RestResponse();
        req.requestURI = '/services/apexrest/FileFeedV1';  
        req.httpMethod = 'POST';
        req.requestBody = Blob.valueof(JSONMsg);
        RestContext.request = req;
        RestContext.response= res;
        
        Test.startTest();
        FileFeed.doPost();
        Test.stopTest();
    }  
}
UPDATE

In the test class the entire section of String JSONMsg = ... code was replaced by the code from @sfdcfox's answer. Then one other line was changed so that JSONMsg was replaced by output:

req.requestBody = Blob.valueof(output);

Now after running a different error is seen:

System.TypeException: Invalid conversion from runtime type Map<String,ANY> to List

3
  • 1
    Please don't edit your question code to change it to what was given in an answer. That makes the answer no longer match the question and can be extremely confusing and unhelpful to future readers. If you are getting a different error after implementing the code in the answer, do as you did and comment on the answer; then wait for the answerer to respond. It could be as simple as a typo in the answerer's code that can be quickly and easily fixed. If it turns out to be something else entirely, then a separate question might be in order.
    – Moonpie
    Commented Sep 30, 2022 at 1:18
  • (Or at most add an "UPDATE" section at the bottom of your question to make note of code updates & changes.) I edited your question to clean up the spacing in the code and to format the error text for readability. I also rolled back the JSON code to what you originally had so that the answer matches the question. Please wait for @sfdcfox to respond to your new error comment.
    – Moonpie
    Commented Sep 30, 2022 at 1:18
  • I went ahead and also appended your question with the update about trying the answer and getting a different error. You should copy/paste the entire error text including line number(s) and stack trace if available.
    – Moonpie
    Commented Sep 30, 2022 at 1:29

1 Answer 1

1

Your JSON is malformed. Notably, unlike JavaScript, the last item in an object or array cannot have a comma after it. For this, and other reasons, I always recommend either loading JSON directly from a Static Resource, or using JSON.serialize.

Here's how I'd make a JSON like yours:

    String output = JSON.serialize(
        new Map<String, Object>{
            'records' => new List<Object> {
                new Map<String, String>{
                    'Action' => 'Change',
                    'Group_Number' => '932',
                    'Employee ID Number' => '1234',
                    'Last Name' => 'Testerson',
                    'First Name' => 'test',
                    'Middle Initial' => 's',
                    'Primary Phone' => '1234567890',
                    'Home Address1' => '638 W Nido Ave',
                    'City' => 'Mesa',
                    'State' => 'Az',
                    'Zip Code' => '85210',
                    'Email Address' => '[email protected]',
                    'Program' => 'Preferred',
                    'Number of Pets' => '1',
                    'Rate' => '10.26'
                },
                new Map<String, String>{
                    'Action' => 'Change',
                    'Group_Number' => '932',
                    'Employee ID Number' => '1234',
                    'Last Name' => 'Testerson',
                    'First Name' => 'test',
                    'Middle Initial' => 's',
                    'Primary Phone' => '1234567890',
                    'Home Address1' => '638 W Nido Ave',
                    'City' => 'Mesa',
                    'State' => 'Az',
                    'Zip Code' => '85210',
                    'Email Address' => '[email protected]',
                    'Program' => 'Preferred',
                    'Number of Pets' => '1',
                    'Rate' => '10.26'
                },
                new Map<String, String>{
                    'Action' => 'Change',
                    'Group_Number' => '932',
                    'Employee ID Number' => '1234',
                    'Last Name' => 'Testerson',
                    'First Name' => 'test',
                    'Middle Initial' => 's',
                    'Primary Phone' => '1234567890',
                    'Home Address1' => '638 W Nido Ave',
                    'City' => 'Mesa',
                    'State' => 'Az',
                    'Zip Code' => '85210',
                    'Email Address' => '[email protected]',
                    'Program' => 'Preferred',
                    'Number of Pets' => '1',
                    'Rate' => '10.26'
                },
                new Map<String, String>{
                    'Action' => 'Change',
                    'Group_Number' => '932',
                    'Employee ID Number' => '1234',
                    'Last Name' => 'Testerson',
                    'First Name' => 'test',
                    'Middle Initial' => 's',
                    'Primary Phone' => '1234567890',
                    'Home Address1' => '638 W Nido Ave',
                    'City' => 'Mesa',
                    'State' => 'Az',
                    'Zip Code' => '85210',
                    'Email Address' => '[email protected]',
                    'Program' => 'Preferred',
                    'Number of Pets' => '1',
                    'Rate' => '10.26'
                },
                new Map<String, String>{
                    'Action' => 'Change',
                    'Group_Number' => '932',
                    'Employee ID Number' => '1234',
                    'Last Name' => 'Testerson',
                    'First Name' => 'test',
                    'Middle Initial' => 's',
                    'Primary Phone' => '1234567890',
                    'Home Address1' => '638 W Nido Ave',
                    'City' => 'Mesa',
                    'State' => 'Az',
                    'Zip Code' => '85210',
                    'Email Address' => '[email protected]',
                    'Program' => 'Preferred',
                    'Number of Pets' => '1',
                    'Rate' => '10.26'
                }
            }
        }
    );

This gives you full syntax highlighting and balanced bracket highlighting, and will fail to compile if you make a mistake.

The moral of the story: do not treat JSON like an ordinary string.

2
  • Thanks for that. I updated and edited the test class but it looks like we are getting System.TypeException: Invalid conversion from runtime type Map<String,ANY> to List<ANY> on the post now. Did I associate it incorrectly? @sfdcfox
    – SoleHack
    Commented Sep 30, 2022 at 0:50
  • @SoleHack I just went off your JSON. Your unit test logic doesn't match the doPost deserialization logic. You'll have to figure out which one is correct. Just use the method of constructing nested Map/List objects, as demonstrated here, rather than trying to write your own JSON strings.
    – sfdcfox
    Commented Sep 30, 2022 at 1:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .