@@ -8,8 +8,16 @@ use ureq::{Agent, http};
88
99const BASE_URL : & str = "https://api.motherduck.com" ;
1010const TIMEOUT : Duration = Duration :: from_secs ( 10 ) ;
11- const USER_AGENT : & str = concat ! ( "dkdc-md-cli/" , env!( "CARGO_PKG_VERSION" ) ) ;
11+ const USER_AGENT_VALUE : & str = concat ! ( "dkdc-md-cli/" , env!( "CARGO_PKG_VERSION" ) ) ;
1212const SUCCESS_STATUS : std:: ops:: Range < u16 > = 200 ..300 ;
13+ const CONTENT_TYPE_JSON : & str = "application/json" ;
14+
15+ // API path segments
16+ const API_V1 : & str = "/v1" ;
17+ const USERS : & str = "users" ;
18+ const TOKENS : & str = "tokens" ;
19+ const INSTANCES : & str = "instances" ;
20+ const ACTIVE_ACCOUNTS : & str = "active_accounts" ;
1321
1422/// Characters that must be percent-encoded in a URL path segment.
1523const PATH_SEGMENT : & AsciiSet = & CONTROLS . add ( b' ' ) . add ( b'#' ) . add ( b'%' ) . add ( b'/' ) . add ( b'?' ) ;
@@ -18,6 +26,34 @@ fn encode_path(s: &str) -> String {
1826 utf8_percent_encode ( s, PATH_SEGMENT ) . to_string ( )
1927}
2028
29+ fn users_path ( ) -> String {
30+ format ! ( "{API_V1}/{USERS}" )
31+ }
32+
33+ fn user_path ( username : & str ) -> String {
34+ format ! ( "{API_V1}/{USERS}/{}" , encode_path( username) )
35+ }
36+
37+ fn user_tokens_path ( username : & str ) -> String {
38+ format ! ( "{API_V1}/{USERS}/{}/{TOKENS}" , encode_path( username) )
39+ }
40+
41+ fn user_token_path ( username : & str , token_id : & str ) -> String {
42+ format ! (
43+ "{API_V1}/{USERS}/{}/{TOKENS}/{}" ,
44+ encode_path( username) ,
45+ encode_path( token_id) ,
46+ )
47+ }
48+
49+ fn user_instances_path ( username : & str ) -> String {
50+ format ! ( "{API_V1}/{USERS}/{}/{INSTANCES}" , encode_path( username) )
51+ }
52+
53+ fn active_accounts_path ( ) -> String {
54+ format ! ( "{API_V1}/{ACTIVE_ACCOUNTS}" )
55+ }
56+
2157pub struct MotherduckClient {
2258 agent : Agent ,
2359 bearer : String ,
@@ -60,8 +96,8 @@ impl MotherduckClient {
6096 let resp = self
6197 . agent
6298 . get ( & url)
63- . header ( "Authorization" , & self . bearer )
64- . header ( "User-Agent" , USER_AGENT )
99+ . header ( http :: header :: AUTHORIZATION , & self . bearer )
100+ . header ( http :: header :: USER_AGENT , USER_AGENT_VALUE )
65101 . call ( )
66102 . context ( "request failed" ) ?;
67103 handle_response ( resp) . with_context ( || format ! ( "GET {path}" ) )
@@ -72,8 +108,8 @@ impl MotherduckClient {
72108 let resp = self
73109 . agent
74110 . delete ( & url)
75- . header ( "Authorization" , & self . bearer )
76- . header ( "User-Agent" , USER_AGENT )
111+ . header ( http :: header :: AUTHORIZATION , & self . bearer )
112+ . header ( http :: header :: USER_AGENT , USER_AGENT_VALUE )
77113 . call ( )
78114 . context ( "request failed" ) ?;
79115 handle_response ( resp) . with_context ( || format ! ( "DELETE {path}" ) )
@@ -85,9 +121,9 @@ impl MotherduckClient {
85121 let resp = self
86122 . agent
87123 . post ( & url)
88- . header ( "Authorization" , & self . bearer )
89- . header ( "User-Agent" , USER_AGENT )
90- . header ( "Content-Type" , "application/json" )
124+ . header ( http :: header :: AUTHORIZATION , & self . bearer )
125+ . header ( http :: header :: USER_AGENT , USER_AGENT_VALUE )
126+ . header ( http :: header :: CONTENT_TYPE , CONTENT_TYPE_JSON )
91127 . send ( & bytes)
92128 . context ( "request failed" ) ?;
93129 handle_response ( resp) . with_context ( || format ! ( "POST {path}" ) )
@@ -99,9 +135,9 @@ impl MotherduckClient {
99135 let resp = self
100136 . agent
101137 . put ( & url)
102- . header ( "Authorization" , & self . bearer )
103- . header ( "User-Agent" , USER_AGENT )
104- . header ( "Content-Type" , "application/json" )
138+ . header ( http :: header :: AUTHORIZATION , & self . bearer )
139+ . header ( http :: header :: USER_AGENT , USER_AGENT_VALUE )
140+ . header ( http :: header :: CONTENT_TYPE , CONTENT_TYPE_JSON )
105141 . send ( & bytes)
106142 . context ( "request failed" ) ?;
107143 handle_response ( resp) . with_context ( || format ! ( "PUT {path}" ) )
@@ -110,17 +146,17 @@ impl MotherduckClient {
110146 // -- Users --
111147
112148 pub fn create_user ( & self , username : & str ) -> Result < Value > {
113- self . post_json ( "/v1/users" , & json ! ( { "username" : username} ) )
149+ self . post_json ( & users_path ( ) , & json ! ( { "username" : username} ) )
114150 }
115151
116152 pub fn delete_user ( & self , username : & str ) -> Result < Value > {
117- self . delete ( & format ! ( "/v1/users/{}" , encode_path ( username) ) )
153+ self . delete ( & user_path ( username) )
118154 }
119155
120156 // -- Tokens --
121157
122158 pub fn list_tokens ( & self , username : & str ) -> Result < Value > {
123- self . get ( & format ! ( "/v1/users/{}/tokens" , encode_path ( username) ) )
159+ self . get ( & user_tokens_path ( username) )
124160 }
125161
126162 pub fn create_token (
@@ -131,7 +167,7 @@ impl MotherduckClient {
131167 token_type : Option < & str > ,
132168 ) -> Result < Value > {
133169 self . post_json (
134- & format ! ( "/v1/users/{}/tokens" , encode_path ( username) ) ,
170+ & user_tokens_path ( username) ,
135171 & CreateTokenRequest {
136172 name,
137173 ttl,
@@ -141,17 +177,13 @@ impl MotherduckClient {
141177 }
142178
143179 pub fn delete_token ( & self , username : & str , token_id : & str ) -> Result < Value > {
144- self . delete ( & format ! (
145- "/v1/users/{}/tokens/{}" ,
146- encode_path( username) ,
147- encode_path( token_id) ,
148- ) )
180+ self . delete ( & user_token_path ( username, token_id) )
149181 }
150182
151183 // -- Ducklings --
152184
153185 pub fn get_duckling_config ( & self , username : & str ) -> Result < Value > {
154- self . get ( & format ! ( "/v1/users/{}/instances" , encode_path ( username) ) )
186+ self . get ( & user_instances_path ( username) )
155187 }
156188
157189 pub fn set_duckling_config (
@@ -162,7 +194,7 @@ impl MotherduckClient {
162194 rs_flock_size : u32 ,
163195 ) -> Result < Value > {
164196 self . put_json (
165- & format ! ( "/v1/users/{}/instances" , encode_path ( username) ) ,
197+ & user_instances_path ( username) ,
166198 & json ! ( {
167199 "config" : {
168200 "read_write" : { "instance_size" : rw_size } ,
@@ -175,7 +207,7 @@ impl MotherduckClient {
175207 // -- Accounts --
176208
177209 pub fn list_active_accounts ( & self ) -> Result < Value > {
178- self . get ( "/v1/active_accounts" )
210+ self . get ( & active_accounts_path ( ) )
179211 }
180212}
181213
0 commit comments