1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
/*! A crate for interacting with the Digital Ocean API. While browsing this documentation, please feel encouraged to reference the [DigitalOcean docs](https://developers.digitalocean.com/documentation/v2/). ## A Basic Example ```rust,no_run extern crate digitalocean; use digitalocean::prelude::*; use std::env; fn main() { let api_key = env::var("API_KEY") .expect("API_KEY not set."); let client = DigitalOcean::new(api_key) .unwrap(); Droplet::list() .execute(&client); } ``` ## Usage Fundamentals All values (`Domain`, `SshKey`, etc) can be found in the `api` module. Calling an action will return a `Request<_,_>` type. For example `Droplet::create()` will create a `Request<Create, Droplet>`. These types may then have specific futher functions to futher build up the request or transform it into some other request. ```rust,no_run extern crate digitalocean; use digitalocean::DigitalOcean; use digitalocean::api::Domain; fn main() { // Gets details of a specific domain. let req = Domain::get("foo.com"); // Get the records for that domain instead (futher build the request) let req = req.records(); // Get the records of a domain without having a prior request. let req = Domain::get("foo.com").records(); // Create a new record for a domain let req = Domain::get("foo.com").records().create("CNAME", "test", "127.0.0.1"); } ``` In order to realize any action, `.execute()` must be called with a `DigitalOcean` client. It is also possible to call `do_client.execute(some_request)`. In order to use the entire API, it is recommended to reference the various `Request` types. ## Design The crate is founded on a few design considerations: * Keep things simple and generic. * Map closely to the DigitalOcean API. * `Request`s are agnostic over `Client`s. * It should be difficult to make an invalid API request. * Use static dispatch as much as possible. * Only the bare minimum amount of information should be carried around. * Allow for easy construction of separate clients (`hyper`, etc.) * No caching (yet). (DigitalOcean does not have [ETags](https://en.wikipedia.org/wiki/HTTP_ETag)) ## Debugging This crate uses the [`log`](https://doc.rust-lang.org/log/log/index.html) crate. You can see `digitalocean` logs by passing an environment variable such as: ```bash RUST_LOG=digitalocean=debug cargo run ``` ## Development Status This crate is in a prototype state. Not all endpoints have been fully end-to-end tested on the production DigitalOcean API. It's very likely that some endpoints will have parsing errors due to unexpected values returned from the API. **If something does not work please file a bug!** Feedback, patches, and new features are encouraged. Please just open an issue or PR! */ use lazy_static::lazy_static; use log::info; #[macro_use] extern crate serde_derive; #[macro_use] extern crate serde_json; pub mod api; mod client; pub mod error; pub mod method; pub mod prelude; pub mod request; use crate::api::HasResponse; use crate::method::Method; use crate::request::{Executable, Request}; use crate::error::Error; use url::Url; const STATIC_URL_ERROR: &str = "Staticly constructed DigitalOcean URL is malformed."; lazy_static! { static ref ROOT_URL: Url = Url::parse("https://api.digitalocean.com/v2").expect(STATIC_URL_ERROR); } /// A DigitalOcean Client that holds an API key. #[derive(Clone)] pub struct DigitalOcean { client: client::Client, token: String } impl DigitalOcean { /// Create a DigitalOcean client with the given API key. pub fn new<T: Into<String>>(token: T) -> Result<Self, Error> { info!("Created."); Ok(DigitalOcean { client: client::Client::new(), token: token.into(), }) } pub fn execute<A: Method, V: HasResponse>(&self, request: Request<A, V>) -> Result<V, Error> where Request<A, V>: Executable<V> { request.execute(self) } }