diff --git a/Cargo.toml b/Cargo.toml index 6283a6e..6b3d394 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ reqwest = "0.8" serde = "1" serde_derive = "1" serde_json = "1" +serde_urlencoded = "0.5.3" url = "1" try_from = "0.2.2" toml = { version = "0.4.6", optional = true } diff --git a/examples/search.rs b/examples/search.rs index 7eb5c13..a918c58 100644 --- a/examples/search.rs +++ b/examples/search.rs @@ -9,9 +9,9 @@ use std::error; fn main() -> Result<(), Box> { let mastodon = register::get_mastodon_data()?; let input = register::read_line("Enter the term you'd like to search: ")?; - let result = mastodon.search_accounts(&input, None, true)?; + let result = mastodon.search(&input, false)?; - println!("{:#?}", result.initial_items); + println!("{:#?}", result); Ok(()) } diff --git a/src/errors.rs b/src/errors.rs index e03279b..7c82043 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -2,6 +2,7 @@ use std::{error, fmt, io::Error as IoError}; use reqwest::{Error as HttpError, StatusCode}; use serde_json::Error as SerdeError; +use serde_urlencoded::ser::Error as UrlEncodedError; #[cfg(feature = "toml")] use tomlcrate::de::Error as TomlDeError; #[cfg(feature = "toml")] @@ -20,6 +21,8 @@ pub enum Error { /// Error deserialising to json. Typically represents a breaking change in /// the Mastodon API Serde(SerdeError), + /// Error serializing to url-encoded string + UrlEncoded(UrlEncodedError), /// Error encountered in the HTTP backend while requesting a route. Http(HttpError), /// Wrapper around the `std::io::Error` struct. @@ -64,6 +67,7 @@ impl error::Error for Error { .or(e.error.as_ref().map(|i| &**i)) .unwrap_or("Unknown API Error"), Error::Serde(ref e) => e.description(), + Error::UrlEncoded(ref e) => e.description(), Error::Http(ref e) => e.description(), Error::Io(ref e) => e.description(), Error::Url(ref e) => e.description(), @@ -110,6 +114,7 @@ from! { HttpError, Http, IoError, Io, SerdeError, Serde, + UrlEncodedError, UrlEncoded, UrlError, Url, ApiError, Api, #[cfg(feature = "toml")] TomlSerError, TomlSer, @@ -121,6 +126,7 @@ mod tests { use super::*; use reqwest; use serde_json; + use serde_urlencoded; use std::io; macro_rules! assert_is { @@ -153,6 +159,13 @@ mod tests { assert_is!(err, Error::Serde(..)); } + #[test] + fn from_url_encoded_error() { + let err: UrlEncodedError = serde_urlencoded::ser::Error::Custom("error".into()); + let err: Error = Error::from(err); + assert_is!(err, Error::UrlEncoded(..)); + } + #[test] fn from_url_error() { let err: UrlError = UrlError::EmptyHost; diff --git a/src/lib.rs b/src/lib.rs index 79bb530..433c9ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,6 +49,7 @@ extern crate serde_json; extern crate chrono; extern crate reqwest; extern crate serde; +extern crate serde_urlencoded; extern crate try_from; extern crate url; @@ -185,7 +186,7 @@ impl MastodonClient for Mastodon { (post (domain: String,)) block_domain: "domain_blocks" => Empty, (post (id: &str,)) authorize_follow_request: "accounts/follow_requests/authorize" => Empty, (post (id: &str,)) reject_follow_request: "accounts/follow_requests/reject" => Empty, - (post (q: String, resolve: bool,)) search: "search" => SearchResult, + (get (q: &'a str, resolve: bool,)) search: "search" => SearchResult, (post (uri: Cow<'static, str>,)) follows: "follows" => Account, (post multipart (file: Cow<'static, str>,)) media: "media" => Attachment, (post) clear_notifications: "notifications/clear" => Empty, diff --git a/src/macros.rs b/src/macros.rs index 8188852..8f03449 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -94,6 +94,43 @@ macro_rules! route { route!{$($rest)*} }; + ((get ($($param:ident: $typ:ty,)*)) $name:ident: $url:expr => $ret:ty, $($rest:tt)*) => { + doc_comment! { + concat!( + "Equivalent to `/api/v1/", + $url, + "`\n# Errors\nIf `access_token` is not set." + ), + fn $name<'a>(&self, $($param: $typ,)*) -> Result<$ret> { + use serde_urlencoded; + + #[derive(Serialize)] + struct Data<'a> { + $( + $param: $typ, + )* + #[serde(skip)] + _marker: ::std::marker::PhantomData<&'a ()>, + } + + let qs_data = Data { + $( + $param: $param, + )* + _marker: ::std::marker::PhantomData, + }; + + let qs = serde_urlencoded::to_string(&qs_data)?; + + let url = format!(concat!("/api/v1/", $url, "?{}"), &qs); + + Ok(self.get(self.route(&url))?) + } + } + + route!{$($rest)*} + }; + (($method:ident ($($param:ident: $typ:ty,)*)) $name:ident: $url:expr => $ret:ty, $($rest:tt)*) => { doc_comment! { concat!( diff --git a/src/mastodon_client.rs b/src/mastodon_client.rs index 4440299..b33dace 100644 --- a/src/mastodon_client.rs +++ b/src/mastodon_client.rs @@ -91,8 +91,8 @@ pub trait MastodonClient { fn reject_follow_request(&self, id: &str) -> Result { unimplemented!("This method was not implemented"); } - /// POST /api/v1/search - fn search(&self, q: String, resolve: bool) -> Result { + /// GET /api/v1/search + fn search<'a>(&self, q: &'a str, resolve: bool) -> Result { unimplemented!("This method was not implemented"); } /// POST /api/v1/follows