11use super :: { Api , Result } ;
22use reqwest:: RequestBuilder ;
33use serde_json:: Value ;
4+ use std:: time:: Duration ;
5+
6+ static DEFAULT_USER_AGENT : & str = "api-podcast-rust" ;
47
58/// Client for accessing Listen Notes API.
69pub struct Client < ' a > {
710 /// HTTP client.
811 client : reqwest:: Client ,
912 /// API context.
1013 api : Api < ' a > ,
14+ /// User Agent Header for API calls.
15+ user_agent : & ' a str ,
16+ }
17+
18+ #[ derive( Debug ) ]
19+ /// Response and request context for API call.
20+ pub struct Response {
21+ /// HTTP response.
22+ pub response : reqwest:: Response ,
23+ /// HTTP request that resulted in this response.
24+ pub request : reqwest:: Request ,
25+ }
26+
27+ impl Response {
28+ /// Get JSON data object from [`reqwest::Response`].
29+ pub async fn json ( self ) -> Result < Value > {
30+ Ok ( self . response . json ( ) . await ?)
31+ }
1132}
1233
1334impl Client < ' _ > {
1435 /// Creates new Listen API Client.
1536 ///
37+ /// Uses default HTTP client with 30 second timeouts.
38+ ///
1639 /// To access production API:
1740 /// ```
18- /// let client = podcast_api::Client::new(reqwest::Client::new(), Some("YOUR-API-KEY"));
41+ /// let client = podcast_api::Client::new(Some("YOUR-API-KEY"));
1942 /// ```
2043 /// To access mock API:
2144 /// ```
22- /// let client = podcast_api::Client::new(reqwest::Client::new(), None);
45+ /// let client = podcast_api::Client::new(None);
2346 /// ```
24- pub fn new ( client : reqwest:: Client , id : Option < & str > ) -> Client {
47+ pub fn new ( id : Option < & str > ) -> Client {
48+ Client {
49+ client : reqwest:: ClientBuilder :: new ( )
50+ . timeout ( Duration :: from_secs ( 30 ) )
51+ . build ( )
52+ . expect ( "Client::new()" ) ,
53+ api : if let Some ( id) = id {
54+ Api :: Production ( id)
55+ } else {
56+ Api :: Mock
57+ } ,
58+ user_agent : DEFAULT_USER_AGENT ,
59+ }
60+ }
61+
62+ /// Creates new Listen API Client with user provided HTTP Client.
63+ pub fn new_custom < ' a > (
64+ client : reqwest:: Client ,
65+ id : Option < & ' a str > ,
66+ user_agent : Option < & ' a str > ,
67+ ) -> Client < ' a > {
2568 Client {
2669 client,
2770 api : if let Some ( id) = id {
2871 Api :: Production ( id)
2972 } else {
3073 Api :: Mock
3174 } ,
75+ user_agent : if let Some ( user_agent) = user_agent {
76+ user_agent
77+ } else {
78+ DEFAULT_USER_AGENT
79+ } ,
3280 }
3381 }
3482
3583 /// Calls [`GET /search`](https://www.listennotes.com/api/docs/#get-api-v2-search) with supplied parameters.
36- pub async fn search ( & self , parameters : & Value ) -> Result < Value > {
84+ pub async fn search ( & self , parameters : & Value ) -> Result < Response > {
3785 self . get ( "search" , parameters) . await
3886 }
3987
4088 /// Calls [`GET /typeahead`](https://www.listennotes.com/api/docs/#get-api-v2-typeahead) with supplied parameters.
41- pub async fn typeahead ( & self , parameters : & Value ) -> Result < Value > {
89+ pub async fn typeahead ( & self , parameters : & Value ) -> Result < Response > {
4290 self . get ( "typeahead" , parameters) . await
4391 }
4492
4593 /// Calls [`GET /best_podcasts`](https://www.listennotes.com/api/docs/#get-api-v2-best_podcasts) with supplied parameters.
46- pub async fn fetch_best_podcasts ( & self , parameters : & Value ) -> Result < Value > {
94+ pub async fn fetch_best_podcasts ( & self , parameters : & Value ) -> Result < Response > {
4795 self . get ( "best_podcasts" , parameters) . await
4896 }
4997
5098 /// Calls [`GET /podcasts/{id}`](https://www.listennotes.com/api/docs/#get-api-v2-podcasts-id) with supplied parameters.
51- pub async fn fetch_podcast_by_id ( & self , id : & str , parameters : & Value ) -> Result < Value > {
99+ pub async fn fetch_podcast_by_id ( & self , id : & str , parameters : & Value ) -> Result < Response > {
52100 self . get ( & format ! ( "podcasts/{}" , id) , parameters) . await
53101 }
54102
55103 /// Calls [`POST /podcasts`](https://www.listennotes.com/api/docs/#post-api-v2-podcasts) with supplied parameters.
56- pub async fn batch_fetch_podcasts ( & self , parameters : & Value ) -> Result < Value > {
104+ pub async fn batch_fetch_podcasts ( & self , parameters : & Value ) -> Result < Response > {
57105 self . post ( "podcasts" , parameters) . await
58106 }
59107
60108 /// Calls [`GET /episodes/{id}`](https://www.listennotes.com/api/docs/#get-api-v2-episodes-id) with supplied parameters.
61- pub async fn fetch_episode_by_id ( & self , id : & str , parameters : & Value ) -> Result < Value > {
109+ pub async fn fetch_episode_by_id ( & self , id : & str , parameters : & Value ) -> Result < Response > {
62110 self . get ( & format ! ( "episodes/{}" , id) , parameters) . await
63111 }
64112
65113 /// Calls [`POST /episodes`](https://www.listennotes.com/api/docs/#post-api-v2-episodes) with supplied parameters.
66- pub async fn batch_fetch_episodes ( & self , parameters : & Value ) -> Result < Value > {
114+ pub async fn batch_fetch_episodes ( & self , parameters : & Value ) -> Result < Response > {
67115 self . post ( "episodes" , parameters) . await
68116 }
69117
70- async fn get ( & self , endpoint : & str , parameters : & Value ) -> Result < Value > {
118+ async fn get ( & self , endpoint : & str , parameters : & Value ) -> Result < Response > {
71119 let request = self
72120 . client
73121 . get ( format ! ( "{}/{}" , self . api. url( ) , endpoint) )
@@ -76,7 +124,7 @@ impl Client<'_> {
76124 Ok ( self . request ( request) . await ?)
77125 }
78126
79- async fn post ( & self , endpoint : & str , parameters : & Value ) -> Result < Value > {
127+ async fn post ( & self , endpoint : & str , parameters : & Value ) -> Result < Response > {
80128 let request = self
81129 . client
82130 . post ( format ! ( "{}/{}" , self . api. url( ) , endpoint) )
@@ -86,16 +134,19 @@ impl Client<'_> {
86134 Ok ( self . request ( request) . await ?)
87135 }
88136
89- async fn request ( & self , request : RequestBuilder ) -> Result < Value > {
90- Ok ( if let Api :: Production ( key) = self . api {
137+ async fn request ( & self , request : RequestBuilder ) -> Result < Response > {
138+ let request = if let Api :: Production ( key) = self . api {
91139 request. header ( "X-ListenAPI-Key" , key)
92140 } else {
93141 request
94142 }
95- . send ( )
96- . await ?
97- . json ( )
98- . await ?)
143+ . header ( "User-Agent" , self . user_agent )
144+ . build ( ) ?;
145+
146+ Ok ( Response {
147+ response : self . client . execute ( request. try_clone ( ) . expect ( "Error can remain unhandled because we're not using streams, which are the try_clone fail condition" ) ) . await ?,
148+ request,
149+ } )
99150 }
100151
101152 fn urlencoded_from_json ( json : & Value ) -> String {
0 commit comments