# CloudflareDNS-java ## Preface This project provides a java client for minimalistic access to the Cloudflare API version 4, which is mainly used for managing DNS settings such as creating, updating and deleting DNS records. If you encounter any bugs or find missing features, feel free to report them on the [Gitea Issues page](https://git.mein-gateway.de/thischwa/CloudflareDNS-java/issues). --- ## Disclaimer This guide comes without any warranty. Use at your own risk. The author is not responsible for potential data loss, hardware damage or keyboard mishaps! --- ## Get It The project has its own maven repository. Follow the instructions on the latest [package](https://git.mein-gateway.de/thischwa/-/packages) to add the repository to your project. ## Changelog See [changelog](changelog.md) ## Methods Overview 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). ### Instantiation of `CfDnsClient` #### With API Token (recommended): ```java CfDnsClient cfDnsClient = new CfDnsClientBuilder() .withApiTokenAuth("your-api-token") .build(); ``` #### With Email/Key (legacy): ```java CfDnsClient cfDnsClient = new CfDnsClientBuilder() .withEmailKeyAuth("email@example.com", "yourApiKey") .build(); ``` ### `zoneList` Retrieve all zones within the Cloudflare account. - **Returns**: A list of `ZoneEntity` objects. ```java List zones = cfDnsClient.zoneList(); zones.forEach(zone -> System.out.println("Zone: " + zone.getName())); ``` --- ### `zoneGet` Get detailed information about a specific zone by its name. - **Parameters**: - `String name` - The zone name (e.g., "example.com"). - **Returns**: A `ZoneEntity` object. ```java ZoneEntity zone = cfDnsClient.zoneGet("example.com"); System.out.println("Zone ID: " + zone.getId()); ``` --- ### `recordList` Retrieve records for a given zone. There are two variants: #### List by SLD Retrieve all records for a specific second-level domain (SLD) under a given zone. - **Parameters**: - `ZoneEntity zone` - The zone object. - `String sld` - Second-level domain (e.g., "www" in "www.example.com"). - **Returns**: A list of `RecordEntity` objects. ```java List records = cfDnsClient.recordList(zone, "sld"); records.forEach(record -> System.out.println("Record Type: "+record.getType() +", Value: "+record.getContent()) ); ``` #### List by Zone (optional filtering) Retrieve DNS record details for a zone or a specific SLD, optionally filtered by record types. - **Parameters**: - `ZoneEntity zone` - The zone object. - `String sld` - (Optional) The second-level domain. - `RecordType... types` - Optional record types to filter by (e.g., A, CNAME). If not specified, returns all record types. - **Returns**: A list of `RecordEntity` objects matching the criteria. ```java // Get all records for a specific SLD List allSldRecords = cfDnsClient.recordList(zone, "www"); // Get only A records for a specific SLD List aSldRecords = cfDnsClient.recordList(zone, "www", RecordType.A); // Get all records of a zone List allZoneRecords = cfDnsClient.recordList(zone); // Get only A and AAAA records of a zone List ipZoneRecords = cfDnsClient.recordList(zone, RecordType.A, RecordType.AAAA); ``` --- ### `recordCreate` Create a new DNS record in a specific zone. - **Parameters**: - `ZoneEntity zone` - DNS zone object. - `String sld` - The sub-tld of the new record. - `int ttl` - The time-to-live in seconds of the new rcord. ```java RecordEntity created = client.recordCreateSld(zone, "api", 60, RecordType.A, "192.168.1.1"); System.out.println("Created Record ID: " + created.getId()); ``` --- ### `recordUpdate` Update an existing DNS record. - **Parameters**: - `ZoneEntity zone` - The zone that contains the record. - `RecordEntity rec` - Updated record data. ```java record.setContent("192.168.1.2"); RecordEntity updated = cfDnsClient.recordUpdate(zone, record); System.out.println("Updated Record: " + updated.getContent()); ``` --- ### `recordDelete` Delete a DNS record from a zone. - **Parameters**: - `ZoneEntity zone` - The parent zone. - `RecordEntity rec` - Record to delete. ```java boolean isDeleted = cfDnsClient.recordDelete(zone, record); System.out.println(isDeleted ? "Deletion successful." : "Deletion failed."); ``` --- ### `recordDeleteTypeIfExists` Delete a DNS record of a specific type if it exists. - **Parameters**: - `ZoneEntity zone` - Target zone. - `String sld` - Second-level domain. - `RecordType type` - Record type. ```java cfDnsClient.recordDeleteTypeIfExists(zone, "api", RecordType.A); System.out.println("Deletion attempt completed."); ``` ### Batch Operations Process multiple DNS record operations (POST, PUT, PATCH, DELETE) in a single batch request. - **Parameters**: - `ZoneEntity zone` - The target zone. - `List postRecords` - Records to create (nullable). Can be built without IDs. - `List putRecords` - Records to fully replace (nullable). **Requires record IDs**. - `List patchRecords` - Records to partially update (nullable). **Requires record IDs**. - `List 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 newRecords = Arrays.asList( 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.println("Created "+result.getPosts().size() +" records."); ``` #### Batch Update (PATCH) Partially update existing records. **Record IDs are required** - fetch them first: ```java // Step 1: Fetch existing records to get their IDs List recordsToUpdate = new ArrayList<>(); recordsToUpdate.add(cfDnsClient.recordList(zone, "api",RecordType.A).get(0)); recordsToUpdate.add(cfDnsClient.recordList(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.println("Updated "+result.getPatches().size() +" records."); ``` #### Batch Replace (PUT) Fully replace existing records. **Record IDs are required** - fetch them first: ```java // Step 1: Fetch existing records to get their IDs List recordsToReplace = new ArrayList<>(); recordsToReplace.add(cfDnsClient.recordList(zone, "mail",RecordType.A).get(0)); recordsToReplace.add(cfDnsClient.recordList(zone, "cdn",RecordType.A).get(0)); // Step 2: Modify all fields as needed (full replacement) recordsToReplace.get(0).setContent("192.168.3.10"); 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.println("Replaced "+result.getPuts().size() +" records."); ``` #### Batch Delete Delete existing records. **Record IDs are required** - fetch them first: ```java // Step 1: Fetch existing records to get their IDs List recordsToDelete = new ArrayList<>(); recordsToDelete.add(cfDnsClient.recordList(zone, "cdn",RecordType.A).get(0)); recordsToDelete.add(cfDnsClient.recordList(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 "+recordsToDelete.size() +" records."); ``` #### Combined Batch Operations Combine multiple operations in a single batch request: ```java // Create new records (no IDs needed) List 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 recordsToUpdate = Arrays.asList( cfDnsClient.recordList(zone, "existing-api", RecordType.A).get(0) ); recordsToUpdate.get(0).setContent("192.168.1.200"); List recordsToDelete = Arrays.asList( cfDnsClient.recordList(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 getRecord client.zone("example.com") .record("api") .create(RecordType.A, "192.168.1.1",60); // Get DNS records of a subdomain List records = client.zone("example.com") .record("www", RecordType.A) .get(); // Get all DNS records of a zone List zoneRecords = client.zone("example.com") .list(RecordType.A, RecordType.AAAA); // Update a DNS getRecord 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 CfDnsClientBuilder() .withApiTokenAuth("your-api-token") .build(); // Create a new getRecord client.zone("example.com") .record("api") .create(RecordType.A, "192.168.100.1",60); // Retrieve and verify List records = client.zone("example.com") .record("api", RecordType.A) .get(); System.out.println("IP: "+records.get(0).getContent()); // Update the getRecord client.zone("example.com") .record("api",RecordType.A) .update("192.168.100.2"); // Clean up client.zone("example.com") .record("api") .delete(RecordType.A); ``` --- # Notes on Error Handling 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 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 CfDnsClientBuilder() .withApiTokenAuth("your-api-token") .withEmptyResultThrowsException(true) .build(); ``` ## Example: ```java try { List records = cfDnsClient.recordList(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; } } ``` ---