0

Need to make the requested body for Rest POST call in which key(API name) and value both go dynamically in JSON format. API name comes from field set and its value come from the database using query.

How i create requested body for Rest call using fieldSet. Below is my JSON format(ID, Trigger_DEMLTNR__c,Order_number_DEORDNR__c,Country_code__c,Invoice_number_DEFAKNR__c... all comes from fieldSet)

"SubscriberAttributes": {
            "Id":"Id",
            "Trigger_DEMLTNR__c":"",
            "Order_number_DEORDNR__c":"",
            "Country_code__c":"",
            "Invoice_number_DEFAKNR__c":"",
            "MiddleName_DEKLVNM__c":"",
            "FirstName_DEKLAVN__c":"",
            "LastName_DEKLANM__c":"",
            "Email_encrypted__c":"Email_encrypted__c"
        }

closed as unclear what you're asking by David Reed, glls, Boris Bachovski, Dave Humm, Derek F Aug 3 '18 at 12:41

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 2
    Harish, this is pretty unclear.... are you making an inbound or outbound REST request? What have you tried to accomplish this task? Have you encountered specific issues? Please edit your question to add more details. – David Reed Aug 2 '18 at 18:10
  • i want to make requested body for Rest POST call, in which i want to send key(api name) and its value which is stored in salesforce database in above JSON format, api name comes from field set – Harish Aug 2 '18 at 18:13
  • 1
    Harish, when people ask you for clarification, about the least helpful thing you can do is repeat the text that already exists in your question (which is exactly what you did). Please put some effort into clarifying your question, and tell us what you've researched and tried so far. – Derek F Aug 3 '18 at 12:41
3

Create a class that we will eventually serialize:

// You'll want to give this class a name more specific to your use case
global class RestBody {
    Map<String, String> subscriberAttributes;

    public restBody() {
        subscriberAttributes = new Map<String, String>();
    }
}

Create an instance of your class and fill with data:

RestBody rb = new RestBody();
Schema.FieldSet fs = Schema.SObjectType.Account.FieldSets.<fieldset name>;

for (SObject record : records) {
     for (Schema.FieldSetMember fsm : fs.getFields()) {
        rb.subscriberAttributes.put(fsm.getPath(), record[fsm.getPath()]);
    }
}

Create your request:

HTTPRequest req = new HTTPRequest();

req.setBody(JSON.serialize(rb));

Notes

This documentation is usually my goto when I need a refresher on working with field sets.

To access a field from a record using a string that contains the API name you use this syntax: record[stringVar]. Works on generic SObjects, I am not 100% sure if it works on typed SObjects such as Account but its easy enough to test and if it doesn't work its easy enough to typecast back to an SObject.

Most basic JSON objects can be represented as Map<String, String> as is your case. Most people use this site to help with the conversion. This site will however, do things very explicitly meaning it will generate hardcoded attributes as opposed to using a more dynamic map of attributes as I have shown above (which is what you'll want in your case).

My attempt at explaining how to convert JSON to APEX

Every JSON object should be represented by a class that stores the attributes of the object. I will usually name these classes based off what they represent. A good example would be when I did a FastSpring integration I created a class called FastSpringOrder which stored all the attributes of an order.

Static JSON

For a more basic use case, you could create a class for each object. For instance, a class called FastSpringOrder which represents the overall order and a class for FastSpringProduct which represents a single line item on the order. This is the structure JSON2Apex uses (the site I linked above) which is great when you're working with a static 3rd party API.

You should only use JSON2Apex until you understand what it is doing. Beyond that it will only make your life more difficult.

Dynamic JSON

Each member of the top level class will convert to a named member of the JSON object. So in your case, SubscriberAttributes is the named attribute so we created a member using this same name in our class.

At their core, every JSON member can be expressed as a Map<String, Object>. The string being the key and the object representing the value. The value could be a String object or another Map<String, Object>. In JSON the value is almost always a String as well; however, this could be a List<String> to represent a JSON array or a Map<String, Object> to represent an object (which subsequently will look the exact same) or Even a List<Map<String, Object>> to represent a list of objects.

Visually, if you see "name":[] you're working with a list. If you see "name":{} you're working with an Map<String, Object>. If you see "name":[{}] you're working with a list of objects. If you see "name":"value" you're working with a primitive type such as String, Boolean, Integer etc.. These primitives are usually represented as strings and the API converts it to the proper data type however, some APIs will expect you to provide them in the primitive type in which case you'd just remove the quotes such as "name":1 or "name":true.

Getting used to this structure will allow you to create very dynamic JSON. This is a bit more advanced and takes some getting used to. This is also great for when the Rest api you're working with uses reserved words as their attribute names or attribute names that don't adhere the the variable name standards in APEX

A couple examples I've run into:

  • The JIRA rest API uses system as an attribute name which is a reserved word
  • The JIRA api also has some attribute names that start with a number which is against naming conventions in APEX
  • record[fsm.getPath()] this part is not working, how i get record field value.. – Harish Aug 3 '18 at 7:11
  • public class testExample { public static Map<String, String> subscriberAttributes; Public static void A(){ Schema.FieldSet fs = Schema.SObjectType.Account.FieldSets.test; List<Account> records = new List<Account>(); records=[Select id from Account]; subscriberAttributes = new Map<String, String>(); for (SObject record : records) { for (Schema.FieldSetMember fsm : fs.getFields()) { subscriberAttributes.put(fsm.getFieldPath(), record[fsm.getFieldPath()]); } } } } – Harish Aug 3 '18 at 7:12
  • As I stated in my Answer, its possible that that only works on SObjects. Try something like SObject record = (SObject) Account; record[fsm.getFieldPath()] If you provide the error you're getting I might be able to provide more help. – gNerb Aug 3 '18 at 15:08
0

Here are the code snippets you can use. The below code, assumes using the standard Account object and a field set for Account.Replace it with your respective custom object.

Retrieve fieldSet instance by Name

Schema.SObjectType.Account.fieldSets.getMap().get('YOUR_FIELD_SET_NAME');

Generate a dynamic Soql query to retrieve Account records based on the FieldSet using the following class

public with sharing SoqlQueryHelper{

    public static String build(SObjectType pObjectType, List<Schema.FieldSetMember> pFieldsetMembers){

        if(pFieldsetMembers == null){
            return null;
        }

        String query = 'Select ';

        for(Schema.FieldSetMember field :pFieldsetMembers){
            query += field.getFieldPath() + ', ';
        }

        //Add more criteria here to filter the exact record
        query += ' Id, Name From ' + pObjectType.getName() + ' Limit 1';

        return query;
    }

    public static String List<Account> execute(String pSoqlQuery){
        return Database.query(pSoqlQuery);
    }
}

Serialize the retrieved results and set it as your REST Service Body

HttpRequest restRequestInstance = new HttpRequest();
.
.
restRequestInstance.setBody(Json.serialize(SoqlQueryHelper.execute('YOUR_SOQL_QUERY')));

Refer the following FieldSet Class article to understand more about using FieldSets within Apex

  • I like this approach and for the most part it works but this does actually serialize additional information beyond the fields queried which the OP may not want. My tests show that it serializes an attribute named "attributes" that is an object of some additional data (in my test it just included the SObject type but there could be more). Additionally, your sample assumes he's only sending the account. The record is an attribute in of the rest call, not the entire rest call. – gNerb Aug 2 '18 at 20:06
  • It does add attributes to the response and hence you will need to write a a custom Json generator using a Map and Dynamic Apex to generate the desired Json string. – Jigar Shah Aug 2 '18 at 20:13
  • 1
    Yup, that's what my answer explains below – gNerb Aug 2 '18 at 20:15
  • The above code was a sample trying to showcase the approach on how the desired requirement can be achieved. – Jigar Shah Aug 2 '18 at 20:15

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