# Cloudflare Client - Public API Documentation

This document provides a comprehensive overview of the public API for the `cloudflare-client` crate.

## Table of Contents

1. [Client Creation](#client-creation)
2. [DNS Service](#dns-service)
3. [Zone Service](#zone-service)
4. [Cache Service](#cache-service)
5. [Error Handling](#error-handling)
6. [Types](#types)

---

## Client Creation

### `CloudflareClient`

The main client for interacting with the Cloudflare API.

```rust
use lmrc_cloudflare::CloudflareClient;

// Method 1: Using builder (recommended)
let client = CloudflareClient::builder()
    .api_token("your-api-token")
    .timeout(std::time::Duration::from_secs(60))  // optional
    .build()?;

// Method 2: Direct creation
let client = CloudflareClient::new("your-api-token")?;
```

### `CloudflareClientBuilder`

Builder for creating `CloudflareClient` instances.

**Methods:**
- `api_token(token: impl Into<String>) -> Self` - Set the API token (required)
- `base_url(url: impl Into<String>) -> Self` - Set custom base URL (optional)
- `timeout(duration: Duration) -> Self` - Set request timeout (optional, default: 30s)
- `build() -> Result<CloudflareClient>` - Build the client

---

## DNS Service

Access via `client.dns()`.

### Operations

#### List DNS Records

```rust
let records = client.dns()
    .list_records("zone_id")
    .record_type(RecordType::A)      // optional filter
    .name("api.example.com")          // optional filter
    .content("192.0.2.1")             // optional filter
    .page(1)                          // optional pagination
    .per_page(50)                     // optional pagination
    .send()
    .await?;
```

#### Get DNS Record

```rust
let record = client.dns()
    .get_record("zone_id", "record_id")
    .await?;
```

#### Create DNS Record

```rust
let record = client.dns()
    .create_record("zone_id")
    .name("api.example.com")
    .record_type(RecordType::A)
    .content("192.0.2.1")
    .proxied(true)                    // optional
    .ttl(1)                           // optional (1 = auto)
    .comment("API server")            // optional
    .priority(10)                     // optional (MX, SRV)
    .send()
    .await?;
```

#### Update DNS Record

```rust
let record = client.dns()
    .update_record("zone_id", "record_id")
    .content("192.0.2.2")
    .proxied(false)                   // optional
    .ttl(3600)                        // optional
    .send()
    .await?;
```

#### Delete DNS Record

```rust
client.dns()
    .delete_record("zone_id", "record_id")
    .await?;
```

#### Find DNS Record

```rust
let record = client.dns()
    .find_record("zone_id", "api.example.com", RecordType::A)
    .await?;  // Returns Option<DnsRecord>
```

#### Sync DNS Records (Idempotent)

Perfect for CI/CD - ensures DNS records match desired state.

```rust
use lmrc_cloudflare::dns::DnsRecordBuilder;

let desired_records = vec![
    DnsRecordBuilder::new()
        .name("api.example.com")
        .record_type(RecordType::A)
        .content("192.0.2.1")
        .proxied(true),
];

// Dry run to see changes
let changes = client.dns()
    .sync_records("zone_id")
    .records(desired_records.clone())
    .dry_run(true)
    .send()
    .await?;

// Apply changes
let changes = client.dns()
    .sync_records("zone_id")
    .records(desired_records)
    .dry_run(false)
    .send()
    .await?;
```

### Types

#### `RecordType`

DNS record types:
- `RecordType::A` - IPv4 address
- `RecordType::AAAA` - IPv6 address
- `RecordType::CNAME` - Canonical name
- `RecordType::MX` - Mail exchange
- `RecordType::TXT` - Text record
- `RecordType::SRV` - Service locator
- `RecordType::NS` - Name server
- `RecordType::CAA` - Certificate authority authorization
- `RecordType::PTR` - Pointer record

#### `DnsRecord`

Response type containing full DNS record information.

**Fields:**
- `id: String` - Record ID
- `record_type: String` - Record type
- `name: String` - Record name
- `content: String` - Record content
- `proxied: bool` - Whether proxied through Cloudflare
- `ttl: u32` - Time to live
- `zone_id: String` - Zone ID
- `zone_name: String` - Zone name
- `created_on: Option<String>` - Creation timestamp
- `modified_on: Option<String>` - Modification timestamp
- `comment: Option<String>` - Record comment
- `priority: Option<u16>` - Priority (MX, SRV)

#### `DnsRecordBuilder`

Builder for creating DNS record specifications.

---

## Zone Service

Access via `client.zones()`.

### Operations

#### List Zones

```rust
let zones = client.zones()
    .list()
    .name("example.com")              // optional filter
    .status("active")                 // optional filter
    .page(1)                          // optional pagination
    .per_page(50)                     // optional pagination
    .send()
    .await?;
```

#### Get Zone

```rust
let zone = client.zones()
    .get("zone_id")
    .await?;
```

#### Find Zone by Name

```rust
let zone = client.zones()
    .find_by_name("example.com")
    .await?;  // Returns Option<Zone>
```

#### Get Zone ID

Convenience method that combines find and ID extraction.

```rust
let zone_id = client.zones()
    .get_zone_id("example.com")
    .await?;  // Returns Result<String>
```

### Types

#### `Zone`

**Fields:**
- `id: String` - Zone ID
- `name: String` - Zone name (domain)
- `status: String` - Zone status
- `paused: bool` - Whether zone is paused
- `zone_type: String` - Zone type (full, partial)
- `development_mode: i32` - Development mode status
- `name_servers: Vec<String>` - Assigned name servers
- `original_name_servers: Vec<String>` - Original name servers
- `created_on: Option<String>` - Creation timestamp
- `modified_on: Option<String>` - Modification timestamp
- `activated_on: Option<String>` - Activation timestamp

---

## Cache Service

Access via `client.cache()`.

### Operations

#### Purge Everything

**Warning:** Purges all cached content for a zone.

```rust
let result = client.cache()
    .purge_everything("zone_id")
    .await?;
```

#### Purge URLs

Purge up to 30 specific URLs.

```rust
let result = client.cache()
    .purge_urls("zone_id")
    .urls(vec![
        "https://example.com/page1",
        "https://example.com/page2",
    ])
    .send()
    .await?;

// Or add URLs individually
let result = client.cache()
    .purge_urls("zone_id")
    .add_url("https://example.com/page1")
    .add_url("https://example.com/page2")
    .send()
    .await?;
```

#### Purge by Tags

Purge cache by tags (Enterprise plan only). Up to 30 tags.

```rust
let result = client.cache()
    .purge_tags("zone_id")
    .tags(vec!["product", "blog"])
    .send()
    .await?;
```

#### Purge by Hosts

Purge cache by hosts (Enterprise plan only). Up to 30 hosts.

```rust
let result = client.cache()
    .purge_hosts("zone_id")
    .hosts(vec!["www.example.com", "api.example.com"])
    .send()
    .await?;
```

#### Purge by Prefixes

Purge cache by URL prefixes (Enterprise plan only). Up to 30 prefixes.

```rust
let result = client.cache()
    .purge_prefixes("zone_id")
    .prefixes(vec!["example.com/images/", "example.com/videos/"])
    .send()
    .await?;
```

### Types

#### `PurgeResponse`

**Fields:**
- `id: String` - Purge operation ID

---

## Error Handling

### `Error`

The main error type with detailed variants.

```rust
use lmrc_cloudflare::Error;

match some_operation().await {
    Ok(result) => { /* handle success */ }
    Err(Error::NotFound(msg)) => { /* resource not found */ }
    Err(Error::Unauthorized(msg)) => { /* auth failed */ }
    Err(Error::RateLimited { retry_after }) => { /* rate limited */ }
    Err(Error::Api(api_error)) => { /* API error */ }
    Err(Error::Http(e)) => { /* HTTP error */ }
    Err(Error::Json(e)) => { /* JSON error */ }
    Err(Error::InvalidInput(msg)) => { /* invalid input */ }
}
```

#### Variants

- `Http(reqwest::Error)` - HTTP request failed
- `Api(ApiError)` - Cloudflare API returned an error
- `Json(serde_json::Error)` - JSON serialization failed
- `NotFound(String)` - Resource not found
- `InvalidInput(String)` - Invalid input or configuration
- `Unauthorized(String)` - Authentication failed
- `RateLimited { retry_after: Option<u64> }` - Rate limited

### `ApiError`

Detailed API error information.

**Fields:**
- `status: u16` - HTTP status code
- `code: Option<i32>` - Error code from Cloudflare
- `message: String` - Error message
- `body: String` - Full response body

### `Result<T>`

Type alias: `Result<T, Error>`

---

## Types

### Common Types

#### `Change<T>`

Represents a change in sync operations.

**Fields:**
- `action: ChangeAction` - The action type
- `current: Option<T>` - Current state
- `desired: Option<T>` - Desired state
- `description: String` - Human-readable description

**Methods:**
- `create(desired: T, description: String) -> Self`
- `update(current: T, desired: T, description: String) -> Self`
- `no_change(current: T, description: String) -> Self`

#### `ChangeAction`

Enumeration of possible change actions.

**Variants:**
- `Create` - Create new resource
- `Update` - Update existing resource
- `Delete` - Delete resource
- `NoChange` - No change needed

**Methods:**
- `is_mutating(&self) -> bool` - Check if action modifies resources

---

## Usage Patterns

### CI/CD Pattern

```rust
// 1. Create client from environment
let client = CloudflareClient::new(env::var("CLOUDFLARE_API_TOKEN")?)?;

// 2. Get zone ID
let zone_id = client.zones().get_zone_id("example.com").await?;

// 3. Define desired state
let records = vec![/* ... */];

// 4. Sync with dry run first
let changes = client.dns()
    .sync_records(&zone_id)
    .records(records.clone())
    .dry_run(true)
    .send()
    .await?;

// 5. Review changes and apply
if user_approves(&changes) {
    client.dns()
        .sync_records(&zone_id)
        .records(records)
        .dry_run(false)
        .send()
        .await?;
}
```

### Error Recovery Pattern

```rust
use lmrc_cloudflare::Error;

match client.dns().create_record(&zone_id)
    .name("api.example.com")
    .record_type(RecordType::A)
    .content("192.0.2.1")
    .send()
    .await
{
    Ok(record) => println!("Created: {}", record.id),
    Err(Error::RateLimited { retry_after: Some(seconds) }) => {
        tokio::time::sleep(Duration::from_secs(seconds)).await;
        // Retry operation
    }
    Err(e) => return Err(e.into()),
}
```

---

## Async Runtime

This library requires an async runtime. All examples use `tokio`:

```toml
[dependencies]
cloudflare-client = "0.1"
tokio = { version = "1", features = ["full"] }
```

```rust
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Your code here
    Ok(())
}
```

---

## Notes

- All API operations are async and require `.await`
- Builder methods can be chained for ergonomic API
- Operations are idempotent where possible (especially sync operations)
- Rate limiting is automatically detected and reported via errors
- All strings are owned (`String`) for simplicity and safety
- The client can be cloned cheaply (uses `Arc` internally via `reqwest::Client`)
