diff --git a/pom.xml b/pom.xml
index fc794962..872447a5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -138,6 +138,11 @@
jsr311-api
${jsr311-api.version}
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.14
+
com.fasterxml.jackson.core
jackson-annotations
@@ -222,6 +227,12 @@
2.2
test
+
+ com.github.npathai
+ hamcrest-optional
+ 2.0.0
+ test
+
org.junit.jupiter
junit-jupiter-engine
diff --git a/src/main/java/com/spotify/github/v3/clients/GithubPage.java b/src/main/java/com/spotify/github/v3/clients/GithubPage.java
index ee3f4436..3e9e6c3a 100644
--- a/src/main/java/com/spotify/github/v3/clients/GithubPage.java
+++ b/src/main/java/com/spotify/github/v3/clients/GithubPage.java
@@ -36,6 +36,9 @@
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.http.client.utils.URIBuilder;
/**
* Async page implementation for github resources
@@ -44,12 +47,27 @@
*/
public class GithubPage implements AsyncPage {
+ static final int ITEM_PER_PAGE_DEFAULT = 30;
private final GitHubClient github;
private final String path;
private final TypeReference> typeReference;
+ private final int itemsPerPage;
+
+ protected static String formatPath(final String path, final int itemsPerPage) {
+ try {
+ URIBuilder uriBuilder = new URIBuilder(path);
+ if (uriBuilder.getQueryParams().stream().anyMatch(p -> p.getName().equals("per_page"))) {
+ return path;
+ }
+ uriBuilder.addParameter("per_page", Integer.toString(itemsPerPage));
+ return uriBuilder.toString();
+ } catch (Exception e) {
+ return path;
+ }
+ }
/**
- * C'tor.
+ * Constructor.
*
* @param github github client
* @param path resource page path
@@ -57,8 +75,27 @@ public class GithubPage implements AsyncPage {
*/
GithubPage(
final GitHubClient github, final String path, final TypeReference> typeReference) {
+ this.itemsPerPage = ITEM_PER_PAGE_DEFAULT;
+ this.github = github;
+ this.path = formatPath(path, ITEM_PER_PAGE_DEFAULT);
+ this.typeReference = typeReference;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param github github client
+ * @param path resource page path
+ * @param typeReference type reference for deserialization
+ */
+ GithubPage(
+ final GitHubClient github,
+ final String path,
+ final TypeReference> typeReference,
+ final int itemsPerPage) {
+ this.itemsPerPage = itemsPerPage;
this.github = github;
- this.path = path;
+ this.path = formatPath(path, itemsPerPage);
this.typeReference = typeReference;
}
@@ -77,7 +114,7 @@ public CompletableFuture pagination() {
.map(
prevLink ->
pageNumberFromUri(prevLink.url().toString())
- .orElseThrow(
+ .orElseThrow(
() ->
new RuntimeException(
"Could not parse page number from Link header with rel=\"next\"")));
@@ -91,7 +128,7 @@ public CompletableFuture pagination() {
.map(
lastLink ->
pageNumberFromUri(lastLink.url().toString())
- .orElseThrow(
+ .orElseThrow(
() ->
new RuntimeException(
"Could not parse page number from Link "
@@ -121,7 +158,7 @@ public CompletableFuture> nextPage() {
Optional.ofNullable(linkMap.get("next"))
.map(nextLink -> nextLink.url().toString().replaceAll(github.urlFor(""), ""))
.orElseThrow(() -> new NoSuchElementException("Page iteration exhausted"));
- return new GithubPage<>(github, nextPath, typeReference);
+ return new GithubPage<>(github, nextPath, typeReference, itemsPerPage);
});
}
@@ -134,7 +171,7 @@ public CompletableFuture hasNextPage() {
/** {@inheritDoc} */
@Override
public AsyncPage clone() {
- return new GithubPage<>(github, path, typeReference);
+ return new GithubPage<>(github, path, typeReference, itemsPerPage);
}
/** {@inheritDoc} */
@@ -153,19 +190,22 @@ private CompletableFuture