serenity/http/
client.rs

1#![allow(clippy::missing_errors_doc)]
2
3use std::borrow::Cow;
4use std::num::NonZeroU64;
5use std::sync::atomic::{AtomicU64, Ordering};
6use std::sync::Arc;
7
8use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
9use reqwest::header::{HeaderMap as Headers, HeaderValue};
10#[cfg(feature = "utils")]
11use reqwest::Url;
12use reqwest::{Client, ClientBuilder, Response as ReqwestResponse, StatusCode};
13use secrecy::{ExposeSecret, SecretString};
14use serde::de::DeserializeOwned;
15use tracing::{debug, instrument, warn};
16
17use super::multipart::{Multipart, MultipartUpload};
18use super::ratelimiting::Ratelimiter;
19use super::request::Request;
20use super::routing::Route;
21use super::typing::Typing;
22use super::{
23    ErrorResponse,
24    GuildPagination,
25    HttpError,
26    LightMethod,
27    MessagePagination,
28    UserPagination,
29};
30use crate::builder::{CreateAllowedMentions, CreateAttachment};
31use crate::constants;
32use crate::internal::prelude::*;
33use crate::json::*;
34use crate::model::prelude::*;
35
36/// A builder for the underlying [`Http`] client that performs requests to Discord's HTTP API
37///
38/// If you do not need to use a proxy or do not need to disable the rate limiter, you can use
39/// [`Http::new`] instead.
40///
41/// ## Example
42///
43/// Create an instance of [`Http`] with a proxy and rate limiter disabled
44///
45/// ```rust
46/// # use serenity::http::HttpBuilder;
47/// # fn run() {
48/// let http =
49///     HttpBuilder::new("token").proxy("http://127.0.0.1:3000").ratelimiter_disabled(true).build();
50/// # }
51/// ```
52#[must_use]
53pub struct HttpBuilder {
54    client: Option<Client>,
55    ratelimiter: Option<Ratelimiter>,
56    ratelimiter_disabled: bool,
57    token: SecretString,
58    proxy: Option<String>,
59    application_id: Option<ApplicationId>,
60    default_allowed_mentions: Option<CreateAllowedMentions>,
61}
62
63impl HttpBuilder {
64    /// Construct a new builder to call methods on for the HTTP construction. The `token` will
65    /// automatically be prefixed "Bot " if not already.
66    pub fn new(token: impl AsRef<str>) -> Self {
67        Self {
68            client: None,
69            ratelimiter: None,
70            ratelimiter_disabled: false,
71            token: SecretString::new(parse_token(token)),
72            proxy: None,
73            application_id: None,
74            default_allowed_mentions: None,
75        }
76    }
77
78    /// Sets the application_id to use interactions.
79    pub fn application_id(mut self, application_id: ApplicationId) -> Self {
80        self.application_id = Some(application_id);
81        self
82    }
83
84    /// Sets a token for the bot. If the token is not prefixed "Bot ", this method will
85    /// automatically do so.
86    pub fn token(mut self, token: impl AsRef<str>) -> Self {
87        self.token = SecretString::new(parse_token(token));
88        self
89    }
90
91    /// Sets the [`reqwest::Client`]. If one isn't provided, a default one will be used.
92    pub fn client(mut self, client: Client) -> Self {
93        self.client = Some(client);
94        self
95    }
96
97    /// Sets the ratelimiter to be used. If one isn't provided, a default one will be used.
98    pub fn ratelimiter(mut self, ratelimiter: Ratelimiter) -> Self {
99        self.ratelimiter = Some(ratelimiter);
100        self
101    }
102
103    /// Sets whether or not the ratelimiter is disabled. By default if this this not used, it is
104    /// enabled. In most cases, this should be used in conjunction with [`Self::proxy`].
105    ///
106    /// **Note**: You should **not** disable the ratelimiter unless you have another form of rate
107    /// limiting. Disabling the ratelimiter has the main purpose of delegating rate limiting to an
108    /// API proxy via [`Self::proxy`] instead of the current process.
109    pub fn ratelimiter_disabled(mut self, ratelimiter_disabled: bool) -> Self {
110        self.ratelimiter_disabled = ratelimiter_disabled;
111        self
112    }
113
114    /// Sets the proxy that Discord HTTP API requests will be passed to. This is mainly intended
115    /// for something like [`twilight-http-proxy`] where multiple processes can make API requests
116    /// while sharing a single ratelimiter.
117    ///
118    /// The proxy should be in the form of the protocol and hostname, e.g. `http://127.0.0.1:3000`
119    /// or `http://myproxy.example`
120    ///
121    /// This will simply send HTTP API requests to the proxy instead of Discord API to allow the
122    /// proxy to intercept, rate limit, and forward requests. This is different than a native
123    /// proxy's behavior where it will tunnel requests that use TLS via [`HTTP CONNECT`] method
124    /// (e.g. using [`reqwest::Proxy`]).
125    ///
126    /// [`twilight-http-proxy`]: https://github.com/twilight-rs/http-proxy
127    /// [`HTTP CONNECT`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/CONNECT
128    pub fn proxy(mut self, proxy: impl Into<String>) -> Self {
129        self.proxy = Some(proxy.into());
130        self
131    }
132
133    /// Sets the [`CreateAllowedMentions`] used by default for each request that would use it.
134    ///
135    /// This only takes effect if you are calling through the model or builder methods, not directly
136    /// calling [`Http`] methods, as [`Http`] is simply used as a convenient storage for these.
137    pub fn default_allowed_mentions(mut self, allowed_mentions: CreateAllowedMentions) -> Self {
138        self.default_allowed_mentions = Some(allowed_mentions);
139        self
140    }
141
142    /// Use the given configuration to build the `Http` client.
143    #[must_use]
144    pub fn build(self) -> Http {
145        let application_id = AtomicU64::new(self.application_id.map_or(0, ApplicationId::get));
146
147        let client = self.client.unwrap_or_else(|| {
148            let builder = configure_client_backend(Client::builder());
149            builder.build().expect("Cannot build reqwest::Client")
150        });
151
152        let ratelimiter = (!self.ratelimiter_disabled).then(|| {
153            self.ratelimiter
154                .unwrap_or_else(|| Ratelimiter::new(client.clone(), self.token.expose_secret()))
155        });
156
157        Http {
158            client,
159            ratelimiter,
160            proxy: self.proxy,
161            token: self.token,
162            application_id,
163            default_allowed_mentions: self.default_allowed_mentions,
164        }
165    }
166}
167
168fn parse_token(token: impl AsRef<str>) -> String {
169    let token = token.as_ref().trim();
170
171    if token.starts_with("Bot ") || token.starts_with("Bearer ") {
172        token.to_string()
173    } else {
174        format!("Bot {token}")
175    }
176}
177
178fn reason_into_header(reason: &str) -> Headers {
179    let mut headers = Headers::new();
180
181    // "The X-Audit-Log-Reason header supports 1-512 URL-encoded UTF-8 characters."
182    // https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object
183    let header_value = match Cow::from(utf8_percent_encode(reason, NON_ALPHANUMERIC)) {
184        Cow::Borrowed(value) => HeaderValue::from_str(value),
185        Cow::Owned(value) => HeaderValue::try_from(value),
186    }
187    .expect("Invalid header value even after percent encode");
188
189    headers.insert("X-Audit-Log-Reason", header_value);
190    headers
191}
192
193/// **Note**: For all member functions that return a [`Result`], the Error kind will be either
194/// [`Error::Http`] or [`Error::Json`].
195#[derive(Debug)]
196pub struct Http {
197    pub(crate) client: Client,
198    pub ratelimiter: Option<Ratelimiter>,
199    pub proxy: Option<String>,
200    token: SecretString,
201    application_id: AtomicU64,
202    pub default_allowed_mentions: Option<CreateAllowedMentions>,
203}
204
205impl Http {
206    #[must_use]
207    pub fn new(token: &str) -> Self {
208        HttpBuilder::new(token).build()
209    }
210
211    pub fn application_id(&self) -> Option<ApplicationId> {
212        let application_id = self.application_id.load(Ordering::Relaxed);
213        NonZeroU64::new(application_id).map(ApplicationId::from)
214    }
215
216    fn try_application_id(&self) -> Result<ApplicationId> {
217        self.application_id().ok_or_else(|| HttpError::ApplicationIdMissing.into())
218    }
219
220    pub fn set_application_id(&self, application_id: ApplicationId) {
221        self.application_id.store(application_id.get(), Ordering::Relaxed);
222    }
223
224    pub fn token(&self) -> &str {
225        self.token.expose_secret()
226    }
227
228    /// Adds a [`User`] to a [`Guild`] with a valid OAuth2 access token.
229    ///
230    /// Returns the created [`Member`] object, or nothing if the user is already a guild member.
231    pub async fn add_guild_member(
232        &self,
233        guild_id: GuildId,
234        user_id: UserId,
235        map: &impl serde::Serialize,
236    ) -> Result<Option<Member>> {
237        let body = to_vec(map)?;
238
239        let response = self
240            .request(Request {
241                body: Some(body),
242                multipart: None,
243                headers: None,
244                method: LightMethod::Put,
245                route: Route::GuildMember {
246                    guild_id,
247                    user_id,
248                },
249                params: None,
250            })
251            .await?;
252
253        if response.status() == 204 {
254            Ok(None)
255        } else {
256            Ok(Some(decode_resp(response).await?))
257        }
258    }
259
260    /// Adds a single [`Role`] to a [`Member`] in a [`Guild`].
261    ///
262    /// **Note**: Requires the [Manage Roles] permission and respect of role hierarchy.
263    ///
264    /// [Manage Roles]: Permissions::MANAGE_ROLES
265    pub async fn add_member_role(
266        &self,
267        guild_id: GuildId,
268        user_id: UserId,
269        role_id: RoleId,
270        audit_log_reason: Option<&str>,
271    ) -> Result<()> {
272        self.wind(204, Request {
273            body: None,
274            multipart: None,
275            headers: audit_log_reason.map(reason_into_header),
276            method: LightMethod::Put,
277            route: Route::GuildMemberRole {
278                guild_id,
279                role_id,
280                user_id,
281            },
282            params: None,
283        })
284        .await
285    }
286
287    /// Bans a [`User`] from a [`Guild`], removing their messages sent in the last X number of
288    /// days.
289    ///
290    /// Passing a `delete_message_days` of `0` is equivalent to not removing any messages. Up to
291    /// `7` days' worth of messages may be deleted.
292    ///
293    /// **Note**: Requires that you have the [Ban Members] permission.
294    ///
295    /// [Ban Members]: Permissions::BAN_MEMBERS
296    pub async fn ban_user(
297        &self,
298        guild_id: GuildId,
299        user_id: UserId,
300        delete_message_days: u8,
301        reason: Option<&str>,
302    ) -> Result<()> {
303        let delete_message_seconds = u32::from(delete_message_days) * 86400;
304
305        self.wind(204, Request {
306            body: None,
307            multipart: None,
308            headers: reason.map(reason_into_header),
309            method: LightMethod::Put,
310            route: Route::GuildBan {
311                guild_id,
312                user_id,
313            },
314            params: Some(vec![("delete_message_seconds", delete_message_seconds.to_string())]),
315        })
316        .await
317    }
318
319    /// Bans multiple users from a [`Guild`], optionally removing their messages.
320    ///
321    /// See the [Discord docs](https://discord.com/developers/docs/resources/guild#bulk-guild-ban)
322    /// for more information.
323    pub async fn bulk_ban_users(
324        &self,
325        guild_id: GuildId,
326        map: &impl serde::Serialize,
327        reason: Option<&str>,
328    ) -> Result<BulkBanResponse> {
329        self.fire(Request {
330            body: Some(to_vec(map)?),
331            multipart: None,
332            headers: reason.map(reason_into_header),
333            method: LightMethod::Post,
334            route: Route::GuildBulkBan {
335                guild_id,
336            },
337            params: None,
338        })
339        .await
340    }
341
342    /// Broadcasts that the current user is typing in the given [`Channel`].
343    ///
344    /// This lasts for about 10 seconds, and will then need to be renewed to indicate that the
345    /// current user is still typing.
346    ///
347    /// This should rarely be used for bots, although it is a good indicator that a long-running
348    /// command is still being processed.
349    pub async fn broadcast_typing(&self, channel_id: ChannelId) -> Result<()> {
350        self.wind(204, Request {
351            body: None,
352            multipart: None,
353            headers: None,
354            method: LightMethod::Post,
355            route: Route::ChannelTyping {
356                channel_id,
357            },
358            params: None,
359        })
360        .await
361    }
362
363    /// Creates a [`GuildChannel`] in the [`Guild`] given its Id.
364    ///
365    /// Refer to the Discord's [docs] for information on what fields this requires.
366    ///
367    /// **Note**: Requires the [Manage Channels] permission.
368    ///
369    /// [docs]: https://discord.com/developers/docs/resources/guild#create-guild-channel
370    /// [Manage Channels]: Permissions::MANAGE_CHANNELS
371    pub async fn create_channel(
372        &self,
373        guild_id: GuildId,
374        map: &impl serde::Serialize,
375        audit_log_reason: Option<&str>,
376    ) -> Result<GuildChannel> {
377        let body = to_vec(map)?;
378
379        self.fire(Request {
380            body: Some(body),
381            multipart: None,
382            headers: audit_log_reason.map(reason_into_header),
383            method: LightMethod::Post,
384            route: Route::GuildChannels {
385                guild_id,
386            },
387            params: None,
388        })
389        .await
390    }
391
392    /// Creates a stage instance.
393    pub async fn create_stage_instance(
394        &self,
395        map: &impl serde::Serialize,
396        audit_log_reason: Option<&str>,
397    ) -> Result<StageInstance> {
398        self.fire(Request {
399            body: Some(to_vec(map)?),
400            multipart: None,
401            headers: audit_log_reason.map(reason_into_header),
402            method: LightMethod::Post,
403            route: Route::StageInstances,
404            params: None,
405        })
406        .await
407    }
408
409    /// Creates a thread channel in the [`GuildChannel`] given its Id, with a base message Id.
410    pub async fn create_thread_from_message(
411        &self,
412        channel_id: ChannelId,
413        message_id: MessageId,
414        map: &impl serde::Serialize,
415        audit_log_reason: Option<&str>,
416    ) -> Result<GuildChannel> {
417        let body = to_vec(map)?;
418
419        self.fire(Request {
420            body: Some(body),
421            multipart: None,
422            headers: audit_log_reason.map(reason_into_header),
423            method: LightMethod::Post,
424            route: Route::ChannelMessageThreads {
425                channel_id,
426                message_id,
427            },
428            params: None,
429        })
430        .await
431    }
432
433    /// Creates a thread channel not attached to a message in the [`GuildChannel`] given its Id.
434    pub async fn create_thread(
435        &self,
436        channel_id: ChannelId,
437        map: &impl serde::Serialize,
438        audit_log_reason: Option<&str>,
439    ) -> Result<GuildChannel> {
440        let body = to_vec(map)?;
441
442        self.fire(Request {
443            body: Some(body),
444            multipart: None,
445            headers: audit_log_reason.map(reason_into_header),
446            method: LightMethod::Post,
447            route: Route::ChannelThreads {
448                channel_id,
449            },
450            params: None,
451        })
452        .await
453    }
454
455    /// Shortcut for [`Self::create_forum_post_with_attachments`]
456    pub async fn create_forum_post(
457        &self,
458        channel_id: ChannelId,
459        map: &impl serde::Serialize,
460        audit_log_reason: Option<&str>,
461    ) -> Result<GuildChannel> {
462        self.create_forum_post_with_attachments(channel_id, map, vec![], audit_log_reason).await
463    }
464
465    /// Creates a forum post channel in the [`GuildChannel`] given its Id.
466    pub async fn create_forum_post_with_attachments(
467        &self,
468        channel_id: ChannelId,
469        map: &impl serde::Serialize,
470        files: Vec<CreateAttachment>,
471        audit_log_reason: Option<&str>,
472    ) -> Result<GuildChannel> {
473        self.fire(Request {
474            body: None,
475            multipart: Some(Multipart {
476                upload: MultipartUpload::Attachments(files.into_iter().collect()),
477                payload_json: Some(to_string(map)?),
478                fields: vec![],
479            }),
480            headers: audit_log_reason.map(reason_into_header),
481            method: LightMethod::Post,
482            route: Route::ChannelForumPosts {
483                channel_id,
484            },
485            params: None,
486        })
487        .await
488    }
489
490    /// Creates an emoji in the given [`Guild`] with the given data.
491    ///
492    /// See [`Guild::create_emoji`] for required fields.
493    ///
494    /// **Note**: Requires the [Create Guild Expressions] permission.
495    ///
496    /// [Create Guild Expressions]: Permissions::CREATE_GUILD_EXPRESSIONS
497    pub async fn create_emoji(
498        &self,
499        guild_id: GuildId,
500        map: &Value,
501        audit_log_reason: Option<&str>,
502    ) -> Result<Emoji> {
503        self.fire(Request {
504            body: Some(to_vec(map)?),
505            multipart: None,
506            headers: audit_log_reason.map(reason_into_header),
507            method: LightMethod::Post,
508            route: Route::GuildEmojis {
509                guild_id,
510            },
511            params: None,
512        })
513        .await
514    }
515
516    /// Creates an application emoji with the given data.
517    ///
518    /// See [`Context::create_application_emoji`] for required fields.
519    ///
520    /// [`Context::create_application_emoji`]: crate::client::Context::create_application_emoji
521    pub async fn create_application_emoji(&self, map: &impl serde::Serialize) -> Result<Emoji> {
522        self.fire(Request {
523            body: Some(to_vec(map)?),
524            multipart: None,
525            headers: None,
526            method: LightMethod::Post,
527            route: Route::Emojis {
528                application_id: self.try_application_id()?,
529            },
530            params: None,
531        })
532        .await
533    }
534
535    /// Create a follow-up message for an Interaction.
536    ///
537    /// Functions the same as [`Self::execute_webhook`]
538    pub async fn create_followup_message(
539        &self,
540        interaction_token: &str,
541        map: &impl serde::Serialize,
542        files: Vec<CreateAttachment>,
543    ) -> Result<Message> {
544        let mut request = Request {
545            body: None,
546            multipart: None,
547            headers: None,
548            method: LightMethod::Post,
549            route: Route::WebhookFollowupMessages {
550                application_id: self.try_application_id()?,
551                token: interaction_token,
552            },
553            params: None,
554        };
555
556        if files.is_empty() {
557            request.body = Some(to_vec(map)?);
558        } else {
559            request.multipart = Some(Multipart {
560                upload: MultipartUpload::Attachments(files),
561                payload_json: Some(to_string(map)?),
562                fields: vec![],
563            });
564        }
565
566        self.fire(request).await
567    }
568
569    /// Creates a new global command.
570    ///
571    /// New global commands will be available in all guilds after 1 hour.
572    ///
573    /// Refer to Discord's [docs] for field information.
574    ///
575    /// **Note**: Creating a command with the same name as an existing command for your application
576    /// will overwrite the old command.
577    ///
578    /// [docs]: https://discord.com/developers/docs/interactions/slash-commands#create-global-application-command
579    pub async fn create_global_command(&self, map: &impl serde::Serialize) -> Result<Command> {
580        self.fire(Request {
581            body: Some(to_vec(map)?),
582            multipart: None,
583            headers: None,
584            method: LightMethod::Post,
585            route: Route::Commands {
586                application_id: self.try_application_id()?,
587            },
588            params: None,
589        })
590        .await
591    }
592
593    /// Creates new global application commands.
594    pub async fn create_global_commands(
595        &self,
596        map: &impl serde::Serialize,
597    ) -> Result<Vec<Command>> {
598        self.fire(Request {
599            body: Some(to_vec(map)?),
600            multipart: None,
601            headers: None,
602            method: LightMethod::Put,
603            route: Route::Commands {
604                application_id: self.try_application_id()?,
605            },
606            params: None,
607        })
608        .await
609    }
610
611    /// Creates new guild application commands.
612    pub async fn create_guild_commands(
613        &self,
614        guild_id: GuildId,
615        map: &impl serde::Serialize,
616    ) -> Result<Vec<Command>> {
617        self.fire(Request {
618            body: Some(to_vec(map)?),
619            multipart: None,
620            headers: None,
621            method: LightMethod::Put,
622            route: Route::GuildCommands {
623                application_id: self.try_application_id()?,
624                guild_id,
625            },
626            params: None,
627        })
628        .await
629    }
630
631    /// Creates a guild with the data provided.
632    ///
633    /// Only a [`PartialGuild`] will be immediately returned, and a full [`Guild`] will be received
634    /// over a [`Shard`], if at least one is running.
635    ///
636    /// **Note**: This endpoint is currently limited to 10 active guilds. The limits are raised for
637    /// whitelisted [GameBridge] applications. See the [documentation on this endpoint] for more
638    /// info.
639    ///
640    /// # Examples
641    ///
642    /// Create a guild called `"test"` in the [US West region]:
643    ///
644    /// ```rust,no_run
645    /// use serenity::http::Http;
646    /// use serenity::json::json;
647    ///
648    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
649    /// # let http: Http = unimplemented!();
650    /// let map = json!({
651    ///     "name": "test",
652    /// });
653    ///
654    /// let _result = http.create_guild(&map).await?;
655    /// # Ok(())
656    /// # }
657    /// ```
658    ///
659    /// [`Shard`]: crate::gateway::Shard
660    /// [GameBridge]: https://discord.com/developers/docs/topics/gamebridge
661    /// [documentation on this endpoint]:
662    /// https://discord.com/developers/docs/resources/guild#create-guild
663    /// [whitelist]: https://discord.com/developers/docs/resources/guild#create-guild
664    pub async fn create_guild(&self, map: &Value) -> Result<PartialGuild> {
665        self.fire(Request {
666            body: Some(to_vec(map)?),
667            multipart: None,
668            headers: None,
669            method: LightMethod::Post,
670            route: Route::Guilds,
671            params: None,
672        })
673        .await
674    }
675
676    /// Creates a new guild command.
677    ///
678    /// New guild commands will be available in the guild immediately.
679    ///
680    /// Refer to Discord's [docs] for field information.
681    ///
682    /// [docs]: https://discord.com/developers/docs/interactions/slash-commands#create-guild-application-command
683    pub async fn create_guild_command(
684        &self,
685        guild_id: GuildId,
686        map: &impl serde::Serialize,
687    ) -> Result<Command> {
688        self.fire(Request {
689            body: Some(to_vec(map)?),
690            multipart: None,
691            headers: None,
692            method: LightMethod::Post,
693            route: Route::GuildCommands {
694                application_id: self.try_application_id()?,
695                guild_id,
696            },
697            params: None,
698        })
699        .await
700    }
701
702    /// Creates an [`Integration`] for a [`Guild`].
703    ///
704    /// Refer to Discord's [docs] for field information.
705    ///
706    /// **Note**: Requires the [Manage Guild] permission.
707    ///
708    /// [Manage Guild]: Permissions::MANAGE_GUILD
709    /// [docs]: https://discord.com/developers/docs/resources/guild#create-guild-integration
710    pub async fn create_guild_integration(
711        &self,
712        guild_id: GuildId,
713        integration_id: IntegrationId,
714        map: &Value,
715        audit_log_reason: Option<&str>,
716    ) -> Result<()> {
717        self.wind(204, Request {
718            body: Some(to_vec(map)?),
719            multipart: None,
720            headers: audit_log_reason.map(reason_into_header),
721            method: LightMethod::Post,
722            route: Route::GuildIntegration {
723                guild_id,
724                integration_id,
725            },
726            params: None,
727        })
728        .await
729    }
730
731    /// Creates a response to an [`Interaction`] from the gateway.
732    ///
733    /// Refer to Discord's [docs] for the object it takes.
734    ///
735    /// [`Interaction`]: crate::model::application::Interaction
736    /// [docs]: https://discord.com/developers/docs/interactions/slash-commands#interaction-interaction-response
737    pub async fn create_interaction_response(
738        &self,
739        interaction_id: InteractionId,
740        interaction_token: &str,
741        map: &impl serde::Serialize,
742        files: Vec<CreateAttachment>,
743    ) -> Result<()> {
744        let mut request = Request {
745            body: None,
746            multipart: None,
747            headers: None,
748            method: LightMethod::Post,
749            route: Route::InteractionResponse {
750                interaction_id,
751                token: interaction_token,
752            },
753            params: None,
754        };
755
756        if files.is_empty() {
757            request.body = Some(to_vec(map)?);
758        } else {
759            request.multipart = Some(Multipart {
760                upload: MultipartUpload::Attachments(files),
761                payload_json: Some(to_string(map)?),
762                fields: vec![],
763            });
764        }
765
766        self.wind(204, request).await
767    }
768
769    /// Creates a [`RichInvite`] for the given [channel][`GuildChannel`].
770    ///
771    /// Refer to Discord's [docs] for field information.
772    ///
773    /// All fields are optional.
774    ///
775    /// **Note**: Requires the [Create Instant Invite] permission.
776    ///
777    /// [Create Instant Invite]: Permissions::CREATE_INSTANT_INVITE
778    /// [docs]: https://discord.com/developers/docs/resources/channel#create-channel-invite
779    pub async fn create_invite(
780        &self,
781        channel_id: ChannelId,
782        map: &impl serde::Serialize,
783        audit_log_reason: Option<&str>,
784    ) -> Result<RichInvite> {
785        let body = to_vec(map)?;
786
787        self.fire(Request {
788            body: Some(body),
789            multipart: None,
790            headers: audit_log_reason.map(reason_into_header),
791            method: LightMethod::Post,
792            route: Route::ChannelInvites {
793                channel_id,
794            },
795            params: None,
796        })
797        .await
798    }
799
800    /// Creates a permission override for a member or a role in a channel.
801    pub async fn create_permission(
802        &self,
803        channel_id: ChannelId,
804        target_id: TargetId,
805        map: &impl serde::Serialize,
806        audit_log_reason: Option<&str>,
807    ) -> Result<()> {
808        let body = to_vec(map)?;
809
810        self.wind(204, Request {
811            body: Some(body),
812            multipart: None,
813            headers: audit_log_reason.map(reason_into_header),
814            method: LightMethod::Put,
815            route: Route::ChannelPermission {
816                channel_id,
817                target_id,
818            },
819            params: None,
820        })
821        .await
822    }
823
824    /// Creates a private channel with a user.
825    pub async fn create_private_channel(&self, map: &Value) -> Result<PrivateChannel> {
826        let body = to_vec(map)?;
827
828        self.fire(Request {
829            body: Some(body),
830            multipart: None,
831            headers: None,
832            method: LightMethod::Post,
833            route: Route::UserMeDmChannels,
834            params: None,
835        })
836        .await
837    }
838
839    async fn create_reaction_(
840        &self,
841        channel_id: ChannelId,
842        message_id: MessageId,
843        reaction_type: &ReactionType,
844        burst: bool,
845    ) -> Result<()> {
846        self.wind(204, Request {
847            body: None,
848            multipart: None,
849            headers: None,
850            method: LightMethod::Put,
851            route: Route::ChannelMessageReactionMe {
852                channel_id,
853                message_id,
854                reaction: &reaction_type.as_data(),
855            },
856            params: Some(vec![("burst", burst.to_string())]),
857        })
858        .await
859    }
860
861    /// Reacts to a message.
862    pub async fn create_reaction(
863        &self,
864        channel_id: ChannelId,
865        message_id: MessageId,
866        reaction_type: &ReactionType,
867    ) -> Result<()> {
868        self.create_reaction_(channel_id, message_id, reaction_type, false).await
869    }
870
871    /// Super reacts to a message.
872    pub async fn create_super_reaction(
873        &self,
874        channel_id: ChannelId,
875        message_id: MessageId,
876        reaction_type: &ReactionType,
877    ) -> Result<()> {
878        self.create_reaction_(channel_id, message_id, reaction_type, true).await
879    }
880
881    /// Creates a role.
882    pub async fn create_role(
883        &self,
884        guild_id: GuildId,
885        body: &impl serde::Serialize,
886        audit_log_reason: Option<&str>,
887    ) -> Result<Role> {
888        let mut value: Value = self
889            .fire(Request {
890                body: Some(to_vec(body)?),
891                multipart: None,
892                headers: audit_log_reason.map(reason_into_header),
893                method: LightMethod::Post,
894                route: Route::GuildRoles {
895                    guild_id,
896                },
897                params: None,
898            })
899            .await?;
900
901        if let Some(map) = value.as_object_mut() {
902            map.insert("guild_id".to_string(), guild_id.get().into());
903        }
904
905        from_value(value).map_err(From::from)
906    }
907
908    /// Creates a Guild Scheduled Event.
909    ///
910    /// Refer to Discord's docs for field information.
911    ///
912    /// **Note**: Requires the [Create Events] permission.
913    ///
914    /// [Create Events]: Permissions::CREATE_EVENTS
915    pub async fn create_scheduled_event(
916        &self,
917        guild_id: GuildId,
918        map: &impl serde::Serialize,
919        audit_log_reason: Option<&str>,
920    ) -> Result<ScheduledEvent> {
921        let body = to_vec(map)?;
922        self.fire(Request {
923            body: Some(body),
924            multipart: None,
925            headers: audit_log_reason.map(reason_into_header),
926            method: LightMethod::Post,
927            route: Route::GuildScheduledEvents {
928                guild_id,
929            },
930            params: None,
931        })
932        .await
933    }
934
935    /// Creates a sticker.
936    ///
937    /// **Note**: Requires the [Create Guild Expressions] permission.
938    ///
939    /// [Create Guild Expressions]: Permissions::CREATE_GUILD_EXPRESSIONS
940    pub async fn create_sticker(
941        &self,
942        guild_id: GuildId,
943        map: impl IntoIterator<Item = (&'static str, String)>,
944        file: CreateAttachment,
945        audit_log_reason: Option<&str>,
946    ) -> Result<Sticker> {
947        self.fire(Request {
948            body: None,
949            multipart: Some(Multipart {
950                upload: MultipartUpload::File(file),
951                fields: map.into_iter().map(|(k, v)| (k.into(), v.into())).collect(),
952                payload_json: None,
953            }),
954            headers: audit_log_reason.map(reason_into_header),
955            method: LightMethod::Post,
956            route: Route::GuildStickers {
957                guild_id,
958            },
959            params: None,
960        })
961        .await
962    }
963
964    /// Creates a test entitlement to a given SKU for a given guild or user. Discord will act as
965    /// though that user/guild has entitlement in perpetuity to the SKU. As a result, the returned
966    /// entitlement will have `starts_at` and `ends_at` both be `None`.
967    pub async fn create_test_entitlement(
968        &self,
969        sku_id: SkuId,
970        owner: EntitlementOwner,
971    ) -> Result<Entitlement> {
972        #[derive(serde::Serialize)]
973        struct TestEntitlement {
974            sku_id: SkuId,
975            owner_id: u64,
976            owner_type: u8,
977        }
978
979        let (owner_id, owner_type) = match owner {
980            EntitlementOwner::Guild(id) => (id.get(), 1),
981            EntitlementOwner::User(id) => (id.get(), 2),
982        };
983
984        let map = TestEntitlement {
985            sku_id,
986            owner_id,
987            owner_type,
988        };
989
990        self.fire(Request {
991            body: Some(to_vec(&map)?),
992            multipart: None,
993            headers: None,
994            method: LightMethod::Post,
995            route: Route::Entitlements {
996                application_id: self.try_application_id()?,
997            },
998            params: None,
999        })
1000        .await
1001    }
1002
1003    /// Creates a webhook for the given [channel][`GuildChannel`]'s Id, passing in the given data.
1004    ///
1005    /// This method requires authentication.
1006    ///
1007    /// The Value is a map with the values of:
1008    /// - **avatar**: base64-encoded 128x128 image for the webhook's default avatar (_optional_);
1009    /// - **name**: the name of the webhook, limited to between 2 and 100 characters long.
1010    ///
1011    /// # Examples
1012    ///
1013    /// Creating a webhook named `test`:
1014    ///
1015    /// ```rust,no_run
1016    /// use serenity::http::Http;
1017    /// use serenity::json::json;
1018    /// use serenity::model::prelude::*;
1019    ///
1020    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
1021    /// # let http: Http = unimplemented!();
1022    /// let channel_id = ChannelId::new(81384788765712384);
1023    /// let map = json!({"name": "test"});
1024    ///
1025    /// let webhook = http.create_webhook(channel_id, &map, None).await?;
1026    /// # Ok(())
1027    /// # }
1028    /// ```
1029    pub async fn create_webhook(
1030        &self,
1031        channel_id: ChannelId,
1032        map: &impl serde::Serialize,
1033        audit_log_reason: Option<&str>,
1034    ) -> Result<Webhook> {
1035        let body = to_vec(map)?;
1036
1037        self.fire(Request {
1038            body: Some(body),
1039            multipart: None,
1040            headers: audit_log_reason.map(reason_into_header),
1041            method: LightMethod::Post,
1042            route: Route::ChannelWebhooks {
1043                channel_id,
1044            },
1045            params: None,
1046        })
1047        .await
1048    }
1049
1050    /// Deletes a private channel or a channel in a guild.
1051    pub async fn delete_channel(
1052        &self,
1053        channel_id: ChannelId,
1054        audit_log_reason: Option<&str>,
1055    ) -> Result<Channel> {
1056        self.fire(Request {
1057            body: None,
1058            multipart: None,
1059            headers: audit_log_reason.map(reason_into_header),
1060            method: LightMethod::Delete,
1061            route: Route::Channel {
1062                channel_id,
1063            },
1064            params: None,
1065        })
1066        .await
1067    }
1068
1069    /// Deletes a stage instance.
1070    pub async fn delete_stage_instance(
1071        &self,
1072        channel_id: ChannelId,
1073        audit_log_reason: Option<&str>,
1074    ) -> Result<()> {
1075        self.wind(204, Request {
1076            body: None,
1077            multipart: None,
1078            headers: audit_log_reason.map(reason_into_header),
1079            method: LightMethod::Delete,
1080            route: Route::StageInstance {
1081                channel_id,
1082            },
1083            params: None,
1084        })
1085        .await
1086    }
1087
1088    /// Deletes an emoji from a guild.
1089    ///
1090    /// See [`GuildId::delete_emoji`] for permissions requirements.
1091    pub async fn delete_emoji(
1092        &self,
1093        guild_id: GuildId,
1094        emoji_id: EmojiId,
1095        audit_log_reason: Option<&str>,
1096    ) -> Result<()> {
1097        self.wind(204, Request {
1098            body: None,
1099            multipart: None,
1100            headers: audit_log_reason.map(reason_into_header),
1101            method: LightMethod::Delete,
1102            route: Route::GuildEmoji {
1103                guild_id,
1104                emoji_id,
1105            },
1106            params: None,
1107        })
1108        .await
1109    }
1110
1111    /// Deletes an application emoji.
1112    pub async fn delete_application_emoji(&self, emoji_id: EmojiId) -> Result<()> {
1113        self.wind(204, Request {
1114            body: None,
1115            multipart: None,
1116            headers: None,
1117            method: LightMethod::Delete,
1118            route: Route::Emoji {
1119                application_id: self.try_application_id()?,
1120                emoji_id,
1121            },
1122            params: None,
1123        })
1124        .await
1125    }
1126
1127    /// Deletes a follow-up message for an interaction.
1128    pub async fn delete_followup_message(
1129        &self,
1130        interaction_token: &str,
1131        message_id: MessageId,
1132    ) -> Result<()> {
1133        self.wind(204, Request {
1134            body: None,
1135            multipart: None,
1136            headers: None,
1137            method: LightMethod::Delete,
1138            route: Route::WebhookFollowupMessage {
1139                application_id: self.try_application_id()?,
1140                token: interaction_token,
1141                message_id,
1142            },
1143            params: None,
1144        })
1145        .await
1146    }
1147
1148    /// Deletes a global command.
1149    pub async fn delete_global_command(&self, command_id: CommandId) -> Result<()> {
1150        self.wind(204, Request {
1151            body: None,
1152            multipart: None,
1153            headers: None,
1154            method: LightMethod::Delete,
1155            route: Route::Command {
1156                application_id: self.try_application_id()?,
1157                command_id,
1158            },
1159            params: None,
1160        })
1161        .await
1162    }
1163
1164    /// Deletes a guild, only if connected account owns it.
1165    pub async fn delete_guild(&self, guild_id: GuildId) -> Result<()> {
1166        self.wind(204, Request {
1167            body: None,
1168            multipart: None,
1169            headers: None,
1170            method: LightMethod::Delete,
1171            route: Route::Guild {
1172                guild_id,
1173            },
1174            params: None,
1175        })
1176        .await
1177    }
1178
1179    /// Deletes a guild command.
1180    pub async fn delete_guild_command(
1181        &self,
1182        guild_id: GuildId,
1183        command_id: CommandId,
1184    ) -> Result<()> {
1185        self.wind(204, Request {
1186            body: None,
1187            multipart: None,
1188            headers: None,
1189            method: LightMethod::Delete,
1190            route: Route::GuildCommand {
1191                application_id: self.try_application_id()?,
1192                guild_id,
1193                command_id,
1194            },
1195            params: None,
1196        })
1197        .await
1198    }
1199
1200    /// Removes an integration from a guild.
1201    pub async fn delete_guild_integration(
1202        &self,
1203        guild_id: GuildId,
1204        integration_id: IntegrationId,
1205        audit_log_reason: Option<&str>,
1206    ) -> Result<()> {
1207        self.wind(204, Request {
1208            body: None,
1209            multipart: None,
1210            headers: audit_log_reason.map(reason_into_header),
1211            method: LightMethod::Delete,
1212            route: Route::GuildIntegration {
1213                guild_id,
1214                integration_id,
1215            },
1216            params: None,
1217        })
1218        .await
1219    }
1220
1221    /// Deletes an invite by code.
1222    pub async fn delete_invite(
1223        &self,
1224        code: &str,
1225        audit_log_reason: Option<&str>,
1226    ) -> Result<Invite> {
1227        self.fire(Request {
1228            body: None,
1229            multipart: None,
1230            headers: audit_log_reason.map(reason_into_header),
1231            method: LightMethod::Delete,
1232            route: Route::Invite {
1233                code,
1234            },
1235            params: None,
1236        })
1237        .await
1238    }
1239
1240    /// Deletes a message if created by us or we have specific permissions.
1241    pub async fn delete_message(
1242        &self,
1243        channel_id: ChannelId,
1244        message_id: MessageId,
1245        audit_log_reason: Option<&str>,
1246    ) -> Result<()> {
1247        self.wind(204, Request {
1248            body: None,
1249            multipart: None,
1250            headers: audit_log_reason.map(reason_into_header),
1251            method: LightMethod::Delete,
1252            route: Route::ChannelMessage {
1253                channel_id,
1254                message_id,
1255            },
1256            params: None,
1257        })
1258        .await
1259    }
1260
1261    /// Deletes a bunch of messages, only works for bots.
1262    pub async fn delete_messages(
1263        &self,
1264        channel_id: ChannelId,
1265        map: &Value,
1266        audit_log_reason: Option<&str>,
1267    ) -> Result<()> {
1268        self.wind(204, Request {
1269            body: Some(to_vec(map)?),
1270            multipart: None,
1271            headers: audit_log_reason.map(reason_into_header),
1272            method: LightMethod::Post,
1273            route: Route::ChannelMessagesBulkDelete {
1274                channel_id,
1275            },
1276            params: None,
1277        })
1278        .await
1279    }
1280
1281    /// Deletes all of the [`Reaction`]s associated with a [`Message`].
1282    ///
1283    /// # Examples
1284    ///
1285    /// ```rust,no_run
1286    /// # use serenity::http::Http;
1287    /// #
1288    /// use serenity::model::id::{ChannelId, MessageId};
1289    ///
1290    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
1291    /// # let http: Http = unimplemented!();
1292    /// let channel_id = ChannelId::new(7);
1293    /// let message_id = MessageId::new(8);
1294    ///
1295    /// http.delete_message_reactions(channel_id, message_id).await?;
1296    /// # Ok(())
1297    /// # }
1298    /// ```
1299    pub async fn delete_message_reactions(
1300        &self,
1301        channel_id: ChannelId,
1302        message_id: MessageId,
1303    ) -> Result<()> {
1304        self.wind(204, Request {
1305            body: None,
1306            multipart: None,
1307            headers: None,
1308            method: LightMethod::Delete,
1309            route: Route::ChannelMessageReactions {
1310                channel_id,
1311                message_id,
1312            },
1313            params: None,
1314        })
1315        .await
1316    }
1317
1318    /// Deletes all the reactions for a given emoji on a message.
1319    pub async fn delete_message_reaction_emoji(
1320        &self,
1321        channel_id: ChannelId,
1322        message_id: MessageId,
1323        reaction_type: &ReactionType,
1324    ) -> Result<()> {
1325        self.wind(204, Request {
1326            body: None,
1327            multipart: None,
1328            headers: None,
1329            method: LightMethod::Delete,
1330            route: Route::ChannelMessageReactionEmoji {
1331                channel_id,
1332                message_id,
1333                reaction: &reaction_type.as_data(),
1334            },
1335            params: None,
1336        })
1337        .await
1338    }
1339
1340    /// Deletes the initial interaction response.
1341    pub async fn delete_original_interaction_response(
1342        &self,
1343        interaction_token: &str,
1344    ) -> Result<()> {
1345        self.wind(204, Request {
1346            body: None,
1347            multipart: None,
1348            headers: None,
1349            method: LightMethod::Delete,
1350            route: Route::WebhookOriginalInteractionResponse {
1351                application_id: self.try_application_id()?,
1352                token: interaction_token,
1353            },
1354            params: None,
1355        })
1356        .await
1357    }
1358
1359    /// Deletes a permission override from a role or a member in a channel.
1360    pub async fn delete_permission(
1361        &self,
1362        channel_id: ChannelId,
1363        target_id: TargetId,
1364        audit_log_reason: Option<&str>,
1365    ) -> Result<()> {
1366        self.wind(204, Request {
1367            body: None,
1368            multipart: None,
1369            headers: audit_log_reason.map(reason_into_header),
1370            method: LightMethod::Delete,
1371            route: Route::ChannelPermission {
1372                channel_id,
1373                target_id,
1374            },
1375            params: None,
1376        })
1377        .await
1378    }
1379
1380    /// Deletes a user's reaction from a message.
1381    pub async fn delete_reaction(
1382        &self,
1383        channel_id: ChannelId,
1384        message_id: MessageId,
1385        user_id: UserId,
1386        reaction_type: &ReactionType,
1387    ) -> Result<()> {
1388        self.wind(204, Request {
1389            body: None,
1390            multipart: None,
1391            headers: None,
1392            method: LightMethod::Delete,
1393            route: Route::ChannelMessageReaction {
1394                channel_id,
1395                message_id,
1396                user_id,
1397                reaction: &reaction_type.as_data(),
1398            },
1399            params: None,
1400        })
1401        .await
1402    }
1403
1404    /// Deletes a reaction by the current user from a message.
1405    pub async fn delete_reaction_me(
1406        &self,
1407        channel_id: ChannelId,
1408        message_id: MessageId,
1409        reaction_type: &ReactionType,
1410    ) -> Result<()> {
1411        self.wind(204, Request {
1412            body: None,
1413            multipart: None,
1414            headers: None,
1415            method: LightMethod::Delete,
1416            route: Route::ChannelMessageReactionMe {
1417                channel_id,
1418                message_id,
1419                reaction: &reaction_type.as_data(),
1420            },
1421            params: None,
1422        })
1423        .await
1424    }
1425
1426    /// Deletes a role from a server. Can't remove the default everyone role.
1427    pub async fn delete_role(
1428        &self,
1429        guild_id: GuildId,
1430        role_id: RoleId,
1431        audit_log_reason: Option<&str>,
1432    ) -> Result<()> {
1433        self.wind(204, Request {
1434            body: None,
1435            multipart: None,
1436            headers: audit_log_reason.map(reason_into_header),
1437            method: LightMethod::Delete,
1438            route: Route::GuildRole {
1439                guild_id,
1440                role_id,
1441            },
1442            params: None,
1443        })
1444        .await
1445    }
1446
1447    /// Deletes a [Scheduled Event] from a server.
1448    ///
1449    /// **Note**: Requires the [Manage Events] permission.
1450    ///
1451    /// [Scheduled Event]: crate::model::guild::ScheduledEvent
1452    /// [Manage Events]: Permissions::MANAGE_EVENTS
1453    pub async fn delete_scheduled_event(
1454        &self,
1455        guild_id: GuildId,
1456        event_id: ScheduledEventId,
1457    ) -> Result<()> {
1458        self.wind(204, Request {
1459            body: None,
1460            multipart: None,
1461            headers: None,
1462            method: LightMethod::Delete,
1463            route: Route::GuildScheduledEvent {
1464                guild_id,
1465                event_id,
1466            },
1467            params: None,
1468        })
1469        .await
1470    }
1471
1472    /// Deletes a sticker from a server.
1473    ///
1474    /// See [`GuildId::delete_sticker`] for permissions requirements.
1475    pub async fn delete_sticker(
1476        &self,
1477        guild_id: GuildId,
1478        sticker_id: StickerId,
1479        audit_log_reason: Option<&str>,
1480    ) -> Result<()> {
1481        self.wind(204, Request {
1482            body: None,
1483            multipart: None,
1484            headers: audit_log_reason.map(reason_into_header),
1485            method: LightMethod::Delete,
1486            route: Route::GuildSticker {
1487                guild_id,
1488                sticker_id,
1489            },
1490            params: None,
1491        })
1492        .await
1493    }
1494
1495    /// Deletes a currently active test entitlement. Discord will act as though the corresponding
1496    /// user/guild *no longer has* an entitlement to the corresponding SKU.
1497    pub async fn delete_test_entitlement(&self, entitlement_id: EntitlementId) -> Result<()> {
1498        self.wind(204, Request {
1499            body: None,
1500            multipart: None,
1501            headers: None,
1502            method: LightMethod::Delete,
1503            route: Route::Entitlement {
1504                application_id: self.try_application_id()?,
1505                entitlement_id,
1506            },
1507            params: None,
1508        })
1509        .await
1510    }
1511
1512    /// Deletes a [`Webhook`] given its Id.
1513    ///
1514    /// This method requires authentication, whereas [`Self::delete_webhook_with_token`] does not.
1515    ///
1516    /// # Examples
1517    ///
1518    /// Deletes a webhook given its Id:
1519    ///
1520    /// ```rust,no_run
1521    /// use serenity::http::Http;
1522    /// use serenity::model::prelude::*;
1523    ///
1524    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
1525    /// # let http: Http = unimplemented!();
1526    /// let webhook_id = WebhookId::new(245037420704169985);
1527    /// http.delete_webhook(webhook_id, None).await?;
1528    /// Ok(())
1529    /// # }
1530    /// ```
1531    pub async fn delete_webhook(
1532        &self,
1533        webhook_id: WebhookId,
1534        audit_log_reason: Option<&str>,
1535    ) -> Result<()> {
1536        self.wind(204, Request {
1537            body: None,
1538            multipart: None,
1539            headers: audit_log_reason.map(reason_into_header),
1540            method: LightMethod::Delete,
1541            route: Route::Webhook {
1542                webhook_id,
1543            },
1544            params: None,
1545        })
1546        .await
1547    }
1548
1549    /// Deletes a [`Webhook`] given its Id and unique token.
1550    ///
1551    /// This method does _not_ require authentication.
1552    ///
1553    /// # Examples
1554    ///
1555    /// Deletes a webhook given its Id and unique token:
1556    ///
1557    /// ```rust,no_run
1558    /// # use serenity::http::Http;
1559    /// # use serenity::model::prelude::*;
1560    /// #
1561    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
1562    /// # let http: Http = unimplemented!();
1563    /// let id = WebhookId::new(245037420704169985);
1564    /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
1565    ///
1566    /// http.delete_webhook_with_token(id, token, None).await?;
1567    /// # Ok(())
1568    /// # }
1569    /// ```
1570    pub async fn delete_webhook_with_token(
1571        &self,
1572        webhook_id: WebhookId,
1573        token: &str,
1574        audit_log_reason: Option<&str>,
1575    ) -> Result<()> {
1576        self.wind(204, Request {
1577            body: None,
1578            multipart: None,
1579            headers: audit_log_reason.map(reason_into_header),
1580            method: LightMethod::Delete,
1581            route: Route::WebhookWithToken {
1582                webhook_id,
1583                token,
1584            },
1585            params: None,
1586        })
1587        .await
1588    }
1589
1590    /// Changes channel information.
1591    pub async fn edit_channel(
1592        &self,
1593        channel_id: ChannelId,
1594        map: &impl serde::Serialize,
1595        audit_log_reason: Option<&str>,
1596    ) -> Result<GuildChannel> {
1597        let body = to_vec(map)?;
1598
1599        self.fire(Request {
1600            body: Some(body),
1601            multipart: None,
1602            headers: audit_log_reason.map(reason_into_header),
1603            method: LightMethod::Patch,
1604            route: Route::Channel {
1605                channel_id,
1606            },
1607            params: None,
1608        })
1609        .await
1610    }
1611
1612    /// Edits a stage instance.
1613    pub async fn edit_stage_instance(
1614        &self,
1615        channel_id: ChannelId,
1616        map: &impl serde::Serialize,
1617        audit_log_reason: Option<&str>,
1618    ) -> Result<StageInstance> {
1619        self.fire(Request {
1620            body: Some(to_vec(map)?),
1621            multipart: None,
1622            headers: audit_log_reason.map(reason_into_header),
1623            method: LightMethod::Patch,
1624            route: Route::StageInstance {
1625                channel_id,
1626            },
1627            params: None,
1628        })
1629        .await
1630    }
1631
1632    /// Changes guild emoji information.
1633    ///
1634    /// See [`GuildId::edit_emoji`] for permissions requirements.
1635    pub async fn edit_emoji(
1636        &self,
1637        guild_id: GuildId,
1638        emoji_id: EmojiId,
1639        map: &Value,
1640        audit_log_reason: Option<&str>,
1641    ) -> Result<Emoji> {
1642        let body = to_vec(map)?;
1643
1644        self.fire(Request {
1645            body: Some(body),
1646            multipart: None,
1647            headers: audit_log_reason.map(reason_into_header),
1648            method: LightMethod::Patch,
1649            route: Route::GuildEmoji {
1650                guild_id,
1651                emoji_id,
1652            },
1653            params: None,
1654        })
1655        .await
1656    }
1657
1658    /// Changes application emoji information.
1659    ///
1660    /// See [`Context::edit_application_emoji`] for required fields.
1661    ///
1662    /// [`Context::edit_application_emoji`]: crate::client::Context::edit_application_emoji
1663    pub async fn edit_application_emoji(
1664        &self,
1665        emoji_id: EmojiId,
1666        map: &impl serde::Serialize,
1667    ) -> Result<Emoji> {
1668        self.fire(Request {
1669            body: Some(to_vec(map)?),
1670            multipart: None,
1671            headers: None,
1672            method: LightMethod::Patch,
1673            route: Route::Emoji {
1674                application_id: self.try_application_id()?,
1675                emoji_id,
1676            },
1677            params: None,
1678        })
1679        .await
1680    }
1681
1682    /// Edits a follow-up message for an interaction.
1683    ///
1684    /// Refer to Discord's [docs] for Edit Webhook Message for field information.
1685    ///
1686    /// [docs]: https://discord.com/developers/docs/resources/webhook#edit-webhook-message
1687    pub async fn edit_followup_message(
1688        &self,
1689        interaction_token: &str,
1690        message_id: MessageId,
1691        map: &impl serde::Serialize,
1692        new_attachments: Vec<CreateAttachment>,
1693    ) -> Result<Message> {
1694        let mut request = Request {
1695            body: None,
1696            multipart: None,
1697            headers: None,
1698            method: LightMethod::Patch,
1699            route: Route::WebhookFollowupMessage {
1700                application_id: self.try_application_id()?,
1701                token: interaction_token,
1702                message_id,
1703            },
1704            params: None,
1705        };
1706
1707        if new_attachments.is_empty() {
1708            request.body = Some(to_vec(map)?);
1709        } else {
1710            request.multipart = Some(Multipart {
1711                upload: MultipartUpload::Attachments(new_attachments),
1712                payload_json: Some(to_string(map)?),
1713                fields: vec![],
1714            });
1715        }
1716
1717        self.fire(request).await
1718    }
1719
1720    /// Get a follow-up message for an interaction.
1721    ///
1722    /// Refer to Discord's [docs] for Get Webhook Message for field information.
1723    ///
1724    /// [docs]: https://discord.com/developers/docs/resources/webhook#get-webhook-message
1725    pub async fn get_followup_message(
1726        &self,
1727        interaction_token: &str,
1728        message_id: MessageId,
1729    ) -> Result<Message> {
1730        self.fire(Request {
1731            body: None,
1732            multipart: None,
1733            headers: None,
1734            method: LightMethod::Get,
1735            route: Route::WebhookFollowupMessage {
1736                application_id: self.try_application_id()?,
1737                token: interaction_token,
1738                message_id,
1739            },
1740            params: None,
1741        })
1742        .await
1743    }
1744
1745    /// Edits a global command.
1746    ///
1747    /// Updates will be available in all guilds after 1 hour.
1748    ///
1749    /// Refer to Discord's [docs] for field information.
1750    ///
1751    /// [docs]: https://discord.com/developers/docs/interactions/slash-commands#edit-global-application-command
1752    pub async fn edit_global_command(
1753        &self,
1754        command_id: CommandId,
1755        map: &impl serde::Serialize,
1756    ) -> Result<Command> {
1757        self.fire(Request {
1758            body: Some(to_vec(map)?),
1759            multipart: None,
1760            headers: None,
1761            method: LightMethod::Patch,
1762            route: Route::Command {
1763                application_id: self.try_application_id()?,
1764                command_id,
1765            },
1766            params: None,
1767        })
1768        .await
1769    }
1770
1771    /// Changes guild information.
1772    pub async fn edit_guild(
1773        &self,
1774        guild_id: GuildId,
1775        map: &impl serde::Serialize,
1776        audit_log_reason: Option<&str>,
1777    ) -> Result<PartialGuild> {
1778        let body = to_vec(map)?;
1779
1780        self.fire(Request {
1781            body: Some(body),
1782            multipart: None,
1783            headers: audit_log_reason.map(reason_into_header),
1784            method: LightMethod::Patch,
1785            route: Route::Guild {
1786                guild_id,
1787            },
1788            params: None,
1789        })
1790        .await
1791    }
1792
1793    /// Edits a guild command.
1794    ///
1795    /// Updates for guild commands will be available immediately.
1796    ///
1797    /// Refer to Discord's [docs] for field information.
1798    ///
1799    /// [docs]: https://discord.com/developers/docs/interactions/slash-commands#edit-guild-application-command
1800    pub async fn edit_guild_command(
1801        &self,
1802        guild_id: GuildId,
1803        command_id: CommandId,
1804        map: &impl serde::Serialize,
1805    ) -> Result<Command> {
1806        self.fire(Request {
1807            body: Some(to_vec(map)?),
1808            multipart: None,
1809            headers: None,
1810            method: LightMethod::Patch,
1811            route: Route::GuildCommand {
1812                application_id: self.try_application_id()?,
1813                guild_id,
1814                command_id,
1815            },
1816            params: None,
1817        })
1818        .await
1819    }
1820
1821    /// Edits a guild command permissions.
1822    ///
1823    /// Updates for guild commands will be available immediately.
1824    ///
1825    /// Refer to Discord's [documentation] for field information.
1826    ///
1827    /// [documentation]: https://discord.com/developers/docs/interactions/application-commands#edit-application-command-permissions
1828    pub async fn edit_guild_command_permissions(
1829        &self,
1830        guild_id: GuildId,
1831        command_id: CommandId,
1832        map: &impl serde::Serialize,
1833    ) -> Result<CommandPermissions> {
1834        self.fire(Request {
1835            body: Some(to_vec(map)?),
1836            multipart: None,
1837            headers: None,
1838            method: LightMethod::Put,
1839            route: Route::GuildCommandPermissions {
1840                application_id: self.try_application_id()?,
1841                guild_id,
1842                command_id,
1843            },
1844            params: None,
1845        })
1846        .await
1847    }
1848
1849    /// Edits the positions of a guild's channels.
1850    pub async fn edit_guild_channel_positions(
1851        &self,
1852        guild_id: GuildId,
1853        value: &Value,
1854    ) -> Result<()> {
1855        let body = to_vec(value)?;
1856
1857        self.wind(204, Request {
1858            body: Some(body),
1859            multipart: None,
1860            headers: None,
1861            method: LightMethod::Patch,
1862            route: Route::GuildChannels {
1863                guild_id,
1864            },
1865            params: None,
1866        })
1867        .await
1868    }
1869
1870    /// Edits the MFA level of a guild. Requires guild ownership.
1871    pub async fn edit_guild_mfa_level(
1872        &self,
1873        guild_id: GuildId,
1874        value: &Value,
1875        audit_log_reason: Option<&str>,
1876    ) -> Result<MfaLevel> {
1877        #[derive(Deserialize)]
1878        struct GuildMfaLevel {
1879            level: MfaLevel,
1880        }
1881
1882        let body = to_vec(value)?;
1883
1884        self.fire(Request {
1885            body: Some(body),
1886            multipart: None,
1887            headers: audit_log_reason.map(reason_into_header),
1888            method: LightMethod::Post,
1889            route: Route::GuildMfa {
1890                guild_id,
1891            },
1892            params: None,
1893        })
1894        .await
1895        .map(|mfa: GuildMfaLevel| mfa.level)
1896    }
1897
1898    /// Edits a [`Guild`]'s widget.
1899    pub async fn edit_guild_widget(
1900        &self,
1901        guild_id: GuildId,
1902        map: &impl serde::Serialize,
1903        audit_log_reason: Option<&str>,
1904    ) -> Result<GuildWidget> {
1905        let body = to_vec(map)?;
1906
1907        self.fire(Request {
1908            body: Some(body),
1909            multipart: None,
1910            headers: audit_log_reason.map(reason_into_header),
1911            method: LightMethod::Patch,
1912            route: Route::GuildWidget {
1913                guild_id,
1914            },
1915            params: None,
1916        })
1917        .await
1918    }
1919
1920    /// Edits a guild welcome screen.
1921    pub async fn edit_guild_welcome_screen(
1922        &self,
1923        guild_id: GuildId,
1924        map: &impl serde::Serialize,
1925        audit_log_reason: Option<&str>,
1926    ) -> Result<GuildWelcomeScreen> {
1927        let body = to_vec(map)?;
1928
1929        self.fire(Request {
1930            body: Some(body),
1931            multipart: None,
1932            headers: audit_log_reason.map(reason_into_header),
1933            method: LightMethod::Patch,
1934            route: Route::GuildWelcomeScreen {
1935                guild_id,
1936            },
1937            params: None,
1938        })
1939        .await
1940    }
1941
1942    /// Does specific actions to a member.
1943    pub async fn edit_member(
1944        &self,
1945        guild_id: GuildId,
1946        user_id: UserId,
1947        map: &impl serde::Serialize,
1948        audit_log_reason: Option<&str>,
1949    ) -> Result<Member> {
1950        let body = to_vec(map)?;
1951
1952        let mut value: Value = self
1953            .fire(Request {
1954                body: Some(body),
1955                multipart: None,
1956                headers: audit_log_reason.map(reason_into_header),
1957                method: LightMethod::Patch,
1958                route: Route::GuildMember {
1959                    guild_id,
1960                    user_id,
1961                },
1962                params: None,
1963            })
1964            .await?;
1965
1966        if let Some(map) = value.as_object_mut() {
1967            map.insert("guild_id".to_string(), guild_id.get().into());
1968        }
1969
1970        from_value::<Member>(value).map_err(From::from)
1971    }
1972
1973    /// Edits a message by Id.
1974    ///
1975    /// **Note**: Only the author of a message can modify it.
1976    pub async fn edit_message(
1977        &self,
1978        channel_id: ChannelId,
1979        message_id: MessageId,
1980        map: &impl serde::Serialize,
1981        new_attachments: Vec<CreateAttachment>,
1982    ) -> Result<Message> {
1983        let mut request = Request {
1984            body: None,
1985            multipart: None,
1986            headers: None,
1987            method: LightMethod::Patch,
1988            route: Route::ChannelMessage {
1989                channel_id,
1990                message_id,
1991            },
1992            params: None,
1993        };
1994
1995        if new_attachments.is_empty() {
1996            request.body = Some(to_vec(map)?);
1997        } else {
1998            request.multipart = Some(Multipart {
1999                upload: MultipartUpload::Attachments(new_attachments),
2000                payload_json: Some(to_string(map)?),
2001                fields: vec![],
2002            });
2003        }
2004
2005        self.fire(request).await
2006    }
2007
2008    /// Crossposts a message by Id.
2009    ///
2010    /// **Note**: Only available on news channels.
2011    pub async fn crosspost_message(
2012        &self,
2013        channel_id: ChannelId,
2014        message_id: MessageId,
2015    ) -> Result<Message> {
2016        self.fire(Request {
2017            body: None,
2018            multipart: None,
2019            headers: None,
2020            method: LightMethod::Post,
2021            route: Route::ChannelMessageCrosspost {
2022                channel_id,
2023                message_id,
2024            },
2025            params: None,
2026        })
2027        .await
2028    }
2029
2030    /// Edits the current member for the provided [`Guild`] via its Id.
2031    pub async fn edit_member_me(
2032        &self,
2033        guild_id: GuildId,
2034        map: &JsonMap,
2035        audit_log_reason: Option<&str>,
2036    ) -> Result<Member> {
2037        let body = to_vec(map)?;
2038
2039        self.fire(Request {
2040            body: Some(body),
2041            multipart: None,
2042            headers: audit_log_reason.map(reason_into_header),
2043            method: LightMethod::Patch,
2044            route: Route::GuildMemberMe {
2045                guild_id,
2046            },
2047            params: None,
2048        })
2049        .await
2050    }
2051
2052    /// Edits the current user's nickname for the provided [`Guild`] via its Id.
2053    ///
2054    /// Pass [`None`] to reset the nickname.
2055    pub async fn edit_nickname(
2056        &self,
2057        guild_id: GuildId,
2058        new_nickname: Option<&str>,
2059        audit_log_reason: Option<&str>,
2060    ) -> Result<()> {
2061        let map = json!({ "nick": new_nickname });
2062        let body = to_vec(&map)?;
2063
2064        self.wind(200, Request {
2065            body: Some(body),
2066            multipart: None,
2067            headers: audit_log_reason.map(reason_into_header),
2068            method: LightMethod::Patch,
2069            route: Route::GuildMemberMe {
2070                guild_id,
2071            },
2072            params: None,
2073        })
2074        .await
2075    }
2076
2077    /// Follow a News Channel to send messages to a target channel.
2078    pub async fn follow_news_channel(
2079        &self,
2080        news_channel_id: ChannelId,
2081        target_channel_id: ChannelId,
2082    ) -> Result<FollowedChannel> {
2083        let map = json!({ "webhook_channel_id": target_channel_id });
2084        let body = to_vec(&map)?;
2085
2086        self.fire(Request {
2087            body: Some(body),
2088            multipart: None,
2089            headers: None,
2090            method: LightMethod::Post,
2091            route: Route::ChannelFollowNews {
2092                channel_id: news_channel_id,
2093            },
2094            params: None,
2095        })
2096        .await
2097    }
2098
2099    /// Gets the initial interaction response.
2100    pub async fn get_original_interaction_response(
2101        &self,
2102        interaction_token: &str,
2103    ) -> Result<Message> {
2104        self.fire(Request {
2105            body: None,
2106            multipart: None,
2107            headers: None,
2108            method: LightMethod::Get,
2109            route: Route::WebhookOriginalInteractionResponse {
2110                application_id: self.try_application_id()?,
2111                token: interaction_token,
2112            },
2113            params: None,
2114        })
2115        .await
2116    }
2117
2118    /// Edits the initial interaction response.
2119    ///
2120    /// Refer to Discord's [docs] for Edit Webhook Message for field information.
2121    ///
2122    /// [docs]: https://discord.com/developers/docs/resources/webhook#edit-webhook-message
2123    pub async fn edit_original_interaction_response(
2124        &self,
2125        interaction_token: &str,
2126        map: &impl serde::Serialize,
2127        new_attachments: Vec<CreateAttachment>,
2128    ) -> Result<Message> {
2129        let mut request = Request {
2130            body: None,
2131            multipart: None,
2132            headers: None,
2133            method: LightMethod::Patch,
2134            route: Route::WebhookOriginalInteractionResponse {
2135                application_id: self.try_application_id()?,
2136                token: interaction_token,
2137            },
2138            params: None,
2139        };
2140
2141        if new_attachments.is_empty() {
2142            request.body = Some(to_vec(map)?);
2143        } else {
2144            request.multipart = Some(Multipart {
2145                upload: MultipartUpload::Attachments(new_attachments.into_iter().collect()),
2146                payload_json: Some(to_string(map)?),
2147                fields: vec![],
2148            });
2149        }
2150
2151        self.fire(request).await
2152    }
2153
2154    /// Edits the current user's profile settings.
2155    pub async fn edit_profile(&self, map: &impl serde::Serialize) -> Result<CurrentUser> {
2156        let body = to_vec(map)?;
2157
2158        self.fire(Request {
2159            body: Some(body),
2160            multipart: None,
2161            headers: None,
2162            method: LightMethod::Patch,
2163            route: Route::UserMe,
2164            params: None,
2165        })
2166        .await
2167    }
2168
2169    /// Changes a role in a guild.
2170    pub async fn edit_role(
2171        &self,
2172        guild_id: GuildId,
2173        role_id: RoleId,
2174        map: &impl serde::Serialize,
2175        audit_log_reason: Option<&str>,
2176    ) -> Result<Role> {
2177        let mut value: Value = self
2178            .fire(Request {
2179                body: Some(to_vec(map)?),
2180                multipart: None,
2181                headers: audit_log_reason.map(reason_into_header),
2182                method: LightMethod::Patch,
2183                route: Route::GuildRole {
2184                    guild_id,
2185                    role_id,
2186                },
2187                params: None,
2188            })
2189            .await?;
2190
2191        if let Some(map) = value.as_object_mut() {
2192            map.insert("guild_id".to_string(), guild_id.get().into());
2193        }
2194
2195        from_value(value).map_err(From::from)
2196    }
2197
2198    /// Changes the position of a role in a guild.
2199    pub async fn edit_role_position(
2200        &self,
2201        guild_id: GuildId,
2202        role_id: RoleId,
2203        position: u16,
2204        audit_log_reason: Option<&str>,
2205    ) -> Result<Vec<Role>> {
2206        let map = json!([{
2207            "id": role_id,
2208            "position": position,
2209        }]);
2210        let body = to_vec(&map)?;
2211
2212        let mut value: Value = self
2213            .fire(Request {
2214                body: Some(body),
2215                multipart: None,
2216                headers: audit_log_reason.map(reason_into_header),
2217                method: LightMethod::Patch,
2218                route: Route::GuildRoles {
2219                    guild_id,
2220                },
2221                params: None,
2222            })
2223            .await?;
2224
2225        if let Some(array) = value.as_array_mut() {
2226            for role in array {
2227                if let Some(map) = role.as_object_mut() {
2228                    map.insert("guild_id".to_string(), guild_id.get().into());
2229                }
2230            }
2231        }
2232
2233        from_value(value).map_err(From::from)
2234    }
2235
2236    /// Modifies a scheduled event.
2237    ///
2238    /// **Note**: Requires the [Manage Events] permission.
2239    ///
2240    /// [Manage Events]: Permissions::MANAGE_EVENTS
2241    pub async fn edit_scheduled_event(
2242        &self,
2243        guild_id: GuildId,
2244        event_id: ScheduledEventId,
2245        map: &impl serde::Serialize,
2246        audit_log_reason: Option<&str>,
2247    ) -> Result<ScheduledEvent> {
2248        let body = to_vec(map)?;
2249        self.fire(Request {
2250            body: Some(body),
2251            multipart: None,
2252            headers: audit_log_reason.map(reason_into_header),
2253            method: LightMethod::Patch,
2254            route: Route::GuildScheduledEvent {
2255                guild_id,
2256                event_id,
2257            },
2258            params: None,
2259        })
2260        .await
2261    }
2262
2263    /// Changes a sticker in a guild.
2264    ///
2265    /// See [`GuildId::edit_sticker`] for permissions requirements.
2266    pub async fn edit_sticker(
2267        &self,
2268        guild_id: GuildId,
2269        sticker_id: StickerId,
2270        map: &impl serde::Serialize,
2271        audit_log_reason: Option<&str>,
2272    ) -> Result<Sticker> {
2273        let body = to_vec(&map)?;
2274
2275        let mut value: Value = self
2276            .fire(Request {
2277                body: Some(body),
2278                multipart: None,
2279                headers: audit_log_reason.map(reason_into_header),
2280                method: LightMethod::Patch,
2281                route: Route::GuildSticker {
2282                    guild_id,
2283                    sticker_id,
2284                },
2285                params: None,
2286            })
2287            .await?;
2288
2289        if let Some(map) = value.as_object_mut() {
2290            map.insert("guild_id".to_string(), guild_id.get().into());
2291        }
2292
2293        from_value(value).map_err(From::from)
2294    }
2295
2296    /// Edits a thread channel in the [`GuildChannel`] given its Id.
2297    pub async fn edit_thread(
2298        &self,
2299        channel_id: ChannelId,
2300        map: &impl serde::Serialize,
2301        audit_log_reason: Option<&str>,
2302    ) -> Result<GuildChannel> {
2303        self.fire(Request {
2304            body: Some(to_vec(map)?),
2305            multipart: None,
2306            headers: audit_log_reason.map(reason_into_header),
2307            method: LightMethod::Patch,
2308            route: Route::Channel {
2309                channel_id,
2310            },
2311            params: None,
2312        })
2313        .await
2314    }
2315
2316    /// Changes another user's voice state in a stage channel.
2317    ///
2318    /// The Value is a map with values of:
2319    /// - **channel_id**: ID of the channel the user is currently in (**required**)
2320    /// - **suppress**: Bool which toggles user's suppressed state. Setting this to `false` will
2321    ///   invite the user to speak.
2322    ///
2323    /// # Example
2324    ///
2325    /// Suppress a user
2326    ///
2327    /// ```rust,no_run
2328    /// use serenity::http::Http;
2329    /// use serenity::json::json;
2330    /// use serenity::model::prelude::*;
2331    ///
2332    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
2333    /// # let http: Http = unimplemented!();
2334    /// let guild_id = GuildId::new(187450744427773963);
2335    /// let user_id = UserId::new(150443906511667200);
2336    /// let map = json!({
2337    ///     "channel_id": "826929611849334784",
2338    ///     "suppress": true,
2339    /// });
2340    ///
2341    /// // Edit state for another user
2342    /// http.edit_voice_state(guild_id, user_id, &map).await?;
2343    /// # Ok(())
2344    /// # }
2345    /// ```
2346    pub async fn edit_voice_state(
2347        &self,
2348        guild_id: GuildId,
2349        user_id: UserId,
2350        map: &impl serde::Serialize,
2351    ) -> Result<()> {
2352        self.wind(204, Request {
2353            body: Some(to_vec(map)?),
2354            multipart: None,
2355            headers: None,
2356            method: LightMethod::Patch,
2357            route: Route::GuildVoiceStates {
2358                guild_id,
2359                user_id,
2360            },
2361            params: None,
2362        })
2363        .await
2364    }
2365
2366    /// Changes the current user's voice state in a stage channel.
2367    ///
2368    /// The Value is a map with values of:
2369    ///
2370    /// - **channel_id**: ID of the channel the user is currently in (**required**)
2371    /// - **suppress**: Bool which toggles user's suppressed state. Setting this to `false` will
2372    ///   invite the user to speak.
2373    /// - **request_to_speak_timestamp**: ISO8601 timestamp to set the user's request to speak. This
2374    ///   can be any present or future time.
2375    ///
2376    /// # Example
2377    ///
2378    /// Unsuppress the current bot user
2379    ///
2380    /// ```rust,no_run
2381    /// use serenity::http::Http;
2382    /// use serenity::json::json;
2383    /// use serenity::model::prelude::*;
2384    ///
2385    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
2386    /// # let http: Http = unimplemented!();
2387    /// let guild_id = GuildId::new(187450744427773963);
2388    /// let map = json!({
2389    ///     "channel_id": "826929611849334784",
2390    ///     "suppress": false,
2391    ///     "request_to_speak_timestamp": "2021-03-31T18:45:31.297561+00:00"
2392    /// });
2393    ///
2394    /// // Edit state for current user
2395    /// http.edit_voice_state_me(guild_id, &map).await?;
2396    /// # Ok(())
2397    /// # }
2398    /// ```
2399    pub async fn edit_voice_state_me(
2400        &self,
2401        guild_id: GuildId,
2402        map: &impl serde::Serialize,
2403    ) -> Result<()> {
2404        self.wind(204, Request {
2405            body: Some(to_vec(map)?),
2406            multipart: None,
2407            headers: None,
2408            method: LightMethod::Patch,
2409            route: Route::GuildVoiceStateMe {
2410                guild_id,
2411            },
2412            params: None,
2413        })
2414        .await
2415    }
2416
2417    /// Changes a voice channel's status.
2418    pub async fn edit_voice_status(
2419        &self,
2420        channel_id: ChannelId,
2421        map: &impl serde::Serialize,
2422        audit_log_reason: Option<&str>,
2423    ) -> Result<()> {
2424        let body = to_vec(map)?;
2425
2426        self.wind(204, Request {
2427            body: Some(body),
2428            multipart: None,
2429            headers: audit_log_reason.map(reason_into_header),
2430            method: LightMethod::Put,
2431            route: Route::ChannelVoiceStatus {
2432                channel_id,
2433            },
2434            params: None,
2435        })
2436        .await
2437    }
2438
2439    /// Edits a the webhook with the given data.
2440    ///
2441    /// The Value is a map with optional values of:
2442    /// - **avatar**: base64-encoded 128x128 image for the webhook's default avatar (_optional_);
2443    /// - **name**: the name of the webhook, limited to between 2 and 100 characters long.
2444    ///
2445    /// Note that, unlike with [`Self::create_webhook`], _all_ values are optional.
2446    ///
2447    /// This method requires authentication, whereas [`Self::edit_webhook_with_token`] does not.
2448    ///
2449    /// # Examples
2450    ///
2451    /// Edit the image of a webhook given its Id and unique token:
2452    ///
2453    /// ```rust,no_run
2454    /// use serenity::builder::CreateAttachment;
2455    /// use serenity::http::Http;
2456    /// use serenity::json::json;
2457    /// use serenity::model::prelude::*;
2458    ///
2459    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
2460    /// # let http: Http = unimplemented!();
2461    /// let id = WebhookId::new(245037420704169985);
2462    /// let image = CreateAttachment::path("./webhook_img.png").await?;
2463    /// let map = json!({
2464    ///     "avatar": image.to_base64(),
2465    /// });
2466    ///
2467    /// let edited = http.edit_webhook(id, &map, None).await?;
2468    /// # Ok(())
2469    /// # }
2470    /// ```
2471    pub async fn edit_webhook(
2472        &self,
2473        webhook_id: WebhookId,
2474        map: &impl serde::Serialize,
2475        audit_log_reason: Option<&str>,
2476    ) -> Result<Webhook> {
2477        self.fire(Request {
2478            body: Some(to_vec(map)?),
2479            multipart: None,
2480            headers: audit_log_reason.map(reason_into_header),
2481            method: LightMethod::Patch,
2482            route: Route::Webhook {
2483                webhook_id,
2484            },
2485            params: None,
2486        })
2487        .await
2488    }
2489
2490    /// Edits the webhook with the given data.
2491    ///
2492    /// Refer to the documentation for [`Self::edit_webhook`] for more information.
2493    ///
2494    /// This method does _not_ require authentication.
2495    ///
2496    /// # Examples
2497    ///
2498    /// Edit the name of a webhook given its Id and unique token:
2499    ///
2500    /// ```rust,no_run
2501    /// use serenity::http::Http;
2502    /// use serenity::json::json;
2503    /// use serenity::model::prelude::*;
2504    ///
2505    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
2506    /// # let http: Http = unimplemented!();
2507    /// let id = WebhookId::new(245037420704169985);
2508    /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
2509    /// let map = json!({"name": "new name"});
2510    ///
2511    /// let edited = http.edit_webhook_with_token(id, token, &map, None).await?;
2512    /// # Ok(())
2513    /// # }
2514    /// ```
2515    pub async fn edit_webhook_with_token(
2516        &self,
2517        webhook_id: WebhookId,
2518        token: &str,
2519        map: &impl serde::Serialize,
2520        audit_log_reason: Option<&str>,
2521    ) -> Result<Webhook> {
2522        let body = to_vec(map)?;
2523
2524        self.fire(Request {
2525            body: Some(body),
2526            multipart: None,
2527            headers: audit_log_reason.map(reason_into_header),
2528            method: LightMethod::Patch,
2529            route: Route::WebhookWithToken {
2530                webhook_id,
2531                token,
2532            },
2533            params: None,
2534        })
2535        .await
2536    }
2537
2538    /// Executes a webhook, posting a [`Message`] in the webhook's associated [`Channel`].
2539    ///
2540    /// This method does _not_ require authentication.
2541    ///
2542    /// If `thread_id` is not `None`, then the message will be sent to the thread in the webhook's
2543    /// associated [`Channel`] with the corresponding Id, which will be automatically unarchived.
2544    ///
2545    /// If `wait` is `false`, this function will return `Ok(None)` on success. Otherwise, it will
2546    /// wait for server confirmation of the message having been sent, and return `Ok(Some(msg))`.
2547    /// From the [Discord docs]:
2548    ///
2549    /// > waits for server confirmation of message send before response, and returns the created
2550    /// > message body (defaults to false; when false a message that is not saved does not return
2551    /// > an error)
2552    ///
2553    /// The map can _optionally_ contain the following data:
2554    /// - `avatar_url`: Override the default avatar of the webhook with a URL.
2555    /// - `tts`: Whether this is a text-to-speech message (defaults to `false`).
2556    /// - `username`: Override the default username of the webhook.
2557    ///
2558    /// Additionally, _at least one_ of the following must be given:
2559    /// - `content`: The content of the message.
2560    /// - `embeds`: An array of rich embeds.
2561    ///
2562    /// **Note**: For embed objects, all fields are registered by Discord except for `height`,
2563    /// `provider`, `proxy_url`, `type` (it will always be `rich`), `video`, and `width`. The rest
2564    /// will be determined by Discord.
2565    ///
2566    /// # Examples
2567    ///
2568    /// Sending a webhook with message content of `test`:
2569    ///
2570    /// ```rust,no_run
2571    /// use serenity::http::Http;
2572    /// use serenity::json::json;
2573    /// use serenity::model::prelude::*;
2574    ///
2575    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
2576    /// # let http: Http = unimplemented!();
2577    /// let id = WebhookId::new(245037420704169985);
2578    /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
2579    /// let map = json!({"content": "test"});
2580    /// let files = vec![];
2581    ///
2582    /// let message = http.execute_webhook(id, None, token, true, files, &map).await?;
2583    /// # Ok(())
2584    /// # }
2585    /// ```
2586    ///
2587    /// [Discord docs]: https://discord.com/developers/docs/resources/webhook#execute-webhook-query-string-params
2588    pub async fn execute_webhook(
2589        &self,
2590        webhook_id: WebhookId,
2591        thread_id: Option<ChannelId>,
2592        token: &str,
2593        wait: bool,
2594        files: Vec<CreateAttachment>,
2595        map: &impl serde::Serialize,
2596    ) -> Result<Option<Message>> {
2597        let mut params = vec![("wait", wait.to_string())];
2598        if let Some(thread_id) = thread_id {
2599            params.push(("thread_id", thread_id.to_string()));
2600        }
2601
2602        let mut request = Request {
2603            body: None,
2604            multipart: None,
2605            headers: None,
2606            method: LightMethod::Post,
2607            route: Route::WebhookWithToken {
2608                webhook_id,
2609                token,
2610            },
2611            params: Some(params),
2612        };
2613
2614        if files.is_empty() {
2615            request.body = Some(to_vec(map)?);
2616        } else {
2617            request.multipart = Some(Multipart {
2618                upload: MultipartUpload::Attachments(files.into_iter().collect()),
2619                payload_json: Some(to_string(map)?),
2620                fields: vec![],
2621            });
2622        }
2623
2624        let response = self.request(request).await?;
2625
2626        Ok(if response.status() == StatusCode::NO_CONTENT {
2627            None
2628        } else {
2629            decode_resp(response).await?
2630        })
2631    }
2632
2633    // Gets a webhook's message by Id
2634    pub async fn get_webhook_message(
2635        &self,
2636        webhook_id: WebhookId,
2637        thread_id: Option<ChannelId>,
2638        token: &str,
2639        message_id: MessageId,
2640    ) -> Result<Message> {
2641        self.fire(Request {
2642            body: None,
2643            multipart: None,
2644            headers: None,
2645            method: LightMethod::Get,
2646            route: Route::WebhookMessage {
2647                webhook_id,
2648                token,
2649                message_id,
2650            },
2651            params: thread_id.map(|thread_id| vec![("thread_id", thread_id.to_string())]),
2652        })
2653        .await
2654    }
2655
2656    /// Edits a webhook's message by Id.
2657    pub async fn edit_webhook_message(
2658        &self,
2659        webhook_id: WebhookId,
2660        thread_id: Option<ChannelId>,
2661        token: &str,
2662        message_id: MessageId,
2663        map: &impl serde::Serialize,
2664        new_attachments: Vec<CreateAttachment>,
2665    ) -> Result<Message> {
2666        let mut request = Request {
2667            body: None,
2668            multipart: None,
2669            headers: None,
2670            method: LightMethod::Patch,
2671            route: Route::WebhookMessage {
2672                webhook_id,
2673                token,
2674                message_id,
2675            },
2676            params: thread_id.map(|thread_id| vec![("thread_id", thread_id.to_string())]),
2677        };
2678
2679        if new_attachments.is_empty() {
2680            request.body = Some(to_vec(map)?);
2681        } else {
2682            request.multipart = Some(Multipart {
2683                upload: MultipartUpload::Attachments(new_attachments),
2684                payload_json: Some(to_string(map)?),
2685                fields: vec![],
2686            });
2687        }
2688
2689        self.fire(request).await
2690    }
2691
2692    /// Deletes a webhook's message by Id.
2693    pub async fn delete_webhook_message(
2694        &self,
2695        webhook_id: WebhookId,
2696        thread_id: Option<ChannelId>,
2697        token: &str,
2698        message_id: MessageId,
2699    ) -> Result<()> {
2700        self.wind(204, Request {
2701            body: None,
2702            multipart: None,
2703            headers: None,
2704            method: LightMethod::Delete,
2705            route: Route::WebhookMessage {
2706                webhook_id,
2707                token,
2708                message_id,
2709            },
2710            params: thread_id.map(|thread_id| vec![("thread_id", thread_id.to_string())]),
2711        })
2712        .await
2713    }
2714
2715    /// Gets the active maintenances from Discord's Status API.
2716    ///
2717    /// Does not require authentication.
2718    pub async fn get_active_maintenances(&self) -> Result<Vec<Maintenance>> {
2719        #[derive(Deserialize)]
2720        struct StatusResponse {
2721            #[serde(default)]
2722            scheduled_maintenances: Vec<Maintenance>,
2723        }
2724
2725        let status: StatusResponse = self
2726            .fire(Request {
2727                body: None,
2728                multipart: None,
2729                headers: None,
2730                method: LightMethod::Get,
2731                route: Route::StatusMaintenancesActive,
2732                params: None,
2733            })
2734            .await?;
2735
2736        Ok(status.scheduled_maintenances)
2737    }
2738
2739    /// Gets all the users that are banned in specific guild, with additional options for
2740    /// filtering.
2741    ///
2742    /// If `limit` is left unset, by default at most 1000 worths of data for banned users is
2743    /// returned.
2744    ///
2745    /// If `target` is set, then users will be filtered by Id, such that their Id comes before or
2746    /// after the provided [`UserId`] wrapped by the [`UserPagination`].
2747    ///
2748    /// [`UserId`]: crate::model::id::UserId
2749    pub async fn get_bans(
2750        &self,
2751        guild_id: GuildId,
2752        target: Option<UserPagination>,
2753        limit: Option<u8>,
2754    ) -> Result<Vec<Ban>> {
2755        let mut params = vec![];
2756
2757        if let Some(limit) = limit {
2758            params.push(("limit", limit.to_string()));
2759        }
2760
2761        if let Some(target) = target {
2762            match target {
2763                UserPagination::After(id) => params.push(("after", id.to_string())),
2764                UserPagination::Before(id) => params.push(("before", id.to_string())),
2765            }
2766        }
2767
2768        self.fire(Request {
2769            body: None,
2770            multipart: None,
2771            headers: None,
2772            method: LightMethod::Get,
2773            route: Route::GuildBans {
2774                guild_id,
2775            },
2776            params: Some(params),
2777        })
2778        .await
2779    }
2780
2781    /// Gets all audit logs in a specific guild.
2782    pub async fn get_audit_logs(
2783        &self,
2784        guild_id: GuildId,
2785        action_type: Option<audit_log::Action>,
2786        user_id: Option<UserId>,
2787        before: Option<AuditLogEntryId>,
2788        limit: Option<u8>,
2789    ) -> Result<AuditLogs> {
2790        let mut params = vec![];
2791        if let Some(action_type) = action_type {
2792            params.push(("action_type", action_type.num().to_string()));
2793        }
2794        if let Some(before) = before {
2795            params.push(("before", before.to_string()));
2796        }
2797        if let Some(limit) = limit {
2798            params.push(("limit", limit.to_string()));
2799        }
2800        if let Some(user_id) = user_id {
2801            params.push(("user_id", user_id.to_string()));
2802        }
2803
2804        self.fire(Request {
2805            body: None,
2806            multipart: None,
2807            headers: None,
2808            method: LightMethod::Get,
2809            route: Route::GuildAuditLogs {
2810                guild_id,
2811            },
2812            params: Some(params),
2813        })
2814        .await
2815    }
2816
2817    /// Retrieves all auto moderation rules in a guild.
2818    ///
2819    /// This method requires `MANAGE_GUILD` permissions.
2820    pub async fn get_automod_rules(&self, guild_id: GuildId) -> Result<Vec<Rule>> {
2821        self.fire(Request {
2822            body: None,
2823            multipart: None,
2824            headers: None,
2825            method: LightMethod::Get,
2826            route: Route::GuildAutomodRules {
2827                guild_id,
2828            },
2829            params: None,
2830        })
2831        .await
2832    }
2833
2834    /// Retrieves an auto moderation rule in a guild.
2835    ///
2836    /// This method requires `MANAGE_GUILD` permissions.
2837    pub async fn get_automod_rule(&self, guild_id: GuildId, rule_id: RuleId) -> Result<Rule> {
2838        self.fire(Request {
2839            body: None,
2840            multipart: None,
2841            headers: None,
2842            method: LightMethod::Get,
2843            route: Route::GuildAutomodRule {
2844                guild_id,
2845                rule_id,
2846            },
2847            params: None,
2848        })
2849        .await
2850    }
2851
2852    /// Creates an auto moderation rule in a guild.
2853    ///
2854    /// This method requires `MANAGE_GUILD` permissions.
2855    pub async fn create_automod_rule(
2856        &self,
2857        guild_id: GuildId,
2858        map: &impl serde::Serialize,
2859        audit_log_reason: Option<&str>,
2860    ) -> Result<Rule> {
2861        let body = to_vec(map)?;
2862
2863        self.fire(Request {
2864            body: Some(body),
2865            multipart: None,
2866            headers: audit_log_reason.map(reason_into_header),
2867            method: LightMethod::Post,
2868            route: Route::GuildAutomodRules {
2869                guild_id,
2870            },
2871            params: None,
2872        })
2873        .await
2874    }
2875
2876    /// Retrieves an auto moderation rule in a guild.
2877    ///
2878    /// This method requires `MANAGE_GUILD` permissions.
2879    pub async fn edit_automod_rule(
2880        &self,
2881        guild_id: GuildId,
2882        rule_id: RuleId,
2883        map: &impl serde::Serialize,
2884        audit_log_reason: Option<&str>,
2885    ) -> Result<Rule> {
2886        let body = to_vec(map)?;
2887
2888        self.fire(Request {
2889            body: Some(body),
2890            multipart: None,
2891            headers: audit_log_reason.map(reason_into_header),
2892            method: LightMethod::Patch,
2893            route: Route::GuildAutomodRule {
2894                guild_id,
2895                rule_id,
2896            },
2897            params: None,
2898        })
2899        .await
2900    }
2901
2902    /// Deletes an auto moderation rule in a guild.
2903    ///
2904    /// This method requires `MANAGE_GUILD` permissions.
2905    pub async fn delete_automod_rule(
2906        &self,
2907        guild_id: GuildId,
2908        rule_id: RuleId,
2909        audit_log_reason: Option<&str>,
2910    ) -> Result<()> {
2911        self.wind(204, Request {
2912            body: None,
2913            multipart: None,
2914            headers: audit_log_reason.map(reason_into_header),
2915            method: LightMethod::Delete,
2916            route: Route::GuildAutomodRule {
2917                guild_id,
2918                rule_id,
2919            },
2920            params: None,
2921        })
2922        .await
2923    }
2924
2925    /// Gets current bot gateway.
2926    pub async fn get_bot_gateway(&self) -> Result<BotGateway> {
2927        self.fire(Request {
2928            body: None,
2929            multipart: None,
2930            headers: None,
2931            method: LightMethod::Get,
2932            route: Route::GatewayBot,
2933            params: None,
2934        })
2935        .await
2936    }
2937
2938    /// Gets all invites for a channel.
2939    pub async fn get_channel_invites(&self, channel_id: ChannelId) -> Result<Vec<RichInvite>> {
2940        self.fire(Request {
2941            body: None,
2942            multipart: None,
2943            headers: None,
2944            method: LightMethod::Get,
2945            route: Route::ChannelInvites {
2946                channel_id,
2947            },
2948            params: None,
2949        })
2950        .await
2951    }
2952
2953    /// Gets all thread members for a thread.
2954    pub async fn get_channel_thread_members(
2955        &self,
2956        channel_id: ChannelId,
2957    ) -> Result<Vec<ThreadMember>> {
2958        self.fire(Request {
2959            body: None,
2960            multipart: None,
2961            headers: None,
2962            method: LightMethod::Get,
2963            route: Route::ChannelThreadMembers {
2964                channel_id,
2965            },
2966            params: None,
2967        })
2968        .await
2969    }
2970
2971    /// Gets all active threads from a guild.
2972    pub async fn get_guild_active_threads(&self, guild_id: GuildId) -> Result<ThreadsData> {
2973        self.fire(Request {
2974            body: None,
2975            multipart: None,
2976            headers: None,
2977            method: LightMethod::Get,
2978            route: Route::GuildThreadsActive {
2979                guild_id,
2980            },
2981            params: None,
2982        })
2983        .await
2984    }
2985
2986    /// Gets all archived public threads from a channel.
2987    pub async fn get_channel_archived_public_threads(
2988        &self,
2989        channel_id: ChannelId,
2990        before: Option<u64>,
2991        limit: Option<u64>,
2992    ) -> Result<ThreadsData> {
2993        let mut params = vec![];
2994        if let Some(before) = before {
2995            params.push(("before", before.to_string()));
2996        }
2997        if let Some(limit) = limit {
2998            params.push(("limit", limit.to_string()));
2999        }
3000
3001        self.fire(Request {
3002            body: None,
3003            multipart: None,
3004            method: LightMethod::Get,
3005            headers: None,
3006            route: Route::ChannelArchivedPublicThreads {
3007                channel_id,
3008            },
3009            params: Some(params),
3010        })
3011        .await
3012    }
3013
3014    /// Gets all archived private threads from a channel.
3015    pub async fn get_channel_archived_private_threads(
3016        &self,
3017        channel_id: ChannelId,
3018        before: Option<u64>,
3019        limit: Option<u64>,
3020    ) -> Result<ThreadsData> {
3021        let mut params = vec![];
3022        if let Some(before) = before {
3023            params.push(("before", before.to_string()));
3024        }
3025        if let Some(limit) = limit {
3026            params.push(("limit", limit.to_string()));
3027        }
3028
3029        self.fire(Request {
3030            body: None,
3031            multipart: None,
3032            headers: None,
3033            method: LightMethod::Get,
3034            route: Route::ChannelArchivedPrivateThreads {
3035                channel_id,
3036            },
3037            params: Some(params),
3038        })
3039        .await
3040    }
3041
3042    /// Gets all archived private threads joined from a channel.
3043    pub async fn get_channel_joined_archived_private_threads(
3044        &self,
3045        channel_id: ChannelId,
3046        before: Option<u64>,
3047        limit: Option<u64>,
3048    ) -> Result<ThreadsData> {
3049        let mut params = vec![];
3050        if let Some(before) = before {
3051            params.push(("before", before.to_string()));
3052        }
3053        if let Some(limit) = limit {
3054            params.push(("limit", limit.to_string()));
3055        }
3056
3057        self.fire(Request {
3058            body: None,
3059            multipart: None,
3060            headers: None,
3061            method: LightMethod::Get,
3062            route: Route::ChannelJoinedPrivateThreads {
3063                channel_id,
3064            },
3065            params: Some(params),
3066        })
3067        .await
3068    }
3069
3070    /// Joins a thread channel.
3071    pub async fn join_thread_channel(&self, channel_id: ChannelId) -> Result<()> {
3072        self.wind(204, Request {
3073            body: None,
3074            multipart: None,
3075            headers: None,
3076            method: LightMethod::Put,
3077            route: Route::ChannelThreadMemberMe {
3078                channel_id,
3079            },
3080            params: None,
3081        })
3082        .await
3083    }
3084
3085    /// Leaves a thread channel.
3086    pub async fn leave_thread_channel(&self, channel_id: ChannelId) -> Result<()> {
3087        self.wind(204, Request {
3088            body: None,
3089            multipart: None,
3090            headers: None,
3091            method: LightMethod::Delete,
3092            route: Route::ChannelThreadMemberMe {
3093                channel_id,
3094            },
3095            params: None,
3096        })
3097        .await
3098    }
3099
3100    /// Adds a member to a thread channel.
3101    pub async fn add_thread_channel_member(
3102        &self,
3103        channel_id: ChannelId,
3104        user_id: UserId,
3105    ) -> Result<()> {
3106        self.wind(204, Request {
3107            body: None,
3108            multipart: None,
3109            headers: None,
3110            method: LightMethod::Put,
3111            route: Route::ChannelThreadMember {
3112                channel_id,
3113                user_id,
3114            },
3115            params: None,
3116        })
3117        .await
3118    }
3119
3120    /// Removes a member from a thread channel.
3121    pub async fn remove_thread_channel_member(
3122        &self,
3123        channel_id: ChannelId,
3124        user_id: UserId,
3125    ) -> Result<()> {
3126        self.wind(204, Request {
3127            body: None,
3128            multipart: None,
3129            headers: None,
3130            method: LightMethod::Delete,
3131            route: Route::ChannelThreadMember {
3132                channel_id,
3133                user_id,
3134            },
3135            params: None,
3136        })
3137        .await
3138    }
3139
3140    pub async fn get_thread_channel_member(
3141        &self,
3142        channel_id: ChannelId,
3143        user_id: UserId,
3144        with_member: bool,
3145    ) -> Result<ThreadMember> {
3146        self.fire(Request {
3147            body: None,
3148            multipart: None,
3149            headers: None,
3150            method: LightMethod::Get,
3151            route: Route::ChannelThreadMember {
3152                channel_id,
3153                user_id,
3154            },
3155            params: Some(vec![("with_member", with_member.to_string())]),
3156        })
3157        .await
3158    }
3159
3160    /// Retrieves the webhooks for the given [channel][`GuildChannel`]'s Id.
3161    ///
3162    /// This method requires authentication.
3163    ///
3164    /// # Examples
3165    ///
3166    /// Retrieve all of the webhooks owned by a channel:
3167    ///
3168    /// ```rust,no_run
3169    /// # use serenity::http::Http;
3170    /// # use serenity::model::prelude::*;
3171    /// #
3172    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
3173    /// # let http: Http = unimplemented!();
3174    /// let channel_id = ChannelId::new(81384788765712384);
3175    ///
3176    /// let webhooks = http.get_channel_webhooks(channel_id).await?;
3177    /// # Ok(())
3178    /// # }
3179    /// ```
3180    pub async fn get_channel_webhooks(&self, channel_id: ChannelId) -> Result<Vec<Webhook>> {
3181        self.fire(Request {
3182            body: None,
3183            multipart: None,
3184            headers: None,
3185            method: LightMethod::Get,
3186            route: Route::ChannelWebhooks {
3187                channel_id,
3188            },
3189            params: None,
3190        })
3191        .await
3192    }
3193
3194    /// Gets channel information.
3195    pub async fn get_channel(&self, channel_id: ChannelId) -> Result<Channel> {
3196        self.fire(Request {
3197            body: None,
3198            multipart: None,
3199            headers: None,
3200            method: LightMethod::Get,
3201            route: Route::Channel {
3202                channel_id,
3203            },
3204            params: None,
3205        })
3206        .await
3207    }
3208
3209    /// Gets all channels in a guild.
3210    pub async fn get_channels(&self, guild_id: GuildId) -> Result<Vec<GuildChannel>> {
3211        self.fire(Request {
3212            body: None,
3213            multipart: None,
3214            headers: None,
3215            method: LightMethod::Get,
3216            route: Route::GuildChannels {
3217                guild_id,
3218            },
3219            params: None,
3220        })
3221        .await
3222    }
3223
3224    /// Gets a stage instance.
3225    pub async fn get_stage_instance(&self, channel_id: ChannelId) -> Result<StageInstance> {
3226        self.fire(Request {
3227            body: None,
3228            multipart: None,
3229            headers: None,
3230            method: LightMethod::Get,
3231            route: Route::StageInstance {
3232                channel_id,
3233            },
3234            params: None,
3235        })
3236        .await
3237    }
3238
3239    /// Get a list of users that voted for this specific answer.
3240    pub async fn get_poll_answer_voters(
3241        &self,
3242        channel_id: ChannelId,
3243        message_id: MessageId,
3244        answer_id: AnswerId,
3245        after: Option<UserId>,
3246        limit: Option<u8>,
3247    ) -> Result<Vec<User>> {
3248        #[derive(Deserialize)]
3249        struct VotersResponse {
3250            users: Vec<User>,
3251        }
3252
3253        let mut params = Vec::with_capacity(2);
3254        if let Some(after) = after {
3255            params.push(("after", after.to_string()));
3256        }
3257
3258        if let Some(limit) = limit {
3259            params.push(("limit", limit.to_string()));
3260        }
3261
3262        let resp: VotersResponse = self
3263            .fire(Request {
3264                body: None,
3265                multipart: None,
3266                headers: None,
3267                method: LightMethod::Get,
3268                route: Route::ChannelPollGetAnswerVoters {
3269                    channel_id,
3270                    message_id,
3271                    answer_id,
3272                },
3273                params: Some(params),
3274            })
3275            .await?;
3276
3277        Ok(resp.users)
3278    }
3279
3280    pub async fn expire_poll(
3281        &self,
3282        channel_id: ChannelId,
3283        message_id: MessageId,
3284    ) -> Result<Message> {
3285        self.fire(Request {
3286            body: None,
3287            multipart: None,
3288            headers: None,
3289            method: LightMethod::Post,
3290            route: Route::ChannelPollExpire {
3291                channel_id,
3292                message_id,
3293            },
3294            params: None,
3295        })
3296        .await
3297    }
3298
3299    /// Gets information about the current application.
3300    ///
3301    /// **Note**: Only applications may use this endpoint.
3302    pub async fn get_current_application_info(&self) -> Result<CurrentApplicationInfo> {
3303        self.fire(Request {
3304            body: None,
3305            multipart: None,
3306            headers: None,
3307            method: LightMethod::Get,
3308            route: Route::Oauth2ApplicationCurrent,
3309            params: None,
3310        })
3311        .await
3312    }
3313
3314    /// Gets information about the user we're connected with.
3315    pub async fn get_current_user(&self) -> Result<CurrentUser> {
3316        self.fire(Request {
3317            body: None,
3318            multipart: None,
3319            headers: None,
3320            method: LightMethod::Get,
3321            route: Route::UserMe,
3322            params: None,
3323        })
3324        .await
3325    }
3326
3327    /// Gets all emojis of a guild.
3328    pub async fn get_emojis(&self, guild_id: GuildId) -> Result<Vec<Emoji>> {
3329        self.fire(Request {
3330            body: None,
3331            multipart: None,
3332            headers: None,
3333            method: LightMethod::Get,
3334            route: Route::GuildEmojis {
3335                guild_id,
3336            },
3337            params: None,
3338        })
3339        .await
3340    }
3341
3342    /// Gets information about an emoji in a guild.
3343    pub async fn get_emoji(&self, guild_id: GuildId, emoji_id: EmojiId) -> Result<Emoji> {
3344        self.fire(Request {
3345            body: None,
3346            multipart: None,
3347            headers: None,
3348            method: LightMethod::Get,
3349            route: Route::GuildEmoji {
3350                guild_id,
3351                emoji_id,
3352            },
3353            params: None,
3354        })
3355        .await
3356    }
3357
3358    /// Gets all emojis for the current application.
3359    pub async fn get_application_emojis(&self) -> Result<Vec<Emoji>> {
3360        // Why, discord...
3361        #[derive(Deserialize)]
3362        struct ApplicationEmojis {
3363            items: Vec<Emoji>,
3364        }
3365
3366        let result: ApplicationEmojis = self
3367            .fire(Request {
3368                body: None,
3369                multipart: None,
3370                headers: None,
3371                method: LightMethod::Get,
3372                route: Route::Emojis {
3373                    application_id: self.try_application_id()?,
3374                },
3375                params: None,
3376            })
3377            .await?;
3378
3379        Ok(result.items)
3380    }
3381
3382    /// Gets information about an application emoji.
3383    pub async fn get_application_emoji(&self, emoji_id: EmojiId) -> Result<Emoji> {
3384        self.fire(Request {
3385            body: None,
3386            multipart: None,
3387            headers: None,
3388            method: LightMethod::Get,
3389            route: Route::Emoji {
3390                application_id: self.try_application_id()?,
3391                emoji_id,
3392            },
3393            params: None,
3394        })
3395        .await
3396    }
3397
3398    #[allow(clippy::too_many_arguments)]
3399    /// Gets all entitlements for the current app, active and expired.
3400    pub async fn get_entitlements(
3401        &self,
3402        user_id: Option<UserId>,
3403        sku_ids: Option<Vec<SkuId>>,
3404        before: Option<EntitlementId>,
3405        after: Option<EntitlementId>,
3406        limit: Option<u8>,
3407        guild_id: Option<GuildId>,
3408        exclude_ended: Option<bool>,
3409    ) -> Result<Vec<Entitlement>> {
3410        let mut params = vec![];
3411        if let Some(user_id) = user_id {
3412            params.push(("user_id", user_id.to_string()));
3413        }
3414        if let Some(sku_ids) = sku_ids {
3415            params.push((
3416                "sku_ids",
3417                sku_ids.iter().map(ToString::to_string).collect::<Vec<_>>().join(","),
3418            ));
3419        }
3420        if let Some(before) = before {
3421            params.push(("before", before.to_string()));
3422        }
3423        if let Some(after) = after {
3424            params.push(("after", after.to_string()));
3425        }
3426        if let Some(limit) = limit {
3427            params.push(("limit", limit.to_string()));
3428        }
3429        if let Some(guild_id) = guild_id {
3430            params.push(("guild_id", guild_id.to_string()));
3431        }
3432        if let Some(exclude_ended) = exclude_ended {
3433            params.push(("exclude_ended", exclude_ended.to_string()));
3434        }
3435
3436        self.fire(Request {
3437            body: None,
3438            multipart: None,
3439            headers: None,
3440            method: LightMethod::Get,
3441            route: Route::Entitlements {
3442                application_id: self.try_application_id()?,
3443            },
3444            params: Some(params),
3445        })
3446        .await
3447    }
3448
3449    /// Gets current gateway.
3450    pub async fn get_gateway(&self) -> Result<Gateway> {
3451        self.fire(Request {
3452            body: None,
3453            multipart: None,
3454            headers: None,
3455            method: LightMethod::Get,
3456            route: Route::Gateway,
3457            params: None,
3458        })
3459        .await
3460    }
3461
3462    /// Fetches all of the global commands for your application.
3463    pub async fn get_global_commands(&self) -> Result<Vec<Command>> {
3464        self.fire(Request {
3465            body: None,
3466            multipart: None,
3467            headers: None,
3468            method: LightMethod::Get,
3469            route: Route::Commands {
3470                application_id: self.try_application_id()?,
3471            },
3472            params: None,
3473        })
3474        .await
3475    }
3476
3477    /// Fetches all of the global commands for your application with localizations.
3478    pub async fn get_global_commands_with_localizations(&self) -> Result<Vec<Command>> {
3479        self.fire(Request {
3480            body: None,
3481            multipart: None,
3482            headers: None,
3483            method: LightMethod::Get,
3484            route: Route::Commands {
3485                application_id: self.try_application_id()?,
3486            },
3487            params: Some(vec![("with_localizations", true.to_string())]),
3488        })
3489        .await
3490    }
3491
3492    /// Fetches a global commands for your application by its Id.
3493    pub async fn get_global_command(&self, command_id: CommandId) -> Result<Command> {
3494        self.fire(Request {
3495            body: None,
3496            multipart: None,
3497            headers: None,
3498            method: LightMethod::Get,
3499            route: Route::Command {
3500                application_id: self.try_application_id()?,
3501                command_id,
3502            },
3503            params: None,
3504        })
3505        .await
3506    }
3507
3508    /// Gets guild information.
3509    pub async fn get_guild(&self, guild_id: GuildId) -> Result<PartialGuild> {
3510        self.fire(Request {
3511            body: None,
3512            multipart: None,
3513            headers: None,
3514            method: LightMethod::Get,
3515            route: Route::Guild {
3516                guild_id,
3517            },
3518            params: None,
3519        })
3520        .await
3521    }
3522
3523    /// Gets guild information with counts.
3524    pub async fn get_guild_with_counts(&self, guild_id: GuildId) -> Result<PartialGuild> {
3525        self.fire(Request {
3526            body: None,
3527            multipart: None,
3528            headers: None,
3529            method: LightMethod::Get,
3530            route: Route::Guild {
3531                guild_id,
3532            },
3533            params: Some(vec![("with_counts", true.to_string())]),
3534        })
3535        .await
3536    }
3537
3538    /// Fetches all of the guild commands for your application for a specific guild.
3539    pub async fn get_guild_commands(&self, guild_id: GuildId) -> Result<Vec<Command>> {
3540        self.fire(Request {
3541            body: None,
3542            multipart: None,
3543            headers: None,
3544            method: LightMethod::Get,
3545            route: Route::GuildCommands {
3546                application_id: self.try_application_id()?,
3547                guild_id,
3548            },
3549            params: None,
3550        })
3551        .await
3552    }
3553
3554    /// Fetches all of the guild commands with localizations for your application for a specific
3555    /// guild.
3556    pub async fn get_guild_commands_with_localizations(
3557        &self,
3558        guild_id: GuildId,
3559    ) -> Result<Vec<Command>> {
3560        self.fire(Request {
3561            body: None,
3562            multipart: None,
3563            headers: None,
3564            method: LightMethod::Get,
3565            route: Route::GuildCommands {
3566                application_id: self.try_application_id()?,
3567                guild_id,
3568            },
3569            params: Some(vec![("with_localizations", true.to_string())]),
3570        })
3571        .await
3572    }
3573
3574    /// Fetches a guild command by its Id.
3575    pub async fn get_guild_command(
3576        &self,
3577        guild_id: GuildId,
3578        command_id: CommandId,
3579    ) -> Result<Command> {
3580        self.fire(Request {
3581            body: None,
3582            multipart: None,
3583            headers: None,
3584            method: LightMethod::Get,
3585            route: Route::GuildCommand {
3586                application_id: self.try_application_id()?,
3587                guild_id,
3588                command_id,
3589            },
3590            params: None,
3591        })
3592        .await
3593    }
3594
3595    /// Fetches all of the guild commands permissions for your application for a specific guild.
3596    pub async fn get_guild_commands_permissions(
3597        &self,
3598        guild_id: GuildId,
3599    ) -> Result<Vec<CommandPermissions>> {
3600        self.fire(Request {
3601            body: None,
3602            multipart: None,
3603            headers: None,
3604            method: LightMethod::Get,
3605            route: Route::GuildCommandsPermissions {
3606                application_id: self.try_application_id()?,
3607                guild_id,
3608            },
3609            params: None,
3610        })
3611        .await
3612    }
3613
3614    /// Gives the guild command permission for your application for a specific guild.
3615    pub async fn get_guild_command_permissions(
3616        &self,
3617        guild_id: GuildId,
3618        command_id: CommandId,
3619    ) -> Result<CommandPermissions> {
3620        self.fire(Request {
3621            body: None,
3622            multipart: None,
3623            headers: None,
3624            method: LightMethod::Get,
3625            route: Route::GuildCommandPermissions {
3626                application_id: self.try_application_id()?,
3627                guild_id,
3628                command_id,
3629            },
3630            params: None,
3631        })
3632        .await
3633    }
3634
3635    /// Gets a guild widget information.
3636    // TODO: according to Discord, this returns different data; namely https://discord.com/developers/docs/resources/guild#guild-widget-object-guild-widget-structure.
3637    // Should investigate if this endpoint actually works
3638    pub async fn get_guild_widget(&self, guild_id: GuildId) -> Result<GuildWidget> {
3639        self.fire(Request {
3640            body: None,
3641            multipart: None,
3642            headers: None,
3643            method: LightMethod::Get,
3644            route: Route::GuildWidget {
3645                guild_id,
3646            },
3647            params: None,
3648        })
3649        .await
3650    }
3651
3652    /// Gets a guild preview.
3653    pub async fn get_guild_preview(&self, guild_id: GuildId) -> Result<GuildPreview> {
3654        self.fire(Request {
3655            body: None,
3656            multipart: None,
3657            headers: None,
3658            method: LightMethod::Get,
3659            route: Route::GuildPreview {
3660                guild_id,
3661            },
3662            params: None,
3663        })
3664        .await
3665    }
3666
3667    /// Gets a guild welcome screen information.
3668    pub async fn get_guild_welcome_screen(&self, guild_id: GuildId) -> Result<GuildWelcomeScreen> {
3669        self.fire(Request {
3670            body: None,
3671            multipart: None,
3672            headers: None,
3673            method: LightMethod::Get,
3674            route: Route::GuildWelcomeScreen {
3675                guild_id,
3676            },
3677            params: None,
3678        })
3679        .await
3680    }
3681
3682    /// Gets integrations that a guild has.
3683    pub async fn get_guild_integrations(&self, guild_id: GuildId) -> Result<Vec<Integration>> {
3684        self.fire(Request {
3685            body: None,
3686            multipart: None,
3687            headers: None,
3688            method: LightMethod::Get,
3689            route: Route::GuildIntegrations {
3690                guild_id,
3691            },
3692            params: None,
3693        })
3694        .await
3695    }
3696
3697    /// Gets all invites to a guild.
3698    pub async fn get_guild_invites(&self, guild_id: GuildId) -> Result<Vec<RichInvite>> {
3699        self.fire(Request {
3700            body: None,
3701            multipart: None,
3702            headers: None,
3703            method: LightMethod::Get,
3704            route: Route::GuildInvites {
3705                guild_id,
3706            },
3707            params: None,
3708        })
3709        .await
3710    }
3711
3712    /// Gets a guild's vanity URL if it has one.
3713    pub async fn get_guild_vanity_url(&self, guild_id: GuildId) -> Result<String> {
3714        #[derive(Deserialize)]
3715        struct GuildVanityUrl {
3716            code: String,
3717        }
3718
3719        self.fire::<GuildVanityUrl>(Request {
3720            body: None,
3721            multipart: None,
3722            headers: None,
3723            method: LightMethod::Get,
3724            route: Route::GuildVanityUrl {
3725                guild_id,
3726            },
3727            params: None,
3728        })
3729        .await
3730        .map(|x| x.code)
3731    }
3732
3733    /// Gets the members of a guild. Optionally pass a `limit` and the Id of the user to offset the
3734    /// result by.
3735    pub async fn get_guild_members(
3736        &self,
3737        guild_id: GuildId,
3738        limit: Option<u64>,
3739        after: Option<u64>,
3740    ) -> Result<Vec<Member>> {
3741        if let Some(l) = limit {
3742            if !(1..=constants::MEMBER_FETCH_LIMIT).contains(&l) {
3743                return Err(Error::NotInRange("limit", l, 1, constants::MEMBER_FETCH_LIMIT));
3744            }
3745        }
3746
3747        let mut params =
3748            vec![("limit", limit.unwrap_or(constants::MEMBER_FETCH_LIMIT).to_string())];
3749        if let Some(after) = after {
3750            params.push(("after", after.to_string()));
3751        }
3752
3753        let mut value: Value = self
3754            .fire(Request {
3755                body: None,
3756                multipart: None,
3757                headers: None,
3758                method: LightMethod::Get,
3759                route: Route::GuildMembers {
3760                    guild_id,
3761                },
3762                params: Some(params),
3763            })
3764            .await?;
3765
3766        if let Some(values) = value.as_array_mut() {
3767            for value in values {
3768                if let Some(element) = value.as_object_mut() {
3769                    element.insert("guild_id".to_string(), guild_id.get().into());
3770                }
3771            }
3772        }
3773
3774        from_value(value).map_err(From::from)
3775    }
3776
3777    /// Gets the amount of users that can be pruned.
3778    pub async fn get_guild_prune_count(&self, guild_id: GuildId, days: u8) -> Result<GuildPrune> {
3779        self.fire(Request {
3780            body: None,
3781            multipart: None,
3782            headers: None,
3783            method: LightMethod::Get,
3784            route: Route::GuildPrune {
3785                guild_id,
3786            },
3787            params: Some(vec![("days", days.to_string())]),
3788        })
3789        .await
3790    }
3791
3792    /// Gets regions that a guild can use. If a guild has the `VIP_REGIONS` feature enabled, then
3793    /// additional VIP-only regions are returned.
3794    pub async fn get_guild_regions(&self, guild_id: GuildId) -> Result<Vec<VoiceRegion>> {
3795        self.fire(Request {
3796            body: None,
3797            multipart: None,
3798            headers: None,
3799            method: LightMethod::Get,
3800            route: Route::GuildRegions {
3801                guild_id,
3802            },
3803            params: None,
3804        })
3805        .await
3806    }
3807
3808    /// Retrieves a specific role in a [`Guild`].
3809    pub async fn get_guild_role(&self, guild_id: GuildId, role_id: RoleId) -> Result<Role> {
3810        let mut value: Value = self
3811            .fire(Request {
3812                body: None,
3813                multipart: None,
3814                headers: None,
3815                method: LightMethod::Get,
3816                route: Route::GuildRole {
3817                    guild_id,
3818                    role_id,
3819                },
3820                params: None,
3821            })
3822            .await?;
3823
3824        if let Some(map) = value.as_object_mut() {
3825            map.insert("guild_id".to_string(), guild_id.get().into());
3826        }
3827
3828        from_value(value).map_err(From::from)
3829    }
3830
3831    /// Retrieves a list of roles in a [`Guild`].
3832    pub async fn get_guild_roles(&self, guild_id: GuildId) -> Result<Vec<Role>> {
3833        let mut value: Value = self
3834            .fire(Request {
3835                body: None,
3836                multipart: None,
3837                headers: None,
3838                method: LightMethod::Get,
3839                route: Route::GuildRoles {
3840                    guild_id,
3841                },
3842                params: None,
3843            })
3844            .await?;
3845
3846        if let Some(array) = value.as_array_mut() {
3847            for sticker in array {
3848                if let Some(map) = sticker.as_object_mut() {
3849                    map.insert("guild_id".to_string(), guild_id.get().into());
3850                }
3851            }
3852        }
3853
3854        from_value(value).map_err(From::from)
3855    }
3856
3857    /// Gets a scheduled event by Id.
3858    ///
3859    /// **Note**: Requires the [View Channel] permission for the channel associated with the event.
3860    ///
3861    /// [View Channel]: Permissions::VIEW_CHANNEL
3862    pub async fn get_scheduled_event(
3863        &self,
3864        guild_id: GuildId,
3865        event_id: ScheduledEventId,
3866        with_user_count: bool,
3867    ) -> Result<ScheduledEvent> {
3868        self.fire(Request {
3869            body: None,
3870            multipart: None,
3871            headers: None,
3872            method: LightMethod::Get,
3873            route: Route::GuildScheduledEvent {
3874                guild_id,
3875                event_id,
3876            },
3877            params: Some(vec![("with_user_count", with_user_count.to_string())]),
3878        })
3879        .await
3880    }
3881
3882    /// Gets a list of all scheduled events for the corresponding guild.
3883    ///
3884    /// **Note**: Requires the [View Channel] permission at the guild level.
3885    ///
3886    /// [View Channel]: Permissions::VIEW_CHANNEL
3887    pub async fn get_scheduled_events(
3888        &self,
3889        guild_id: GuildId,
3890        with_user_count: bool,
3891    ) -> Result<Vec<ScheduledEvent>> {
3892        self.fire(Request {
3893            body: None,
3894            multipart: None,
3895            headers: None,
3896            method: LightMethod::Get,
3897            route: Route::GuildScheduledEvents {
3898                guild_id,
3899            },
3900            params: Some(vec![("with_user_count", with_user_count.to_string())]),
3901        })
3902        .await
3903    }
3904
3905    /// Gets a list of all interested users for the corresponding scheduled event, with additional
3906    /// options for filtering.
3907    ///
3908    /// If `limit` is left unset, by default at most 100 users are returned.
3909    ///
3910    /// If `target` is set, then users will be filtered by Id, such that their Id comes before or
3911    /// after the provided [`UserId`] wrapped by the [`UserPagination`].
3912    ///
3913    /// If `with_member` is set to `Some(true)`, then the [`member`] field of the user struct will
3914    /// be populated with [`Guild Member`] information, if the interested user is a member of the
3915    /// guild the event takes place in.
3916    ///
3917    /// **Note**: Requires the [View Channel] permission for the channel associated with the event.
3918    ///
3919    /// [`member`]: ScheduledEventUser::member
3920    /// [`Guild Member`]: crate::model::guild::Member
3921    pub async fn get_scheduled_event_users(
3922        &self,
3923        guild_id: GuildId,
3924        event_id: ScheduledEventId,
3925        limit: Option<u64>,
3926        target: Option<UserPagination>,
3927        with_member: Option<bool>,
3928    ) -> Result<Vec<ScheduledEventUser>> {
3929        let mut params = vec![];
3930        if let Some(limit) = limit {
3931            params.push(("limit", limit.to_string()));
3932        }
3933        if let Some(with_member) = with_member {
3934            params.push(("with_member", with_member.to_string()));
3935        }
3936        if let Some(target) = target {
3937            match target {
3938                UserPagination::After(id) => params.push(("after", id.to_string())),
3939                UserPagination::Before(id) => params.push(("before", id.to_string())),
3940            }
3941        }
3942
3943        self.fire(Request {
3944            body: None,
3945            multipart: None,
3946            headers: None,
3947            method: LightMethod::Get,
3948            route: Route::GuildScheduledEventUsers {
3949                guild_id,
3950                event_id,
3951            },
3952            params: Some(params),
3953        })
3954        .await
3955    }
3956
3957    /// Retrieves a list of stickers in a [`Guild`].
3958    pub async fn get_guild_stickers(&self, guild_id: GuildId) -> Result<Vec<Sticker>> {
3959        let mut value: Value = self
3960            .fire(Request {
3961                body: None,
3962                multipart: None,
3963                headers: None,
3964                method: LightMethod::Get,
3965                route: Route::GuildStickers {
3966                    guild_id,
3967                },
3968                params: None,
3969            })
3970            .await?;
3971
3972        if let Some(array) = value.as_array_mut() {
3973            for role in array {
3974                if let Some(map) = role.as_object_mut() {
3975                    map.insert("guild_id".to_string(), guild_id.get().into());
3976                }
3977            }
3978        }
3979
3980        from_value(value).map_err(From::from)
3981    }
3982
3983    /// Retrieves a single sticker in a [`Guild`].
3984    pub async fn get_guild_sticker(
3985        &self,
3986        guild_id: GuildId,
3987        sticker_id: StickerId,
3988    ) -> Result<Sticker> {
3989        let mut value: Value = self
3990            .fire(Request {
3991                body: None,
3992                multipart: None,
3993                headers: None,
3994                method: LightMethod::Get,
3995                route: Route::GuildSticker {
3996                    guild_id,
3997                    sticker_id,
3998                },
3999                params: None,
4000            })
4001            .await?;
4002
4003        if let Some(map) = value.as_object_mut() {
4004            map.insert("guild_id".to_string(), guild_id.get().into());
4005        }
4006
4007        from_value(value).map_err(From::from)
4008    }
4009
4010    /// Retrieves the webhooks for the given [guild][`Guild`]'s Id.
4011    ///
4012    /// This method requires authentication.
4013    ///
4014    /// # Examples
4015    ///
4016    /// Retrieve all of the webhooks owned by a guild:
4017    ///
4018    /// ```rust,no_run
4019    /// # use serenity::http::Http;
4020    /// # use serenity::model::prelude::*;
4021    /// #
4022    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
4023    /// # let http: Http = unimplemented!();
4024    /// let guild_id = GuildId::new(81384788765712384);
4025    ///
4026    /// let webhooks = http.get_guild_webhooks(guild_id).await?;
4027    /// # Ok(())
4028    /// # }
4029    /// ```
4030    pub async fn get_guild_webhooks(&self, guild_id: GuildId) -> Result<Vec<Webhook>> {
4031        self.fire(Request {
4032            body: None,
4033            multipart: None,
4034            headers: None,
4035            method: LightMethod::Get,
4036            route: Route::GuildWebhooks {
4037                guild_id,
4038            },
4039            params: None,
4040        })
4041        .await
4042    }
4043
4044    /// Gets a paginated list of the current user's guilds.
4045    ///
4046    /// The `limit` has a maximum value of 100.
4047    ///
4048    /// [Discord's documentation][docs]
4049    ///
4050    /// # Examples
4051    ///
4052    /// Get the first 10 guilds after a certain guild's Id:
4053    ///
4054    /// ```rust,no_run
4055    /// # use serenity::http::Http;
4056    /// #
4057    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
4058    /// # let http: Http = unimplemented!();
4059    /// use serenity::http::GuildPagination;
4060    /// use serenity::model::id::GuildId;
4061    ///
4062    /// let guild_id = GuildId::new(81384788765712384);
4063    ///
4064    /// let guilds = http.get_guilds(Some(GuildPagination::After(guild_id)), Some(10)).await?;
4065    /// # Ok(())
4066    /// # }
4067    /// ```
4068    ///
4069    /// [docs]: https://discord.com/developers/docs/resources/user#get-current-user-guilds
4070    pub async fn get_guilds(
4071        &self,
4072        target: Option<GuildPagination>,
4073        limit: Option<u64>,
4074    ) -> Result<Vec<GuildInfo>> {
4075        let mut params = vec![];
4076        if let Some(limit) = limit {
4077            params.push(("limit", limit.to_string()));
4078        }
4079        if let Some(target) = target {
4080            match target {
4081                GuildPagination::After(id) => params.push(("after", id.to_string())),
4082                GuildPagination::Before(id) => params.push(("before", id.to_string())),
4083            }
4084        }
4085
4086        self.fire(Request {
4087            body: None,
4088            multipart: None,
4089            headers: None,
4090            method: LightMethod::Get,
4091            route: Route::UserMeGuilds,
4092            params: Some(params),
4093        })
4094        .await
4095    }
4096
4097    /// Returns a guild [`Member`] object for the current user.
4098    ///
4099    /// # Authorization
4100    ///
4101    /// This method only works for user tokens with the [`GuildsMembersRead`] OAuth2 scope.
4102    ///
4103    /// [`GuildsMembersRead`]: crate::model::application::Scope::GuildsMembersRead
4104    ///
4105    /// # Examples
4106    ///
4107    /// Get the member object for the current user within the specified guild.
4108    ///
4109    /// ```rust,no_run
4110    /// # use serenity::http::Http;
4111    /// #
4112    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
4113    /// # let http: Http = unimplemented!();
4114    /// use serenity::model::id::GuildId;
4115    ///
4116    /// let guild_id = GuildId::new(81384788765712384);
4117    ///
4118    /// let member = http.get_current_user_guild_member(guild_id).await?;
4119    /// # Ok(())
4120    /// # }
4121    /// ```
4122    ///
4123    /// See the [Discord Developer Portal documentation][docs] for more.
4124    ///
4125    /// [docs]: https://discord.com/developers/docs/resources/user#get-current-user-guild-member
4126    pub async fn get_current_user_guild_member(&self, guild_id: GuildId) -> Result<Member> {
4127        let mut value: Value = self
4128            .fire(Request {
4129                body: None,
4130                multipart: None,
4131                headers: None,
4132                method: LightMethod::Get,
4133                route: Route::UserMeGuildMember {
4134                    guild_id,
4135                },
4136                params: None,
4137            })
4138            .await?;
4139
4140        if let Some(map) = value.as_object_mut() {
4141            map.insert("guild_id".to_string(), guild_id.get().into());
4142        }
4143
4144        from_value(value).map_err(From::from)
4145    }
4146
4147    /// Gets information about a specific invite.
4148    ///
4149    /// # Arguments
4150    /// * `code` - The invite code.
4151    /// * `member_counts` - Whether to include information about the current number of members in
4152    ///   the server that the invite belongs to.
4153    /// * `expiration` - Whether to include information about when the invite expires.
4154    /// * `event_id` - An optional server event ID to include with the invite.
4155    ///
4156    /// More information about these arguments can be found on Discord's
4157    /// [API documentation](https://discord.com/developers/docs/resources/invite#get-invite).
4158    pub async fn get_invite(
4159        &self,
4160        code: &str,
4161        member_counts: bool,
4162        expiration: bool,
4163        event_id: Option<ScheduledEventId>,
4164    ) -> Result<Invite> {
4165        #[cfg(feature = "utils")]
4166        let code = crate::utils::parse_invite(code);
4167
4168        let mut params = vec![
4169            ("member_counts", member_counts.to_string()),
4170            ("expiration", expiration.to_string()),
4171        ];
4172        if let Some(event_id) = event_id {
4173            params.push(("event_id", event_id.to_string()));
4174        }
4175
4176        self.fire(Request {
4177            body: None,
4178            multipart: None,
4179            headers: None,
4180            method: LightMethod::Get,
4181            route: Route::Invite {
4182                code,
4183            },
4184            params: Some(params),
4185        })
4186        .await
4187    }
4188
4189    /// Gets member of a guild.
4190    pub async fn get_member(&self, guild_id: GuildId, user_id: UserId) -> Result<Member> {
4191        let mut value: Value = self
4192            .fire(Request {
4193                body: None,
4194                multipart: None,
4195                headers: None,
4196                method: LightMethod::Get,
4197                route: Route::GuildMember {
4198                    guild_id,
4199                    user_id,
4200                },
4201                params: None,
4202            })
4203            .await?;
4204
4205        if let Some(map) = value.as_object_mut() {
4206            map.insert("guild_id".to_string(), guild_id.get().into());
4207        }
4208
4209        from_value(value).map_err(From::from)
4210    }
4211
4212    /// Gets a message by an Id, bots only.
4213    pub async fn get_message(
4214        &self,
4215        channel_id: ChannelId,
4216        message_id: MessageId,
4217    ) -> Result<Message> {
4218        self.fire(Request {
4219            body: None,
4220            multipart: None,
4221            headers: None,
4222            method: LightMethod::Get,
4223            route: Route::ChannelMessage {
4224                channel_id,
4225                message_id,
4226            },
4227            params: None,
4228        })
4229        .await
4230    }
4231
4232    /// Gets X messages from a channel.
4233    pub async fn get_messages(
4234        &self,
4235        channel_id: ChannelId,
4236        target: Option<MessagePagination>,
4237        limit: Option<u8>,
4238    ) -> Result<Vec<Message>> {
4239        let mut params = vec![];
4240        if let Some(limit) = limit {
4241            params.push(("limit", limit.to_string()));
4242        }
4243        if let Some(target) = target {
4244            match target {
4245                MessagePagination::After(id) => params.push(("after", id.to_string())),
4246                MessagePagination::Around(id) => params.push(("around", id.to_string())),
4247                MessagePagination::Before(id) => params.push(("before", id.to_string())),
4248            }
4249        }
4250
4251        self.fire(Request {
4252            body: None,
4253            multipart: None,
4254            headers: None,
4255            method: LightMethod::Get,
4256            route: Route::ChannelMessages {
4257                channel_id,
4258            },
4259            params: Some(params),
4260        })
4261        .await
4262    }
4263
4264    /// Retrieves a specific [`StickerPack`] from it's [`StickerPackId`]
4265    pub async fn get_sticker_pack(&self, sticker_pack_id: StickerPackId) -> Result<StickerPack> {
4266        self.fire(Request {
4267            body: None,
4268            multipart: None,
4269            headers: None,
4270            method: LightMethod::Get,
4271            route: Route::StickerPack {
4272                sticker_pack_id,
4273            },
4274            params: None,
4275        })
4276        .await
4277    }
4278
4279    /// Retrieves a list of all nitro sticker packs.
4280    pub async fn get_nitro_stickers(&self) -> Result<Vec<StickerPack>> {
4281        #[derive(Deserialize)]
4282        struct StickerPacks {
4283            sticker_packs: Vec<StickerPack>,
4284        }
4285
4286        self.fire::<StickerPacks>(Request {
4287            body: None,
4288            multipart: None,
4289            headers: None,
4290            method: LightMethod::Get,
4291            route: Route::StickerPacks,
4292            params: None,
4293        })
4294        .await
4295        .map(|s| s.sticker_packs)
4296    }
4297
4298    /// Gets all pins of a channel.
4299    pub async fn get_pins(&self, channel_id: ChannelId) -> Result<Vec<Message>> {
4300        self.fire(Request {
4301            body: None,
4302            multipart: None,
4303            headers: None,
4304            method: LightMethod::Get,
4305            route: Route::ChannelPins {
4306                channel_id,
4307            },
4308            params: None,
4309        })
4310        .await
4311    }
4312
4313    /// Gets user Ids based on their reaction to a message. This endpoint is dumb.
4314    pub async fn get_reaction_users(
4315        &self,
4316        channel_id: ChannelId,
4317        message_id: MessageId,
4318        reaction_type: &ReactionType,
4319        limit: u8,
4320        after: Option<u64>,
4321    ) -> Result<Vec<User>> {
4322        let mut params = vec![("limit", limit.to_string())];
4323        if let Some(after) = after {
4324            params.push(("after", after.to_string()));
4325        }
4326        self.fire(Request {
4327            body: None,
4328            multipart: None,
4329            headers: None,
4330            method: LightMethod::Get,
4331            route: Route::ChannelMessageReactionEmoji {
4332                channel_id,
4333                message_id,
4334                reaction: &reaction_type.as_data(),
4335            },
4336            params: Some(params),
4337        })
4338        .await
4339    }
4340
4341    /// Gets all SKUs for the current application.
4342    pub async fn get_skus(&self) -> Result<Vec<Sku>> {
4343        self.fire(Request {
4344            body: None,
4345            multipart: None,
4346            headers: None,
4347            method: LightMethod::Get,
4348            route: Route::Skus {
4349                application_id: self.try_application_id()?,
4350            },
4351            params: None,
4352        })
4353        .await
4354    }
4355
4356    /// Gets a sticker.
4357    pub async fn get_sticker(&self, sticker_id: StickerId) -> Result<Sticker> {
4358        self.fire(Request {
4359            body: None,
4360            multipart: None,
4361            headers: None,
4362            method: LightMethod::Get,
4363            route: Route::Sticker {
4364                sticker_id,
4365            },
4366            params: None,
4367        })
4368        .await
4369    }
4370
4371    /// Gets the current unresolved incidents from Discord's Status API.
4372    ///
4373    /// Does not require authentication.
4374    pub async fn get_unresolved_incidents(&self) -> Result<Vec<Incident>> {
4375        #[derive(Deserialize)]
4376        struct StatusResponse {
4377            #[serde(default)]
4378            incidents: Vec<Incident>,
4379        }
4380
4381        let status: StatusResponse = self
4382            .fire(Request {
4383                body: None,
4384                multipart: None,
4385                headers: None,
4386                method: LightMethod::Get,
4387                route: Route::StatusIncidentsUnresolved,
4388                params: None,
4389            })
4390            .await?;
4391
4392        Ok(status.incidents)
4393    }
4394
4395    /// Gets the upcoming (planned) maintenances from Discord's Status API.
4396    ///
4397    /// Does not require authentication.
4398    pub async fn get_upcoming_maintenances(&self) -> Result<Vec<Maintenance>> {
4399        #[derive(Deserialize)]
4400        struct StatusResponse {
4401            #[serde(default)]
4402            scheduled_maintenances: Vec<Maintenance>,
4403        }
4404
4405        let status: StatusResponse = self
4406            .fire(Request {
4407                body: None,
4408                multipart: None,
4409                headers: None,
4410                method: LightMethod::Get,
4411                route: Route::StatusMaintenancesUpcoming,
4412                params: None,
4413            })
4414            .await?;
4415
4416        Ok(status.scheduled_maintenances)
4417    }
4418
4419    /// Gets a user by Id.
4420    pub async fn get_user(&self, user_id: UserId) -> Result<User> {
4421        self.fire(Request {
4422            body: None,
4423            multipart: None,
4424            headers: None,
4425            method: LightMethod::Get,
4426            route: Route::User {
4427                user_id,
4428            },
4429            params: None,
4430        })
4431        .await
4432    }
4433
4434    /// Gets the current user's third party connections.
4435    ///
4436    /// This method only works for user tokens with the [`Connections`] OAuth2 scope.
4437    ///
4438    /// [`Connections`]: crate::model::application::Scope::Connections
4439    pub async fn get_user_connections(&self) -> Result<Vec<Connection>> {
4440        self.fire(Request {
4441            body: None,
4442            multipart: None,
4443            headers: None,
4444            method: LightMethod::Get,
4445            route: Route::UserMeConnections,
4446            params: None,
4447        })
4448        .await
4449    }
4450
4451    /// Gets our DM channels.
4452    pub async fn get_user_dm_channels(&self) -> Result<Vec<PrivateChannel>> {
4453        self.fire(Request {
4454            body: None,
4455            multipart: None,
4456            headers: None,
4457            method: LightMethod::Get,
4458            route: Route::UserMeDmChannels,
4459            params: None,
4460        })
4461        .await
4462    }
4463
4464    /// Gets all voice regions.
4465    pub async fn get_voice_regions(&self) -> Result<Vec<VoiceRegion>> {
4466        self.fire(Request {
4467            body: None,
4468            multipart: None,
4469            headers: None,
4470            method: LightMethod::Get,
4471            route: Route::VoiceRegions,
4472            params: None,
4473        })
4474        .await
4475    }
4476
4477    /// Retrieves a webhook given its Id.
4478    ///
4479    /// This method requires authentication, whereas [`Http::get_webhook_with_token`] and
4480    /// [`Http::get_webhook_from_url`] do not.
4481    ///
4482    /// # Examples
4483    ///
4484    /// Retrieve a webhook by Id:
4485    ///
4486    /// ```rust,no_run
4487    /// # use serenity::http::Http;
4488    /// # use serenity::model::prelude::*;
4489    ///
4490    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
4491    /// # let http: Http = unimplemented!();
4492    /// let id = WebhookId::new(245037420704169985);
4493    /// let webhook = http.get_webhook(id).await?;
4494    /// # Ok(())
4495    /// # }
4496    /// ```
4497    pub async fn get_webhook(&self, webhook_id: WebhookId) -> Result<Webhook> {
4498        self.fire(Request {
4499            body: None,
4500            multipart: None,
4501            headers: None,
4502            method: LightMethod::Get,
4503            route: Route::Webhook {
4504                webhook_id,
4505            },
4506            params: None,
4507        })
4508        .await
4509    }
4510
4511    /// Retrieves a webhook given its Id and unique token.
4512    ///
4513    /// This method does _not_ require authentication.
4514    ///
4515    /// # Examples
4516    ///
4517    /// Retrieve a webhook by Id and its unique token:
4518    ///
4519    /// ```rust,no_run
4520    /// # use serenity::http::Http;
4521    /// # use serenity::model::prelude::*;
4522    /// #
4523    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
4524    /// # let http: Http = unimplemented!();
4525    /// let id = WebhookId::new(245037420704169985);
4526    /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
4527    ///
4528    /// let webhook = http.get_webhook_with_token(id, token).await?;
4529    /// # Ok(())
4530    /// # }
4531    /// ```
4532    pub async fn get_webhook_with_token(
4533        &self,
4534        webhook_id: WebhookId,
4535        token: &str,
4536    ) -> Result<Webhook> {
4537        self.fire(Request {
4538            body: None,
4539            multipart: None,
4540            headers: None,
4541            method: LightMethod::Get,
4542            route: Route::WebhookWithToken {
4543                webhook_id,
4544                token,
4545            },
4546            params: None,
4547        })
4548        .await
4549    }
4550
4551    /// Retrieves a webhook given its url.
4552    ///
4553    /// This method does _not_ require authentication
4554    ///
4555    /// # Examples
4556    ///
4557    /// Retrieve a webhook by url:
4558    ///
4559    /// ```rust,no_run
4560    /// # use serenity::http::Http;
4561    /// #
4562    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
4563    /// # let http: Http = unimplemented!();
4564    /// let url = "https://discord.com/api/webhooks/245037420704169985/ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
4565    /// let webhook = http.get_webhook_from_url(url).await?;
4566    /// # Ok(())
4567    /// # }
4568    /// ```
4569    #[cfg(feature = "utils")]
4570    pub async fn get_webhook_from_url(&self, url: &str) -> Result<Webhook> {
4571        let url = Url::parse(url).map_err(HttpError::Url)?;
4572        let (webhook_id, token) =
4573            crate::utils::parse_webhook(&url).ok_or(HttpError::InvalidWebhook)?;
4574        self.fire(Request {
4575            body: None,
4576            multipart: None,
4577            headers: None,
4578            method: LightMethod::Get,
4579            route: Route::WebhookWithToken {
4580                webhook_id,
4581                token,
4582            },
4583            params: None,
4584        })
4585        .await
4586    }
4587
4588    /// Kicks a member from a guild with a provided reason.
4589    pub async fn kick_member(
4590        &self,
4591        guild_id: GuildId,
4592        user_id: UserId,
4593        reason: Option<&str>,
4594    ) -> Result<()> {
4595        self.wind(204, Request {
4596            body: None,
4597            multipart: None,
4598            headers: reason.map(reason_into_header),
4599            method: LightMethod::Delete,
4600            route: Route::GuildMember {
4601                guild_id,
4602                user_id,
4603            },
4604            params: None,
4605        })
4606        .await
4607    }
4608
4609    /// Leaves a guild.
4610    pub async fn leave_guild(&self, guild_id: GuildId) -> Result<()> {
4611        self.wind(204, Request {
4612            body: None,
4613            multipart: None,
4614            headers: None,
4615            method: LightMethod::Delete,
4616            route: Route::UserMeGuild {
4617                guild_id,
4618            },
4619            params: None,
4620        })
4621        .await
4622    }
4623
4624    /// Sends a message to a channel.
4625    ///
4626    /// # Errors
4627    ///
4628    /// Returns an [`HttpError::UnsuccessfulRequest`] if the files are too large to send.
4629    pub async fn send_message(
4630        &self,
4631        channel_id: ChannelId,
4632        files: Vec<CreateAttachment>,
4633        map: &impl serde::Serialize,
4634    ) -> Result<Message> {
4635        let mut request = Request {
4636            body: None,
4637            multipart: None,
4638            headers: None,
4639            method: LightMethod::Post,
4640            route: Route::ChannelMessages {
4641                channel_id,
4642            },
4643            params: None,
4644        };
4645
4646        if files.is_empty() {
4647            request.body = Some(to_vec(map)?);
4648        } else {
4649            request.multipart = Some(Multipart {
4650                upload: MultipartUpload::Attachments(files.into_iter().collect()),
4651                payload_json: Some(to_string(map)?),
4652                fields: vec![],
4653            });
4654        }
4655
4656        self.fire(request).await
4657    }
4658
4659    /// Pins a message in a channel.
4660    pub async fn pin_message(
4661        &self,
4662        channel_id: ChannelId,
4663        message_id: MessageId,
4664        audit_log_reason: Option<&str>,
4665    ) -> Result<()> {
4666        self.wind(204, Request {
4667            body: None,
4668            multipart: None,
4669            headers: audit_log_reason.map(reason_into_header),
4670            method: LightMethod::Put,
4671            route: Route::ChannelPin {
4672                channel_id,
4673                message_id,
4674            },
4675            params: None,
4676        })
4677        .await
4678    }
4679
4680    /// Unbans a user from a guild.
4681    pub async fn remove_ban(
4682        &self,
4683        guild_id: GuildId,
4684        user_id: UserId,
4685        audit_log_reason: Option<&str>,
4686    ) -> Result<()> {
4687        self.wind(204, Request {
4688            body: None,
4689            multipart: None,
4690            headers: audit_log_reason.map(reason_into_header),
4691            method: LightMethod::Delete,
4692            route: Route::GuildBan {
4693                guild_id,
4694                user_id,
4695            },
4696            params: None,
4697        })
4698        .await
4699    }
4700
4701    /// Deletes a single [`Role`] from a [`Member`] in a [`Guild`].
4702    ///
4703    /// **Note**: Requires the [Manage Roles] permission and respect of role hierarchy.
4704    ///
4705    /// [Manage Roles]: Permissions::MANAGE_ROLES
4706    pub async fn remove_member_role(
4707        &self,
4708        guild_id: GuildId,
4709        user_id: UserId,
4710        role_id: RoleId,
4711        audit_log_reason: Option<&str>,
4712    ) -> Result<()> {
4713        self.wind(204, Request {
4714            body: None,
4715            multipart: None,
4716            headers: audit_log_reason.map(reason_into_header),
4717            method: LightMethod::Delete,
4718            route: Route::GuildMemberRole {
4719                guild_id,
4720                user_id,
4721                role_id,
4722            },
4723            params: None,
4724        })
4725        .await
4726    }
4727
4728    /// Returns a list of [`Member`]s in a [`Guild`] whose username or nickname starts with a
4729    /// provided string.
4730    pub async fn search_guild_members(
4731        &self,
4732        guild_id: GuildId,
4733        query: &str,
4734        limit: Option<u64>,
4735    ) -> Result<Vec<Member>> {
4736        let mut value: Value = self
4737            .fire(Request {
4738                body: None,
4739                multipart: None,
4740                headers: None,
4741                method: LightMethod::Get,
4742                route: Route::GuildMembersSearch {
4743                    guild_id,
4744                },
4745                params: Some(vec![
4746                    ("query", query.to_string()),
4747                    ("limit", limit.unwrap_or(constants::MEMBER_FETCH_LIMIT).to_string()),
4748                ]),
4749            })
4750            .await?;
4751
4752        if let Some(members) = value.as_array_mut() {
4753            for member in members {
4754                if let Some(map) = member.as_object_mut() {
4755                    map.insert("guild_id".to_string(), guild_id.get().into());
4756                }
4757            }
4758        }
4759
4760        from_value(value).map_err(From::from)
4761    }
4762
4763    /// Starts removing some members from a guild based on the last time they've been online.
4764    pub async fn start_guild_prune(
4765        &self,
4766        guild_id: GuildId,
4767        days: u8,
4768        audit_log_reason: Option<&str>,
4769    ) -> Result<GuildPrune> {
4770        self.fire(Request {
4771            body: None,
4772            multipart: None,
4773            headers: audit_log_reason.map(reason_into_header),
4774            method: LightMethod::Post,
4775            route: Route::GuildPrune {
4776                guild_id,
4777            },
4778            params: Some(vec![("days", days.to_string())]),
4779        })
4780        .await
4781    }
4782
4783    /// Starts syncing an integration with a guild.
4784    pub async fn start_integration_sync(
4785        &self,
4786        guild_id: GuildId,
4787        integration_id: IntegrationId,
4788    ) -> Result<()> {
4789        self.wind(204, Request {
4790            body: None,
4791            multipart: None,
4792            headers: None,
4793            method: LightMethod::Post,
4794            route: Route::GuildIntegrationSync {
4795                guild_id,
4796                integration_id,
4797            },
4798            params: None,
4799        })
4800        .await
4801    }
4802
4803    /// Starts typing in the specified [`Channel`] for an indefinite period of time.
4804    ///
4805    /// Returns [`Typing`] that is used to trigger the typing. [`Typing::stop`] must be called on
4806    /// the returned struct to stop typing. Note that on some clients, typing may persist for a few
4807    /// seconds after [`Typing::stop`] is called. Typing is also stopped when the struct is
4808    /// dropped.
4809    ///
4810    /// If a message is sent while typing is triggered, the user will stop typing for a brief
4811    /// period of time and then resume again until either [`Typing::stop`] is called or the struct
4812    /// is dropped.
4813    ///
4814    /// This should rarely be used for bots, although it is a good indicator that a long-running
4815    /// command is still being processed.
4816    ///
4817    /// ## Examples
4818    ///
4819    /// ```rust,no_run
4820    /// # use std::sync::Arc;
4821    /// # use serenity::http::{Http, Typing};
4822    /// # use serenity::Result;
4823    /// # use serenity::model::prelude::*;
4824    /// #
4825    /// # fn long_process() {}
4826    /// # fn main() {
4827    /// # let http: Arc<Http> = unimplemented!();
4828    /// // Initiate typing (assuming http is `Arc<Http>`)
4829    /// let channel_id = ChannelId::new(7);
4830    /// let typing = http.start_typing(channel_id);
4831    ///
4832    /// // Run some long-running process
4833    /// long_process();
4834    ///
4835    /// // Stop typing
4836    /// typing.stop();
4837    /// # }
4838    /// ```
4839    pub fn start_typing(self: &Arc<Self>, channel_id: ChannelId) -> Typing {
4840        Typing::start(Arc::clone(self), channel_id)
4841    }
4842
4843    /// Unpins a message from a channel.
4844    pub async fn unpin_message(
4845        &self,
4846        channel_id: ChannelId,
4847        message_id: MessageId,
4848        audit_log_reason: Option<&str>,
4849    ) -> Result<()> {
4850        self.wind(204, Request {
4851            body: None,
4852            multipart: None,
4853            headers: audit_log_reason.map(reason_into_header),
4854            method: LightMethod::Delete,
4855            route: Route::ChannelPin {
4856                channel_id,
4857                message_id,
4858            },
4859            params: None,
4860        })
4861        .await
4862    }
4863
4864    /// Fires off a request, deserializing the response reader via the given type bound.
4865    ///
4866    /// If you don't need to deserialize the response and want the response instance itself, use
4867    /// [`Self::request`].
4868    ///
4869    /// # Examples
4870    ///
4871    /// Create a new message and deserialize the response into a [`Message`]:
4872    ///
4873    /// ```rust,no_run
4874    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
4875    /// # use serenity::http::Http;
4876    /// #
4877    /// # let http: Http = unimplemented!();
4878    /// use serenity::{
4879    ///     http::{LightMethod, Request, Route},
4880    ///     model::prelude::*,
4881    /// };
4882    ///
4883    /// let bytes = vec![
4884    ///     // payload bytes here
4885    /// ];
4886    /// let channel_id = ChannelId::new(381880193700069377);
4887    /// let route = Route::ChannelMessages { channel_id };
4888    ///
4889    /// let mut request = Request::new(route, LightMethod::Post).body(Some(bytes));
4890    ///
4891    /// let message = http.fire::<Message>(request).await?;
4892    ///
4893    /// println!("Message content: {}", message.content);
4894    /// # Ok(())
4895    /// # }
4896    /// ```
4897    ///
4898    /// # Errors
4899    ///
4900    /// If there is an error, it will be either [`Error::Http`] or [`Error::Json`].
4901    pub async fn fire<T: DeserializeOwned>(&self, req: Request<'_>) -> Result<T> {
4902        let response = self.request(req).await?;
4903        decode_resp(response).await
4904    }
4905
4906    /// Performs a request, ratelimiting it if necessary.
4907    ///
4908    /// Returns the raw reqwest Response. Use [`Self::fire`] to deserialize the response into some
4909    /// type.
4910    ///
4911    /// # Examples
4912    ///
4913    /// Send a body of bytes over the create message endpoint:
4914    ///
4915    /// ```rust,no_run
4916    /// # use serenity::http::Http;
4917    /// # use serenity::model::prelude::*;
4918    /// #
4919    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
4920    /// # let http: Http = unimplemented!();
4921    /// use serenity::http::{LightMethod, Request, Route};
4922    ///
4923    /// let bytes = vec![
4924    ///     // payload bytes here
4925    /// ];
4926    /// let channel_id = ChannelId::new(381880193700069377);
4927    /// let route = Route::ChannelMessages { channel_id };
4928    ///
4929    /// let mut request = Request::new(route, LightMethod::Post).body(Some(bytes));
4930    ///
4931    /// let response = http.request(request).await?;
4932    ///
4933    /// println!("Response successful?: {}", response.status().is_success());
4934    /// # Ok(())
4935    /// # }
4936    /// ```
4937    #[instrument]
4938    pub async fn request(&self, req: Request<'_>) -> Result<ReqwestResponse> {
4939        let method = req.method.reqwest_method();
4940        let response = if let Some(ratelimiter) = &self.ratelimiter {
4941            ratelimiter.perform(req).await?
4942        } else {
4943            let request = req.build(&self.client, self.token(), self.proxy.as_deref())?.build()?;
4944            self.client.execute(request).await?
4945        };
4946
4947        if response.status().is_success() {
4948            Ok(response)
4949        } else {
4950            Err(Error::Http(HttpError::UnsuccessfulRequest(
4951                ErrorResponse::from_response(response, method).await,
4952            )))
4953        }
4954    }
4955
4956    /// Performs a request and then verifies that the response status code is equal to the expected
4957    /// value.
4958    ///
4959    /// This is a function that performs a light amount of work and returns an empty tuple, so it's
4960    /// called "self.wind" to denote that it's lightweight.
4961    pub(super) async fn wind(&self, expected: u16, req: Request<'_>) -> Result<()> {
4962        let route = req.route;
4963        let method = req.method.reqwest_method();
4964        let response = self.request(req).await?;
4965
4966        if response.status().is_success() {
4967            let response_status = response.status().as_u16();
4968            if response_status != expected {
4969                let route = route.path();
4970                warn!("Mismatched successful response status from {route}! Expected {expected} but got {response_status}");
4971            }
4972
4973            return Ok(());
4974        }
4975
4976        debug!("Unsuccessful response: {response:?}");
4977        Err(Error::Http(HttpError::UnsuccessfulRequest(
4978            ErrorResponse::from_response(response, method).await,
4979        )))
4980    }
4981}
4982
4983#[cfg(not(feature = "native_tls_backend"))]
4984fn configure_client_backend(builder: ClientBuilder) -> ClientBuilder {
4985    builder.use_rustls_tls()
4986}
4987
4988#[cfg(feature = "native_tls_backend")]
4989fn configure_client_backend(builder: ClientBuilder) -> ClientBuilder {
4990    builder.use_native_tls()
4991}
4992
4993impl AsRef<Http> for Http {
4994    fn as_ref(&self) -> &Http {
4995        self
4996    }
4997}