NOTE: This bug report is for JIRA Service Desk Server. Using JIRA Service Desk Cloud? See the corresponding bug report.

      Summary

      The Pagination used in JIRA Service Desk REST API does not return consistent results

      Environment

      JIRA Service Desk REST API

      Steps to Reproduce

      1. Create a GET request for Customer Requests
        <baseURL>/rest/api-name/resource-name?start=0&limit=100
        
      2. Observe the "size" from the result
        Results
          "size": 76,
          "start": 0,
          "limit": 100,
          "isLastPage": true,
        
      3. Change the start to a higher value and re-send the GET request
      4. <baseURL>/rest/servicedeskapi/request?start=20&limit=100
        
      5. Observe the "size" from the result
        Results
          "size": 36,
          "start": 20,
          "limit": 100,
          "isLastPage": true,
        
      6. Change the start to a higher value and re-send the GET request
      7. <baseURL>/rest/servicedeskapi/request?start=30&limit=100
        
      8. Observe the "size" from the result
        Results
          "size": 16,
          "start": 30,
          "limit": 100,
          "isLastPage": true,
        

      Expected Results

      From the above example, Pagination should return 56 and 46 respectively

      Actual Results

      Returned values are not 56 and 46 respectively

      Notes

      JIRA Service Desk REST API is still an experimental release as per this comment

      Workaround

      It seems that the Servicedesk api code actually skips “start” parameter amount of entires twice. So, if you add start=10, its actually doing start=20 internally. If you say start=100, its actually doing start=200.
      In order to get it working correctly, you would need to use half of the value of the start parameter that you intend to use. For instance, I tried this : 
       

      http://localhost:8080/jira792/rest/servicedeskapi/request?start=0&limit=10

      and then

      http://localhost:8080/jira792/rest/servicedeskapi/request?start=5&limit=10

            [JSDSERVER-4187] Inconsistent JIRA Service Desk REST API Pagination

            I found the issue in JSD codebase. Using sources decompiled by Intellij IDEA, but it gives you the idea.

            Let's say there are 70 requests for the user, and I'm running a query with start=50. That means there should be 20 requests on the page. Now, see comments in code below.

            ServiceDeskCustomerRequestServiceImpl:

            public Either<AnError, PagedResponse<CustomerRequest>> getCustomerRequests(@Nullable ApplicationUser user, 
                                                                                       @Nonnull CustomerRequestQuery customerRequestQuery) {
                Assertions.notNull("customerRequestQuery", customerRequestQuery);
                return Steps.begin(this.userFactory.wrap(user)).then((cu) -> {
                    return this.dispatchCustomerRequestQuery(cu.forJIRA(), customerRequestQuery);
                }).yield((cu, customerRequests) -> {
                    return customerRequests;
                }).map((input) -> {
                    // At this point input is a list of 20 CustomRequests
                    return PagedResponseImpl.toPagedResponse(customerRequestQuery.pagedRequest(), input);
                });
            }
            

            PagedResponseImpl:

            public static <T> PagedResponse<T> toPagedResponse(LimitedPagedRequest limitedPagedRequest, List<T> items) {
                // items has 20 entries, limitedPageRequest.start=50
                return filteredPageResponse(limitedPagedRequest, items, Predicates.alwaysTrue());
            }
            
            public static <T> PagedResponse<T> filteredPageResponse(LimitedPagedRequest limitedPagedRequest,
                                                                    List<T> items,
                                                                    Predicate<? super T> predicate) {
                if (predicate == null) {
                    predicate = Predicates.alwaysTrue();
                }
            
                boolean hasMore = items.size() > limitedPagedRequest.getStart() + limitedPagedRequest.getLimit();
                // This takes the iterable of 20 items and skips 50, so the result is empty. BAM!
                List<T> filteredItems = FluentIterable.from(items).skip(limitedPagedRequest.getStart())
                                                      .limit(limitedPagedRequest.getLimit()).filter(predicate).toList();
                return from(filteredItems, hasMore).pageRequest(limitedPagedRequest).build();
            }
            

            One way to fix this to replace the call in getCustomerRequests:

            // From:
            return PagedResponseImpl.toPagedResponse(customerRequestQuery.pagedRequest(), input);
            // To:
            LimitedPagedRequest pagedRequest = customerRequestQuery.pagedRequest();
            boolean hasMore = input.size() > pagedRequest.getStart() + pagedRequest.getLimit();
            return PagedResponseImpl.from(input, hasMore).pageRequest(pagedRequest).build();
            

            Konrad Garus added a comment - I found the issue in JSD codebase. Using sources decompiled by Intellij IDEA, but it gives you the idea. Let's say there are 70 requests for the user, and I'm running a query with start=50. That means there should be 20 requests on the page. Now, see comments in code below. ServiceDeskCustomerRequestServiceImpl : public Either<AnError, PagedResponse<CustomerRequest>> getCustomerRequests(@Nullable ApplicationUser user, @Nonnull CustomerRequestQuery customerRequestQuery) { Assertions.notNull( "customerRequestQuery" , customerRequestQuery); return Steps.begin( this .userFactory.wrap(user)).then((cu) -> { return this .dispatchCustomerRequestQuery(cu.forJIRA(), customerRequestQuery); }).yield((cu, customerRequests) -> { return customerRequests; }).map((input) -> { // At this point input is a list of 20 CustomRequests return PagedResponseImpl.toPagedResponse(customerRequestQuery.pagedRequest(), input); }); } PagedResponseImpl : public static <T> PagedResponse<T> toPagedResponse(LimitedPagedRequest limitedPagedRequest, List<T> items) { // items has 20 entries, limitedPageRequest.start=50 return filteredPageResponse(limitedPagedRequest, items, Predicates.alwaysTrue()); } public static <T> PagedResponse<T> filteredPageResponse(LimitedPagedRequest limitedPagedRequest, List<T> items, Predicate<? super T> predicate) { if (predicate == null ) { predicate = Predicates.alwaysTrue(); } boolean hasMore = items.size() > limitedPagedRequest.getStart() + limitedPagedRequest.getLimit(); // This takes the iterable of 20 items and skips 50, so the result is empty. BAM! List<T> filteredItems = FluentIterable.from(items).skip(limitedPagedRequest.getStart()) .limit(limitedPagedRequest.getLimit()).filter(predicate).toList(); return from(filteredItems, hasMore).pageRequest(limitedPagedRequest).build(); } One way to fix this to replace the call in getCustomerRequests : // From: return PagedResponseImpl.toPagedResponse(customerRequestQuery.pagedRequest(), input); // To: LimitedPagedRequest pagedRequest = customerRequestQuery.pagedRequest(); boolean hasMore = input.size() > pagedRequest.getStart() + pagedRequest.getLimit(); return PagedResponseImpl.from(input, hasMore).pageRequest(pagedRequest).build();

            This is a disastrous show-stopper, not a low-priority bug that deserves no attentions for years. Since the assignee is showing as inactive, does it mean it will take 2 more years for someon to notice it again?

            Konrad Garus added a comment - This is a disastrous show-stopper, not a low-priority bug that deserves no attentions for years. Since the assignee is showing as inactive, does it mean it will take 2 more years for someon to notice it again?

            Andrew Sharpe added a comment - - edited

            WORKAROUND: It appears that the start parameter is affected by a factor of 2.  Using all the examples in this thread, if you imagine applying a start value that is double what was requested, the responses line up.  This has worked out OK in my testing so far, though it should be considered a workaround at best.

            It's possible there are interactions with the other parameters that might affect this, YMMV.  See also https://jira.atlassian.com/browse/JSDSERVER-397

            Andrew Sharpe added a comment - - edited WORKAROUND: It appears that the start parameter is affected by a factor of 2.  Using all the examples in this thread, if you imagine applying a start value that is double what was requested, the responses line up.  This has worked out OK in my testing so far, though it should be considered a workaround at best. It's possible there are interactions with the other parameters that might affect this, YMMV.  See also  https://jira.atlassian.com/browse/JSDSERVER-397

            This was reported just over 2 years ago, and the API is no longer listed as experimental.  This issue also makes the API useless for anything other than the first page of results, and has more than "minor" severity for those wishing to use it.

            Andrew Sharpe added a comment - This was reported just over 2 years ago, and the API is no longer listed as experimental.  This issue also makes the API useless for anything other than the first page of results, and has more than "minor" severity for those wishing to use it.

            I'm having the same issue about the results fetch. start parameter is not offsetting the result correctly.

            I have 13 issues on my list, when I tried to get limit=3&start=0 it returns (1-3) items which is correct. But when I query the next list which is limit=3&start=3, it returns (7-9) items which is wrong.

             

            Hope it will be fixed sooner.

            Rechie Sanchez added a comment - I'm having the same issue about the results fetch. start parameter is not offsetting the result correctly. I have 13 issues on my list, when I tried to get limit=3&start=0 it returns (1-3) items which is correct. But when I query the next list which is limit=3&start=3, it returns (7-9) items which is wrong.   Hope it will be fixed sooner.

              mwadhwa@atlassian.com Milap Wadhwa (Inactive)
              cchan Chung Park Chan
              Affected customers:
              10 This affects my team
              Watchers:
              15 Start watching this issue

                Created:
                Updated:
                Resolved: