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}