twitch_api/helix/endpoints/subscriptions/
get_broadcaster_subscriptions.rs

1//! Get all of a broadcaster’s subscriptions.
2//! [`get-broadcaster-subscriptions`](https://dev.twitch.tv/docs/api/reference#get-broadcaster-subscriptions)
3//!
4//! # Accessing the endpoint
5//!
6//! ## Request: [GetBroadcasterSubscriptionsRequest]
7//!
8//! To use this endpoint, construct a [`GetBroadcasterSubscriptionsRequest`] with the [`GetBroadcasterSubscriptionsRequest::broadcaster_id()`] method.
9//!
10//! ```rust
11//! use twitch_api::helix::subscriptions::get_broadcaster_subscriptions;
12//! let request =
13//!     get_broadcaster_subscriptions::GetBroadcasterSubscriptionsRequest::broadcaster_id("1234");
14//! ```
15//!
16//! ## Response: [BroadcasterSubscription]
17//!
18//! Send the request to receive the response with [`HelixClient::req_get()`](helix::HelixClient::req_get).
19//!
20//! ```rust, no_run
21//! use twitch_api::helix::{self, subscriptions::get_broadcaster_subscriptions};
22//! # use twitch_api::client;
23//! # #[tokio::main]
24//! # async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
25//! # let client: helix::HelixClient<'static, client::DummyHttpClient> = helix::HelixClient::default();
26//! # let token = twitch_oauth2::AccessToken::new("validtoken".to_string());
27//! # let token = twitch_oauth2::UserToken::from_existing(&client, token, None, None).await?;
28//! let request =
29//!     get_broadcaster_subscriptions::GetBroadcasterSubscriptionsRequest::broadcaster_id("1234");
30//! let response: Vec<get_broadcaster_subscriptions::BroadcasterSubscription> = client.req_get(request, &token).await?.data;
31//! # Ok(())
32//! # }
33//! ```
34//!
35//! You can also get the [`http::Request`] with [`request.create_request(&token, &client_id)`](helix::RequestGet::create_request)
36//! and parse the [`http::Response`] with [`GetBroadcasterSubscriptionsRequest::parse_response(None, &request.get_uri(), response)`](GetBroadcasterSubscriptionsRequest::parse_response)
37
38use super::*;
39use helix::RequestGet;
40
41/// Query Parameters for [Get Broadcaster Subscriptions](super::get_broadcaster_subscriptions)
42///
43/// [`get-broadcaster-subscriptions`](https://dev.twitch.tv/docs/api/reference#get-broadcaster-subscriptions)
44#[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)]
45#[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))]
46#[must_use]
47#[non_exhaustive]
48pub struct GetBroadcasterSubscriptionsRequest<'a> {
49    /// User ID of the broadcaster. Must match the User ID in the Bearer token.
50    #[cfg_attr(feature = "typed-builder", builder(setter(into)))]
51    #[cfg_attr(feature = "deser_borrow", serde(borrow = "'a"))]
52    pub broadcaster_id: Cow<'a, types::UserIdRef>,
53    /// Unique identifier of account to get subscription status of. Accepts up to 100 values.
54    #[cfg_attr(feature = "typed-builder", builder(default))]
55    #[cfg_attr(feature = "deser_borrow", serde(borrow = "'a"))]
56    // FIXME: This is essentially the same as borrow, but worse
57    #[cfg_attr(not(feature = "deser_borrow"), serde(bound(deserialize = "'de: 'a")))]
58    pub user_id: types::Collection<'a, types::UserId>,
59    /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query.
60    #[cfg_attr(feature = "typed-builder", builder(default))]
61    #[cfg_attr(feature = "deser_borrow", serde(borrow = "'a"))]
62    pub after: Option<Cow<'a, helix::CursorRef>>,
63    /// Number of values to be returned per page. Limit: 100. Default: 20.
64    #[cfg_attr(feature = "typed-builder", builder(setter(into), default))]
65    pub first: Option<usize>,
66}
67
68impl<'a> GetBroadcasterSubscriptionsRequest<'a> {
69    /// Get a broadcasters subscribers
70    pub fn broadcaster_id(broadcaster_id: impl types::IntoCow<'a, types::UserIdRef> + 'a) -> Self {
71        Self {
72            broadcaster_id: broadcaster_id.into_cow(),
73            user_id: types::Collection::default(),
74            after: Default::default(),
75            first: Default::default(),
76        }
77    }
78
79    /// check for specific users in broadcasters subscriptions
80    pub fn subscriber(mut self, user_ids: impl Into<types::Collection<'a, types::UserId>>) -> Self {
81        self.user_id = user_ids.into();
82        self
83    }
84
85    /// Set amount of results returned per page.
86    pub const fn first(mut self, first: usize) -> Self {
87        self.first = Some(first);
88        self
89    }
90}
91
92/// Return Values for [Get Broadcaster Subscriptions](super::get_broadcaster_subscriptions)
93///
94/// [`get-broadcaster-subscriptions`](https://dev.twitch.tv/docs/api/reference#get-broadcaster-subscriptions)
95#[derive(PartialEq, Eq, Deserialize, Serialize, Debug, Clone)]
96#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
97#[non_exhaustive]
98pub struct BroadcasterSubscription {
99    /// User ID of the broadcaster.
100    pub broadcaster_id: types::UserId,
101    /// Login of the broadcaster.
102    pub broadcaster_login: types::UserName,
103    /// Display name of the broadcaster.
104    pub broadcaster_name: types::DisplayName,
105    /// User ID of the broadcaster.
106    #[serde(
107        default,
108        deserialize_with = "crate::deserialize_none_from_empty_string"
109    )]
110    pub gifter_id: Option<types::UserId>,
111    /// Login of the gifter.
112    #[serde(
113        default,
114        deserialize_with = "crate::deserialize_none_from_empty_string"
115    )]
116    pub gifter_login: Option<types::UserName>,
117    /// Display name of the gifter.
118    #[serde(
119        default,
120        deserialize_with = "crate::deserialize_none_from_empty_string"
121    )]
122    pub gifter_name: Option<types::DisplayName>,
123    /// Determines if the subscription is a gift subscription.
124    pub is_gift: bool,
125    /// Type of subscription (Tier 1, Tier 2, Tier 3). 1000 = Tier 1, 2000 = Tier 2, 3000 = Tier 3 subscriptions.
126    pub tier: types::SubscriptionTier,
127    /// Name of the subscription.
128    pub plan_name: String,
129    /// ID of the subscribed user.
130    pub user_id: types::UserId,
131    /// Login of the subscribed user.
132    pub user_login: types::UserName,
133    /// Display name of the subscribed user.
134    pub user_name: types::DisplayName,
135}
136
137impl Request for GetBroadcasterSubscriptionsRequest<'_> {
138    type Response = Vec<BroadcasterSubscription>;
139
140    const PATH: &'static str = "subscriptions";
141    #[cfg(feature = "twitch_oauth2")]
142    const SCOPE: twitch_oauth2::Validator =
143        twitch_oauth2::validator![twitch_oauth2::Scope::ChannelReadSubscriptions];
144}
145
146impl RequestGet for GetBroadcasterSubscriptionsRequest<'_> {}
147
148impl helix::Paginated for GetBroadcasterSubscriptionsRequest<'_> {
149    fn set_pagination(&mut self, cursor: Option<helix::Cursor>) {
150        self.after = cursor.map(|c| c.into_cow())
151    }
152}
153
154impl helix::Response<GetBroadcasterSubscriptionsRequest<'_>, Vec<BroadcasterSubscription>> {
155    /// The current number of subscriber points earned by this broadcaster.
156    pub fn points(&self) -> Result<i64, BroadcasterSubscriptionPointsError> {
157        let points = self.get_other("points")?;
158        if let Some(points) = points {
159            Ok(points)
160        } else {
161            Err(BroadcasterSubscriptionPointsError::PointsNotFound)
162        }
163    }
164}
165
166/// Errors when retrieving `points` in [Get Broadcaster Subscriptions](self)
167#[derive(Debug, thiserror::Error)]
168#[non_exhaustive]
169pub enum BroadcasterSubscriptionPointsError {
170    /// Deserialization error
171    #[error(transparent)]
172    DeserError(#[from] serde_json::Error),
173    /// `points` not found in the response
174    #[error("`points` not found in the response")]
175    PointsNotFound,
176}
177
178#[cfg(test)]
179#[test]
180fn test_request() {
181    use helix::*;
182    let req = GetBroadcasterSubscriptionsRequest::broadcaster_id("123");
183
184    // From twitch docs. Example has ...
185    let data = br#"
186    {
187        "data": [
188          {
189            "broadcaster_id": "141981764",
190            "broadcaster_login": "twitchdev",
191            "broadcaster_name": "TwitchDev",
192            "gifter_id": "12826",
193            "gifter_login": "twitch",
194            "gifter_name": "Twitch",
195            "is_gift": true,
196            "tier": "1000",
197            "plan_name": "Channel Subscription (twitchdev)",
198            "user_id": "527115020",
199            "user_name": "twitchgaming",
200            "user_login": "twitchgaming"
201          }
202        ],
203        "pagination": {
204          "cursor": "xxxx"
205        },
206        "total": 13,
207        "points": 13
208      }
209"#
210    .to_vec();
211
212    let http_response = http::Response::builder().body(data).unwrap();
213
214    let uri = req.get_uri().unwrap();
215    assert_eq!(
216        uri.to_string(),
217        "https://api.twitch.tv/helix/subscriptions?broadcaster_id=123"
218    );
219
220    let resp =
221        dbg!(
222            GetBroadcasterSubscriptionsRequest::parse_response(Some(req), &uri, http_response)
223                .unwrap()
224        );
225    assert_eq!(resp.total, Some(13));
226    assert_eq!(resp.points().unwrap(), 13);
227}