kittycad/lib.rs
1//! A fully generated & opinionated API client for the KittyCAD API.
2//!
3//! [](https://docs.rs/kittycad)
4//!
5//! ## API Details
6//!
7//! API server for Zoo
8//!
9//!
10//!
11//! ### Contact
12//!
13//!
14//! | url | email |
15//! |----|----|
16//! | <https://zoo.dev> | api@zoo.dev |
17//!
18//!
19//!
20//! ## Client Details
21//!
22//! This client is generated from the [OpenAPI specs](https://api.zoo.dev) based on API spec version `0.1.0`. This way it will remain up to date as features are added.
23//!
24//! The documentation for the crate is generated
25//! along with the code to make this library easy to use.
26//!
27//!
28//! To install the library, add the following to your `Cargo.toml` file.
29//!
30//! ```toml
31//! [dependencies]
32//! kittycad = "0.4.9"
33//! ```
34//!
35//! ## Basic example
36//!
37//! Typical use will require intializing a `Client`. This requires
38//! a user agent string and set of credentials.
39//!
40//! ```rust,no_run
41//! use kittycad::Client;
42//!
43//! let client = Client::new(String::from("api-key"));
44//! ```
45//!
46//! Alternatively, the library can search for most of the variables required for
47//! the client in the environment:
48//!
49//! - `KITTYCAD_API_TOKEN`
50//! - `ZOO_API_TOKEN`
51//!
52//! And then you can create a client from the environment.
53//!
54//! ```rust,no_run
55//! use kittycad::Client;
56//!
57//! let client = Client::new_from_env();
58//! ```
59#![allow(mismatched_lifetime_syntaxes)]
60#![allow(missing_docs)]
61#![allow(unused_imports)]
62#![allow(clippy::needless_lifetimes)]
63#![allow(clippy::too_many_arguments)]
64#![cfg_attr(docsrs, feature(doc_cfg))]
65
66/// API calls that have been performed by users can be queried by the API. This is helpful for debugging as well as billing.
67///
68/// FROM: <https://zoo.dev/docs/api/api-calls>
69#[cfg(feature = "requests")]
70pub mod api_calls;
71/// API tokens allow users to call the API outside of their session token that is used as a cookie in the user interface. Users can create, delete, and list their API tokens. But, of course, you need an API token to do this, so first be sure to generate one in the account UI.
72///
73/// FROM: <https://zoo.dev/docs/api/api-tokens>
74#[cfg(feature = "requests")]
75pub mod api_tokens;
76/// Endpoints for third party app grant flows.
77///
78/// FROM: <https://zoo.dev/docs/api/apps>
79#[cfg(feature = "requests")]
80pub mod apps;
81/// Endpoints that allow for code execution or creation of code execution environments.
82///
83/// FROM: <https://zoo.dev/docs/api/executor>
84#[cfg(feature = "requests")]
85pub mod executor;
86/// CAD file operations. Create, get, and list CAD file conversions. More endpoints will be added here in the future as we build out transforms, etc on CAD models.
87///
88/// FROM: <https://zoo.dev/docs/api/file>
89#[cfg(feature = "requests")]
90pub mod file;
91/// Hidden API endpoints that should not show up in the docs.
92///
93/// FROM: <https://zoo.dev/docs/api/hidden>
94#[cfg(feature = "requests")]
95pub mod hidden;
96/// Meta information about the API.
97///
98/// FROM: <https://zoo.dev/docs/api/meta>
99#[cfg(feature = "requests")]
100pub mod meta;
101mod methods;
102/// Machine learning to generate CAD models and other things.
103///
104/// FROM: <https://zoo.dev/docs/api/ml>
105#[cfg(feature = "requests")]
106pub mod ml;
107/// Modeling API for updating your 3D files using the Zoo engine.
108///
109/// FROM: <https://zoo.dev/docs/api/modeling>
110#[cfg(feature = "requests")]
111pub mod modeling;
112/// Endpoints that implement OAuth 2.0 grant flows.
113///
114/// FROM: <https://zoo.dev/docs/api/oauth2>
115#[cfg(feature = "requests")]
116pub mod oauth2;
117/// An organization is a group of users of the Zoo API. Here, we can add users to an org and perform operations on orgs.
118///
119/// FROM: <https://zoo.dev/docs/api/orgs>
120#[cfg(feature = "requests")]
121pub mod orgs;
122/// Operations around payments and billing.
123///
124/// FROM: <https://zoo.dev/docs/api/payments>
125#[cfg(feature = "requests")]
126pub mod payments;
127/// Service accounts allow organizations to call the API. Organization admins can create, delete, and list the service accounts for their org. Service accounts are scoped to an organization not individual users, these are better to use for automations than individual API tokens, since they won't stop working when an individual leaves the company.
128///
129/// FROM: <https://zoo.dev/docs/api/service-accounts>
130#[cfg(feature = "requests")]
131pub mod service_accounts;
132/// Operations involving our swag store.
133///
134/// FROM: <https://zoo.dev/docs/api/store>
135#[cfg(feature = "requests")]
136pub mod store;
137#[cfg(test)]
138mod tests;
139pub mod types;
140/// Unit conversion operations.
141///
142/// FROM: <https://zoo.dev/docs/api/file>
143#[cfg(feature = "requests")]
144pub mod unit;
145/// A user is someone who uses the Zoo API. Here, we can create, delete, and list users. We can also get information about a user. Operations will only be authorized if the user is requesting information about themselves.
146///
147/// FROM: <https://zoo.dev/docs/api/users>
148#[cfg(feature = "requests")]
149pub mod users;
150
151#[cfg(feature = "requests")]
152use std::env;
153
154#[cfg(not(target_arch = "wasm32"))]
155#[cfg(feature = "requests")]
156static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
157
158/// Entrypoint for interacting with the API client.
159#[derive(Clone, Debug)]
160#[cfg(feature = "requests")]
161pub struct Client {
162 token: String,
163 base_url: String,
164
165 #[cfg(feature = "retry")]
166 client: reqwest_middleware::ClientWithMiddleware,
167 #[cfg(feature = "retry")]
168 #[cfg(not(target_arch = "wasm32"))]
169 #[allow(dead_code)]
170 client_http1_only: reqwest_middleware::ClientWithMiddleware,
171
172 #[cfg(not(feature = "retry"))]
173 client: reqwest::Client,
174 #[cfg(not(feature = "retry"))]
175 #[cfg(not(target_arch = "wasm32"))]
176 #[allow(dead_code)]
177 client_http1_only: reqwest::Client,
178}
179
180/// A request builder.
181#[cfg(feature = "retry")]
182#[cfg(feature = "requests")]
183pub struct RequestBuilder(pub reqwest_middleware::RequestBuilder);
184#[cfg(not(feature = "retry"))]
185#[cfg(feature = "requests")]
186pub struct RequestBuilder(pub reqwest::RequestBuilder);
187
188#[cfg(feature = "requests")]
189impl Client {
190 /// Create a new Client struct. It takes a type that can convert into
191 /// an &str (`String` or `Vec<u8>` for example). As long as the function is
192 /// given a valid API key your requests will work.
193 /// Also takes reqwest client builders, for customizing the client's behaviour.
194 #[tracing::instrument(skip(token))]
195 #[cfg(not(target_arch = "wasm32"))]
196 pub fn new_from_reqwest<T>(
197 token: T,
198 builder_http: reqwest::ClientBuilder,
199 builder_websocket: reqwest::ClientBuilder,
200 ) -> Self
201 where
202 T: ToString + std::fmt::Debug,
203 {
204 #[cfg(feature = "retry")]
205 {
206 // Retry up to 3 times with increasing intervals between attempts.
207 let retry_policy =
208 reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
209 match (builder_http.build(), builder_websocket.build()) {
210 (Ok(c), Ok(c1)) => {
211 let client = reqwest_middleware::ClientBuilder::new(c)
212 // Trace HTTP requests. See the tracing crate to make use of these traces.
213 .with(reqwest_tracing::TracingMiddleware::default())
214 // Retry failed requests.
215 .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
216 reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
217 |req: &reqwest::Request| req.try_clone().is_some(),
218 ))
219 .build();
220 let client_http1_only = reqwest_middleware::ClientBuilder::new(c1)
221 .with(reqwest_tracing::TracingMiddleware::default())
222 .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
223 reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
224 |req: &reqwest::Request| req.try_clone().is_some(),
225 ))
226 .build();
227 Client {
228 token: token.to_string(),
229 base_url: "https://api.zoo.dev".to_string(),
230
231 client,
232 client_http1_only,
233 }
234 }
235 (Err(e), _) | (_, Err(e)) => panic!("creating reqwest client failed: {:?}", e),
236 }
237 }
238 #[cfg(not(feature = "retry"))]
239 {
240 match (builder_http.build(), builder_websocket.build()) {
241 (Ok(c), Ok(c1)) => Client {
242 token: token.to_string(),
243 base_url: "https://api.zoo.dev".to_string(),
244
245 client: c,
246 client_http1_only: c1,
247 },
248 (Err(e), _) | (_, Err(e)) => panic!("creating reqwest client failed: {:?}", e),
249 }
250 }
251 }
252
253 /// Create a new Client struct. It takes a type that can convert into
254 /// an &str (`String` or `Vec<u8>` for example). As long as the function is
255 /// given a valid API key your requests will work.
256 /// Also takes reqwest client builders, for customizing the client's behaviour.
257 #[tracing::instrument(skip(token))]
258 #[cfg(target_arch = "wasm32")]
259 pub fn new_from_reqwest<T>(token: T, builder_http: reqwest::ClientBuilder) -> Self
260 where
261 T: ToString + std::fmt::Debug,
262 {
263 #[cfg(feature = "retry")]
264 {
265 // Retry up to 3 times with increasing intervals between attempts.
266 let retry_policy =
267 reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
268 match builder_http.build() {
269 Ok(c) => {
270 let client = reqwest_middleware::ClientBuilder::new(c)
271 // Trace HTTP requests. See the tracing crate to make use of these traces.
272 .with(reqwest_tracing::TracingMiddleware::default())
273 // Retry failed requests.
274 .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
275 reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
276 |req: &reqwest::Request| req.try_clone().is_some(),
277 ))
278 .build();
279 Client {
280 token: token.to_string(),
281 base_url: "https://api.zoo.dev".to_string(),
282
283 client,
284 }
285 }
286 Err(e) => panic!("creating reqwest client failed: {:?}", e),
287 }
288 }
289 #[cfg(not(feature = "retry"))]
290 {
291 match builder_http.build() {
292 Ok(c) => Client {
293 token: token.to_string(),
294 base_url: "https://api.zoo.dev".to_string(),
295
296 client: c,
297 },
298 Err(e) => panic!("creating reqwest client failed: {:?}", e),
299 }
300 }
301 }
302
303 /// Create a new Client struct. It takes a type that can convert into
304 /// an &str (`String` or `Vec<u8>` for example). As long as the function is
305 /// given a valid API key your requests will work.
306 #[tracing::instrument(skip(token))]
307 pub fn new<T>(token: T) -> Self
308 where
309 T: ToString + std::fmt::Debug,
310 {
311 #[cfg(not(target_arch = "wasm32"))]
312 let client = reqwest::Client::builder()
313 .user_agent(APP_USER_AGENT)
314 // For file conversions we need this to be long.
315 .timeout(std::time::Duration::from_secs(600))
316 .connect_timeout(std::time::Duration::from_secs(60));
317 #[cfg(target_arch = "wasm32")]
318 let client = reqwest::Client::builder();
319 #[cfg(not(target_arch = "wasm32"))]
320 let client_http1 = reqwest::Client::builder()
321 // For file conversions we need this to be long.
322 .user_agent(APP_USER_AGENT)
323 .timeout(std::time::Duration::from_secs(600))
324 .connect_timeout(std::time::Duration::from_secs(60))
325 .http1_only();
326 #[cfg(not(target_arch = "wasm32"))]
327 return Self::new_from_reqwest(token, client, client_http1);
328 #[cfg(target_arch = "wasm32")]
329 Self::new_from_reqwest(token, client)
330 }
331
332 /// Set the base URL for the client to something other than the default: <https://api.zoo.dev>.
333 #[tracing::instrument]
334 pub fn set_base_url<H>(&mut self, base_url: H)
335 where
336 H: Into<String> + std::fmt::Display + std::fmt::Debug,
337 {
338 self.base_url = base_url.to_string().trim_end_matches('/').to_string();
339 }
340
341 /// Create a new Client struct from the environment variable: `ENV_VARIABLE_PREFIX_API_TOKEN`.
342 #[tracing::instrument]
343 pub fn new_from_env() -> Self {
344 let token = if let Ok(token) = env::var("KITTYCAD_API_TOKEN") {
345 token
346 } else if let Ok(token) = env::var("ZOO_API_TOKEN") {
347 token
348 } else {
349 panic!("must set KITTYCAD_API_TOKEN or ZOO_API_TOKEN");
350 };
351 let base_url = if let Ok(base_url) = env::var("KITTYCAD_HOST") {
352 base_url
353 } else if let Ok(base_url) = env::var("ZOO_HOST") {
354 base_url
355 } else {
356 "https://api.zoo.dev".to_string()
357 };
358
359 let mut c = Client::new(token);
360 c.set_base_url(base_url);
361 c
362 }
363
364 /// Create a raw request to our API.
365 #[tracing::instrument]
366 pub async fn request_raw(
367 &self,
368 method: reqwest::Method,
369 uri: &str,
370 body: Option<reqwest::Body>,
371 ) -> anyhow::Result<RequestBuilder> {
372 let u = if uri.starts_with("https://") || uri.starts_with("http://") {
373 uri.to_string()
374 } else {
375 format!("{}/{}", self.base_url, uri.trim_start_matches('/'))
376 };
377
378 let mut req = self.client.request(method, &u);
379
380 // Add in our authentication.
381 req = req.bearer_auth(&self.token);
382
383 // Set the default headers.
384 req = req.header(
385 reqwest::header::ACCEPT,
386 reqwest::header::HeaderValue::from_static("application/json"),
387 );
388 req = req.header(
389 reqwest::header::CONTENT_TYPE,
390 reqwest::header::HeaderValue::from_static("application/json"),
391 );
392
393 if let Some(body) = body {
394 req = req.body(body);
395 }
396
397 Ok(RequestBuilder(req))
398 }
399
400 /// API calls that have been performed by users can be queried by the API. This is helpful for debugging as well as billing.
401 ///
402 /// FROM: <https://zoo.dev/docs/api/api-calls>
403 pub fn api_calls(&self) -> api_calls::ApiCalls {
404 api_calls::ApiCalls::new(self.clone())
405 }
406
407 /// API tokens allow users to call the API outside of their session token that is used as a cookie in the user interface. Users can create, delete, and list their API tokens. But, of course, you need an API token to do this, so first be sure to generate one in the account UI.
408 ///
409 /// FROM: <https://zoo.dev/docs/api/api-tokens>
410 pub fn api_tokens(&self) -> api_tokens::ApiTokens {
411 api_tokens::ApiTokens::new(self.clone())
412 }
413
414 /// Endpoints for third party app grant flows.
415 ///
416 /// FROM: <https://zoo.dev/docs/api/apps>
417 pub fn apps(&self) -> apps::Apps {
418 apps::Apps::new(self.clone())
419 }
420
421 /// Endpoints that allow for code execution or creation of code execution environments.
422 ///
423 /// FROM: <https://zoo.dev/docs/api/executor>
424 pub fn executor(&self) -> executor::Executor {
425 executor::Executor::new(self.clone())
426 }
427
428 /// CAD file operations. Create, get, and list CAD file conversions. More endpoints will be added here in the future as we build out transforms, etc on CAD models.
429 ///
430 /// FROM: <https://zoo.dev/docs/api/file>
431 pub fn file(&self) -> file::File {
432 file::File::new(self.clone())
433 }
434
435 /// Hidden API endpoints that should not show up in the docs.
436 ///
437 /// FROM: <https://zoo.dev/docs/api/hidden>
438 pub fn hidden(&self) -> hidden::Hidden {
439 hidden::Hidden::new(self.clone())
440 }
441
442 /// Meta information about the API.
443 ///
444 /// FROM: <https://zoo.dev/docs/api/meta>
445 pub fn meta(&self) -> meta::Meta {
446 meta::Meta::new(self.clone())
447 }
448
449 /// Machine learning to generate CAD models and other things.
450 ///
451 /// FROM: <https://zoo.dev/docs/api/ml>
452 pub fn ml(&self) -> ml::Ml {
453 ml::Ml::new(self.clone())
454 }
455
456 /// Modeling API for updating your 3D files using the Zoo engine.
457 ///
458 /// FROM: <https://zoo.dev/docs/api/modeling>
459 pub fn modeling(&self) -> modeling::Modeling {
460 modeling::Modeling::new(self.clone())
461 }
462
463 /// Endpoints that implement OAuth 2.0 grant flows.
464 ///
465 /// FROM: <https://zoo.dev/docs/api/oauth2>
466 pub fn oauth2(&self) -> oauth2::Oauth2 {
467 oauth2::Oauth2::new(self.clone())
468 }
469
470 /// An organization is a group of users of the Zoo API. Here, we can add users to an org and perform operations on orgs.
471 ///
472 /// FROM: <https://zoo.dev/docs/api/orgs>
473 pub fn orgs(&self) -> orgs::Orgs {
474 orgs::Orgs::new(self.clone())
475 }
476
477 /// Operations around payments and billing.
478 ///
479 /// FROM: <https://zoo.dev/docs/api/payments>
480 pub fn payments(&self) -> payments::Payments {
481 payments::Payments::new(self.clone())
482 }
483
484 /// Service accounts allow organizations to call the API. Organization admins can create, delete, and list the service accounts for their org. Service accounts are scoped to an organization not individual users, these are better to use for automations than individual API tokens, since they won't stop working when an individual leaves the company.
485 ///
486 /// FROM: <https://zoo.dev/docs/api/service-accounts>
487 pub fn service_accounts(&self) -> service_accounts::ServiceAccounts {
488 service_accounts::ServiceAccounts::new(self.clone())
489 }
490
491 /// Operations involving our swag store.
492 ///
493 /// FROM: <https://zoo.dev/docs/api/store>
494 pub fn store(&self) -> store::Store {
495 store::Store::new(self.clone())
496 }
497
498 /// Unit conversion operations.
499 ///
500 /// FROM: <https://zoo.dev/docs/api/file>
501 pub fn unit(&self) -> unit::Unit {
502 unit::Unit::new(self.clone())
503 }
504
505 /// A user is someone who uses the Zoo API. Here, we can create, delete, and list users. We can also get information about a user. Operations will only be authorized if the user is requesting information about themselves.
506 ///
507 /// FROM: <https://zoo.dev/docs/api/users>
508 pub fn users(&self) -> users::Users {
509 users::Users::new(self.clone())
510 }
511}