digitalocean_api/
lib.rs

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