2

I have a scenario where the external party might send three different types of payloads: TypeA, TypeB, TypeC. for TypeA I will match and update 20 Account fields, for TypeB = 10 fiels, for TypeC = 5fiels. Using Json2Apex, now I have 3 classes for each Type and a restresource class where I will need to check if the incoming payload is typeA, typeB, or TypeC to make the correct mappings and updates. ** all the payloads have the parameter called 'Type' where it indicates the Type. I have an example code, I want to know if there is a better way to build and implement this scenario. thank you.

@RestResource(urlMapping='/urlMapping')
global without sharing class TSTscriptForwebService {
global class ResponseClass {
    public boolean success;
    public string message;
    public ResponseClass(boolean success, string message){
        this.success = success;
        this.message = message;
    }
}
@httpPost    
global static ResponseClass postCalls(){

    String requestBody ;

    try {

        requestBody = RestContext.request.requestBody.toString();
        typeA payloadA = typeA.parse(requestBody);

        if(payloadA.type == 'A') {
            /* 
            SOQL
            name = payloadA.Name 
            age = payloadA.age
            etc...   update; 
            */
        } else if(payloadA.type == 'B') {
            typeB payloadB = typeB.parse(requestBody); 
            /* 
            SOQL
            name = payloadB.Name 
            age = payloadB.age
            etc...   update; 
            */

        } else /*typeC*/ {
            typeC payloadC = typeC.parse(requestBody); 
            /* 
            SOQL
            name = payloadC.Name 
            age = payloadC.age
            etc...   update; 
            */
        }
    } catch(Exception e) {    
        ResponseClass resp = new ResponseClass(false, e.getMessage());
        return resp;
    }
    
    return new ResponseClass(true, '');    
  }
}
3
  • Why do you need to have three different types of Parser class? Can it not be a single class and you simply parse to it. Commented Oct 23, 2022 at 16:06
  • payloads have different parameters which i map to different fields on each scenario. I could create 1 parser class with all the parameters and use the Safe Navigation but wanted to separate each logic to different class to have readability and scalability.
    – kkJhn
    Commented Oct 23, 2022 at 16:09
  • 1
    Haven't tried it, but what happens if you would have only one type that contains all properties? Then you could implement a "setIfNotEmpty" function and spare the if condition for selecting the type
    – Hyperzwerg
    Commented Oct 23, 2022 at 16:35

2 Answers 2

1

You can create a metadata where you can store all the fields and its type in which it falls.

And you can create 1 parser class with all the parameter.

Based on type you can get the fields that need to be mapped using dynamic apex.

I had implemented similar kind of stuff using metadata. So next time any other type come you need not to modify your code. You just have to update the metadata with new type.

1

Based on the comments if readability is the goal, one way would be to keep the mappings in the Parser class like below and use Interfaces and do a dependency injection.

public Interface GenericType {
    
    public void updateAccount();
}

// TypeB Class Example

public class TypeB implements GenericType{
    Account acc;

     public TypeB(String requestBody) {
         typeB payloadB = typeB.parse(requestBody); 
        /* 
        SOQL
        name = payloadB.Name 
        age = payloadB.age
        
        */
     }
     
     public void updateAccount() {
         update this.acc;
     }
}

// Implement same way for Class A and Class C.

And then I would Create an generic interface

@RestResource(urlMapping='/urlMapping')
global without sharing class TSTscriptForwebService {
global class ResponseClass {
    public boolean success;
    public string message;
    public ResponseClass(boolean success, string message){
        this.success = success;
        this.message = message;
    }
}
@httpPost    
global static ResponseClass postCalls(){

    String requestBody ;

    try {
        Map<String, String> mapTypeByImplementation = new Map<String, String>();
        mapTypeByImplementation.put('A', 'TypeA');
        mapTypeByImplementation.put('B', 'TypeB');
        mapTypeByImplementation.put('C', 'TypeC');
        requestBody = RestContext.request.requestBody.toString();
        typeA payloadA = typeA.parse(requestBody);
        if(mapTypeByImplementation.get(payloadA.type) != null) {
 GenericType implementation = (GenericType)Type.forName(mapTypeByImplementation.get(payloadA.type));
        implementation.updateAccount();
        }
        
      }
    } catch(Exception e) {    
        ResponseClass resp = new ResponseClass(false, e.getMessage());
        return resp;
    }
    
    return new ResponseClass(true, '');    
  }
}

To understand how dependency injection can help, check out here.

BONUS -- Add custom metadata to the design to make mappings more generic.

You must log in to answer this question.

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