issue #9:
Change default behavior of `emptyResultThrowsException` to `false`, update `ResponseValidator` for improved handling of single and multiple results, and enhance test coverage and documentation. Add Fluent API for DNS operations, update `README`, and refactor `CfDnsClient` for zone-level chaining. Validate record type in `RecordEntity#build`, throw exception for invalid types, and add test coverage. Refactor `RecordEntity#getSld` to handle `zoneName` cases, improve null safety, and enhance substring logic. Refactor `RecordEntity` getter (`getName` → `getSld`) for clarity, improve string handling in batch processing, and enhance type safety in HTTP operations. Update tests and documentation accordingly. Refactor `deleteRequest` and `patchRequest` to accept `responseType` parameter for improved flexibility. Extract methods for cleaning and processing batch DNS records. Refactor API method names for consistency (`zoneListAll` → `zoneList`, `zoneInfo` → `zoneGet`, `sldListAll` → `recordList`, `sldInfo` → `recordGet`) and update related documentation and tests.
This commit is contained in:
@@ -50,6 +50,16 @@ The dependency is:
|
||||
## Changelog
|
||||
|
||||
- 0.2.0-beta-SNAPSHOT:
|
||||
- **New Fluent API**: Added chainable method interface for more readable DNS operations (
|
||||
`client.zone().record()...`)
|
||||
- **Breaking Change**: `emptyResultThrowsException` default changed from `true` to `false`. Now applies to both
|
||||
single and multiple result requests. Empty results will be returned by default without throwing exceptions.
|
||||
- API method names refactored for consistency: `zoneListAll` → `zoneList`, `zoneInfo` → `zoneGet`, `sldListAll` →
|
||||
`recordList`, `sldInfo` → `recordGet`
|
||||
- RecordEntity getter methods renamed for clarity: `getName()` → `getSld()`
|
||||
- Code quality improvements: eliminated duplication in batch operations, improved type safety in HTTP methods,
|
||||
optimized string concatenation, removed mutable setters from CfDnsClient
|
||||
- Enhanced type validation in `RecordEntity.build()` with better error messages
|
||||
- CfClient#sldInfo must return multiple RecordEntries
|
||||
- add a missing source jar
|
||||
- ResponseResultInfo#Errors: wrong object structure
|
||||
@@ -68,6 +78,11 @@ The methods can be categorized as follows:
|
||||
- `Zone`: list, info
|
||||
- `Record`: list, info, create, update, delete
|
||||
|
||||
The API provides two styles for working with DNS records:
|
||||
|
||||
1. **Traditional API**: Direct method calls with explicit parameters
|
||||
2. **Fluent API**: Chainable method calls for more readable code
|
||||
|
||||
The following text focuses on the basic methods. For further information, take a look at
|
||||
the [javadoc of the CfDnsClient](https://cloudflaredns-java-f4ee3a.gitlab.io/apidocs/codes/thischwa/cf/CfDnsClient.html).
|
||||
|
||||
@@ -79,20 +94,20 @@ CfDnsClient cfDnsClient = new CfDnsClient(
|
||||
);
|
||||
```
|
||||
|
||||
### `zoneListAll`
|
||||
### `zoneList`
|
||||
|
||||
Retrieve all zones within the Cloudflare account.
|
||||
|
||||
- **Returns**: A list of `ZoneEntity` objects.
|
||||
|
||||
```java
|
||||
List<ZoneEntity> zones = cfDnsClient.zoneListAll();
|
||||
List<ZoneEntity> zones = cfDnsClient.zoneList();
|
||||
zones.forEach(zone -> System.out.println("Zone: " + zone.getName()));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `zoneInfo`
|
||||
### `zoneGet`
|
||||
|
||||
Get detailed information about a specific zone by its name.
|
||||
|
||||
@@ -101,13 +116,13 @@ Get detailed information about a specific zone by its name.
|
||||
- **Returns**: A `ZoneEntity` object.
|
||||
|
||||
```java
|
||||
ZoneEntity zone = cfDnsClient.zoneInfo("example.com");
|
||||
ZoneEntity zone = cfDnsClient.zoneGet("example.com");
|
||||
System.out.println("Zone ID: " + zone.getId());
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `sldListAll`
|
||||
### `recordList`
|
||||
|
||||
Retrieve all records for a specific second-level domain (SLD) under a given zone.
|
||||
|
||||
@@ -117,15 +132,17 @@ Retrieve all records for a specific second-level domain (SLD) under a given zone
|
||||
- **Returns**: A list of `RecordEntity` objects.
|
||||
|
||||
```java
|
||||
List<RecordEntity> records = cfDnsClient.sldListAll(zone, "sld");
|
||||
records.forEach(record ->
|
||||
List<RecordEntity> records = cfDnsClient.recordList(zone, "sld");
|
||||
records.
|
||||
|
||||
forEach(record ->
|
||||
System.out.println("Record Type: " + record.getType() + ", Value: " + record.getContent())
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `sldInfo`
|
||||
### `recordGet`
|
||||
|
||||
Retrieve DNS record details for a specific SLD and zone, optionally filtered by record types.
|
||||
|
||||
@@ -138,28 +155,28 @@ Retrieve DNS record details for a specific SLD and zone, optionally filtered by
|
||||
|
||||
```java
|
||||
// Get all records for a specific SLD
|
||||
List<RecordEntity> allRecords = cfDnsClient.sldInfo(zone, "www");
|
||||
List<RecordEntity> allRecords = cfDnsClient.recordGet(zone, "www");
|
||||
allRecords.
|
||||
|
||||
forEach(record ->
|
||||
System.out.
|
||||
|
||||
println("Type: "+record.getType() +", Content: "+record.
|
||||
println("Type: "+record.getType()+", Content: "+record.
|
||||
|
||||
getContent())
|
||||
);
|
||||
getContent()));
|
||||
|
||||
// Get only A records
|
||||
List<RecordEntity> aRecords = cfDnsClient.sldInfo(zone, "www", RecordType.A);
|
||||
List<RecordEntity> aRecords = cfDnsClient.recordGet(zone, "www", RecordType.A);
|
||||
System.out.
|
||||
|
||||
println("Found "+aRecords.size() +" A records");
|
||||
|
||||
// Get A and AAAA records
|
||||
List<RecordEntity> ipRecords = cfDnsClient.sldInfo(zone, "www", RecordType.A, RecordType.AAAA);
|
||||
List<RecordEntity> ipRecords = cfDnsClient.recordGet(zone, "www", RecordType.A, RecordType.AAAA);
|
||||
ipRecords.
|
||||
|
||||
forEach(record ->System.out.
|
||||
forEach(record ->
|
||||
System.out.
|
||||
|
||||
println("IP Record: "+record.getContent()));
|
||||
```
|
||||
@@ -232,20 +249,25 @@ Process multiple DNS record operations (POST, PUT, PATCH, DELETE) in a single ba
|
||||
|
||||
- **Parameters**:
|
||||
- `ZoneEntity zone` - The target zone.
|
||||
- `List<RecordEntity> postRecords` - Records to create (nullable).
|
||||
- `List<RecordEntity> putRecords` - Records to fully replace (nullable).
|
||||
- `List<RecordEntity> patchRecords` - Records to partially update (nullable).
|
||||
- `List<RecordEntity> deleteRecords` - Records to delete (nullable).
|
||||
- `List<RecordEntity> postRecords` - Records to create (nullable). Can be built without IDs.
|
||||
- `List<RecordEntity> putRecords` - Records to fully replace (nullable). **Requires record IDs**.
|
||||
- `List<RecordEntity> patchRecords` - Records to partially update (nullable). **Requires record IDs**.
|
||||
- `List<RecordEntity> deleteRecords` - Records to delete (nullable). **Requires record IDs**.
|
||||
- **Returns**: A `BatchEntry` object containing the processed records.
|
||||
|
||||
**Important**: For UPDATE (PATCH), REPLACE (PUT), and DELETE operations, you must first retrieve the existing records to
|
||||
obtain their IDs.
|
||||
|
||||
#### Batch Create (POST)
|
||||
|
||||
Create new records, IDs are not required:
|
||||
|
||||
```java
|
||||
List<RecordEntity> newRecords = Arrays.asList(
|
||||
RecordEntity.build("api." + zone.getName(), RecordType.A, 60, "192.168.1.10"),
|
||||
RecordEntity.build("cdn." + zone.getName(), RecordType.A, 60, "192.168.1.11"),
|
||||
RecordEntity.build("mail." + zone.getName(), RecordType.A, 60, "192.168.1.12")
|
||||
);
|
||||
|
||||
BatchEntry result = cfDnsClient.recordBatch(zone, newRecords, null, null, null);
|
||||
System.out.
|
||||
|
||||
@@ -256,18 +278,30 @@ size() +" records.");
|
||||
|
||||
#### Batch Update (PATCH)
|
||||
|
||||
Partially update existing records. **Record IDs are required** - fetch them first:
|
||||
|
||||
```java
|
||||
// Fetch existing records and modify them
|
||||
List<RecordEntity> recordsToUpdate = Arrays.asList(
|
||||
cfDnsClient.sldInfo(zone, "api", RecordType.A),
|
||||
cfDnsClient.sldInfo(zone, "cdn", RecordType.A)
|
||||
);
|
||||
// Step 1: Fetch existing records to get their IDs
|
||||
List<RecordEntity> recordsToUpdate = new ArrayList<>();
|
||||
recordsToUpdate.
|
||||
|
||||
add(cfDnsClient.recordGet(zone, "api",RecordType.A).
|
||||
|
||||
get(0));
|
||||
recordsToUpdate.
|
||||
|
||||
add(cfDnsClient.recordGet(zone, "cdn",RecordType.A).
|
||||
|
||||
get(0));
|
||||
|
||||
// Step 2: Modify only the fields you want to update
|
||||
recordsToUpdate.
|
||||
|
||||
forEach(record ->record.
|
||||
|
||||
setContent("192.168.2.10"));
|
||||
|
||||
// Step 3: Send batch update request
|
||||
BatchEntry result = cfDnsClient.recordBatch(zone, null, null, recordsToUpdate, null);
|
||||
System.out.
|
||||
|
||||
@@ -278,14 +312,25 @@ size() +" records.");
|
||||
|
||||
#### Batch Replace (PUT)
|
||||
|
||||
Fully replace existing records. **Record IDs are required** - fetch them first:
|
||||
|
||||
```java
|
||||
// Fetch existing records and fully replace them
|
||||
List<RecordEntity> recordsToReplace = Arrays.asList(
|
||||
cfDnsClient.sldInfo(zone, "api", RecordType.A),
|
||||
cfDnsClient.sldInfo(zone, "cdn", RecordType.A)
|
||||
);
|
||||
// Step 1: Fetch existing records to get their IDs
|
||||
List<RecordEntity> recordsToReplace = new ArrayList<>();
|
||||
recordsToReplace.
|
||||
|
||||
add(cfDnsClient.recordGet(zone, "mail",RecordType.A).
|
||||
|
||||
get(0));
|
||||
recordsToReplace.
|
||||
|
||||
add(cfDnsClient.recordGet(zone, "cdn",RecordType.A).
|
||||
|
||||
get(0));
|
||||
|
||||
// Step 2: Modify all fields as needed (full replacement)
|
||||
recordsToReplace.
|
||||
|
||||
get(0).
|
||||
|
||||
setContent("192.168.3.10");
|
||||
@@ -294,7 +339,18 @@ recordsToReplace.
|
||||
get(0).
|
||||
|
||||
setTtl(120);
|
||||
recordsToReplace.
|
||||
|
||||
get(1).
|
||||
|
||||
setContent("192.168.3.11");
|
||||
recordsToReplace.
|
||||
|
||||
get(1).
|
||||
|
||||
setTtl(120);
|
||||
|
||||
// Step 3: Send batch replace request
|
||||
BatchEntry result = cfDnsClient.recordBatch(zone, null, recordsToReplace, null, null);
|
||||
System.out.
|
||||
|
||||
@@ -305,28 +361,177 @@ size() +" records.");
|
||||
|
||||
#### Batch Delete
|
||||
|
||||
Delete existing records. **Record IDs are required** - fetch them first:
|
||||
|
||||
```java
|
||||
List<RecordEntity> recordsToDelete = Arrays.asList(
|
||||
cfDnsClient.sldInfo(zone, "api", RecordType.A),
|
||||
cfDnsClient.sldInfo(zone, "mail", RecordType.A)
|
||||
);
|
||||
// Step 1: Fetch existing records to get their IDs
|
||||
List<RecordEntity> recordsToDelete = new ArrayList<>();
|
||||
recordsToDelete.
|
||||
|
||||
add(cfDnsClient.recordGet(zone, "cdn",RecordType.A).
|
||||
|
||||
get(0));
|
||||
recordsToDelete.
|
||||
|
||||
add(cfDnsClient.recordGet(zone, "mail",RecordType.A).
|
||||
|
||||
get(0));
|
||||
|
||||
// Step 2: Send batch delete request
|
||||
BatchEntry result = cfDnsClient.recordBatch(zone, null, null, null, recordsToDelete);
|
||||
System.out.
|
||||
|
||||
println("Deleted records.");
|
||||
println("Deleted "+recordsToDelete.size() +" records.");
|
||||
```
|
||||
|
||||
#### Combined Batch Operations
|
||||
|
||||
Combine multiple operations in a single batch request:
|
||||
|
||||
```java
|
||||
// You can combine multiple operations in a single batch request
|
||||
BatchEntry result = cfDnsClient.recordBatch(
|
||||
zone,
|
||||
newRecords, // POST
|
||||
putRecords, // PUT
|
||||
patchRecords, // PATCH
|
||||
deleteRecords // DELETE
|
||||
// Create new records (no IDs needed)
|
||||
List<RecordEntity> newRecords = Arrays.asList(
|
||||
RecordEntity.build("new-api." + zone.getName(), RecordType.A, 60, "192.168.1.100")
|
||||
);
|
||||
|
||||
// Fetch existing records for update/delete (IDs required)
|
||||
List<RecordEntity> recordsToUpdate = Arrays.asList(
|
||||
cfDnsClient.recordGet(zone, "existing-api", RecordType.A).get(0)
|
||||
);
|
||||
recordsToUpdate.
|
||||
|
||||
get(0).
|
||||
|
||||
setContent("192.168.1.200");
|
||||
|
||||
List<RecordEntity> recordsToDelete = Arrays.asList(
|
||||
cfDnsClient.recordGet(zone, "old-api", RecordType.A).get(0)
|
||||
);
|
||||
|
||||
// Execute all operations in a single batch request
|
||||
BatchEntry result = cfDnsClient.recordBatch(
|
||||
zone,
|
||||
newRecords, // POST - create new records
|
||||
null, // PUT - not used in this example
|
||||
recordsToUpdate, // PATCH - update existing records
|
||||
recordsToDelete // DELETE - remove records
|
||||
);
|
||||
|
||||
System.out.
|
||||
|
||||
println("Batch completed:");
|
||||
System.out.
|
||||
|
||||
println(" Created: "+result.getPosts().
|
||||
|
||||
size());
|
||||
System.out.
|
||||
|
||||
println(" Updated: "+result.getPatches().
|
||||
|
||||
size());
|
||||
System.out.
|
||||
|
||||
println(" Deleted: "+result.getDeletes().
|
||||
|
||||
size());
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fluent API
|
||||
|
||||
The fluent API provides a chainable, readable interface for DNS operations. It's an alternative to the traditional API
|
||||
that reduces verbosity and improves code readability.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```java
|
||||
// Create a DNS record
|
||||
client.zone("example.com")
|
||||
.
|
||||
|
||||
record("api")
|
||||
.
|
||||
|
||||
create(RecordType.A, "192.168.1.1",60);
|
||||
|
||||
// Get DNS records
|
||||
List<RecordEntity> records = client.zone("example.com")
|
||||
.record("www", RecordType.A)
|
||||
.get();
|
||||
|
||||
// Update a DNS record
|
||||
RecordEntity updated = client.zone("example.com")
|
||||
.record("api", RecordType.A)
|
||||
.update("192.168.1.2");
|
||||
|
||||
// Delete DNS records
|
||||
client.
|
||||
|
||||
zone("example.com")
|
||||
.
|
||||
|
||||
record("old-service")
|
||||
.
|
||||
|
||||
delete(RecordType.A, RecordType.AAAA);
|
||||
```
|
||||
|
||||
### Advantages of Fluent API
|
||||
|
||||
- **More Readable**: The chain of method calls reads like natural language
|
||||
- **Less Verbose**: No need to pass zone objects between method calls
|
||||
- **Type Safe**: Full compile-time type checking
|
||||
- **IDE Friendly**: Excellent autocomplete support
|
||||
|
||||
### Complete Example
|
||||
|
||||
```java
|
||||
CfDnsClient client = new CfDnsClient("email@example.com", "yourApiKey");
|
||||
|
||||
// Create a new record
|
||||
client.
|
||||
|
||||
zone("example.com")
|
||||
.
|
||||
|
||||
record("api")
|
||||
.
|
||||
|
||||
create(RecordType.A, "192.168.100.1",60);
|
||||
|
||||
// Retrieve and verify
|
||||
List<RecordEntity> records = client.zone("example.com")
|
||||
.record("api", RecordType.A)
|
||||
.get();
|
||||
System.out.
|
||||
|
||||
println("IP: "+records.get(0).
|
||||
|
||||
getContent());
|
||||
|
||||
// Update the record
|
||||
client.
|
||||
|
||||
zone("example.com")
|
||||
.
|
||||
|
||||
record("api",RecordType.A)
|
||||
.
|
||||
|
||||
update("192.168.100.2");
|
||||
|
||||
// Clean up
|
||||
client.
|
||||
|
||||
zone("example.com")
|
||||
.
|
||||
|
||||
record("api")
|
||||
.
|
||||
|
||||
delete(RecordType.A);
|
||||
```
|
||||
|
||||
---
|
||||
@@ -335,21 +540,33 @@ BatchEntry result = cfDnsClient.recordBatch(
|
||||
|
||||
The `CfDnsClient` provides internal error-handling mechanisms through exceptions. For example:
|
||||
- `CloudflareApiException` is thrown for errors during API communication or invalid responses.
|
||||
- `CloudflareNotFoundException` is thrown when the requested single resource is not found, if enabled via the `emptyResultThrowsException` flag during initialization.
|
||||
- `CloudflareNotFoundException` is thrown when the requested resource (single or multiple) is not found, if enabled via
|
||||
the `emptyResultThrowsException` flag during initialization. **Default is `false`**, meaning empty results will be
|
||||
returned without throwing an exception.
|
||||
|
||||
To enable exception throwing for empty results:
|
||||
|
||||
```java
|
||||
CfDnsClient client = new CfDnsClient(true, "email@example.com", "yourApiKey");
|
||||
```
|
||||
|
||||
#### Example:
|
||||
|
||||
```java
|
||||
try {
|
||||
RecordEntity record = cfDnsClient.sldInfo(zone, "www", RecordType.A);
|
||||
System.out.println("Record IP: " + record.getContent());
|
||||
List<RecordEntity> records = cfDnsClient.recordGet(zone, "www", RecordType.A);
|
||||
System.out.
|
||||
|
||||
println("Record IP: "+records.get(0).
|
||||
|
||||
getContent());
|
||||
} catch (CloudflareApiException e) {
|
||||
if (e instanceof CloudflareNotFoundException) {
|
||||
log.warn("Sld not found: www");
|
||||
} else {
|
||||
log.error("Error while getting sld info of www", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user