twilight_http/request/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
//! Typed request builders, [multipart form support], a [manual request builder]
//! for low-level request construction, and [audit log reason] support.
//!
//! # Request Builders
//!
//! Requests are created in the form of builders. These can be `await`ed to
//! receive a [`Response`]. Every route of Discord's API has its own builder:
//! creating a message is performed via the [`CreateMessage`] builder; updating
//! a guild is done via [`UpdateGuild`]; and so on. All typed request builders
//! are instantiated via the primary [`Client`]. When the library doesn't yet
//! support a new feature or fine-grained support is required, requests can be
//! manually built via [`RequestBuilder`].
//!
//! # Audit Log Reasons
//!
//! Audit log reasons can be added to supported requests via the
//! [`AuditLogReason`] trait:
//!
//! ```no_run
//! # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # use twilight_model::id::Id;
//! #
//! # let guild_id = Id::new(1);
//! # let user_id = Id::new(2);
//! use twilight_http::{client::Client, request::AuditLogReason};
//!
//! let client = Client::new(std::env::var("DISCORD_TOKEN")?);
//! client
//! .delete_ban(guild_id, user_id)
//! .reason("ban expired")
//! .await?;
//! # Ok(()) }
//! ```
//!
//! [`Client`]: crate::client::Client
//! [`CreateMessage`]: channel::message::CreateMessage
//! [`Response`]: crate::Response
//! [`UpdateGuild`]: guild::UpdateGuild
//! [audit log reason]: AuditLogReason
//! [manual request builder]: RequestBuilder
//! [multipart form support]: Form
pub mod application;
pub mod attachment;
pub mod channel;
pub mod guild;
pub mod poll;
pub mod scheduled_event;
pub mod sticker;
pub mod template;
pub mod user;
mod audit_reason;
mod base;
mod get_current_authorization_information;
mod get_gateway;
mod get_gateway_authed;
mod get_user_application;
mod get_voice_regions;
mod multipart;
mod try_into_request;
mod update_user_application;
pub use self::{
audit_reason::AuditLogReason,
base::{Request, RequestBuilder},
get_current_authorization_information::GetCurrentAuthorizationInformation,
get_gateway::GetGateway,
get_gateway_authed::GetGatewayAuthed,
get_user_application::GetUserApplicationInfo,
get_voice_regions::GetVoiceRegions,
multipart::Form,
try_into_request::TryIntoRequest,
update_user_application::UpdateCurrentUserApplication,
};
pub use twilight_http_ratelimiting::request::Method;
use crate::error::{Error, ErrorType};
use http::header::{HeaderName, HeaderValue};
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use serde::Serialize;
use std::iter;
/// Name of the audit log reason header.
const REASON_HEADER_NAME: &str = "x-audit-log-reason";
/// Type that either serializes to null or a value.
///
/// This is particularly useful when combined with an `Option` by allowing three
/// states via `Option<Nullable<T>>`: undefined, null, and T.
///
/// When the request value is `None` it can skip serialization, while if
/// `Nullable` is provided with `None` within it then it will serialize as
/// null. This mechanism is primarily used in patch requests.
#[derive(Serialize)]
struct Nullable<T>(Option<T>);
fn audit_header(reason: &str) -> Result<impl Iterator<Item = (HeaderName, HeaderValue)>, Error> {
let header_name = HeaderName::from_static(REASON_HEADER_NAME);
let encoded_reason = utf8_percent_encode(reason, NON_ALPHANUMERIC).to_string();
let header_value = HeaderValue::from_str(&encoded_reason).map_err(|e| Error {
kind: ErrorType::CreatingHeader {
name: encoded_reason,
},
source: Some(Box::new(e)),
})?;
Ok(iter::once((header_name, header_value)))
}