0

I have some code where I am building a JSON response. My JSON looks like this

String jsonString = '';
            jsonString += '{"Order":{';
            // order fields
            jsonString += '"Id":"'+orderObj.id+'",';
            jsonString += '"Billing_Contact__c":"'+orderObj.Billing_Contact__c+'",';
            jsonString += '"AccountId":"'+orderObj.AccountId+'",';
            jsonString += '"Synced_With_Platform_Date__c":"'+orderObj.Synced_With_Platform_Date__c+'",';
            jsonString += '"Account.Universal_ID__c":"'+orderObj.Account.Universal_ID__c+'",';
            jsonString += '"Account.Universal_ID__c":"'+orderObj.Account.Universal_ID__c+'",';
            jsonString += '"Client_Ultimate_Universal_ID__c":"'+orderObj.Client_Ultimate_Universal_ID__c+'",';
            jsonString += '"Account_Universal_ID__c":"'+orderObj.Account_Universal_ID__c+'",';
            //end order fields
            jsonString += '"OrderProducts":[';
            for(OrderItem orderItemObj : orderObj.OrderItems){
                jsonString += '{';
                //orderitem fields 
                jsonString += '"Id":"'+orderItemObj.Id+'",';
                jsonString += '"Location__c":"'+orderItemObj.Location__c+'",';
                jsonString += '"Location__r.Universal_ID__c":"'+orderItemObj.Location__r.Universal_ID__c+'",';
                jsonString += '"Location__r.Ultimate_Global_Universal_ID__c":"'+orderItemObj.Location__r.Ultimate_Global_Universal_ID__c+'",';
                jsonString += '"Location__r.Ultimate_Global_Account_ID__c":"'+orderItemObj.Location__r.Ultimate_Global_Account_ID__c+'",';
                jsonString += '"Product2.Product_Line__c":"'+orderItemObj.Product2.Product_Line__c+'",';
                jsonString += '"Product2.StockKeepingUnit":"'+orderItemObj.Product2.StockKeepingUnit+'",';
                jsonString += '"Product2.Product_Type__c":"'+orderItemObj.Product2.Product_Type__c+'",';
                jsonString += '"Product2Id":"'+orderItemObj.Product2Id+'",';
                jsonString += '"Product2Id":"'+orderItemObj.Product2Id+'",';
                jsonString += '"Product_SKU__c":"'+orderItemObj.Product_SKU__c+'",';
                jsonString += '"Quantity":"'+orderItemObj.Quantity+'",';
                jsonString += '"ServiceDate":"'+orderItemObj.ServiceDate+'",';
                jsonString += '"EndDate":"'+orderItemObj.EndDate+'",';
                jsonString += '"Product2.Name":"'+orderItemObj.Product2.Name+'",';
                // end orderitem fields
                jsonString += '"Features":[';
                for(Id featureId : productIdToFeatureIds.get(orderItemObj.Product2Id)){
                    if (productFeatureMap.containsKey(featureId)) {
                        Product_Features__c productFeatureObj = productFeatureMap.get(featureId);
                        jsonString += '{';
                        //product feature feilds
                        jsonString += '"Id":"'+productFeatureObj.Id+'",';
                        jsonString += '"Name":"'+productFeatureObj.Name+'",';
                        jsonString += '"Feature_Type__c":"'+productFeatureObj.Feature_Type__c+'",';
                        jsonString += '"Feature_AlphaNumeric__c":"'+productFeatureObj.Feature_AlphaNumeric__c+'",';
                        jsonString += '"Feature__c":"'+productFeatureObj.Feature__c+'",';
                        jsonString += '"Feature__r.Name":"'+productFeatureObj.Feature__r.Name+'",';
                        jsonString += '"Feature__r.Feature_Type__c":"'+productFeatureObj.Feature__r.Feature_Type__c+'",';
                        jsonString += '"Feature__r.Feature_ID__c":"'+productFeatureObj.Feature__r.Feature_ID__c+'",';
                        jsonString += '"Product__c":"'+productFeatureObj.Product__c+'"},';
                        // end product feature fields
                    }                        
                }
                jsonString = jsonString.removeEnd(',')+']';
                jsonString += '},';
            }
            jsonString = jsonString.removeEnd(',')+']';

        jsonString += '}}';

The problem is that when I return that value the other system is getting

"{\"Order\":{\"Id\":\"80117000000cYSGAA2\",\"Billing_Contact__c\":\"0037000001vaQN7AAM\",\"AccountId\":\"0017000001OkdAdAAJ\",\"Synced_With_Platform_Date__c\":\"null\",\"Account.Universal_ID__c\":\"F1645C76-08B0-47D7-BE77-05B39B0870E4\",\"Account.Universal_ID__c\":\"F1645C76-08B0-47D7-BE77-05B39B0870E4\",\"Client_Ultimate_Universal_ID__c\":\"0017000001OkdAd\",\"Account_Universal_ID__c\":\"F1645C76-08B0-47D7-BE77-05B39B0870E4\",\"OrderProducts\":[{\"Id\":\"80217000000lrNdAAI\",\"Location__c\":\"0017000001OkdAdAAJ\",\"Location__r.Universal_ID__c\":\"F1645C76-08B0-47D7-BE77-05B39B0870E4\",\"Location__r.Ultimate_Global_Universal_ID__c\":\"F1645C76-08B0-47D7-BE77-05B39B0870E4\",\"Location__r.Ultimate_Global_Account_ID__c\":\"0017000001OkdAd\",\"Product2.Product_Line__c\":\"F&I\",\"Product2.StockKeepingUnit\":\"null\",\"Product2.Product_Type__c\":\"Both\",\"Product2Id\":\"01t3900000RuGz7AAF\",\"Product2Id\":\"01t3900000RuGz7AAF\",\"Product_SKU__c\":\"null\",\"Quantity\":\"1.00\",\"ServiceDate\":\"2019-11-01 00:00:00\",\"EndDate\":\"2021-10-31 00:00:00\",\"Product2.Name\":\"F&I Fundamental (Maximum 15 Deal Jackets)\",\"Features\":[{\"Id\":\"a0x17000001FZUoAAO\",\"Name\":\"F&I Fundamental (Maximum 15 Deal Jackets) MKO Package 24\",\"Feature_Type__c\":\"MKO Package\",\"Feature_AlphaNumeric__c\":\"24\",\"Feature__c\":\"a0w17000004GA23AAG\",\"Feature__r.Name\":\"MKO Package 24\",\"Feature__r.Feature_Type__c\":\"MKO Package\",\"Feature__r.Feature_ID__c\":\"24\",\"Product__c\":\"01t3900000RuGz7AAF\"},{\"Id\":\"a0x17000001FZYlAAO\",\"Name\":\"F&I Fundamental (Maximum 15 Deal Jackets) Vera Suite 1\",\"Feature_Type__c\":\"Vera Suite\",\"Feature_AlphaNumeric__c\":\"1\",\"Feature__c\":\"a0w17000004GA2vAAG\",\"Feature__r.Name\":\"Vera Suite 1\",\"Feature__r.Feature_Type__c\":\"Vera Suite\",\"Feature__r.Feature_ID__c\":\"1\",\"Product__c\":\"01t3900000RuGz7AAF\"}]},{\"Id\":\"80217000000lrNeAAI\",\"Location__c\":\"0017000001OkdAdAAJ\",\"Location__r.Universal_ID__c\":\"F1645C76-08B0-47D7-BE77-05B39B0870E4\",\"Location__r.Ultimate_Global_Universal_ID__c\":\"F1645C76-08B0-47D7-BE77-05B39B0870E4\",\"Location__r.Ultimate_Global_Account_ID__c\":\"0017000001OkdAd\",\"Product2.Product_Line__c\":\"EHS Direct\",\"Product2.StockKeepingUnit\":\"null\",\"Product2.Product_Type__c\":\"Software\",\"Product2Id\":\"01t3900000RuwGvAAJ\",\"Product2Id\":\"01t3900000RuwGvAAJ\",\"Product_SKU__c\":\"null\",\"Quantity\":\"2.00\",\"ServiceDate\":\"2019-11-01 00:00:00\",\"EndDate\":\"2021-10-31 00:00:00\",\"Product2.Name\":\"EHS Elements (Winery)\",\"Features\":[]}]}}"

The other system is not able to read \". I tried using JSON.serialize(jsonString); but then the other system got \\". What is the proper way to send it so that there is no \ ?

2
  • 2
    How are you returning the JSON? It looks like the system's automatically serializing the value, which is not what you want to happen. – David Reed Nov 6 '19 at 23:43
  • @DavidReed here is how I am returning it return jsonString; – Travis Nov 7 '19 at 0:09
1

When you want to generate the JSON return value for an Apex REST call directly, rather than returning an Apex type for the system, you need to set that JSON body in the RestResponse object. The docs specify how return values are handled (under responseBody):

The response is either the serialized form of the method return value or it's the value of the responseBody property based on the following rules:

  • If the method returns void, then Apex REST returns the response in the responseBody property.
  • If the method returns a value, then Apex REST serializes the return value as the response.

What's happening here is the second case. Your method returns a String, containing JSON. But the system doesn't know it's got JSON in it - it could be any textual data, needing serialization to become valid JSON. So it serializes it for you, in this case resulting in invalid JSON.

Instead, return void from your method, and set your JSON in the response object, i.e.,

 RestResponse res = RestContext.response;
 res.responseBody = Blob.valueOf(jsonString):

It's also fine (and often preferable) to construct a complex type in Apex, including primitives, collections, and sObject instances, that would serialize down to the JSON you want. Then, just return an instance of that type, and let the system itself manage the serialization for you.

I'd recommend you consider that approach here. Since you're embedding strings under user control into your JSON without escaping them, you run the risk of generating invalid JSON if special characters are contained in those fields, which could potentially accrue to a security issue in your remote system depending on how the data's used and processed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.