Skip to main content

serenity/http/
client.rs

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