qcs_api_client_openapi/apis/
client_applications_api.rs

1// Copyright 2022 Rigetti Computing
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/*
16 * Rigetti QCS API
17 *
18 * # Introduction  This is the documentation for the Rigetti QCS HTTP API.  You can find out more about Rigetti at [https://rigetti.com](https://rigetti.com), and also interact with QCS via the web at [https://qcs.rigetti.com](https://qcs.rigetti.com).  This API is documented in **OpenAPI format** and so is compatible with the dozens of language-specific client generators available [here](https://github.com/OpenAPITools/openapi-generator) and elsewhere on the web.  # Principles  This API follows REST design principles where appropriate, and otherwise an HTTP RPC paradigm. We adhere to the Google [API Improvement Proposals](https://google.aip.dev/general) where reasonable to provide a consistent, intuitive developer experience. HTTP response codes match their specifications, and error messages fit a common format.  # Authentication  All access to the QCS API requires OAuth2 authentication provided by Okta. You can request access [here](https://www.rigetti.com/get-quantum). Once you have a user account, you can download your access token from QCS [here](https://qcs.rigetti.com/auth/token).   That access token is valid for 24 hours after issuance. The value of `access_token` within the JSON file is the token used for authentication (don't use the entire JSON file).  Authenticate requests using the `Authorization` header and a `Bearer` prefix:  ``` curl --header \"Authorization: Bearer eyJraW...Iow\" ```  # Quantum Processor Access  Access to the quantum processors themselves is not yet provided directly by this HTTP API, but is instead performed over ZeroMQ/[rpcq](https://github.com/rigetti/rpcq). Until that changes, we suggest using [pyquil](https://github.com/rigetti/pyquil) to build and execute quantum programs via the Legacy API.  # Legacy API  Our legacy HTTP API remains accessible at https://forest-server.qcs.rigetti.com, and it shares a source of truth with this API's services. You can use either service with the same user account and means of authentication. We strongly recommend using the API documented here, as the legacy API is on the path to deprecation.
19 *
20 * The version of the OpenAPI document: 2020-07-31
21 * Contact: support@rigetti.com
22 * Generated by: https://openapi-generator.tech
23 */
24
25use super::{configuration, Error};
26use crate::apis::ResponseContent;
27use ::qcs_api_client_common::backoff::{
28    duration_from_io_error, duration_from_reqwest_error, duration_from_response, ExponentialBackoff,
29};
30#[cfg(feature = "tracing")]
31use qcs_api_client_common::configuration::tokens::TokenRefresher;
32use reqwest::StatusCode;
33use serde::{Deserialize, Serialize};
34
35/// Serialize command-line arguments for [`check_client_application`]
36#[cfg(feature = "clap")]
37#[derive(Debug, clap::Args)]
38pub struct CheckClientApplicationClapParams {
39    pub check_client_application_request:
40        crate::clap_utils::JsonMaybeStdin<crate::models::CheckClientApplicationRequest>,
41}
42
43#[cfg(feature = "clap")]
44impl CheckClientApplicationClapParams {
45    pub async fn execute(
46        self,
47        configuration: &configuration::Configuration,
48    ) -> Result<crate::models::CheckClientApplicationResponse, anyhow::Error> {
49        let request = self
50            .check_client_application_request
51            .into_inner()
52            .into_inner();
53
54        check_client_application(configuration, request)
55            .await
56            .map_err(Into::into)
57    }
58}
59
60/// Serialize command-line arguments for [`get_client_application`]
61#[cfg(feature = "clap")]
62#[derive(Debug, clap::Args)]
63pub struct GetClientApplicationClapParams {
64    #[arg(long)]
65    pub client_application_name: String,
66}
67
68#[cfg(feature = "clap")]
69impl GetClientApplicationClapParams {
70    pub async fn execute(
71        self,
72        configuration: &configuration::Configuration,
73    ) -> Result<crate::models::ClientApplication, anyhow::Error> {
74        get_client_application(configuration, self.client_application_name.as_str())
75            .await
76            .map_err(Into::into)
77    }
78}
79
80/// Serialize command-line arguments for [`list_client_applications`]
81#[cfg(feature = "clap")]
82#[derive(Debug, clap::Args)]
83pub struct ListClientApplicationsClapParams {}
84
85#[cfg(feature = "clap")]
86impl ListClientApplicationsClapParams {
87    pub async fn execute(
88        self,
89        configuration: &configuration::Configuration,
90    ) -> Result<crate::models::ListClientApplicationsResponse, anyhow::Error> {
91        list_client_applications(configuration)
92            .await
93            .map_err(Into::into)
94    }
95}
96
97/// struct for typed errors of method [`check_client_application`]
98#[derive(Debug, Clone, Serialize, Deserialize)]
99#[serde(untagged)]
100pub enum CheckClientApplicationError {
101    Status404(crate::models::Error),
102    Status422(crate::models::Error),
103    UnknownValue(serde_json::Value),
104}
105
106/// struct for typed errors of method [`get_client_application`]
107#[derive(Debug, Clone, Serialize, Deserialize)]
108#[serde(untagged)]
109pub enum GetClientApplicationError {
110    Status404(crate::models::Error),
111    UnknownValue(serde_json::Value),
112}
113
114/// struct for typed errors of method [`list_client_applications`]
115#[derive(Debug, Clone, Serialize, Deserialize)]
116#[serde(untagged)]
117pub enum ListClientApplicationsError {
118    UnknownValue(serde_json::Value),
119}
120
121async fn check_client_application_inner(
122    configuration: &configuration::Configuration,
123    backoff: &mut ExponentialBackoff,
124    check_client_application_request: crate::models::CheckClientApplicationRequest,
125) -> Result<crate::models::CheckClientApplicationResponse, Error<CheckClientApplicationError>> {
126    let local_var_configuration = configuration;
127
128    let local_var_client = &local_var_configuration.client;
129
130    let local_var_uri_str = format!(
131        "{}/v1/clientApplications:check",
132        local_var_configuration.qcs_config.api_url()
133    );
134    let mut local_var_req_builder =
135        local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
136
137    #[cfg(feature = "tracing")]
138    {
139        // Ignore parsing errors if the URL is invalid for some reason.
140        // If it is invalid, it will turn up as an error later when actually making the request.
141        let local_var_do_tracing = local_var_uri_str
142            .parse::<::url::Url>()
143            .ok()
144            .is_none_or(|url| {
145                configuration
146                    .qcs_config
147                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
148            });
149
150        if local_var_do_tracing {
151            ::tracing::debug!(
152                url=%local_var_uri_str,
153                method="POST",
154                "making check_client_application request",
155            );
156        }
157    }
158
159    // Use the QCS Bearer token if a client OAuthSession is present,
160    // but do not require one when the security schema says it is optional.
161    {
162        use qcs_api_client_common::configuration::TokenError;
163
164        #[allow(
165            clippy::nonminimal_bool,
166            clippy::eq_op,
167            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
168        )]
169        let is_jwt_bearer_optional: bool = false;
170
171        let token = local_var_configuration
172            .qcs_config
173            .get_bearer_access_token()
174            .await;
175
176        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
177            // the client is configured without any OAuthSession, but this call does not require one.
178            #[cfg(feature = "tracing")]
179            tracing::debug!(
180                "No client credentials found, but this call does not require authentication."
181            );
182        } else {
183            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
184        }
185    }
186
187    local_var_req_builder = local_var_req_builder.json(&check_client_application_request);
188
189    let local_var_req = local_var_req_builder.build()?;
190    let local_var_resp = local_var_client.execute(local_var_req).await?;
191
192    let local_var_status = local_var_resp.status();
193
194    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
195        let local_var_content = local_var_resp.text().await?;
196        serde_json::from_str(&local_var_content).map_err(Error::from)
197    } else {
198        let local_var_retry_delay =
199            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
200        let local_var_content = local_var_resp.text().await?;
201        let local_var_entity: Option<CheckClientApplicationError> =
202            serde_json::from_str(&local_var_content).ok();
203        let local_var_error = ResponseContent {
204            status: local_var_status,
205            content: local_var_content,
206            entity: local_var_entity,
207            retry_delay: local_var_retry_delay,
208        };
209        Err(Error::ResponseError(local_var_error))
210    }
211}
212
213/// Check the requested client application version against the latest and minimum version.
214pub async fn check_client_application(
215    configuration: &configuration::Configuration,
216    check_client_application_request: crate::models::CheckClientApplicationRequest,
217) -> Result<crate::models::CheckClientApplicationResponse, Error<CheckClientApplicationError>> {
218    let mut backoff = configuration.backoff.clone();
219    let mut refreshed_credentials = false;
220    let method = reqwest::Method::POST;
221    loop {
222        let result = check_client_application_inner(
223            configuration,
224            &mut backoff,
225            check_client_application_request.clone(),
226        )
227        .await;
228
229        match result {
230            Ok(result) => return Ok(result),
231            Err(Error::ResponseError(response)) => {
232                if !refreshed_credentials
233                    && matches!(
234                        response.status,
235                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
236                    )
237                {
238                    configuration.qcs_config.refresh().await?;
239                    refreshed_credentials = true;
240                    continue;
241                } else if let Some(duration) = response.retry_delay {
242                    tokio::time::sleep(duration).await;
243                    continue;
244                }
245
246                return Err(Error::ResponseError(response));
247            }
248            Err(Error::Reqwest(error)) => {
249                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
250                    tokio::time::sleep(duration).await;
251                    continue;
252                }
253
254                return Err(Error::Reqwest(error));
255            }
256            Err(Error::Io(error)) => {
257                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
258                    tokio::time::sleep(duration).await;
259                    continue;
260                }
261
262                return Err(Error::Io(error));
263            }
264            Err(error) => return Err(error),
265        }
266    }
267}
268async fn get_client_application_inner(
269    configuration: &configuration::Configuration,
270    backoff: &mut ExponentialBackoff,
271    client_application_name: &str,
272) -> Result<crate::models::ClientApplication, Error<GetClientApplicationError>> {
273    let local_var_configuration = configuration;
274
275    let local_var_client = &local_var_configuration.client;
276
277    let local_var_uri_str = format!(
278        "{}/v1/clientApplications/{clientApplicationName}",
279        local_var_configuration.qcs_config.api_url(),
280        clientApplicationName = crate::apis::urlencode(client_application_name)
281    );
282    let mut local_var_req_builder =
283        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
284
285    #[cfg(feature = "tracing")]
286    {
287        // Ignore parsing errors if the URL is invalid for some reason.
288        // If it is invalid, it will turn up as an error later when actually making the request.
289        let local_var_do_tracing = local_var_uri_str
290            .parse::<::url::Url>()
291            .ok()
292            .is_none_or(|url| {
293                configuration
294                    .qcs_config
295                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
296            });
297
298        if local_var_do_tracing {
299            ::tracing::debug!(
300                url=%local_var_uri_str,
301                method="GET",
302                "making get_client_application request",
303            );
304        }
305    }
306
307    // Use the QCS Bearer token if a client OAuthSession is present,
308    // but do not require one when the security schema says it is optional.
309    {
310        use qcs_api_client_common::configuration::TokenError;
311
312        #[allow(
313            clippy::nonminimal_bool,
314            clippy::eq_op,
315            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
316        )]
317        let is_jwt_bearer_optional: bool = false;
318
319        let token = local_var_configuration
320            .qcs_config
321            .get_bearer_access_token()
322            .await;
323
324        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
325            // the client is configured without any OAuthSession, but this call does not require one.
326            #[cfg(feature = "tracing")]
327            tracing::debug!(
328                "No client credentials found, but this call does not require authentication."
329            );
330        } else {
331            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
332        }
333    }
334
335    let local_var_req = local_var_req_builder.build()?;
336    let local_var_resp = local_var_client.execute(local_var_req).await?;
337
338    let local_var_status = local_var_resp.status();
339
340    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
341        let local_var_content = local_var_resp.text().await?;
342        serde_json::from_str(&local_var_content).map_err(Error::from)
343    } else {
344        let local_var_retry_delay =
345            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
346        let local_var_content = local_var_resp.text().await?;
347        let local_var_entity: Option<GetClientApplicationError> =
348            serde_json::from_str(&local_var_content).ok();
349        let local_var_error = ResponseContent {
350            status: local_var_status,
351            content: local_var_content,
352            entity: local_var_entity,
353            retry_delay: local_var_retry_delay,
354        };
355        Err(Error::ResponseError(local_var_error))
356    }
357}
358
359/// Get details of a specific Rigetti system component along with its latest and minimum supported versions.
360pub async fn get_client_application(
361    configuration: &configuration::Configuration,
362    client_application_name: &str,
363) -> Result<crate::models::ClientApplication, Error<GetClientApplicationError>> {
364    let mut backoff = configuration.backoff.clone();
365    let mut refreshed_credentials = false;
366    let method = reqwest::Method::GET;
367    loop {
368        let result = get_client_application_inner(
369            configuration,
370            &mut backoff,
371            client_application_name.clone(),
372        )
373        .await;
374
375        match result {
376            Ok(result) => return Ok(result),
377            Err(Error::ResponseError(response)) => {
378                if !refreshed_credentials
379                    && matches!(
380                        response.status,
381                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
382                    )
383                {
384                    configuration.qcs_config.refresh().await?;
385                    refreshed_credentials = true;
386                    continue;
387                } else if let Some(duration) = response.retry_delay {
388                    tokio::time::sleep(duration).await;
389                    continue;
390                }
391
392                return Err(Error::ResponseError(response));
393            }
394            Err(Error::Reqwest(error)) => {
395                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
396                    tokio::time::sleep(duration).await;
397                    continue;
398                }
399
400                return Err(Error::Reqwest(error));
401            }
402            Err(Error::Io(error)) => {
403                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
404                    tokio::time::sleep(duration).await;
405                    continue;
406                }
407
408                return Err(Error::Io(error));
409            }
410            Err(error) => return Err(error),
411        }
412    }
413}
414async fn list_client_applications_inner(
415    configuration: &configuration::Configuration,
416    backoff: &mut ExponentialBackoff,
417) -> Result<crate::models::ListClientApplicationsResponse, Error<ListClientApplicationsError>> {
418    let local_var_configuration = configuration;
419
420    let local_var_client = &local_var_configuration.client;
421
422    let local_var_uri_str = format!(
423        "{}/v1/clientApplications",
424        local_var_configuration.qcs_config.api_url()
425    );
426    let mut local_var_req_builder =
427        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
428
429    #[cfg(feature = "tracing")]
430    {
431        // Ignore parsing errors if the URL is invalid for some reason.
432        // If it is invalid, it will turn up as an error later when actually making the request.
433        let local_var_do_tracing = local_var_uri_str
434            .parse::<::url::Url>()
435            .ok()
436            .is_none_or(|url| {
437                configuration
438                    .qcs_config
439                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
440            });
441
442        if local_var_do_tracing {
443            ::tracing::debug!(
444                url=%local_var_uri_str,
445                method="GET",
446                "making list_client_applications request",
447            );
448        }
449    }
450
451    // Use the QCS Bearer token if a client OAuthSession is present,
452    // but do not require one when the security schema says it is optional.
453    {
454        use qcs_api_client_common::configuration::TokenError;
455
456        #[allow(
457            clippy::nonminimal_bool,
458            clippy::eq_op,
459            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
460        )]
461        let is_jwt_bearer_optional: bool = false;
462
463        let token = local_var_configuration
464            .qcs_config
465            .get_bearer_access_token()
466            .await;
467
468        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
469            // the client is configured without any OAuthSession, but this call does not require one.
470            #[cfg(feature = "tracing")]
471            tracing::debug!(
472                "No client credentials found, but this call does not require authentication."
473            );
474        } else {
475            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
476        }
477    }
478
479    let local_var_req = local_var_req_builder.build()?;
480    let local_var_resp = local_var_client.execute(local_var_req).await?;
481
482    let local_var_status = local_var_resp.status();
483
484    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
485        let local_var_content = local_var_resp.text().await?;
486        serde_json::from_str(&local_var_content).map_err(Error::from)
487    } else {
488        let local_var_retry_delay =
489            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
490        let local_var_content = local_var_resp.text().await?;
491        let local_var_entity: Option<ListClientApplicationsError> =
492            serde_json::from_str(&local_var_content).ok();
493        let local_var_error = ResponseContent {
494            status: local_var_status,
495            content: local_var_content,
496            entity: local_var_entity,
497            retry_delay: local_var_retry_delay,
498        };
499        Err(Error::ResponseError(local_var_error))
500    }
501}
502
503/// List supported clients of Rigetti system components along with their latest and minimum supported versions.
504pub async fn list_client_applications(
505    configuration: &configuration::Configuration,
506) -> Result<crate::models::ListClientApplicationsResponse, Error<ListClientApplicationsError>> {
507    let mut backoff = configuration.backoff.clone();
508    let mut refreshed_credentials = false;
509    let method = reqwest::Method::GET;
510    loop {
511        let result = list_client_applications_inner(configuration, &mut backoff).await;
512
513        match result {
514            Ok(result) => return Ok(result),
515            Err(Error::ResponseError(response)) => {
516                if !refreshed_credentials
517                    && matches!(
518                        response.status,
519                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
520                    )
521                {
522                    configuration.qcs_config.refresh().await?;
523                    refreshed_credentials = true;
524                    continue;
525                } else if let Some(duration) = response.retry_delay {
526                    tokio::time::sleep(duration).await;
527                    continue;
528                }
529
530                return Err(Error::ResponseError(response));
531            }
532            Err(Error::Reqwest(error)) => {
533                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
534                    tokio::time::sleep(duration).await;
535                    continue;
536                }
537
538                return Err(Error::Reqwest(error));
539            }
540            Err(Error::Io(error)) => {
541                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
542                    tokio::time::sleep(duration).await;
543                    continue;
544                }
545
546                return Err(Error::Io(error));
547            }
548            Err(error) => return Err(error),
549        }
550    }
551}