Replies: 2 comments 1 reply
-
I turned this issue into a discussion it's not quite actionable as an issue yet. The reason for this is that I have difficulties to believe that the CLIs still compile, but yet are so fundamentally broken from the description about Thus I think what would help here is to see reference to the code that let you arrive at that conclusion.
That sounds about like I remember it. However, it's a tough topic as years passed since I last tried to do anything with it. It's not entirely clear to me which authentication flow the CLI is using these days, and if that works for every API similarly. Typically it will start a user-based authentication flow if no key is locally present. Ultimately, my role here can be advisory only, but if you dig in I am sure you will find what's wrong and eventually fix it, either locally or via PR, so either way, it should be good :). |
Beta Was this translation helpful? Give feedback.
-
I'm not intelligent enough to wade through the generator code, so I'm going to instead post my minimum working example for people that stumble across this in the future. The missing pieces of the puzzle for me were reqwest's bearer_auth() and query() functions for their Client Builder. More unwraps than I'd like, but you can make your own match cases if you want. This function returns a Vector containing (title: String, link: String) pairs for some query: use std::error::Error;
use hyper_rustls::{HttpsConnectorBuilder};
use serde_json::Value;
use yup_oauth2 as oauth2;
use yup_oauth2::{InstalledFlowAuthenticator, InstalledFlowReturnMethod};
pub async fn search_query(query: &str) -> Result<Vec<(String, String)>, Box<dyn Error>> {
let mut result_vec: Vec<(String, String)> = vec![]; // Tuples containing titles and links
// !!! the JSON file location obtained from Google Cloud Console, containing client_id/client_secret
let secret_file_path = "KEY_LOCATION_HERE";
let secret = oauth2::read_application_secret(secret_file_path).await?;
let scopes = &["https://www.googleapis.com/auth/cse"];
// honestly i have no idea what this does
let connector = HttpsConnectorBuilder::new().with_native_roots()
.https_or_http()
.enable_http1()
.build();
let client = hyper::Client::builder().build(connector);
let auth = InstalledFlowAuthenticator::with_client(
secret,
InstalledFlowReturnMethod::HTTPRedirect,
client.clone(),
).persist_tokens_to_disk("./TOKEN_CACHE_LOCATION_HERE") // !!! SOME LOCATION TO STORE YOUR TOKEN
.build()
.await?;
let token = auth.token(scopes).await.unwrap();
println!("Token: {:?}", &token);
// Obtained via creating a custom search engine
// https://developers.google.com/custom-search/docs/tutorial/creatingcse
let cse_id = "CSE_ID_HERE"; // !!! YOUR VALID CSE ID HERE
let token_string = token.token();
let mut final_token;
match token_string {
Some(token) => {
println!("Token: {}", &token);
final_token = token;
},
None => {
println!("Token is None");
return Err("Token is None".into());
}
}
let query = vec![("q", query), ("cx", cse_id)];
// Construct an HTTP client with a http authorization header
let client = reqwest::Client::builder().build()?
.get("https://www.googleapis.com/customsearch/v1")
.bearer_auth(final_token)
.query(&query)
.send().await?;
let response = client.text().await?;
let jsoned_response: Value = serde_json::from_str(&response)?;
jsoned_response.get("items").unwrap().as_array().unwrap().iter().for_each(|item| {
let title = item.get("title").unwrap().as_str().unwrap();
let link = item.get("link").unwrap().as_str().unwrap();
println!("Title: {}", title);
println!("Link: {}", link);
result_vec.push((title.to_string(), link.to_string()));
});
println!("{:?}", &result_vec);
Ok(result_vec)
} Feel free to close this discussion if you want. |
Beta Was this translation helpful? Give feedback.
-
For the customsearch1-cli issue, I've narrowed it down to the fact that in google-apis-rs/gen/customsearch1/src/api.rs, Engine::new() always calls _doit with the dry_run variable set to true.
Within the _doit function, there is a conditional that only returns Ok with the query result if dry_run is false.
I noticed that that this function returning Ok results in unreachable code, so the CLI will simply never return Ok, and never return a result.
Within customsearch1/lib.rs itself, I was under the impression that the only authorisation required was an OAuth access token, obtainable via the Google Cloud Console (https://console.cloud.google.com) and downloaded as a JSON, setting scopes, and then sending the request via an HTTPS Authorisation Request Header:
"After an application obtains an access token, it sends the token to a Google API in an HTTP Authorization request header."
However, calling CseListCall's doit() function results in a delegate api_key() call, and consequently a MissingAPIKey Error.
Am I doing this wrong?
Thanks for the help.
Beta Was this translation helpful? Give feedback.
All reactions