0

I have rest resource exposed to a external system. It is a simple rest api where i get a single parameter from the URL and query a custom object based on that param and return the results in a custom wrapper class.

This custom object has more that 150000 records. now the external system is asking for pagination. Please let me know how do i achieve this.

I tried using StandardSetController and i got an error saying No Visualforce context has been established!

please find the sample code below without pagination...

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

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

        customWrapper result = new customWrapper(); 
        String federationId=req.params.get('recid');

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

        List<Asset__c> assets = [Select Id, Name, createddate, serial__c, Description__c from Asset__c where ownerId = : usr.id Limit 30000];

        result.name = usr.name;
        result.name = usr.LanguageLocaleKey;
        result.assets = 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<Asset__c> assets{get;set;}

        public customWrapper(){}

    }
}

Below is the sample code with pagination using standardsetcontroller. For pagination i receive 2 more params offset and limit. But i am getting No Visualforce context has been established! error.

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

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

        customWrapper result = new customWrapper(); 
        ApexPages.StandardSetController setController = null;
        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, Description__c from Asset__c where ownerId = : usr.id];

        setController = new ApexPages.StandardSetController(assets);
        if((pageSize != '' || pageSize != null) && (pageNumber != '' || pageNumber != null)) {
            setController.setPageSize(Integer.valueOf(pageSize));
            setController.setPageNumber(Integer.valueOf(pageNumber));
        }else {
            setController.setPageSize(1000);
            setController.setPageNumber(1);
        }

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

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

    global class customWrapper extends PaginatedResult {
        public String name{get;set;}
        public String language{get;set;}
        public List<Asset__c> assets{get;set;}

        public customWrapper(){}

        public customWrapper (String name, String lan, ApexPages.StandardSetController c) {
            super(c);
            name = name;
            language = lan;
            for (Asset__c a : (Asset__c[])c.getRecords()) {
                assets.add(a);
            }
        }
    }

    public virtual class PaginatedResult {
    public Integer page; 
    public Integer pageSize;
    public Integer pageCount;
    public Integer total;

    public PaginatedResult() {}

    public PaginatedResult(ApexPages.StandardSetController c) {

      page = c.getPageNumber();
      total = c.getResultSize();
      calcPagination(c.getPageSize());
    }

    public void calcPagination(Integer pageSize) {
      this.pageSize = pageSize;
      pageCount = total / pageSize;
      pageCount = (Integer)(Math.floor(pageCount) + ((Math.mod(total, pageSize) > 0) ? 1 : 0));
    }
  }
}

Please help....

  • 2
    Why are you marking a HTTP endpoint with the webservice keyword webservice keyword is for marking a SOAP endpoint? – Zach Hutchins Nov 21 '19 at 14:15
  • @ZachHutchins i get what you are saying. even i had the same doubt. but this is an existing code in my org. Not sure why they have written like that. Need to get more info on that as well. – Sisir Nov 21 '19 at 14:30
1

You will have to use the [OFFSET][1] keyword in your SOQL query for Assets. However, the problem you will run into is that the OFFSET keyword has a max value of 2000. Salesforce does have a workaround for this.

|improve this answer|||||
2

I would suggest you do the following:

  • Add an autonumber field to Asset
  • Adapt the queryMore pattern used in OOTB REST.
  • Change your query to look something like this:

    ... WHERE MyAutoNumberField__c > urlParamOffset
        ORDER BY MyAutoNumberField__c
        LIMIT 1000 // or whatever pgsize you need to use
    

where `urlParamOffset defaults to zero but otherwise is supplied by the REST client because you pass it back as a response to the client the last autoNumberField fetched in the query (i.e. the 1000th record retrieved)

|improve this answer|||||
  • There is already a unique field which i used to apply pagination. – Sisir Nov 25 '19 at 9:08

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.