2

I have a rest resource which fetches more than 10000 records. iterates the list using foreach and adds each record to a custom wrapper class list and finally returns the custom wrapper list as response. when I hit this API with post man. It takes more than 4 seconds to get the response. is there any way to improve the performance?

What are some general best practices to improve the performance of a rest api in apex.

please find the code below.

@RestResource(urlMapping='/custom_info/*')
global class custom_Service{

    @HttpGet
    Webservice static void getAssetListForSelectedUser(){
        RestRequest req = RestContext.request;
        RestResponse res = RestContext.response;

        customWrapper result; 
        String federationId=req.params.get('recid');
        String pageSize = req.params.get('limit');
        String pageNumber = req.params.get('offset');

        User usr = new User();
        usr = [Select Id, Name, LanguageLocaleKey from User where FederationIdentifier = :federationId];

        List<Asset__c> assets = [Select Id, Name, createddate, serial__c, Field_one__c,Field_two__c,Field_three__c, Field_four__c, Field_five__c, Field_six__c Description__c from Asset__c where ownerId = : usr.id];

        result = new customWrapper(usr.name, usr.LanguageLocaleKey, assets);

        res.statusCode = 200;
        res.responseBody = Blob.valueOf(JSON.serialize(result));
        return;
    }

    global class customWrapper {
        public String name{get;set;}
        public String language{get;set;}
        public List<innerWrapper> astList{get;set;}

        public customWrapper(){}

        public customWrapper (String name, String lan, List<Asset__c> assets) {
            name = name;
            language = lan;
            for (Asset__c a : assets) {
                astList.add(new innerWrapper(a));
            }
        }
    }

    global class inner wrapper {
        public String name{get;set;}
        public String createdDate{get;set;}
        public String serial{get;set;}
        public String Field_one__c{get;set;}
        public String Field_two__c{get;set;}
        public String Field_three__c{get;set;}
        public String Field_four__c{get;set;}
        public String Field_five__c{get;set;}
        public String Field_six__c{get;set;}

        public innerWrapper(){}

        public innerWrapper(List<Asset__c> assets) {
            name = assets.name;
            createdDate = assets.createdDate;
            serial = assets.serial__c;
            fieldOne = assets.Field_one__c;
            fieldTwo = assets.Field_two__c;
            fieldThree = assets.Field_three__c;
            fieldFour = assets.Field_four__c;
            fieldFive = assets.Field_five__c;
            fieldSix = assets.Field_six__c;
        }
    }
}

please help.

4
  • Can you include your code? That would be a good start to allow specific responses on what you have written. One immediate thing to try is that a for(Integer i=0...) loop is faster than for(SObject o in list)
    – Aidan
    Apr 21, 2020 at 12:05
  • @Aidan I am working on that for loop with integer. please go through my code and let me know if it can me optimized.
    – Sisir
    Apr 21, 2020 at 12:09
  • FYI, do not use webservice when you mean global. This might confuse some developers who read your code later. webservice means you want to call this method with SOAP instead of REST, but you're using REST-only properties.
    – sfdcfox
    Apr 21, 2020 at 12:24
  • One possibility to consider: with 10k or more rows, even if your fields average a mere 8 ASCII characters, you're still looking at multiple megabits of data that you're trying to transfer. If your internet connection only gives you 1 Mbps download speed, then refactoring/optimizing your code will only give limited improvement (you'll start receiving data faster, but you'd still need to wait for all of it to be transferred).
    – Derek F
    Apr 21, 2020 at 15:03

1 Answer 1

6

Processing server-side will always cost performance. The best performance would be if you could return the data without a wrapper. Failing that, the next best option would be to optimize the code.

Several optimizations when you're talking about 10k+ items follow.

Pre-Initialize Arrays

Using List.add is relatively expensive. You can save that per-item cost with one upfront heap allocation:

Integer queryResultsSize = queryResults.size();
Wrapper[] results = new Wrapper[queryResultsSize];

In your loop, you then:

Wrapper temp = new Wrapper();
// populate temp //
// then add to list //
results[i] = temp;

Calculate Size Only Once

Many developers write this:

for(Integer i = 0; i < queryResults.size(); i++) {

You'll get better performance with:

for(Integer i = 0, s = queryResults.size(); i < s; i++) {

The difference is minimal for small lists, but really adds up when you're talking about tens of thousands of method calls.

Minimize Field Copies

If you need a wrapper, if you can at least reuse the record, you'll get better performance:

public class Wrapper {
  public String someValue;
  public Boolean someFlag;
  public sObject someRecord;
}

Is better than:

public class Wrapper {
  public String field1, field2, field3, field4, field5, field6;
  public Boolean field7, field8, field9, field10;
  public Date field11, field12, field13, field14, field15, field16;
  // ... etc ... //
}

Every field you have to set costs you CPU and wall-clock time.

Use Automatic Serialization

@HttpGet global static Wrapper[] doGet() {
  Wrapper[] results; // ... populate results //
  return results;
}

Is faster than:

@HttpGet global static void doGet() {
  Wrapper[] results; // ... populate results //
  RestContext.response.responseBody = JSON.serialize(results);
}

And:

@HttpGet global static String doGet() {
  Wrapper[] results; // ... populate results //
  return JSON.serialize(results);
}

The system is much more efficient when you let it serialize for you. The downside, of course, is you lose some control over exactly how the results are serialized.

Using a method return value also has the advantage of switching from JSON to XML by changing the Accept header with no further modification to your Apex.

You must log in to answer this question.

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