api_client_framework/endpoint.rs
1use serde::{Deserialize, Serialize};
2use std::{borrow::Cow, fmt::Debug};
3use url::Url;
4
5/// Represents a specification for an API call that can be built into an HTTP request and sent.
6/// New endpoints should implement this trait.
7///
8/// If the request succeeds, the call will resolve to a `Response`.
9pub trait Endpoint {
10 type Response: for<'a> Deserialize<'a> + Debug;
11
12 /// The HTTP Method used for this endpoint (e.g. GET, PATCH, DELETE)
13 fn method(&self) -> reqwest::Method;
14
15 /// The relative URL path for this endpoint
16 fn path(&self) -> String;
17
18 /// The url-encoded query string associated with this endpoint. Defaults to `None`.
19 ///
20 /// Implementors should inline this.
21 #[inline]
22 fn query(&self) -> Option<String> {
23 None
24 }
25
26 /// The set of headers to be sent with request. Defaults to `None`.
27 ///
28 /// Implementors should inline this.
29 #[inline]
30 fn headers(&self) -> Option<reqwest::header::HeaderMap> {
31 None
32 }
33
34 /// The HTTP body associated with this endpoint. If not implemented, defaults to `None`.
35 ///
36 /// Implementors should inline this.
37 #[inline]
38 fn body(&self) -> Option<String> {
39 None
40 }
41
42 /// Builds and returns a formatted full URL, including query, for the endpoint.
43 ///
44 /// Implementors should generally not override this.
45 fn url(&self, base_url: &Url) -> Url {
46 let mut url = base_url.join(&self.path()).unwrap();
47 url.set_query(self.query().as_deref());
48 url
49 }
50
51 /// If `body` is populated, indicates the body MIME type (defaults to JSON).
52 ///
53 /// Implementors generally do not need to override this.
54 fn content_type(&self) -> Cow<'static, str> {
55 Cow::Borrowed("application/json")
56 }
57}
58
59/// A utility function for serializing parameters into a URL query string.
60#[inline]
61pub fn serialize_query<Q: Serialize>(q: &Q) -> Option<String> {
62 serde_urlencoded::to_string(q).ok()
63}