Skip to content

just azure_svc_blobstorage package-2021-02 for review of #1040#1043

Closed
cataggar wants to merge 2 commits intoAzure:mainfrom
cataggar:single-response-review
Closed

just azure_svc_blobstorage package-2021-02 for review of #1040#1043
cataggar wants to merge 2 commits intoAzure:mainfrom
cataggar:single-response-review

Conversation

@cataggar
Copy link
Member

This contains all of the AutoRust changes in #1040. It limits the code generation to the azure_svc_blobstorage crate and the package-2021-02 package. The operation Service_GetAccountInfo is a good example to focus on. It is implemented in our SDK and I #1039 contains the corresponding .NET SDK code for both its generated rest client and the manually coded SDK.

Here is the API specification:
https://github.com/Azure/azure-rest-api-specs/blob/2ed424dccf778022a6babff3b655203aa78ec0d8/specification/storage/data-plane/Microsoft.BlobStorage/preview/2021-02-12/blob.json#L421-L532

    "/?restype=account&comp=properties": {
      "get": {
        "tags": [
          "service"
        ],
        "operationId": "Service_GetAccountInfo",
        "description": "Returns the sku name and account kind ",
        "parameters": [
          {
            "$ref": "#/parameters/ApiVersionParameter"
          }
        ],
        "responses": {
          "200": {
            "description": "Success (OK)",
            "headers": {
              "x-ms-client-request-id": {
                "x-ms-client-name": "ClientRequestId",
                "type": "string",
                "description": "If a client request id header is sent in the request, this header will be present in the response with the same value."
              },
              "x-ms-request-id": {
                "x-ms-client-name": "RequestId",
                "type": "string",
                "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request."
              },
              "x-ms-version": {
                "x-ms-client-name": "Version",
                "type": "string",
                "description": "Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above."
              },
              "Date": {
                "type": "string",
                "format": "date-time-rfc1123",
                "description": "UTC date/time value generated by the service that indicates the time at which the response was initiated"
              },
              "x-ms-sku-name": {
                "x-ms-client-name": "SkuName",
                "type": "string",
                "enum": [
                  "Standard_LRS",
                  "Standard_GRS",
                  "Standard_RAGRS",
                  "Standard_ZRS",
                  "Premium_LRS"
                ],
                "x-ms-enum": {
                  "name": "SkuName",
                  "modelAsString": false
                },
                "description": "Identifies the sku name of the account"
              },
              "x-ms-account-kind": {
                "x-ms-client-name": "AccountKind",
                "type": "string",
                "enum": [
                  "Storage",
                  "BlobStorage",
                  "StorageV2",
                  "FileStorage",
                  "BlockBlobStorage"
                ],
                "x-ms-enum": {
                  "name": "AccountKind",
                  "modelAsString": false
                },
                "description": "Identifies the account kind"
              },
              "x-ms-is-hns-enabled": {
                "x-ms-client-name": "IsHierarchicalNamespaceEnabled",
                "type": "boolean",
                "description": "Version 2019-07-07 and newer. Indicates if the account has a hierarchical namespace enabled."
              }
            }
          },
          "default": {
            "description": "Failure",
            "headers": {
              "x-ms-error-code": {
                "x-ms-client-name": "ErrorCode",
                "type": "string"
              }
            },
            "schema": {
              "$ref": "#/definitions/StorageError"
            }
          }
        }
      },
      "parameters": [
        {
          "name": "restype",
          "description": "restype",
          "in": "query",
          "required": true,
          "type": "string",
          "enum": [
            "account"
          ]
        },
        {
          "name": "comp",
          "description": "comp",
          "in": "query",
          "required": true,
          "type": "string",
          "enum": [
            "properties"
          ]
        }
      ]
    },

The implementation from the SDK:

use crate::clients::ServiceType;
use crate::core::prelude::*;
use crate::headers::CommonStorageResponseHeaders;
use azure_core::headers::{account_kind_from_headers, sku_name_from_headers, Headers};
operation! {
GetAccountInformation,
client: StorageClient,
}
impl GetAccountInformationBuilder {
pub fn into_future(mut self) -> GetAccountInformation {
Box::pin(async move {
let mut request = self.client.blob_storage_request(azure_core::Method::Get)?;
for (k, v) in [("restype", "account"), ("comp", "properties")].iter() {
request.url_mut().query_pairs_mut().append_pair(k, v);
}
let response = self
.client
.send(&mut self.context, &mut request, ServiceType::Blob)
.await?;
GetAccountInformationResponse::try_from(response.headers())
})
}
}
#[derive(Debug, Clone)]
pub struct GetAccountInformationResponse {
pub common: CommonStorageResponseHeaders,
pub sku_name: String,
pub account_kind: String,
}
impl GetAccountInformationResponse {
pub(crate) fn try_from(headers: &Headers) -> azure_core::Result<GetAccountInformationResponse> {
let common = CommonStorageResponseHeaders::try_from(headers)?;
let sku_name = sku_name_from_headers(headers)?;
let account_kind = account_kind_from_headers(headers)?;
Ok(GetAccountInformationResponse {
common,
sku_name,
account_kind,
})
}
}

Today, in the generated crate, the response body is returned. There is no response body, so () is returned.

pub mod get_account_info {
use super::models;
type Response = ();
#[derive(Clone)]
pub struct RequestBuilder {
pub(crate) client: super::super::Client,
pub(crate) x_ms_version: String,
}
impl RequestBuilder {
pub fn into_future(self) -> futures::future::BoxFuture<'static, azure_core::Result<Response>> {
Box::pin({
let this = self.clone();
async move {
let url = azure_core::Url::parse(&format!("{}/?restype=account&comp=properties", this.client.endpoint(),))?;
let mut req = azure_core::Request::new(url, azure_core::Method::Get);
let credential = this.client.token_credential();
let token_response = credential.get_token(&this.client.scopes().join(" ")).await?;
req.insert_header(
azure_core::headers::AUTHORIZATION,
format!("Bearer {}", token_response.token.secret()),
);
req.insert_header("x-ms-version", &this.x_ms_version);
let req_body = azure_core::EMPTY_BODY;
req.set_body(req_body);
let rsp = this.client.send(&mut req).await?;
let (rsp_status, rsp_headers, rsp_stream) = rsp.deconstruct();
match rsp_status {
azure_core::StatusCode::Ok => Ok(()),
status_code => Err(azure_core::error::Error::from(azure_core::error::ErrorKind::HttpResponse {
status: status_code,
error_code: None,
})),
}
}
})
}
}
}

This pull request will return a Response type instead. In a follow-up PR, it will allow access to the headers.

}
}
pub mod get_account_info {
use super::models;
type Response = ();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current into_future sends the request and returns the response body, which is (). Not very useful.

#[derive(Clone)]
pub struct RequestBuilder {
pub(crate) client: super::super::Client,
pub(crate) x_ms_version: String,
}
impl RequestBuilder {
pub fn into_future(self) -> futures::future::BoxFuture<'static, azure_core::Result<Response>> {
#[doc = "Send the request and returns the response."]
pub fn send(self) -> futures::future::BoxFuture<'static, azure_core::Result<Response>> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The send function will send the request and return the response. There is no into_body function on the Response or this RequestBuilder because there is no body returned in the API specification. Since there are headers, typed access to the headers will be provided (in the next pull request).

@cataggar
Copy link
Member Author

Here is a cadl for how the SDK is modeling the function.

import "@cadl-lang/rest";
import "@cadl-lang/openapi";
using Cadl.Http;
using OpenAPI;
@serviceTitle("Blob Storage")
@serviceVersion("2021-02-12")
namespace BlobStorage;

model AccountInfo {
  @header("x-ms-sku-name") skuName: string;
  @header("x-ms-account-kind") accountKind: string;
}

@error
model Error {
  @header contentType: "application/xml";
  @header("x-ms-error-code") code: string;
  message: string;
}

@operationId("Service_GetAccountInfo")
@get
@route("/")
op get_account_info(): (OkResponse & AccountInfo) | Error;

But when you put it in openapi, you are missing a bunch of the design. Eventually, we'll move the specs to cadl https://github.com/Azure/cadl-azure/issues/1948 and it we will be able to generate code closer to what the SDK is doing.

@cataggar cataggar closed this Aug 29, 2022
@cataggar cataggar deleted the single-response-review branch August 29, 2022 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments