twitch_api/helix/endpoints/subscriptions/
check_user_subscription.rs

1//! Checks if a specific user is subscribed to a specific channel.
2//! [`check-user-subscription`](https://dev.twitch.tv/docs/api/reference#check-user-subscription)
3//!
4//! # Accessing the endpoint
5//!
6//! ## Request: [CheckUserSubscriptionRequest]
7//!
8//! To use this endpoint, construct a [`CheckUserSubscriptionRequest`] with the [`CheckUserSubscriptionRequest::broadcaster_id()`] method.
9//!
10//! ```rust
11//! use twitch_api::helix::subscriptions::check_user_subscription;
12//! let request =
13//!     check_user_subscription::CheckUserSubscriptionRequest::broadcaster_id(
14//!         "1234",
15//!     );
16//! ```
17//!
18//! ## Response: [UserSubscription]
19//!
20//! Send the request to receive the response with [`HelixClient::req_get()`](helix::HelixClient::req_get).
21//!
22//! ```rust, no_run
23//! use twitch_api::helix::{self, subscriptions::check_user_subscription};
24//! # use twitch_api::client;
25//! # #[tokio::main]
26//! # async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
27//! # let client: helix::HelixClient<'static, client::DummyHttpClient> = helix::HelixClient::default();
28//! # let token = twitch_oauth2::AccessToken::new("validtoken".to_string());
29//! # let token = twitch_oauth2::UserToken::from_existing(&client, token, None, None).await?;
30//! let request = check_user_subscription::CheckUserSubscriptionRequest::broadcaster_id("1234");
31//! let response: check_user_subscription::UserSubscription = client.req_get(request, &token).await?.data;
32//! # Ok(())
33//! # }
34//! ```
35//!
36//! You can also get the [`http::Request`] with [`request.create_request(&token, &client_id)`](helix::RequestGet::create_request)
37//! and parse the [`http::Response`] with [`CheckUserSubscriptionRequest::parse_response(None, &request.get_uri(), response)`](CheckUserSubscriptionRequest::parse_response)
38use super::*;
39use helix::RequestGet;
40
41/// Query Parameters for [Check User Subscription](super::check_user_subscription)
42///
43/// [`check-user-subscription`](https://dev.twitch.tv/docs/api/reference#check-user-subscription)
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 CheckUserSubscriptionRequest<'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}
60
61impl<'a> CheckUserSubscriptionRequest<'a> {
62    /// Checks subscribed users to this specific channel.
63    pub fn broadcaster_id(broadcaster_id: impl types::IntoCow<'a, types::UserIdRef> + 'a) -> Self {
64        Self {
65            broadcaster_id: broadcaster_id.into_cow(),
66            user_id: types::Collection::default(),
67        }
68    }
69
70    /// Filter the results for specific users.
71    pub fn user_ids(mut self, user_ids: impl Into<types::Collection<'a, types::UserId>>) -> Self {
72        self.user_id = user_ids.into();
73        self
74    }
75}
76
77/// Return Values for [Check User Subscription](super::check_user_subscription)
78///
79/// [`check-user-subscription`](https://dev.twitch.tv/docs/api/reference#check-user-subscription)
80#[derive(PartialEq, Eq, Deserialize, Serialize, Debug, Clone)]
81#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
82#[non_exhaustive]
83pub struct UserSubscription {
84    /// User ID of the broadcaster.
85    pub broadcaster_id: types::UserId,
86    /// Login of the broadcaster.
87    pub broadcaster_login: types::UserName,
88    /// Display name of the broadcaster.
89    pub broadcaster_name: types::DisplayName,
90    /// Indicates if the subscription is a gift.
91    pub is_gift: bool,
92    /// Login of the gifter (if is_gift is true).
93    pub gifter_login: Option<types::UserName>,
94    /// Display name of the gifter (if is_gift is true).
95    pub gifter_name: Option<types::DisplayName>,
96    /// Subscription tier. 1000 is tier 1, 2000 is tier 2, and 3000 is tier 3.
97    pub tier: types::SubscriptionTier,
98}
99
100impl Request for CheckUserSubscriptionRequest<'_> {
101    type Response = UserSubscription;
102
103    const PATH: &'static str = "subscriptions/user";
104    #[cfg(feature = "twitch_oauth2")]
105    const SCOPE: twitch_oauth2::Validator =
106        twitch_oauth2::validator![twitch_oauth2::Scope::UserReadSubscriptions];
107}
108
109impl RequestGet for CheckUserSubscriptionRequest<'_> {
110    fn parse_inner_response(
111        request: Option<Self>,
112        uri: &http::Uri,
113        text: &str,
114        status: http::StatusCode,
115    ) -> Result<helix::Response<Self, Self::Response>, helix::HelixRequestGetError>
116    where
117        Self: Sized,
118    {
119        let inner_response: helix::InnerResponse<Vec<_>> =
120            helix::parse_json(text, true).map_err(|e| {
121                helix::HelixRequestGetError::DeserializeError(
122                    text.to_string(),
123                    e,
124                    uri.clone(),
125                    status,
126                )
127            })?;
128        Ok(helix::Response::new(
129            inner_response.data.into_iter().next().ok_or(
130                helix::HelixRequestGetError::InvalidResponse {
131                    reason: "expected an entry in `data`",
132                    response: text.to_string(),
133                    status,
134                    uri: uri.clone(),
135                },
136            )?,
137            inner_response.pagination.cursor,
138            request,
139            inner_response.total,
140            inner_response.other,
141        ))
142    }
143}
144
145#[cfg(test)]
146#[test]
147fn test_request1() {
148    use helix::*;
149    let req = CheckUserSubscriptionRequest::broadcaster_id("123");
150
151    // From twitch docs.
152    let data = br#"
153    {
154        "data": [
155          {
156            "broadcaster_id": "149747285",
157            "broadcaster_name": "TwitchPresents",
158            "broadcaster_login": "twitchpresents",
159            "is_gift": false,
160            "tier": "1000"
161          }
162        ]
163      }
164"#
165    .to_vec();
166
167    let http_response = http::Response::builder().body(data).unwrap();
168
169    let uri = req.get_uri().unwrap();
170    assert_eq!(
171        uri.to_string(),
172        "https://api.twitch.tv/helix/subscriptions/user?broadcaster_id=123"
173    );
174
175    dbg!(CheckUserSubscriptionRequest::parse_response(Some(req), &uri, http_response).unwrap());
176}
177
178#[cfg(test)]
179#[test]
180fn test_request2() {
181    use helix::*;
182    let req = CheckUserSubscriptionRequest::broadcaster_id("123");
183
184    // From twitch docs.
185    let data = br#"
186    {
187        "error": "Not Found",
188        "message": "twitchdev has no subscription to twitchpresents",
189        "status": 404
190      }
191"#
192    .to_vec();
193
194    let http_response = http::Response::builder().status(404).body(data).unwrap();
195
196    let uri = req.get_uri().unwrap();
197    assert_eq!(
198        uri.to_string(),
199        "https://api.twitch.tv/helix/subscriptions/user?broadcaster_id=123"
200    );
201
202    dbg!(CheckUserSubscriptionRequest::parse_response(Some(req), &uri, http_response).unwrap_err());
203}