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#[cfg(feature = "clap")]
36#[allow(unused, reason = "not used in all templates, but required in some")]
37use ::{miette::IntoDiagnostic as _, qcs_api_client_common::clap_utils::JsonMaybeStdin};
38
39/// Serialize command-line arguments for [`check_client_application`]
40#[cfg(feature = "clap")]
41#[derive(Debug, clap::Args)]
42pub struct CheckClientApplicationClapParams {
43    pub check_client_application_request:
44        JsonMaybeStdin<crate::models::CheckClientApplicationRequest>,
45}
46
47#[cfg(feature = "clap")]
48impl CheckClientApplicationClapParams {
49    pub async fn execute(
50        self,
51        configuration: &configuration::Configuration,
52    ) -> Result<crate::models::CheckClientApplicationResponse, miette::Error> {
53        let request = self
54            .check_client_application_request
55            .into_inner()
56            .into_inner();
57
58        check_client_application(configuration, request)
59            .await
60            .into_diagnostic()
61    }
62}
63
64/// Serialize command-line arguments for [`get_client_application`]
65#[cfg(feature = "clap")]
66#[derive(Debug, clap::Args)]
67pub struct GetClientApplicationClapParams {
68    #[arg(long)]
69    pub client_application_name: String,
70}
71
72#[cfg(feature = "clap")]
73impl GetClientApplicationClapParams {
74    pub async fn execute(
75        self,
76        configuration: &configuration::Configuration,
77    ) -> Result<crate::models::ClientApplication, miette::Error> {
78        get_client_application(configuration, self.client_application_name.as_str())
79            .await
80            .into_diagnostic()
81    }
82}
83
84/// Serialize command-line arguments for [`list_client_applications`]
85#[cfg(feature = "clap")]
86#[derive(Debug, clap::Args)]
87pub struct ListClientApplicationsClapParams {}
88
89#[cfg(feature = "clap")]
90impl ListClientApplicationsClapParams {
91    pub async fn execute(
92        self,
93        configuration: &configuration::Configuration,
94    ) -> Result<crate::models::ListClientApplicationsResponse, miette::Error> {
95        list_client_applications(configuration)
96            .await
97            .into_diagnostic()
98    }
99}
100
101/// struct for typed errors of method [`check_client_application`]
102#[derive(Debug, Clone, Serialize, Deserialize)]
103#[serde(untagged)]
104pub enum CheckClientApplicationError {
105    Status404(crate::models::Error),
106    Status422(crate::models::Error),
107    UnknownValue(serde_json::Value),
108}
109
110/// struct for typed errors of method [`get_client_application`]
111#[derive(Debug, Clone, Serialize, Deserialize)]
112#[serde(untagged)]
113pub enum GetClientApplicationError {
114    Status404(crate::models::Error),
115    UnknownValue(serde_json::Value),
116}
117
118/// struct for typed errors of method [`list_client_applications`]
119#[derive(Debug, Clone, Serialize, Deserialize)]
120#[serde(untagged)]
121pub enum ListClientApplicationsError {
122    UnknownValue(serde_json::Value),
123}
124
125async fn check_client_application_inner(
126    configuration: &configuration::Configuration,
127    backoff: &mut ExponentialBackoff,
128    check_client_application_request: crate::models::CheckClientApplicationRequest,
129) -> Result<crate::models::CheckClientApplicationResponse, Error<CheckClientApplicationError>> {
130    let local_var_configuration = configuration;
131
132    let local_var_client = &local_var_configuration.client;
133
134    let local_var_uri_str = format!(
135        "{}/v1/clientApplications:check",
136        local_var_configuration.qcs_config.api_url()
137    );
138    let mut local_var_req_builder =
139        local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
140
141    #[cfg(feature = "tracing")]
142    {
143        // Ignore parsing errors if the URL is invalid for some reason.
144        // If it is invalid, it will turn up as an error later when actually making the request.
145        let local_var_do_tracing = local_var_uri_str
146            .parse::<::url::Url>()
147            .ok()
148            .is_none_or(|url| {
149                configuration
150                    .qcs_config
151                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
152            });
153
154        if local_var_do_tracing {
155            ::tracing::debug!(
156                url=%local_var_uri_str,
157                method="POST",
158                "making check_client_application request",
159            );
160        }
161    }
162
163    // Use the QCS Bearer token if a client OAuthSession is present,
164    // but do not require one when the security schema says it is optional.
165    {
166        use qcs_api_client_common::configuration::TokenError;
167
168        #[allow(
169            clippy::nonminimal_bool,
170            clippy::eq_op,
171            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
172        )]
173        let is_jwt_bearer_optional: bool = false;
174
175        let token = local_var_configuration
176            .qcs_config
177            .get_bearer_access_token()
178            .await;
179
180        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
181            // the client is configured without any OAuthSession, but this call does not require one.
182            #[cfg(feature = "tracing")]
183            tracing::debug!(
184                "No client credentials found, but this call does not require authentication."
185            );
186        } else {
187            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
188        }
189    }
190
191    local_var_req_builder = local_var_req_builder.json(&check_client_application_request);
192
193    let local_var_req = local_var_req_builder.build()?;
194    let local_var_resp = local_var_client.execute(local_var_req).await?;
195
196    let local_var_status = local_var_resp.status();
197
198    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
199        let local_var_content = local_var_resp.text().await?;
200        serde_json::from_str(&local_var_content).map_err(Error::from)
201    } else {
202        let local_var_retry_delay =
203            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
204        let local_var_content = local_var_resp.text().await?;
205        let local_var_entity: Option<CheckClientApplicationError> =
206            serde_json::from_str(&local_var_content).ok();
207        let local_var_error = ResponseContent {
208            status: local_var_status,
209            content: local_var_content,
210            entity: local_var_entity,
211            retry_delay: local_var_retry_delay,
212        };
213        Err(Error::ResponseError(local_var_error))
214    }
215}
216
217/// Check the requested client application version against the latest and minimum version.
218pub async fn check_client_application(
219    configuration: &configuration::Configuration,
220    check_client_application_request: crate::models::CheckClientApplicationRequest,
221) -> Result<crate::models::CheckClientApplicationResponse, Error<CheckClientApplicationError>> {
222    let mut backoff = configuration.backoff.clone();
223    let mut refreshed_credentials = false;
224    let method = reqwest::Method::POST;
225    loop {
226        let result = check_client_application_inner(
227            configuration,
228            &mut backoff,
229            check_client_application_request.clone(),
230        )
231        .await;
232
233        match result {
234            Ok(result) => return Ok(result),
235            Err(Error::ResponseError(response)) => {
236                if !refreshed_credentials
237                    && matches!(
238                        response.status,
239                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
240                    )
241                {
242                    configuration.qcs_config.refresh().await?;
243                    refreshed_credentials = true;
244                    continue;
245                } else if let Some(duration) = response.retry_delay {
246                    tokio::time::sleep(duration).await;
247                    continue;
248                }
249
250                return Err(Error::ResponseError(response));
251            }
252            Err(Error::Reqwest(error)) => {
253                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
254                    tokio::time::sleep(duration).await;
255                    continue;
256                }
257
258                return Err(Error::Reqwest(error));
259            }
260            Err(Error::Io(error)) => {
261                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
262                    tokio::time::sleep(duration).await;
263                    continue;
264                }
265
266                return Err(Error::Io(error));
267            }
268            Err(error) => return Err(error),
269        }
270    }
271}
272async fn get_client_application_inner(
273    configuration: &configuration::Configuration,
274    backoff: &mut ExponentialBackoff,
275    client_application_name: &str,
276) -> Result<crate::models::ClientApplication, Error<GetClientApplicationError>> {
277    let local_var_configuration = configuration;
278
279    let local_var_client = &local_var_configuration.client;
280
281    let local_var_uri_str = format!(
282        "{}/v1/clientApplications/{clientApplicationName}",
283        local_var_configuration.qcs_config.api_url(),
284        clientApplicationName = crate::apis::urlencode(client_application_name)
285    );
286    let mut local_var_req_builder =
287        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
288
289    #[cfg(feature = "tracing")]
290    {
291        // Ignore parsing errors if the URL is invalid for some reason.
292        // If it is invalid, it will turn up as an error later when actually making the request.
293        let local_var_do_tracing = local_var_uri_str
294            .parse::<::url::Url>()
295            .ok()
296            .is_none_or(|url| {
297                configuration
298                    .qcs_config
299                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
300            });
301
302        if local_var_do_tracing {
303            ::tracing::debug!(
304                url=%local_var_uri_str,
305                method="GET",
306                "making get_client_application request",
307            );
308        }
309    }
310
311    // Use the QCS Bearer token if a client OAuthSession is present,
312    // but do not require one when the security schema says it is optional.
313    {
314        use qcs_api_client_common::configuration::TokenError;
315
316        #[allow(
317            clippy::nonminimal_bool,
318            clippy::eq_op,
319            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
320        )]
321        let is_jwt_bearer_optional: bool = false;
322
323        let token = local_var_configuration
324            .qcs_config
325            .get_bearer_access_token()
326            .await;
327
328        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
329            // the client is configured without any OAuthSession, but this call does not require one.
330            #[cfg(feature = "tracing")]
331            tracing::debug!(
332                "No client credentials found, but this call does not require authentication."
333            );
334        } else {
335            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
336        }
337    }
338
339    let local_var_req = local_var_req_builder.build()?;
340    let local_var_resp = local_var_client.execute(local_var_req).await?;
341
342    let local_var_status = local_var_resp.status();
343
344    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
345        let local_var_content = local_var_resp.text().await?;
346        serde_json::from_str(&local_var_content).map_err(Error::from)
347    } else {
348        let local_var_retry_delay =
349            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
350        let local_var_content = local_var_resp.text().await?;
351        let local_var_entity: Option<GetClientApplicationError> =
352            serde_json::from_str(&local_var_content).ok();
353        let local_var_error = ResponseContent {
354            status: local_var_status,
355            content: local_var_content,
356            entity: local_var_entity,
357            retry_delay: local_var_retry_delay,
358        };
359        Err(Error::ResponseError(local_var_error))
360    }
361}
362
363/// Get details of a specific Rigetti system component along with its latest and minimum supported versions.
364pub async fn get_client_application(
365    configuration: &configuration::Configuration,
366    client_application_name: &str,
367) -> Result<crate::models::ClientApplication, Error<GetClientApplicationError>> {
368    let mut backoff = configuration.backoff.clone();
369    let mut refreshed_credentials = false;
370    let method = reqwest::Method::GET;
371    loop {
372        let result = get_client_application_inner(
373            configuration,
374            &mut backoff,
375            client_application_name.clone(),
376        )
377        .await;
378
379        match result {
380            Ok(result) => return Ok(result),
381            Err(Error::ResponseError(response)) => {
382                if !refreshed_credentials
383                    && matches!(
384                        response.status,
385                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
386                    )
387                {
388                    configuration.qcs_config.refresh().await?;
389                    refreshed_credentials = true;
390                    continue;
391                } else if let Some(duration) = response.retry_delay {
392                    tokio::time::sleep(duration).await;
393                    continue;
394                }
395
396                return Err(Error::ResponseError(response));
397            }
398            Err(Error::Reqwest(error)) => {
399                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
400                    tokio::time::sleep(duration).await;
401                    continue;
402                }
403
404                return Err(Error::Reqwest(error));
405            }
406            Err(Error::Io(error)) => {
407                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
408                    tokio::time::sleep(duration).await;
409                    continue;
410                }
411
412                return Err(Error::Io(error));
413            }
414            Err(error) => return Err(error),
415        }
416    }
417}
418async fn list_client_applications_inner(
419    configuration: &configuration::Configuration,
420    backoff: &mut ExponentialBackoff,
421) -> Result<crate::models::ListClientApplicationsResponse, Error<ListClientApplicationsError>> {
422    let local_var_configuration = configuration;
423
424    let local_var_client = &local_var_configuration.client;
425
426    let local_var_uri_str = format!(
427        "{}/v1/clientApplications",
428        local_var_configuration.qcs_config.api_url()
429    );
430    let mut local_var_req_builder =
431        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
432
433    #[cfg(feature = "tracing")]
434    {
435        // Ignore parsing errors if the URL is invalid for some reason.
436        // If it is invalid, it will turn up as an error later when actually making the request.
437        let local_var_do_tracing = local_var_uri_str
438            .parse::<::url::Url>()
439            .ok()
440            .is_none_or(|url| {
441                configuration
442                    .qcs_config
443                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
444            });
445
446        if local_var_do_tracing {
447            ::tracing::debug!(
448                url=%local_var_uri_str,
449                method="GET",
450                "making list_client_applications request",
451            );
452        }
453    }
454
455    // Use the QCS Bearer token if a client OAuthSession is present,
456    // but do not require one when the security schema says it is optional.
457    {
458        use qcs_api_client_common::configuration::TokenError;
459
460        #[allow(
461            clippy::nonminimal_bool,
462            clippy::eq_op,
463            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
464        )]
465        let is_jwt_bearer_optional: bool = false;
466
467        let token = local_var_configuration
468            .qcs_config
469            .get_bearer_access_token()
470            .await;
471
472        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
473            // the client is configured without any OAuthSession, but this call does not require one.
474            #[cfg(feature = "tracing")]
475            tracing::debug!(
476                "No client credentials found, but this call does not require authentication."
477            );
478        } else {
479            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
480        }
481    }
482
483    let local_var_req = local_var_req_builder.build()?;
484    let local_var_resp = local_var_client.execute(local_var_req).await?;
485
486    let local_var_status = local_var_resp.status();
487
488    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
489        let local_var_content = local_var_resp.text().await?;
490        serde_json::from_str(&local_var_content).map_err(Error::from)
491    } else {
492        let local_var_retry_delay =
493            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
494        let local_var_content = local_var_resp.text().await?;
495        let local_var_entity: Option<ListClientApplicationsError> =
496            serde_json::from_str(&local_var_content).ok();
497        let local_var_error = ResponseContent {
498            status: local_var_status,
499            content: local_var_content,
500            entity: local_var_entity,
501            retry_delay: local_var_retry_delay,
502        };
503        Err(Error::ResponseError(local_var_error))
504    }
505}
506
507/// List supported clients of Rigetti system components along with their latest and minimum supported versions.
508pub async fn list_client_applications(
509    configuration: &configuration::Configuration,
510) -> Result<crate::models::ListClientApplicationsResponse, Error<ListClientApplicationsError>> {
511    let mut backoff = configuration.backoff.clone();
512    let mut refreshed_credentials = false;
513    let method = reqwest::Method::GET;
514    loop {
515        let result = list_client_applications_inner(configuration, &mut backoff).await;
516
517        match result {
518            Ok(result) => return Ok(result),
519            Err(Error::ResponseError(response)) => {
520                if !refreshed_credentials
521                    && matches!(
522                        response.status,
523                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
524                    )
525                {
526                    configuration.qcs_config.refresh().await?;
527                    refreshed_credentials = true;
528                    continue;
529                } else if let Some(duration) = response.retry_delay {
530                    tokio::time::sleep(duration).await;
531                    continue;
532                }
533
534                return Err(Error::ResponseError(response));
535            }
536            Err(Error::Reqwest(error)) => {
537                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
538                    tokio::time::sleep(duration).await;
539                    continue;
540                }
541
542                return Err(Error::Reqwest(error));
543            }
544            Err(Error::Io(error)) => {
545                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
546                    tokio::time::sleep(duration).await;
547                    continue;
548                }
549
550                return Err(Error::Io(error));
551            }
552            Err(error) => return Err(error),
553        }
554    }
555}