Mercurial > lbo > hg > async-google-apis
changeset 172:9dc67ed1079b
Rust generator: Early start
Fetching documents and deserialization works. For #3
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sun, 13 Dec 2020 23:40:03 +0100 |
parents | 714165191d0d |
children | |
files | generate_rs/Cargo.toml generate_rs/src/discovery_v1_types.rs generate_rs/src/main.rs |
diffstat | 3 files changed, 883 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/generate_rs/Cargo.toml Sun Dec 13 23:40:03 2020 +0100 @@ -0,0 +1,16 @@ +[package] +name = "generate_rs" +version = "0.1.0" +authors = ["Lewin Bormann <lewin@lewin-bormann.info>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-google-apis-common = { path = "../async-google-apis-common" } +serde = "~1.0" +serde_json = "~1.0" +reqwest = "~0.10" +tokio = { version = "~0.2" } +clap = "~2.33" +anyhow = "~1.0"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/generate_rs/src/discovery_v1_types.rs Sun Dec 13 23:40:03 2020 +0100 @@ -0,0 +1,769 @@ +#![allow(unused_variables, unused_mut, dead_code)] +//! This file was generated by async-google-apis. (https://github.com/dermesser/async-google-apis) +//! +//! (c) 2020 Lewin Bormann <lbo@spheniscida.de> +//! +//! ## Getting started +//! +//! **Tip**: Take a look at those types ending in `...Service`. These represent API resources +//! and contain methods to interact with an API. The remaining types are used by those methods +//! and can be explored starting from a method you want to use. +//! +//! I'd be happy if you let me know about your use case of this code. +//! +//! THIS FILE HAS BEEN GENERATED -- SAVE ANY MODIFICATIONS BEFORE REPLACING. + +use async_google_apis_common::*; + +/// +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RestResource { + /// Sub-resources on this resource. + #[serde(rename = "resources")] + #[serde(skip_serializing_if = "Option::is_none")] + pub resources: Option<HashMap<String, Box<RestResource>>>, + /// Methods on this resource. + #[serde(rename = "methods")] + #[serde(skip_serializing_if = "Option::is_none")] + pub methods: Option<HashMap<String, RestMethod>>, +} + +/// The schema for the request. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RestMethodRequest { + /// Schema ID for the request schema. + #[serde(rename = "$ref")] + #[serde(skip_serializing_if = "Option::is_none")] + pub dollarref: Option<String>, + /// parameter name. + #[serde(rename = "parameterName")] + #[serde(skip_serializing_if = "Option::is_none")] + pub parameter_name: Option<String>, +} + +/// The schema for the response. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RestMethodResponse { + /// Schema ID for the response schema. + #[serde(rename = "$ref")] + #[serde(skip_serializing_if = "Option::is_none")] + pub dollarref: Option<String>, +} + +/// Supports the Resumable Media Upload protocol. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RestMethodMediaUploadProtocolsResumable { + /// The URI path to be used for upload. Should be used in conjunction with the basePath property at the api-level. + #[serde(rename = "path")] + #[serde(skip_serializing_if = "Option::is_none")] + pub path: Option<String>, + /// True if this endpoint supports uploading multipart media. + #[serde(rename = "multipart")] + #[serde(skip_serializing_if = "Option::is_none")] + pub multipart: Option<bool>, +} + +/// Supports uploading as a single HTTP request. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RestMethodMediaUploadProtocolsSimple { + /// The URI path to be used for upload. Should be used in conjunction with the basePath property at the api-level. + #[serde(rename = "path")] + #[serde(skip_serializing_if = "Option::is_none")] + pub path: Option<String>, + /// True if this endpoint supports upload multipart media. + #[serde(rename = "multipart")] + #[serde(skip_serializing_if = "Option::is_none")] + pub multipart: Option<bool>, +} + +/// Supported upload protocols. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RestMethodMediaUploadProtocols { + /// Supports the Resumable Media Upload protocol. + #[serde(rename = "resumable")] + #[serde(skip_serializing_if = "Option::is_none")] + pub resumable: Option<RestMethodMediaUploadProtocolsResumable>, + /// Supports uploading as a single HTTP request. + #[serde(rename = "simple")] + #[serde(skip_serializing_if = "Option::is_none")] + pub simple: Option<RestMethodMediaUploadProtocolsSimple>, +} + +/// Media upload parameters. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RestMethodMediaUpload { + /// MIME Media Ranges for acceptable media uploads to this method. + #[serde(rename = "accept")] + #[serde(skip_serializing_if = "Option::is_none")] + pub accept: Option<Vec<String>>, + /// Maximum size of a media upload, such as "1MB", "2GB" or "3TB". + #[serde(rename = "maxSize")] + #[serde(skip_serializing_if = "Option::is_none")] + pub max_size: Option<String>, + /// Supported upload protocols. + #[serde(rename = "protocols")] + #[serde(skip_serializing_if = "Option::is_none")] + pub protocols: Option<RestMethodMediaUploadProtocols>, +} + +/// +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RestMethod { + /// A unique ID for this method. This property can be used to match methods between different versions of Discovery. + #[serde(rename = "id")] + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option<String>, + /// The schema for the request. + #[serde(rename = "request")] + #[serde(skip_serializing_if = "Option::is_none")] + pub request: Option<RestMethodRequest>, + /// Description of this method. + #[serde(rename = "description")] + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option<String>, + /// Ordered list of required parameters, serves as a hint to clients on how to structure their method signatures. The array is ordered such that the "most-significant" parameter appears first. + #[serde(rename = "parameterOrder")] + #[serde(skip_serializing_if = "Option::is_none")] + pub parameter_order: Option<Vec<String>>, + /// Details for all parameters in this method. + #[serde(rename = "parameters")] + #[serde(skip_serializing_if = "Option::is_none")] + pub parameters: Option<HashMap<String, JsonSchema>>, + /// Whether this method supports subscriptions. + #[serde(rename = "supportsSubscription")] + #[serde(skip_serializing_if = "Option::is_none")] + pub supports_subscription: Option<bool>, + /// Whether this method requires an ETag to be specified. The ETag is sent as an HTTP If-Match or If-None-Match header. + #[serde(rename = "etagRequired")] + #[serde(skip_serializing_if = "Option::is_none")] + pub etag_required: Option<bool>, + /// Indicates that downloads from this method should use the download service URL (i.e. "/download"). Only applies if the method supports media download. + #[serde(rename = "useMediaDownloadService")] + #[serde(skip_serializing_if = "Option::is_none")] + pub use_media_download_service: Option<bool>, + /// The schema for the response. + #[serde(rename = "response")] + #[serde(skip_serializing_if = "Option::is_none")] + pub response: Option<RestMethodResponse>, + /// Whether this method supports media downloads. + #[serde(rename = "supportsMediaDownload")] + #[serde(skip_serializing_if = "Option::is_none")] + pub supports_media_download: Option<bool>, + /// Whether this method supports media uploads. + #[serde(rename = "supportsMediaUpload")] + #[serde(skip_serializing_if = "Option::is_none")] + pub supports_media_upload: Option<bool>, + /// The URI path of this REST method. Should be used in conjunction with the basePath property at the api-level. + #[serde(rename = "path")] + #[serde(skip_serializing_if = "Option::is_none")] + pub path: Option<String>, + /// HTTP method used by this method. + #[serde(rename = "httpMethod")] + #[serde(skip_serializing_if = "Option::is_none")] + pub http_method: Option<String>, + /// OAuth 2.0 scopes applicable to this method. + #[serde(rename = "scopes")] + #[serde(skip_serializing_if = "Option::is_none")] + pub scopes: Option<Vec<String>>, + /// Media upload parameters. + #[serde(rename = "mediaUpload")] + #[serde(skip_serializing_if = "Option::is_none")] + pub media_upload: Option<RestMethodMediaUpload>, +} + +/// Links to 16x16 and 32x32 icons representing the API. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RestDescriptionIcons { + /// The URL of the 16x16 icon. + #[serde(rename = "x16")] + #[serde(skip_serializing_if = "Option::is_none")] + pub x16: Option<String>, + /// The URL of the 32x32 icon. + #[serde(rename = "x32")] + #[serde(skip_serializing_if = "Option::is_none")] + pub x32: Option<String>, +} + +/// The scope value. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RestDescriptionAuthOauth2Scopes { + /// Description of scope. + #[serde(rename = "description")] + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option<String>, +} + +/// OAuth 2.0 authentication information. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RestDescriptionAuthOauth2 { + /// Available OAuth 2.0 scopes. + #[serde(rename = "scopes")] + #[serde(skip_serializing_if = "Option::is_none")] + pub scopes: Option<HashMap<String, RestDescriptionAuthOauth2Scopes>>, +} + +/// Authentication information. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RestDescriptionAuth { + /// OAuth 2.0 authentication information. + #[serde(rename = "oauth2")] + #[serde(skip_serializing_if = "Option::is_none")] + pub oauth2: Option<RestDescriptionAuthOauth2>, +} + +/// +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct RestDescription { + /// API-level methods for this API. + #[serde(rename = "methods")] + #[serde(skip_serializing_if = "Option::is_none")] + pub methods: Option<HashMap<String, RestMethod>>, + #[serde(rename = "version_module")] + #[serde(skip_serializing_if = "Option::is_none")] + pub version_module: Option<bool>, + /// The base path for all REST requests. + #[serde(rename = "servicePath")] + #[serde(skip_serializing_if = "Option::is_none")] + pub service_path: Option<String>, + /// Enable exponential backoff for suitable methods in the generated clients. + #[serde(rename = "exponentialBackoffDefault")] + #[serde(skip_serializing_if = "Option::is_none")] + pub exponential_backoff_default: Option<bool>, + /// Links to 16x16 and 32x32 icons representing the API. + #[serde(rename = "icons")] + #[serde(skip_serializing_if = "Option::is_none")] + pub icons: Option<RestDescriptionIcons>, + /// The domain of the owner of this API. Together with the ownerName and a packagePath values, this can be used to generate a library for this API which would have a unique fully qualified name. + #[serde(rename = "ownerDomain")] + #[serde(skip_serializing_if = "Option::is_none")] + pub owner_domain: Option<String>, + /// The ID of this API. + #[serde(rename = "id")] + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option<String>, + /// The root URL under which all API services live. + #[serde(rename = "rootUrl")] + #[serde(skip_serializing_if = "Option::is_none")] + pub root_url: Option<String>, + /// The name of the owner of this API. See ownerDomain. + #[serde(rename = "ownerName")] + #[serde(skip_serializing_if = "Option::is_none")] + pub owner_name: Option<String>, + /// The version of this API. + #[serde(rename = "version")] + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option<String>, + /// The version of this API. + #[serde(rename = "revision")] + #[serde(skip_serializing_if = "Option::is_none")] + pub revision: Option<String>, + /// A link to human readable documentation for the API. + #[serde(rename = "documentationLink")] + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation_link: Option<String>, + /// The path for REST batch requests. + #[serde(rename = "batchPath")] + #[serde(skip_serializing_if = "Option::is_none")] + pub batch_path: Option<String>, + /// The name of this API. + #[serde(rename = "name")] + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option<String>, + /// The description of this API. + #[serde(rename = "description")] + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option<String>, + /// A list of supported features for this API. + #[serde(rename = "features")] + #[serde(skip_serializing_if = "Option::is_none")] + pub features: Option<Vec<String>>, + /// [DEPRECATED] The base path for REST requests. + #[serde(rename = "basePath")] + #[serde(skip_serializing_if = "Option::is_none")] + pub base_path: Option<String>, + /// Common parameters that apply across all apis. + #[serde(rename = "parameters")] + #[serde(skip_serializing_if = "Option::is_none")] + pub parameters: Option<HashMap<String, JsonSchema>>, + /// Indicate the version of the Discovery API used to generate this doc. + #[serde(rename = "discoveryVersion")] + #[serde(skip_serializing_if = "Option::is_none")] + pub discovery_version: Option<String>, + /// Authentication information. + #[serde(rename = "auth")] + #[serde(skip_serializing_if = "Option::is_none")] + pub auth: Option<RestDescriptionAuth>, + /// The title of this API. + #[serde(rename = "title")] + #[serde(skip_serializing_if = "Option::is_none")] + pub title: Option<String>, + /// [DEPRECATED] The base URL for REST requests. + #[serde(rename = "baseUrl")] + #[serde(skip_serializing_if = "Option::is_none")] + pub base_url: Option<String>, + /// The kind for this response. + #[serde(rename = "kind")] + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option<String>, + /// Labels for the status of this API, such as labs or deprecated. + #[serde(rename = "labels")] + #[serde(skip_serializing_if = "Option::is_none")] + pub labels: Option<Vec<String>>, + /// The ETag for this response. + #[serde(rename = "etag")] + #[serde(skip_serializing_if = "Option::is_none")] + pub etag: Option<String>, + /// The package of the owner of this API. See ownerDomain. + #[serde(rename = "packagePath")] + #[serde(skip_serializing_if = "Option::is_none")] + pub package_path: Option<String>, + /// The protocol described by this document. + #[serde(rename = "protocol")] + #[serde(skip_serializing_if = "Option::is_none")] + pub protocol: Option<String>, + /// The schemas for this API. + #[serde(rename = "schemas")] + #[serde(skip_serializing_if = "Option::is_none")] + pub schemas: Option<HashMap<String, JsonSchema>>, + /// The resources in this API. + #[serde(rename = "resources")] + #[serde(skip_serializing_if = "Option::is_none")] + pub resources: Option<HashMap<String, RestResource>>, + /// Indicates how the API name should be capitalized and split into various parts. Useful for generating pretty class names. + #[serde(rename = "canonicalName")] + #[serde(skip_serializing_if = "Option::is_none")] + pub canonical_name: Option<String>, +} + +/// Additional information about this property. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct JsonSchemaAnnotations { + /// A list of methods for which this property is required on requests. + #[serde(rename = "required")] + #[serde(skip_serializing_if = "Option::is_none")] + pub required: Option<Vec<String>>, +} + +/// +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct JsonSchemaVariantMap { + #[serde(rename = "$ref")] + #[serde(skip_serializing_if = "Option::is_none")] + pub dollarref: Option<String>, + #[serde(rename = "type_value")] + #[serde(skip_serializing_if = "Option::is_none")] + pub type_value: Option<String>, +} + +/// In a variant data type, the value of one property is used to determine how to interpret the entire entity. Its value must exist in a map of descriminant values to schema names. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct JsonSchemaVariant { + /// The name of the type discriminant property. + #[serde(rename = "discriminant")] + #[serde(skip_serializing_if = "Option::is_none")] + pub discriminant: Option<String>, + /// The map of discriminant value to schema to use for parsing.. + #[serde(rename = "map")] + #[serde(skip_serializing_if = "Option::is_none")] + pub map: Option<Vec<JsonSchemaVariantMap>>, +} + +/// +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct JsonSchema { + /// A description of this object. + #[serde(rename = "description")] + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option<String>, + /// The maximum value of this parameter. + #[serde(rename = "maximum")] + #[serde(skip_serializing_if = "Option::is_none")] + pub maximum: Option<String>, + /// Whether this parameter may appear multiple times. + #[serde(rename = "repeated")] + #[serde(skip_serializing_if = "Option::is_none")] + pub repeated: Option<bool>, + /// Values this parameter may take (if it is an enum). + #[serde(rename = "enum")] + #[serde(skip_serializing_if = "Option::is_none")] + pub enums: Option<Vec<String>>, + /// The descriptions for the enums. Each position maps to the corresponding value in the "enum" array. + #[serde(rename = "enumDescriptions")] + #[serde(skip_serializing_if = "Option::is_none")] + pub enum_descriptions: Option<Vec<String>>, + /// Unique identifier for this schema. + #[serde(rename = "id")] + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option<String>, + #[serde(rename = "additionalProperties")] + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_properties: Option<Box<JsonSchema>>, + /// If this is a schema for an object, list the schema for each property of this object. + #[serde(rename = "properties")] + #[serde(skip_serializing_if = "Option::is_none")] + pub properties: Option<HashMap<String, Box<JsonSchema>>>, + /// Additional information about this property. + #[serde(rename = "annotations")] + #[serde(skip_serializing_if = "Option::is_none")] + pub annotations: Option<JsonSchemaAnnotations>, + #[serde(rename = "items")] + #[serde(skip_serializing_if = "Option::is_none")] + pub items: Option<Box<JsonSchema>>, + /// In a variant data type, the value of one property is used to determine how to interpret the entire entity. Its value must exist in a map of descriminant values to schema names. + #[serde(rename = "variant")] + #[serde(skip_serializing_if = "Option::is_none")] + pub variant: Option<JsonSchemaVariant>, + /// Whether this parameter goes in the query or the path for REST requests. + #[serde(rename = "location")] + #[serde(skip_serializing_if = "Option::is_none")] + pub location: Option<String>, + /// Whether the parameter is required. + #[serde(rename = "required")] + #[serde(skip_serializing_if = "Option::is_none")] + pub required: Option<bool>, + /// The value is read-only, generated by the service. The value cannot be modified by the client. If the value is included in a POST, PUT, or PATCH request, it is ignored by the service. + #[serde(rename = "readOnly")] + #[serde(skip_serializing_if = "Option::is_none")] + pub read_only: Option<bool>, + /// The default value of this property (if one exists). + #[serde(rename = "default")] + #[serde(skip_serializing_if = "Option::is_none")] + pub default: Option<String>, + /// The minimum value of this parameter. + #[serde(rename = "minimum")] + #[serde(skip_serializing_if = "Option::is_none")] + pub minimum: Option<String>, + /// An additional regular expression or key that helps constrain the value. For more details see: http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.23 + #[serde(rename = "format")] + #[serde(skip_serializing_if = "Option::is_none")] + pub format: Option<String>, + /// The value type for this schema. A list of values can be found here: http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1 + #[serde(rename = "type")] + #[serde(skip_serializing_if = "Option::is_none")] + pub typ: Option<String>, + /// The regular expression this parameter must conform to. Uses Java 6 regex format: http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html + #[serde(rename = "pattern")] + #[serde(skip_serializing_if = "Option::is_none")] + pub pattern: Option<String>, + /// A reference to another schema. The value of this property is the "id" of another schema. + #[serde(rename = "$ref")] + #[serde(skip_serializing_if = "Option::is_none")] + pub dollarref: Option<String>, +} + +/// Links to 16x16 and 32x32 icons representing the API. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct DirectoryListItemsIcons { + /// The URL of the 16x16 icon. + #[serde(rename = "x16")] + #[serde(skip_serializing_if = "Option::is_none")] + pub x16: Option<String>, + /// The URL of the 32x32 icon. + #[serde(rename = "x32")] + #[serde(skip_serializing_if = "Option::is_none")] + pub x32: Option<String>, +} + +/// +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct DirectoryListItems { + /// A link to human readable documentation for the API. + #[serde(rename = "documentationLink")] + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation_link: Option<String>, + /// True if this version is the preferred version to use. + #[serde(rename = "preferred")] + #[serde(skip_serializing_if = "Option::is_none")] + pub preferred: Option<bool>, + /// The version of the API. + #[serde(rename = "version")] + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option<String>, + /// A link to the discovery document. + #[serde(rename = "discoveryLink")] + #[serde(skip_serializing_if = "Option::is_none")] + pub discovery_link: Option<String>, + /// The description of this API. + #[serde(rename = "description")] + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option<String>, + /// Labels for the status of this API, such as labs or deprecated. + #[serde(rename = "labels")] + #[serde(skip_serializing_if = "Option::is_none")] + pub labels: Option<Vec<String>>, + /// Links to 16x16 and 32x32 icons representing the API. + #[serde(rename = "icons")] + #[serde(skip_serializing_if = "Option::is_none")] + pub icons: Option<DirectoryListItemsIcons>, + /// The title of this API. + #[serde(rename = "title")] + #[serde(skip_serializing_if = "Option::is_none")] + pub title: Option<String>, + /// The id of this API. + #[serde(rename = "id")] + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option<String>, + /// The kind for this response. + #[serde(rename = "kind")] + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option<String>, + /// The URL for the discovery REST document. + #[serde(rename = "discoveryRestUrl")] + #[serde(skip_serializing_if = "Option::is_none")] + pub discovery_rest_url: Option<String>, + /// The name of the API. + #[serde(rename = "name")] + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option<String>, +} + +/// +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct DirectoryList { + /// The kind for this response. + #[serde(rename = "kind")] + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option<String>, + /// The individual directory entries. One entry per api/version pair. + #[serde(rename = "items")] + #[serde(skip_serializing_if = "Option::is_none")] + pub items: Option<Vec<DirectoryListItems>>, + /// Indicate the version of the Discovery API used to generate this doc. + #[serde(rename = "discoveryVersion")] + #[serde(skip_serializing_if = "Option::is_none")] + pub discovery_version: Option<String>, +} + +/// +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct DiscoveryParams { + /// Data format for the response. + #[serde(rename = "alt")] + #[serde(skip_serializing_if = "Option::is_none")] + pub alt: Option<String>, + /// OAuth 2.0 token for the current user. + #[serde(rename = "oauth_token")] + #[serde(skip_serializing_if = "Option::is_none")] + pub oauth_token: Option<String>, + /// Returns response with indentations and line breaks. + #[serde(rename = "prettyPrint")] + #[serde(skip_serializing_if = "Option::is_none")] + pub pretty_print: Option<bool>, + /// Deprecated. Please use quotaUser instead. + #[serde(rename = "userIp")] + #[serde(skip_serializing_if = "Option::is_none")] + pub user_ip: Option<String>, + /// API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. + #[serde(rename = "key")] + #[serde(skip_serializing_if = "Option::is_none")] + pub key: Option<String>, + /// An opaque string that represents a user for quota purposes. Must not exceed 40 characters. + #[serde(rename = "quotaUser")] + #[serde(skip_serializing_if = "Option::is_none")] + pub quota_user: Option<String>, + /// Selector specifying which fields to include in a partial response. + #[serde(rename = "fields")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fields: Option<String>, +} + +/// Parameters for the `apis.list` method. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct ApisListParams { + /// General attributes applying to any API call + #[serde(flatten)] + pub discovery_params: Option<DiscoveryParams>, + /// Return only the preferred version of an API. + #[serde(rename = "preferred")] + pub preferred: Option<bool>, + /// Only include APIs with the given name. + #[serde(rename = "name")] + pub name: Option<String>, +} + +impl std::fmt::Display for ApisListParams { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if let Some(ref v) = self.preferred { + write!( + f, + "&preferred={}", + percent_encode(format!("{}", v).as_bytes(), NON_ALPHANUMERIC).to_string() + )?; + } + if let Some(ref v) = self.name { + write!( + f, + "&name={}", + percent_encode(format!("{}", v).as_bytes(), NON_ALPHANUMERIC).to_string() + )?; + } + Ok(()) + } +} + +/// Parameters for the `apis.getRest` method. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct ApisGetRestParams { + /// General attributes applying to any API call + #[serde(flatten)] + pub discovery_params: Option<DiscoveryParams>, + /// The version of the API. + #[serde(rename = "version")] + pub version: String, + /// The name of the API. + #[serde(rename = "api")] + pub api: String, +} + +impl std::fmt::Display for ApisGetRestParams { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Ok(()) + } +} + +impl std::fmt::Display for DiscoveryParams { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if let Some(ref v) = self.alt { + write!( + f, + "&alt={}", + percent_encode(format!("{}", v).as_bytes(), NON_ALPHANUMERIC).to_string() + )?; + } + if let Some(ref v) = self.oauth_token { + write!( + f, + "&oauth_token={}", + percent_encode(format!("{}", v).as_bytes(), NON_ALPHANUMERIC).to_string() + )?; + } + if let Some(ref v) = self.pretty_print { + write!( + f, + "&prettyPrint={}", + percent_encode(format!("{}", v).as_bytes(), NON_ALPHANUMERIC).to_string() + )?; + } + if let Some(ref v) = self.user_ip { + write!( + f, + "&userIp={}", + percent_encode(format!("{}", v).as_bytes(), NON_ALPHANUMERIC).to_string() + )?; + } + if let Some(ref v) = self.key { + write!( + f, + "&key={}", + percent_encode(format!("{}", v).as_bytes(), NON_ALPHANUMERIC).to_string() + )?; + } + if let Some(ref v) = self.quota_user { + write!( + f, + ""aUser={}", + percent_encode(format!("{}", v).as_bytes(), NON_ALPHANUMERIC).to_string() + )?; + } + if let Some(ref v) = self.fields { + write!( + f, + "&fields={}", + percent_encode(format!("{}", v).as_bytes(), NON_ALPHANUMERIC).to_string() + )?; + } + Ok(()) + } +} + +/// The Discovery Apis service represents the Apis resource. +pub struct ApisService { + client: TlsClient, + + base_url: String, + root_url: String, +} + +impl ApisService { + /// Create a new ApisService object. The easiest way to call this is wrapping the Authenticator + /// into an `Rc`: `new(client.clone(), Rc::new(authenticator))`. + /// This way, one authenticator can be shared among several services. + pub fn new(client: TlsClient) -> ApisService { + ApisService { + client: client, + base_url: "https://www.googleapis.com/discovery/v1/".into(), + root_url: "https://www.googleapis.com/".into(), + } + } + + /// Provide the base URL of this API. The returned URL is guaranteed to end with a '/'. + fn base_url(&self) -> String { + if self.base_url.ends_with("/") { + return self.base_url.clone(); + } + return self.base_url.clone() + "/"; + } + /// Provide the root URL of this API. The returned URL is guaranteed to end with a '/'. + fn root_url(&self) -> String { + if self.root_url.ends_with("/") { + return self.root_url.clone(); + } + return self.root_url.clone(); + } + /// Returns appropriate URLs for relative and absolute paths. + fn format_path(&self, path: &str) -> String { + if path.starts_with("/") { + return self.root_url().trim_end_matches("/").to_string() + path; + } else { + return self.base_url() + path; + } + } + + #[cfg(test)] + /// Override API URLs. `base` is the base path relative to which (relative) method paths are interpreted, + /// whereas `root` is the URL relative to which absolute paths are interpreted. + pub fn set_urls(&mut self, base: String, root: String) { + self.base_url = base; + self.root_url = root; + } + + /// Retrieve the list of APIs supported at this endpoint. + pub async fn list(&mut self, params: &ApisListParams) -> Result<DirectoryList> { + let rel_path = format!("apis",); + let path = self.format_path(rel_path.as_str()); + + let mut headers = vec![]; + + let mut url_params = format!("?{params}", params = params); + if let Some(ref api_params) = ¶ms.discovery_params { + url_params.push_str(&format!("{}", api_params)); + } + + let full_uri = path + &url_params; + + let opt_request: Option<&EmptyRequest> = None; + do_request(&self.client, &full_uri, &headers, "GET", opt_request).await + } + + /// Retrieve the description of a particular version of an api. + pub async fn get_rest(&mut self, params: &ApisGetRestParams) -> Result<RestDescription> { + let rel_path = format!( + "apis/{api}/{version}/rest", + api = percent_encode(params.api.as_bytes(), NON_ALPHANUMERIC), + version = percent_encode(params.version.as_bytes(), NON_ALPHANUMERIC) + ); + let path = self.format_path(rel_path.as_str()); + + let mut headers = vec![]; + + let mut url_params = format!("?{params}", params = params); + if let Some(ref api_params) = ¶ms.discovery_params { + url_params.push_str(&format!("{}", api_params)); + } + + let full_uri = path + &url_params; + + let opt_request: Option<&EmptyRequest> = None; + do_request(&self.client, &full_uri, &headers, "GET", opt_request).await + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/generate_rs/src/main.rs Sun Dec 13 23:40:03 2020 +0100 @@ -0,0 +1,98 @@ +mod discovery_v1_types; + +use anyhow::{Error, Result}; +use clap::{App, Arg, SubCommand}; + +enum ApiSource { + /// API ID to fetch + ApiId(String), + /// URL of document to fetch + ApiDoc(String), +} + +struct RunConfig { + api: ApiSource, + discovery_base: String, +} + +fn argparse() -> Result<RunConfig> { + let app = App::new("generate_rs") + .about("Generate asynchronous Rust stubs for Google REST APIs") + .arg( + Arg::with_name("api") + .long("api") + .value_name("API-ID") + .help("Google API ID, e.g. drive:v3 or discovery:v1."), + ) + .arg( + Arg::with_name("discovery_base") + .long("discovery_base") + .value_name("DISCOVERY-BASE") + .help("Base URL of Discovery service"), + ) + .arg( + Arg::with_name("doc_url") + .long("doc_url") + .value_name("DOC-URL") + .help("URL of Discovery document to process directly (instead of --api)"), + ); + let matches = app.get_matches(); + + let api = match (matches.value_of("api"), matches.value_of("doc_url")) { + (Some(id), None) => ApiSource::ApiId(id.into()), + (None, Some(url)) => ApiSource::ApiDoc(url.into()), + (None, None) => return Err(anyhow::anyhow!("Please specify either --api or --doc_url")), + (Some(_), Some(_)) => { + return Err(anyhow::anyhow!("Please specify either --api or --doc_url")) + } + }; + + let discovery_base = matches + .value_of("discovery_base") + .unwrap_or("https://www.googleapis.com/discovery/v1/apis") + .into(); + Ok(RunConfig { + api: api, + discovery_base: discovery_base, + }) +} + +async fn fetch_doc_by_api_id( + base_url: &str, + id: &str, +) -> Result<discovery_v1_types::RestDescription> { + let list: discovery_v1_types::DirectoryList = fetch_url(base_url).await?; + + if let Some(items) = list.items { + if let Some(found) = items + .iter() + .find(|it| it.id.as_ref().map(|s| s.as_str()).unwrap_or("") == id) + { + let url = found.discovery_rest_url.clone().unwrap(); + return fetch_doc_by_url(url.as_str()).await; + } + } + Err(anyhow::anyhow!("No API with this ID could be found")) +} + +async fn fetch_doc_by_url(doc_url: &str) -> Result<discovery_v1_types::RestDescription> { + fetch_url(doc_url).await +} + +async fn fetch_url<Out: serde::de::DeserializeOwned>(url: &str) -> Result<Out> { + let doc = reqwest::get(url).await?.text().await?; + serde_json::from_reader(doc.as_bytes()).map_err(|e| e.into()) +} + +#[tokio::main] +async fn main() { + let cfg = argparse().unwrap(); + + let doc = match cfg.api { + ApiSource::ApiDoc(url) => fetch_doc_by_url(url.as_str()).await.unwrap(), + ApiSource::ApiId(id) => fetch_doc_by_api_id(cfg.discovery_base.as_str(), id.as_str()) + .await + .unwrap(), + }; + println!("{:?}", doc); +}