migamake_api_cloudflare/
lib.rs

1//! This library is a wrapper for [3 cloudflare
2//! api calls](https://api.cloudflare.com).
3//!
4//! The 3 api calls are
5//! * `list zones`
6//! * `create a dns record for a domain`
7//! * `delete a dns record for a domain`
8//!
9//! ### Authentication
10//!
11//! All endpoints need authentication. This library supports authentication
12//! using Authorization: Bearer header.
13//!
14//! You need to export this key - CLOUDFLARE_API_KEY.
15//!
16//! ### Usage
17//! ```no_run
18//!     use migamake_api_cloudflare::{Cloudflare, dns};
19//!
20//!     let domain = "example.com".into();
21//!     let zoneid = "some id";
22//!     // Initialize using an environment variable CLOUDFLARE_API_KEY
23//!     let cloudflare = Cloudflare::default(None);
24//!
25//!     // or the api key could be passed explicitly to the default method
26//!     // let cloudflare = Cloudflare::default(Some("api-key").into());
27//!
28//!     let mut txt_dns_record = dns::TXTRecord::new();
29//!     txt_dns_record.name = domain;
30//!     txt_dns_record.content = "create a txt record".into();
31//!     let response = cloudflare.create_dns_record(txt_dns_record, &zoneid);
32//!     let res = response.unwrap();
33//!     if res.success {
34//!        println!("{}", "Record created");
35//!     }
36//!     else{
37//!        println!("{:?}", res.errors);
38
39//! }
40//! ```
41
42pub mod dns;
43pub mod parameters;
44pub mod response;
45pub mod zone;
46
47use crate::parameters::DnsRecordType;
48use crate::zone::Zone;
49use serde::Serialize;
50use std::env;
51
52use validator::{Validate, ValidationErrors};
53
54/// Base url of Cloudflare API
55pub const API_PREFIX: &str = "https://api.cloudflare.com/client/v4/";
56/// This represents object to talk to cloudflare api
57pub struct Cloudflare {
58    auth_key: String,
59}
60
61impl Cloudflare {
62    /// Initializes the struct with an api token.
63    ///
64    /// If the api token is not passed as a parameter then uses the
65    /// environment variable `CLOUDFLARE_API_KEY` to get the api token
66    pub fn default(api_key: Option<String>) -> Cloudflare {
67        match api_key {
68            Some(value) => Cloudflare { auth_key: value },
69            None => {
70                let api_key =
71                    env::var("CLOUDFLARE_API_KEY").expect("CLOUDFLARE_API_KEY was not found");
72                Cloudflare { auth_key: api_key }
73            }
74        }
75    }
76
77    /// builds a request object based on http verb with authentication headers
78    fn make_request(&self, url: String, httpverb: parameters::HttpVerb) -> ureq::Request {
79        let mut request = if httpverb == parameters::HttpVerb::GET {
80            ureq::get(&url)
81        } else if httpverb == parameters::HttpVerb::DELETE {
82            ureq::delete(&url)
83        } else {
84            ureq::post(&url)
85        };
86
87        request
88            .set("Authorization", &format!("Bearer {}", &self.auth_key))
89            .set("Content-Type", "application/json");
90
91        request
92    }
93
94    /// List zones
95    ///
96    /// [List Zones](https://api.cloudflare.com/#zone-list-zones)
97    pub fn list(self, zone: Zone) -> crate::response::CFResponse {
98        let mut url = format!("{}zones?", API_PREFIX);
99        url.push_str(&format!("match={}", zone.search.to_string()));
100        if let Some(i) = zone.per_page {
101            url.push_str(&(format!("&per_page={:?}", i)));
102        }
103        if let Some(i) = zone.name {
104            url.push_str(&(format!("&name={}", i)));
105        }
106        if let Some(i) = zone.status {
107            url.push_str(&(format!("&status={}", i)));
108        }
109
110        if let Some(i) = zone.direction {
111            url.push_str(&(format!("&direction={}", i)));
112        }
113
114        if let Some(i) = zone.order {
115            url.push_str(&(format!("&order={}", i)));
116        }
117
118        if let Some(i) = zone.account_name {
119            url.push_str(&(format!("&account.name={}", i)));
120        }
121
122        if let Some(i) = zone.page {
123            url.push_str(&(format!("&page={}", i)));
124        }
125
126        if let Some(i) = zone.account_id {
127            url.push_str(&(format!("&account.id={}", i)));
128        }
129
130        println!("{:?}", url);
131
132        let response = self.make_request(url, parameters::HttpVerb::GET).call();
133
134        println!("{:?}", response);
135        response
136            .into_json_deserialize::<crate::response::CFResponse>()
137            .unwrap()
138    }
139
140    /// List dns record
141    ///
142    /// [List Zones](https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records)
143    pub fn list_dns_record(
144        &self,
145        dns_type: DnsRecordType,
146        domain_name: &str,
147        zone: &str,
148    ) -> crate::response::CFResponse {
149        let mut url = format!("{}zones/{}/dns_records?", API_PREFIX, zone);
150        url.push_str(&format!("type={}", dns_type.to_string()));
151        url.push_str(&(format!("&name={}", domain_name)));
152
153        let response = self.make_request(url, parameters::HttpVerb::GET).call();
154
155        response
156            .into_json_deserialize::<crate::response::CFResponse>()
157            .unwrap()
158    }
159
160    /// Create a dns record
161    ///
162    /// POST zones/:zone_identifier/dns_records
163    ///
164    /// [Create DNS Record](https://api.cloudflare.com/#dns-records-for-a-zone-create-dns-record)
165    pub fn create_dns_record<T: Validate + Serialize>(
166        &self,
167        record: T,
168        zone: &str,
169    ) -> Result<crate::response::CFCreateResponse, ValidationErrors> {
170        let url = format!("{}zones/{}/dns_records", API_PREFIX, zone);
171
172        record.validate()?;
173
174        let response = self
175            .make_request(url, parameters::HttpVerb::POST)
176            .send_json(ureq::json!(record));
177
178        Ok(response
179            .into_json_deserialize::<crate::response::CFCreateResponse>()
180            .unwrap())
181    }
182
183    /// Delete a dns record
184    ///
185    /// DELETE zones/:zone_identifier/dns_records/:identifier
186    ///
187    /// [Delete DNS Record ](https://api.cloudflare.com/#dns-records-for-a-zone-delete-dns-record)
188    pub fn delete_dns_record(
189        &self,
190        zone: &str,
191        dns_record: &str,
192    ) -> crate::response::CFDeleteResponse {
193        let url = format!("{}zones/{}/dns_records/{}", API_PREFIX, zone, dns_record);
194
195        let response = self.make_request(url, parameters::HttpVerb::DELETE).call();
196
197        response
198            .into_json_deserialize::<crate::response::CFDeleteResponse>()
199            .unwrap()
200    }
201}