How to use InventoryApi to query paginated data

Hi,

we’re using the Java Microservice SDK 1020.155.0 in a Cumulocity Microservice. The Microservice offers a REST API to its users where they can query some specific objects in the Inventory.

Now we have a question rgd the usage of pagination queries using the InventoryApi.

As long as the Micropservice exists, this logic (probably inherited and/or copied from some tutorial/example) is being used:

// the filter contains something like "owner" or "type", but it does *not* contain the requested currentPage or pageSize
final ManagedObjectCollection managedObjectsByFilter = inventoryApi.getManagedObjectsByFilter(filter); 

// here we use the pageSize
PagedManagedObjectCollectionRepresentation collectionRepresentation = managedObjectsByFilter.get(pageSize); 

// here we use currentPage & pageSize
PagedManagedObjectCollectionRepresentation pagedMOCollection = managedObjectsByFilter.getPage(collectionRepresentation, currentPage, pageSize); 

When debugging this code section and recording the actual REST requests to Inventory made under the hood (to find an unrelated bug), we surprisingly found out that actually two requests were made:

1. managedObjectsByFilter.get(pageSize): executes a REST request with the filter criteria and pageSize; since there is no way to define the currentPage, the platform defaults will be used, i.e. the first page will be loaded
2. managedObjectsByFilter.getPage(collectionRepresentation, currentPage, pageSize): executes another REST request based on the previously defined filter plus the given pageSize & currentPage

While the first request *always* queries the first page, only the second one queries for the data which the user actually requested. At the end, the data returned is correct, but obviously we questioned if this is the right way to go.

So now we came up with a slightly different approach:

// the filter now contains the query but also the requested *currentPage*, but not the pageSize !
final ManagedObjectCollection managedObjectsByFilter = getInventoryApi().getManagedObjectsByFilter(filter); 

// now this is the same call as above using the pageSize
PagedManagedObjectCollectionRepresentation collectionRepresentation = managedObjectsByFilter.get(pageSize);

Since the com.cumulocity.sdk.client.inventory.InventoryFilter class does not provide the “currentPage” field, we extended it like this:

public class CustomInventoryFilter extends InventoryFilter {

    @Getter
    @ParamSource
    private String currentPage;

    public CustomInventoryFilter withCurrentPage(int currentPage) {
        this.currentPage = String.valueOf(currentPage);
        return this;
    } 
}

While all our Unit/Cypress tests are still green :slight_smile: we’d still get your feedback on this topic. Are there any disadvantages of using the new approach? Any use cases of the initial implementation that are not covered with the new one? Did we miss an example or hint in the doc? Here I can only see usages like this, but this does not fit our use case:

inventory.getManagedObjectsByFilter(inventoryFilter).get().allPages();

Is the latter approach even considered best practice?

Thanks a lot!

Michael

3 Likes

TBH i had the above code in one of the projects. But this no longer seems to work in my new project where i was trying to query all the data along with the pagesize/allpages/query. I was also looking into how to get it working. Well atleast i can give your approach a try otherwise i was thinking of using the rest connector directly.

managedObjectsByFilter.get(pageSize)

This method above does allow specifying the desired page through providing a QueryParam in the varags argument (see: PagedCollectionResource.java#L48). You can define custom query params this way, including currentPage. You just need to be aware that subsequent calls to the returned collection may also be affected.

Admittedly, declaring and using aQueryParam implementation is somewhat clunky but the possibility exists.

Also: Feel free to contribute this approach as change to Cumulocity-IoT/cumulocity-clients-java. The repository is open-source and we welcome worthwhile changes from both internal and external contributors.

1 Like

Thank you Philipp, we refactored our approach and it works as expected:

// filter without currentPage, pageSize, withTotal* parameters
final ManagedObjectCollection managedObjectsByFilter = getInventoryApi().getManagedObjectsByFilter(inventoryFilter); 
QueryParam currentPageParam = new QueryParam(() -> "currentPage", String.valueOf(currentPage)); 
QueryParam withTotalElementsParam = new QueryParam(() -> "withTotalElements", Boolean.TRUE.toString()); 
QueryParam totalPagesParam = new QueryParam(PagingParam.WITH_TOTAL_PAGES, Boolean.TRUE.toString()); 
managedObjectsByFilter.get(pageSize, currentPageParam, totalPagesParam, withTotalElementsParam);

As you said, the missing QueryParams for various parameters are a bit hacky to create, but could surely be improved.