Skip to main content

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, ContentType, Error};
26use crate::{apis::ResponseContent, models};
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<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<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<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(models::Error),
106    Status422(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(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<models::CheckClientApplicationResponse, Error<CheckClientApplicationError>> {
130    let local_var_configuration = configuration;
131    // add a prefix to parameters to efficiently prevent name collisions
132    let p_body_check_client_application_request = check_client_application_request;
133
134    let local_var_client = &local_var_configuration.client;
135
136    let local_var_uri_str = format!(
137        "{}/v1/clientApplications:check",
138        local_var_configuration.qcs_config.api_url()
139    );
140    let mut local_var_req_builder =
141        local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
142
143    #[cfg(feature = "tracing")]
144    {
145        // Ignore parsing errors if the URL is invalid for some reason.
146        // If it is invalid, it will turn up as an error later when actually making the request.
147        let local_var_do_tracing = local_var_uri_str
148            .parse::<::url::Url>()
149            .ok()
150            .is_none_or(|url| {
151                configuration
152                    .qcs_config
153                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
154            });
155
156        if local_var_do_tracing {
157            ::tracing::debug!(
158                url=%local_var_uri_str,
159                method="POST",
160                "making check_client_application request",
161            );
162        }
163    }
164
165    // Use the QCS Bearer token if a client OAuthSession is present,
166    // but do not require one when the security schema says it is optional.
167    {
168        use qcs_api_client_common::configuration::TokenError;
169
170        #[allow(
171            clippy::nonminimal_bool,
172            clippy::eq_op,
173            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
174        )]
175        let is_jwt_bearer_optional: bool = false;
176
177        let token = local_var_configuration
178            .qcs_config
179            .get_bearer_access_token()
180            .await;
181
182        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
183            // the client is configured without any OAuthSession, but this call does not require one.
184            #[cfg(feature = "tracing")]
185            tracing::debug!(
186                "No client credentials found, but this call does not require authentication."
187            );
188        } else {
189            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
190        }
191    }
192
193    local_var_req_builder = local_var_req_builder.json(&p_body_check_client_application_request);
194
195    let local_var_req = local_var_req_builder.build()?;
196    let local_var_resp = local_var_client.execute(local_var_req).await?;
197
198    let local_var_status = local_var_resp.status();
199    let local_var_raw_content_type = local_var_resp
200        .headers()
201        .get("content-type")
202        .and_then(|v| v.to_str().ok())
203        .unwrap_or("application/octet-stream")
204        .to_string();
205    let local_var_content_type = super::ContentType::from(local_var_raw_content_type.as_str());
206
207    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
208        let local_var_content = local_var_resp.text().await?;
209        match local_var_content_type {
210            ContentType::Json => serde_path_to_error::deserialize(
211                &mut serde_json::Deserializer::from_str(&local_var_content),
212            )
213            .map_err(Error::from),
214            ContentType::Text => Err(Error::InvalidContentType {
215                content_type: local_var_raw_content_type,
216                return_type: "models::CheckClientApplicationResponse",
217            }),
218            ContentType::Unsupported(unknown_type) => Err(Error::InvalidContentType {
219                content_type: unknown_type,
220                return_type: "models::CheckClientApplicationResponse",
221            }),
222        }
223    } else {
224        let local_var_retry_delay =
225            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
226        let local_var_content = local_var_resp.text().await?;
227        let local_var_entity: Option<CheckClientApplicationError> =
228            serde_json::from_str(&local_var_content).ok();
229        let local_var_error = ResponseContent {
230            status: local_var_status,
231            content: local_var_content,
232            entity: local_var_entity,
233            retry_delay: local_var_retry_delay,
234        };
235        Err(Error::ResponseError(local_var_error))
236    }
237}
238
239/// Check the requested client application version against the latest and minimum version.
240pub async fn check_client_application(
241    configuration: &configuration::Configuration,
242    check_client_application_request: crate::models::CheckClientApplicationRequest,
243) -> Result<models::CheckClientApplicationResponse, Error<CheckClientApplicationError>> {
244    let mut backoff = configuration.backoff.clone();
245    let mut refreshed_credentials = false;
246    let method = reqwest::Method::POST;
247    loop {
248        let result = check_client_application_inner(
249            configuration,
250            &mut backoff,
251            check_client_application_request.clone(),
252        )
253        .await;
254
255        match result {
256            Ok(result) => return Ok(result),
257            Err(Error::ResponseError(response)) => {
258                if !refreshed_credentials
259                    && matches!(
260                        response.status,
261                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
262                    )
263                {
264                    configuration.qcs_config.refresh().await?;
265                    refreshed_credentials = true;
266                    continue;
267                } else if let Some(duration) = response.retry_delay {
268                    tokio::time::sleep(duration).await;
269                    continue;
270                }
271
272                return Err(Error::ResponseError(response));
273            }
274            Err(Error::Reqwest(error)) => {
275                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
276                    tokio::time::sleep(duration).await;
277                    continue;
278                }
279
280                return Err(Error::Reqwest(error));
281            }
282            Err(Error::Io(error)) => {
283                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
284                    tokio::time::sleep(duration).await;
285                    continue;
286                }
287
288                return Err(Error::Io(error));
289            }
290            Err(error) => return Err(error),
291        }
292    }
293}
294async fn get_client_application_inner(
295    configuration: &configuration::Configuration,
296    backoff: &mut ExponentialBackoff,
297    client_application_name: &str,
298) -> Result<models::ClientApplication, Error<GetClientApplicationError>> {
299    let local_var_configuration = configuration;
300    // add a prefix to parameters to efficiently prevent name collisions
301    let p_path_client_application_name = client_application_name;
302
303    let local_var_client = &local_var_configuration.client;
304
305    let local_var_uri_str = format!(
306        "{}/v1/clientApplications/{clientApplicationName}",
307        local_var_configuration.qcs_config.api_url(),
308        clientApplicationName = crate::apis::urlencode(p_path_client_application_name)
309    );
310    let mut local_var_req_builder =
311        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
312
313    #[cfg(feature = "tracing")]
314    {
315        // Ignore parsing errors if the URL is invalid for some reason.
316        // If it is invalid, it will turn up as an error later when actually making the request.
317        let local_var_do_tracing = local_var_uri_str
318            .parse::<::url::Url>()
319            .ok()
320            .is_none_or(|url| {
321                configuration
322                    .qcs_config
323                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
324            });
325
326        if local_var_do_tracing {
327            ::tracing::debug!(
328                url=%local_var_uri_str,
329                method="GET",
330                "making get_client_application request",
331            );
332        }
333    }
334
335    // Use the QCS Bearer token if a client OAuthSession is present,
336    // but do not require one when the security schema says it is optional.
337    {
338        use qcs_api_client_common::configuration::TokenError;
339
340        #[allow(
341            clippy::nonminimal_bool,
342            clippy::eq_op,
343            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
344        )]
345        let is_jwt_bearer_optional: bool = false;
346
347        let token = local_var_configuration
348            .qcs_config
349            .get_bearer_access_token()
350            .await;
351
352        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
353            // the client is configured without any OAuthSession, but this call does not require one.
354            #[cfg(feature = "tracing")]
355            tracing::debug!(
356                "No client credentials found, but this call does not require authentication."
357            );
358        } else {
359            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
360        }
361    }
362
363    let local_var_req = local_var_req_builder.build()?;
364    let local_var_resp = local_var_client.execute(local_var_req).await?;
365
366    let local_var_status = local_var_resp.status();
367    let local_var_raw_content_type = local_var_resp
368        .headers()
369        .get("content-type")
370        .and_then(|v| v.to_str().ok())
371        .unwrap_or("application/octet-stream")
372        .to_string();
373    let local_var_content_type = super::ContentType::from(local_var_raw_content_type.as_str());
374
375    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
376        let local_var_content = local_var_resp.text().await?;
377        match local_var_content_type {
378            ContentType::Json => serde_path_to_error::deserialize(
379                &mut serde_json::Deserializer::from_str(&local_var_content),
380            )
381            .map_err(Error::from),
382            ContentType::Text => Err(Error::InvalidContentType {
383                content_type: local_var_raw_content_type,
384                return_type: "models::ClientApplication",
385            }),
386            ContentType::Unsupported(unknown_type) => Err(Error::InvalidContentType {
387                content_type: unknown_type,
388                return_type: "models::ClientApplication",
389            }),
390        }
391    } else {
392        let local_var_retry_delay =
393            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
394        let local_var_content = local_var_resp.text().await?;
395        let local_var_entity: Option<GetClientApplicationError> =
396            serde_json::from_str(&local_var_content).ok();
397        let local_var_error = ResponseContent {
398            status: local_var_status,
399            content: local_var_content,
400            entity: local_var_entity,
401            retry_delay: local_var_retry_delay,
402        };
403        Err(Error::ResponseError(local_var_error))
404    }
405}
406
407/// Get details of a specific Rigetti system component along with its latest and minimum supported versions.
408pub async fn get_client_application(
409    configuration: &configuration::Configuration,
410    client_application_name: &str,
411) -> Result<models::ClientApplication, Error<GetClientApplicationError>> {
412    let mut backoff = configuration.backoff.clone();
413    let mut refreshed_credentials = false;
414    let method = reqwest::Method::GET;
415    loop {
416        let result = get_client_application_inner(
417            configuration,
418            &mut backoff,
419            client_application_name.clone(),
420        )
421        .await;
422
423        match result {
424            Ok(result) => return Ok(result),
425            Err(Error::ResponseError(response)) => {
426                if !refreshed_credentials
427                    && matches!(
428                        response.status,
429                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
430                    )
431                {
432                    configuration.qcs_config.refresh().await?;
433                    refreshed_credentials = true;
434                    continue;
435                } else if let Some(duration) = response.retry_delay {
436                    tokio::time::sleep(duration).await;
437                    continue;
438                }
439
440                return Err(Error::ResponseError(response));
441            }
442            Err(Error::Reqwest(error)) => {
443                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
444                    tokio::time::sleep(duration).await;
445                    continue;
446                }
447
448                return Err(Error::Reqwest(error));
449            }
450            Err(Error::Io(error)) => {
451                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
452                    tokio::time::sleep(duration).await;
453                    continue;
454                }
455
456                return Err(Error::Io(error));
457            }
458            Err(error) => return Err(error),
459        }
460    }
461}
462async fn list_client_applications_inner(
463    configuration: &configuration::Configuration,
464    backoff: &mut ExponentialBackoff,
465) -> Result<models::ListClientApplicationsResponse, Error<ListClientApplicationsError>> {
466    let local_var_configuration = configuration;
467
468    let local_var_client = &local_var_configuration.client;
469
470    let local_var_uri_str = format!(
471        "{}/v1/clientApplications",
472        local_var_configuration.qcs_config.api_url()
473    );
474    let mut local_var_req_builder =
475        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
476
477    #[cfg(feature = "tracing")]
478    {
479        // Ignore parsing errors if the URL is invalid for some reason.
480        // If it is invalid, it will turn up as an error later when actually making the request.
481        let local_var_do_tracing = local_var_uri_str
482            .parse::<::url::Url>()
483            .ok()
484            .is_none_or(|url| {
485                configuration
486                    .qcs_config
487                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
488            });
489
490        if local_var_do_tracing {
491            ::tracing::debug!(
492                url=%local_var_uri_str,
493                method="GET",
494                "making list_client_applications request",
495            );
496        }
497    }
498
499    // Use the QCS Bearer token if a client OAuthSession is present,
500    // but do not require one when the security schema says it is optional.
501    {
502        use qcs_api_client_common::configuration::TokenError;
503
504        #[allow(
505            clippy::nonminimal_bool,
506            clippy::eq_op,
507            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
508        )]
509        let is_jwt_bearer_optional: bool = false;
510
511        let token = local_var_configuration
512            .qcs_config
513            .get_bearer_access_token()
514            .await;
515
516        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
517            // the client is configured without any OAuthSession, but this call does not require one.
518            #[cfg(feature = "tracing")]
519            tracing::debug!(
520                "No client credentials found, but this call does not require authentication."
521            );
522        } else {
523            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
524        }
525    }
526
527    let local_var_req = local_var_req_builder.build()?;
528    let local_var_resp = local_var_client.execute(local_var_req).await?;
529
530    let local_var_status = local_var_resp.status();
531    let local_var_raw_content_type = local_var_resp
532        .headers()
533        .get("content-type")
534        .and_then(|v| v.to_str().ok())
535        .unwrap_or("application/octet-stream")
536        .to_string();
537    let local_var_content_type = super::ContentType::from(local_var_raw_content_type.as_str());
538
539    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
540        let local_var_content = local_var_resp.text().await?;
541        match local_var_content_type {
542            ContentType::Json => serde_path_to_error::deserialize(
543                &mut serde_json::Deserializer::from_str(&local_var_content),
544            )
545            .map_err(Error::from),
546            ContentType::Text => Err(Error::InvalidContentType {
547                content_type: local_var_raw_content_type,
548                return_type: "models::ListClientApplicationsResponse",
549            }),
550            ContentType::Unsupported(unknown_type) => Err(Error::InvalidContentType {
551                content_type: unknown_type,
552                return_type: "models::ListClientApplicationsResponse",
553            }),
554        }
555    } else {
556        let local_var_retry_delay =
557            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
558        let local_var_content = local_var_resp.text().await?;
559        let local_var_entity: Option<ListClientApplicationsError> =
560            serde_json::from_str(&local_var_content).ok();
561        let local_var_error = ResponseContent {
562            status: local_var_status,
563            content: local_var_content,
564            entity: local_var_entity,
565            retry_delay: local_var_retry_delay,
566        };
567        Err(Error::ResponseError(local_var_error))
568    }
569}
570
571/// List supported clients of Rigetti system components along with their latest and minimum supported versions.
572pub async fn list_client_applications(
573    configuration: &configuration::Configuration,
574) -> Result<models::ListClientApplicationsResponse, Error<ListClientApplicationsError>> {
575    let mut backoff = configuration.backoff.clone();
576    let mut refreshed_credentials = false;
577    let method = reqwest::Method::GET;
578    loop {
579        let result = list_client_applications_inner(configuration, &mut backoff).await;
580
581        match result {
582            Ok(result) => return Ok(result),
583            Err(Error::ResponseError(response)) => {
584                if !refreshed_credentials
585                    && matches!(
586                        response.status,
587                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
588                    )
589                {
590                    configuration.qcs_config.refresh().await?;
591                    refreshed_credentials = true;
592                    continue;
593                } else if let Some(duration) = response.retry_delay {
594                    tokio::time::sleep(duration).await;
595                    continue;
596                }
597
598                return Err(Error::ResponseError(response));
599            }
600            Err(Error::Reqwest(error)) => {
601                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
602                    tokio::time::sleep(duration).await;
603                    continue;
604                }
605
606                return Err(Error::Reqwest(error));
607            }
608            Err(Error::Io(error)) => {
609                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
610                    tokio::time::sleep(duration).await;
611                    continue;
612                }
613
614                return Err(Error::Io(error));
615            }
616            Err(error) => return Err(error),
617        }
618    }
619}