5

Say I have a server exposing an api that let me retrieve 'things', there are a lot of things, and as such retrieving all things at once could take down the server, hence the exposed API returns paginated things instead. The exposed API is something like this:

Page<Thing> getThings(int pageSize, Optional<Token> previousPageToken)

With Page<T> being like this:

class Page<T> {
  List<T> getValues();
  Token nextPageToken();
  boolean isLastPage();
}

On the server side I want to protect myself against clients sending overly large pageSize, e.g. by doing something like min(pageSizeSentByClient, MAX_PAGE_SIZE_AS_CONFIGURED_BY_SERVER. There might be other circumstances where the server might decide to even more/less than MAX_PAGE_SIZE_AS_CONFIGURED_BY_SERVER things at once, point is the client pageSize argument isn't nothing more than a 'soft' request, and the only way to know all pages have been consumed is to check isLastPage, and the only way to consume n items is to read pages until you've seen n items (i.e. you can't be sure that requesting 10 pages of 10 items each will give you 100 things, let's assume for a moment that we know there's >> 100 things overall to begin with).

Now my question is how to document the pageSize argument, I could say something along the lines of 'pageSize is a hint used by the server to decide how many things to return per page, consecutive pages may contain different number of things that may be bigger/smaller than pageSize'. This is long winded and I was wondering if there's a succinct/broadly accepted way to convey the very same meaning, e.g. some adjective/noun that would clear this up and make it clear that the client shouldn't see pageSize as a hard requirement for the function/API to return successfully e.g. 'pageSize is advisory', 'pageSize is best-effort', or 'pageSize is a hint'.

3
  • "I was wondering if there's a succinct [...] way to convey the very same meaning" - why? For the purposes of documentation, one sentence is not "long winded"; sure, you can refine the sentence itself in some ways, but there's danger in being too succinct. E.g. when one reads "pageSize is a hint", what should one make of that without extra context. Does that mean that the argument can be ignored for the most part? Is it OK to just send zero every time? Will a wrong interpretation result in undesirable side effects? Too concise is too vague; give me the info that I need to know. Commented Jun 14, 2020 at 23:18
  • 1
    The other issue to consider is if a consumer of your API is going bother to read the documentation in the first place. If the name 'pageSize' leads me to presume that it is just what it says on the label, I may not read the documentation for it in any depth until I run into an apparent problem. On the other hand, if the name was something like 'pageSizeHint', I'll either know from the get-go that it's intended as a suggestion, or at the very least I'll know that it's not simply the "page size", and I'll go read your docs. Commented Jun 14, 2020 at 23:18
  • Of course, I'm exaggerating a bit here to make a point, but still - go for the combination of good naming + good documentation. That's what will let you communicate the most information in a succinct way, with the level of granularity that's appropriate for the given form of communication. Commented Jun 14, 2020 at 23:27

4 Answers 4

5

If it is an argument to request something, but the caller is not sure to get it as requested, you can use the term desired page size. Desired makes clear that it's not guaranteed.

But you can be more specific in your case with desired minimum page size. This conveys the fact that the server may choose a smaller minimum, but that the page can anyway be larger.

1

If the server will never return more than pageSize items in a Page, but it can return less, then I would document pageSize as the largest size that the client is willing/able to handle.

It doesn't have to be part of the pageSize description, but it should be documented that getThings can return pages of varying size for arbitrary reasons, because the normal convention is that all pages except the last one will have the same size (in number of elements). That stems from the olden days, when the paging of information would actually be reflected in the UI.

0

You are describing a pageSizeLimit. You need a name that makes clear this value will not be exceeded without promising that it's size will be achieved.

Being less than this is not a failure. You're putting content in a fixed size box. Content can be as big as it likes. So you use as many boxes as it takes. Sometimes the box isn't completely filled. The box just limits how much content you get at a time.

This is integer division. The underfilled box is the remainder. So you could call pageSizeLimit the divisor but that puts far too much emphasis on the process that got us here rather than the result.

0

Well, I have used hint variables in the past. They tend to make callers miserable, unfortunately... Having an argument express desire instead of order certainly makes the caller of the API feel weak. Based on your description, you can never know whether your request will be served as expected. This is merely an invitation for tricks.

First thing I would do as a caller of the API would be a binary search to find out which is the maximum page size that can be requested and actually served. Thereafter, I would scale that down in various divisions, so if I find out it's 824, I would make some constants such as 10, 50, 100, 500 and expose only those to callers of my API, which is using your API. It's really all about consistency and nice, round numbers!

How would this use case make you feel? So, while I don't really know what exactly these things are, think about whether it makes sense to have a continuum of values, instead of just a few, tightly controlled ones. How much actual difference is there in calling your method with pageSize values of 9 and 10. 33 and 50? 78 and 100? If there is too little benefit to be gained in non-round-value requests, better make the requests round and specific by defining a "strongly-typed integer". This could be an enum or a strong type with statically defined instances representing actual values. int really can't help you much.

Think about it... applying a minimum of 10 and a maximum of 100 practically teaches your callers about your capabilities... and they don't even have to read the instructions! Win-win!

Example (c#):

public sealed class PageSize
{
    private int _actualSize;

    public static PageSize TenPages { get; } = new PageSize(10);

    public static PageSize FiftyPages { get; } = new PageSize(50);

    public static PageSize HundredPages { get; } = new PageSize(100);

    private PageSize(int actualSize)
    {
        _actualSize = actualSize;
    }
}

//Okay, now I want to request 50 pages of things... whatever that means!
List<T> things = getThings(PageSize.FiftyPages, previousPageToken);

Use this PageSize argument and everyone will know what to expect... 10, 50, 100. Of course, you might want to be a bit less restrictive with the available values, as well as a bit more inventive with the variable names. The point is that this allows callers to know what to expect and this makes them feel stronger in control.

Keep in mind, that if it is considerably different to make calls with a difference of even 1 in your original int pageSize argument, then you may want to actually keep your existing implementation, provide maximum flexibility to your callers, of course at the expense of not always knowing what to expect. Heed the advice of the rest of the answers in that scenario. What you have in that case is, really, only a maximum page-size limit, indeed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.