issue #15 Add paging support in recordList API, update tests, and streamline query parameter names.
This commit is contained in:
@@ -116,7 +116,7 @@ public class CfDnsClient extends CfBasicHttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides fluent API access to operations on a specific zone.
|
* Provides fluent API access to operations in a specific zone.
|
||||||
* This method returns a ZoneOperations interface that allows chaining operations
|
* This method returns a ZoneOperations interface that allows chaining operations
|
||||||
* on DNS records within the specified zone.
|
* on DNS records within the specified zone.
|
||||||
*
|
*
|
||||||
@@ -177,6 +177,33 @@ public class CfDnsClient extends CfBasicHttpClient {
|
|||||||
return response.getResult().get(0);
|
return response.getResult().get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a list of DNS records for a specified zone, with optional paging support.
|
||||||
|
*
|
||||||
|
* @param zone The zone entity containing information about the target zone.
|
||||||
|
* @return A list of RecordEntity objects representing the DNS records of the specified zone.
|
||||||
|
* @throws CloudflareApiException If an error occurs during the API request or response processing.
|
||||||
|
*/
|
||||||
|
public List<RecordEntity> recordList(ZoneEntity zone) throws CloudflareApiException {
|
||||||
|
return recordList(zone, (PagingRequest) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a list of DNS records for a specified zone, with optional paging support.
|
||||||
|
*
|
||||||
|
* @param zone The zone entity containing information about the target zone.
|
||||||
|
* @param pagingRequest The paging request containing parameters such as page size and number.
|
||||||
|
* @return A list of RecordEntity objects representing the DNS records of the specified zone.
|
||||||
|
* @throws CloudflareApiException If an error occurs during the API request or response processing.
|
||||||
|
*/
|
||||||
|
public List<RecordEntity> recordList(ZoneEntity zone, @Nullable PagingRequest pagingRequest) throws CloudflareApiException {
|
||||||
|
PagingRequest pr = pagingRequest == null ? PagingRequest.defaultPaging() : pagingRequest;
|
||||||
|
String endpoint = pr.addQueryString(CfRequest.RECORD_LIST.buildPath(zone.getId()));
|
||||||
|
RecordMultipleResponse resp = getRequest(endpoint, RecordMultipleResponse.class);
|
||||||
|
checkResponse(resp);
|
||||||
|
return resp.getResult();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves DNS records for the specified second-level domain (SLD) within a zone.
|
* Retrieves DNS records for the specified second-level domain (SLD) within a zone.
|
||||||
*
|
*
|
||||||
@@ -203,35 +230,17 @@ public class CfDnsClient extends CfBasicHttpClient {
|
|||||||
*/
|
*/
|
||||||
public List<RecordEntity> recordList(ZoneEntity zone, String sld, @Nullable RecordType... types)
|
public List<RecordEntity> recordList(ZoneEntity zone, String sld, @Nullable RecordType... types)
|
||||||
throws CloudflareApiException {
|
throws CloudflareApiException {
|
||||||
PagingRequest pagingRequest = PagingRequest.defaultPaging();
|
|
||||||
List<RecordEntity> recs = recordList(zone, sld, pagingRequest);
|
|
||||||
return filterAndSetZoneRecords(zone, types, recs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves all getRecord entities for a specific second-level domain (SLD) within a given DNS
|
|
||||||
* zone using the provided paging request parameters.
|
|
||||||
*
|
|
||||||
* @param zone The DNS zone entity for which the SLD records are to be fetched.
|
|
||||||
* @param sld The second-level domain name for which the records are retrieved.
|
|
||||||
* @param pagingRequest The paging request.
|
|
||||||
* @return A list of {@code RecordEntity} associated with the desired SLD.
|
|
||||||
* @throws CloudflareApiException If an error occurs while interacting with the Cloudflare API.
|
|
||||||
*/
|
|
||||||
public List<RecordEntity> recordList(ZoneEntity zone, String sld, PagingRequest pagingRequest)
|
|
||||||
throws CloudflareApiException {
|
|
||||||
String fqdn = buildFqdn(zone, sld);
|
String fqdn = buildFqdn(zone, sld);
|
||||||
String endpoint =
|
String endpoint = CfRequest.RECORD_LIST_NAME.buildPath(zone.getId(), fqdn);
|
||||||
pagingRequest.addQueryString(CfRequest.RECORD_INFO_NAME.buildPath(zone.getId(), fqdn));
|
|
||||||
RecordMultipleResponse resp = getRequest(endpoint, RecordMultipleResponse.class);
|
RecordMultipleResponse resp = getRequest(endpoint, RecordMultipleResponse.class);
|
||||||
checkResponse(resp);
|
checkResponse(resp, false);
|
||||||
return resp.getResult();
|
List<RecordEntity> recs = resp.getResult();
|
||||||
|
return filterAndSetZoneRecords(zone, types, recs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a list of all DNS records for a given zone.
|
* Retrieves a list of all DNS records for a given zone.
|
||||||
* Optionally filters by one or more DNS getRecord types.
|
* Optionally, filters by one or more DNS getRecord types.
|
||||||
*
|
*
|
||||||
* @param zone The zone entity containing information about the domain zone.
|
* @param zone The zone entity containing information about the domain zone.
|
||||||
* @param types Optional parameter specifying one or more DNS getRecord types to filter the results.
|
* @param types Optional parameter specifying one or more DNS getRecord types to filter the results.
|
||||||
@@ -438,7 +447,7 @@ public class CfDnsClient extends CfBasicHttpClient {
|
|||||||
Set<RecordType> allowedTypes = new HashSet<>(Arrays.asList(types));
|
Set<RecordType> allowedTypes = new HashSet<>(Arrays.asList(types));
|
||||||
filtered = recs.stream()
|
filtered = recs.stream()
|
||||||
.filter(rec -> allowedTypes.contains(RecordType.valueOf(rec.getType())))
|
.filter(rec -> allowedTypes.contains(RecordType.valueOf(rec.getType())))
|
||||||
.collect(Collectors.toList());;
|
.collect(Collectors.toList());
|
||||||
} else {
|
} else {
|
||||||
filtered = new ArrayList<>(recs);
|
filtered = new ArrayList<>(recs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,25 +26,24 @@ public enum CfRequest {
|
|||||||
* needs to be provided to construct the complete path.
|
* needs to be provided to construct the complete path.
|
||||||
*/
|
*/
|
||||||
RECORD_LIST("/zones/%s/dns_records"),
|
RECORD_LIST("/zones/%s/dns_records"),
|
||||||
|
/**
|
||||||
|
* Represents the API endpoint path for retrieving information about a DNS getRecord within a
|
||||||
|
* specific DNS zone by its name. The endpoint path includes placeholders for the zone identifier
|
||||||
|
* and the getRecord name, which need to be provided to construct the complete path.
|
||||||
|
*/
|
||||||
|
RECORD_LIST_NAME("/zones/%s/dns_records?name=%s"),
|
||||||
/**
|
/**
|
||||||
* Represents the API endpoint path for creating a new DNS getRecord within a specific DNS zone. The
|
* Represents the API endpoint path for creating a new DNS getRecord within a specific DNS zone. The
|
||||||
* endpoint path includes a placeholder for the zone identifier, which needs to be provided to
|
* endpoint path includes a placeholder for the zone identifier, which needs to be provided to
|
||||||
* construct the complete path.
|
* construct the complete path.
|
||||||
*/
|
*/
|
||||||
RECORD_CREATE("/zones/%s/dns_records"),
|
RECORD_CREATE("/zones/%s/dns_records"),
|
||||||
/**
|
|
||||||
* Represents the API endpoint path for retrieving information about a DNS getRecord within a
|
|
||||||
* specific DNS zone by its name. The endpoint path includes placeholders for the zone identifier
|
|
||||||
* and the getRecord name, which need to be provided to construct the complete path.
|
|
||||||
*/
|
|
||||||
RECORD_INFO_NAME("/zones/%s/dns_records?name=%s"),
|
|
||||||
/**
|
/**
|
||||||
* Represents the API endpoint path for updating an existing DNS getRecord within a specific DNS
|
* Represents the API endpoint path for updating an existing DNS getRecord within a specific DNS
|
||||||
* zone. The endpoint path includes placeholders for the zone identifier and the getRecord
|
* zone. The endpoint path includes placeholders for the zone identifier and the getRecord
|
||||||
* identifier, which need to be provided to construct the complete path.
|
* identifier, which need to be provided to construct the complete path.
|
||||||
*/
|
*/
|
||||||
RECORD_UPDATE("/zones/%s/dns_records/%s"),
|
RECORD_UPDATE("/zones/%s/dns_records/%s"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the API endpoint path for performing batch operations on DNS records within a specific zone.
|
* Represents the API endpoint path for performing batch operations on DNS records within a specific zone.
|
||||||
* The placeholder "%s" in the path is intended to be replaced by a zone identifier.
|
* The placeholder "%s" in the path is intended to be replaced by a zone identifier.
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public class PagingRequest {
|
|||||||
* Default page size for retrieving all records in a single request.
|
* Default page size for retrieving all records in a single request.
|
||||||
* Set to a very high value to effectively disable pagination when fetching all records.
|
* Set to a very high value to effectively disable pagination when fetching all records.
|
||||||
*/
|
*/
|
||||||
private static final int DEFAULT_ALL_RECORDS_PAGE_SIZE = 5_000_000;
|
private static final int DEFAULT_ALL_RECORDS_PAGE_SIZE = 1000;
|
||||||
|
|
||||||
private int page;
|
private int page;
|
||||||
private int perPage;
|
private int perPage;
|
||||||
@@ -77,7 +77,7 @@ public class PagingRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String queryString(boolean add) {
|
private String queryString(boolean add) {
|
||||||
String qs = "page=" + page + "&perPage=" + perPage;
|
String qs = "page=" + page + "&per_page=" + perPage;
|
||||||
return add ? "&" + qs : "?" + qs;
|
return add ? "&" + qs : "?" + qs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,14 +9,18 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||||
|
|
||||||
import codes.thischwa.cf.model.BatchEntry;
|
import codes.thischwa.cf.model.BatchEntry;
|
||||||
|
import codes.thischwa.cf.model.PagingRequest;
|
||||||
import codes.thischwa.cf.model.RecordEntity;
|
import codes.thischwa.cf.model.RecordEntity;
|
||||||
import codes.thischwa.cf.model.RecordType;
|
import codes.thischwa.cf.model.RecordType;
|
||||||
import codes.thischwa.cf.model.ZoneEntity;
|
import codes.thischwa.cf.model.ZoneEntity;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -91,6 +95,19 @@ public class CfClientTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testZoneList() throws CloudflareApiException {
|
||||||
|
List<ZoneEntity> zones = client.zoneList();
|
||||||
|
assertNotNull(zones);
|
||||||
|
assertFalse(zones.isEmpty());
|
||||||
|
assertEquals(ZONE_STR, zones.get(0).getName());
|
||||||
|
|
||||||
|
zones = client.zoneList(PagingRequest.of(1, 100));
|
||||||
|
assertNotNull(zones);
|
||||||
|
assertFalse(zones.isEmpty());
|
||||||
|
assertEquals(ZONE_STR, zones.get(0).getName());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testZoneListAnlFailedSldList() throws Exception {
|
void testZoneListAnlFailedSldList() throws Exception {
|
||||||
List<ZoneEntity> zList = client.zoneList();
|
List<ZoneEntity> zList = client.zoneList();
|
||||||
@@ -445,4 +462,68 @@ public class CfClientTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPaging() throws Exception {
|
||||||
|
ZoneEntity zone = client.zoneGet(ZONE_STR);
|
||||||
|
String pagingSld = "paging-" + System.currentTimeMillis();
|
||||||
|
|
||||||
|
try {
|
||||||
|
int existingCount = 0;
|
||||||
|
try {
|
||||||
|
List<RecordEntity> allRecords = client.recordList(zone);
|
||||||
|
existingCount = allRecords.size();
|
||||||
|
} catch (CloudflareApiException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate how many records we need to create to reach at least 12 total A records
|
||||||
|
// (to test paging with pageSize 5: page 1 = 5, page 2 = 5, page 3 = 2+)
|
||||||
|
int targetCount = 12;
|
||||||
|
int recordsToCreate = Math.max(0, targetCount - existingCount);
|
||||||
|
|
||||||
|
// Create additional A records if needed
|
||||||
|
List<RecordEntity> createdRecords = new ArrayList<>();
|
||||||
|
for (int i = 1; i <= recordsToCreate; i++) {
|
||||||
|
RecordEntity record = RecordEntity.build(pagingSld, RecordType.A, TTL, "127.0.0." + i);
|
||||||
|
RecordEntity created = client.recordCreate(zone, record);
|
||||||
|
createdRecords.add(created);
|
||||||
|
assertNotNull(created.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test paging with page size of 5
|
||||||
|
PagingRequest page1Request = PagingRequest.of(1, 5);
|
||||||
|
List<RecordEntity> page1Records = client.recordList(zone, page1Request);
|
||||||
|
assertEquals(5, page1Records.size(), "First page should contain 5 records");
|
||||||
|
|
||||||
|
// 2nd page should also contain 5 records (if we have at least 12 total)
|
||||||
|
PagingRequest page2Request = PagingRequest.of(2, 5);
|
||||||
|
List<RecordEntity> page2Records = client.recordList(zone, page2Request);
|
||||||
|
assertEquals(5, page2Records.size(), "Second page should contain at least 5 records");
|
||||||
|
|
||||||
|
// 3rd page should contain 2 records
|
||||||
|
PagingRequest page3Request = PagingRequest.of(3, 5);
|
||||||
|
List<RecordEntity> page3Records = client.recordList(zone, page3Request);
|
||||||
|
assertEquals(2, page3Records.size(), "Third page should contain 2 records");
|
||||||
|
|
||||||
|
// Verify no overlap between pages
|
||||||
|
List<String> page1Ids = page1Records.stream().map(RecordEntity::getId).toList();
|
||||||
|
List<String> page2Ids = page2Records.stream().map(RecordEntity::getId).toList();
|
||||||
|
List<String> page3Ids = page3Records.stream().map(RecordEntity::getId).toList();
|
||||||
|
Set<String> generatedRecordIds = new HashSet<>(page1Ids);
|
||||||
|
generatedRecordIds.addAll(page2Ids);
|
||||||
|
generatedRecordIds.addAll(page3Ids);
|
||||||
|
assertEquals(createdRecords.size(), generatedRecordIds.size());
|
||||||
|
|
||||||
|
// Verify our created records are in the zone
|
||||||
|
List<RecordEntity> allRecords = client.recordList(zone);
|
||||||
|
Set<String> allRecordIds = allRecords.stream().map(RecordEntity::getId).collect(Collectors.toSet());
|
||||||
|
assertEquals(createdRecords.size(), allRecordIds.size());
|
||||||
|
assertTrue(allRecordIds.containsAll(generatedRecordIds));
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
client.recordDeleteTypeIfExists(zone, pagingSld, RecordType.A);
|
||||||
|
} catch (Exception e) { /* ignore */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class CfRequestTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBuildRecordInfoName() {
|
public void testBuildRecordInfoName() {
|
||||||
String result = CfRequest.RECORD_INFO_NAME.buildPath("zone123", "sub.domain.com");
|
String result = CfRequest.RECORD_LIST_NAME.buildPath("zone123", "sub.domain.com");
|
||||||
assertEquals("/zones/zone123/dns_records?name=sub.domain.com", result);
|
assertEquals("/zones/zone123/dns_records?name=sub.domain.com", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ public class CfRequestTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBuildRecordInfo() {
|
public void testBuildRecordInfo() {
|
||||||
String result = CfRequest.RECORD_INFO_NAME.buildPath("zone123", "sld.domain.com");
|
String result = CfRequest.RECORD_LIST_NAME.buildPath("zone123", "sld.domain.com");
|
||||||
assertEquals("/zones/zone123/dns_records?name=sld.domain.com", result);
|
assertEquals("/zones/zone123/dns_records?name=sld.domain.com", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ public class PagingRequestTest {
|
|||||||
@Test
|
@Test
|
||||||
void testBuildPath() {
|
void testBuildPath() {
|
||||||
String result = PagingRequest.defaultPaging().addQueryString("/zones");
|
String result = PagingRequest.defaultPaging().addQueryString("/zones");
|
||||||
assertEquals("/zones?page=1&perPage=5000000", result);
|
assertEquals("/zones?page=1&per_page=1000", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testBuildPathAdditional() {
|
void testBuildPathAdditional() {
|
||||||
String result = new PagingRequest( 10, 100).addQueryString("/zones?foo=bar");
|
String result = new PagingRequest( 10, 100).addQueryString("/zones?foo=bar");
|
||||||
assertEquals("/zones?foo=bar&page=10&perPage=100", result);
|
assertEquals("/zones?foo=bar&page=10&per_page=100", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration>
|
<configuration debug="true">
|
||||||
|
|
||||||
<appender name="current"
|
<appender name="current"
|
||||||
class="ch.qos.logback.core.ConsoleAppender">
|
class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
|||||||
Reference in New Issue
Block a user