@apollo-deploy/tesseract 0.9.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/csharp/index.d.ts +12 -0
- package/dist/adapters/csharp/index.d.ts.map +1 -0
- package/dist/adapters/csharp/index.js +99 -0
- package/dist/adapters/csharp/index.js.map +1 -0
- package/dist/adapters/go/index.d.ts +12 -0
- package/dist/adapters/go/index.d.ts.map +1 -0
- package/dist/adapters/go/index.js +135 -0
- package/dist/adapters/go/index.js.map +1 -0
- package/dist/adapters/kotlin/index.d.ts +13 -0
- package/dist/adapters/kotlin/index.d.ts.map +1 -0
- package/dist/adapters/kotlin/index.js +188 -0
- package/dist/adapters/kotlin/index.js.map +1 -0
- package/dist/adapters/php/index.d.ts +20 -0
- package/dist/adapters/php/index.d.ts.map +1 -0
- package/dist/adapters/php/index.js +123 -0
- package/dist/adapters/php/index.js.map +1 -0
- package/dist/adapters/python/index.d.ts +12 -0
- package/dist/adapters/python/index.d.ts.map +1 -0
- package/dist/adapters/python/index.js +145 -0
- package/dist/adapters/python/index.js.map +1 -0
- package/dist/adapters/ruby/index.d.ts +12 -0
- package/dist/adapters/ruby/index.d.ts.map +1 -0
- package/dist/adapters/ruby/index.js +86 -0
- package/dist/adapters/ruby/index.js.map +1 -0
- package/dist/adapters/rust/index.d.ts +13 -0
- package/dist/adapters/rust/index.d.ts.map +1 -0
- package/dist/adapters/rust/index.js +213 -0
- package/dist/adapters/rust/index.js.map +1 -0
- package/dist/adapters/typescript/emitter/emitSchema.d.ts +1 -1
- package/dist/adapters/typescript/emitter/emitSchema.d.ts.map +1 -1
- package/dist/adapters/typescript/emitter/emitSchema.js +1 -1
- package/dist/adapters/typescript/emitter/emitSchema.js.map +1 -1
- package/dist/adapters/typescript/emitter/emitTypeScriptModels.d.ts +2 -2
- package/dist/adapters/typescript/emitter/emitTypeScriptModels.d.ts.map +1 -1
- package/dist/adapters/typescript/emitter/emitTypeScriptModels.js +5 -3
- package/dist/adapters/typescript/emitter/emitTypeScriptModels.js.map +1 -1
- package/dist/adapters/typescript/emitter/importCollector.d.ts +1 -1
- package/dist/adapters/typescript/emitter/importCollector.d.ts.map +1 -1
- package/dist/adapters/typescript/index.d.ts.map +1 -1
- package/dist/adapters/typescript/index.js +43 -2
- package/dist/adapters/typescript/index.js.map +1 -1
- package/dist/cli.js +2 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/pipeline/intake.d.ts.map +1 -1
- package/dist/pipeline/intake.js +32 -21
- package/dist/pipeline/intake.js.map +1 -1
- package/dist/types/ir.d.ts +1 -1
- package/dist/types/ir.d.ts.map +1 -1
- package/dist/types/sdk-module.d.ts +22 -2
- package/dist/types/sdk-module.d.ts.map +1 -1
- package/dist/types/sdk-module.js +1 -1
- package/package.json +1 -1
- package/templates/csharp/client.hbs +95 -0
- package/templates/csharp/csproj.hbs +18 -0
- package/templates/csharp/domain.hbs +183 -0
- package/templates/csharp/errors.hbs +45 -0
- package/templates/csharp/readme.hbs +76 -0
- package/templates/csharp/transport.hbs +291 -0
- package/templates/csharp/types.hbs +104 -0
- package/templates/go/client.hbs +158 -0
- package/templates/go/domain.hbs +89 -0
- package/templates/go/errors.hbs +38 -0
- package/templates/go/go-mod.hbs +6 -0
- package/templates/go/readme.hbs +73 -0
- package/templates/go/transport.hbs +379 -0
- package/templates/go/types.hbs +80 -0
- package/templates/go/utils.hbs +45 -0
- package/templates/kotlin/build-gradle.hbs +151 -0
- package/templates/kotlin/client.hbs +57 -0
- package/templates/kotlin/domain.hbs +73 -0
- package/templates/kotlin/errors.hbs +42 -0
- package/templates/kotlin/gradle-properties.hbs +2 -0
- package/templates/kotlin/readme.hbs +133 -0
- package/templates/kotlin/settings-gradle.hbs +1 -0
- package/templates/kotlin/transport.hbs +246 -0
- package/templates/kotlin/types.hbs +100 -0
- package/templates/php/client.hbs +74 -0
- package/templates/php/composer.hbs +19 -0
- package/templates/php/domain.hbs +173 -0
- package/templates/php/errors.hbs +131 -0
- package/templates/php/readme.hbs +89 -0
- package/templates/php/transport.hbs +285 -0
- package/templates/php/types.hbs +95 -0
- package/templates/python/client.hbs +102 -0
- package/templates/python/domain.hbs +139 -0
- package/templates/python/index.hbs +20 -0
- package/templates/python/pyproject.hbs +26 -0
- package/templates/python/readme.hbs +64 -0
- package/templates/python/resources-init.hbs +11 -0
- package/templates/python/transport.hbs +191 -0
- package/templates/python/types-errors.hbs +75 -0
- package/templates/python/types.hbs +79 -0
- package/templates/ruby/Gemfile.hbs +5 -0
- package/templates/ruby/client.hbs +86 -0
- package/templates/ruby/domain.hbs +110 -0
- package/templates/ruby/errors.hbs +150 -0
- package/templates/ruby/gemspec.hbs +30 -0
- package/templates/ruby/index.hbs +54 -0
- package/templates/ruby/readme.hbs +113 -0
- package/templates/ruby/transport.hbs +177 -0
- package/templates/ruby/types.hbs +126 -0
- package/templates/ruby/version.hbs +5 -0
- package/templates/rust/api-mod.hbs +3 -0
- package/templates/rust/cargo.hbs +22 -0
- package/templates/rust/client.hbs +114 -0
- package/templates/rust/domain.hbs +94 -0
- package/templates/rust/error.hbs +74 -0
- package/templates/rust/lib.hbs +85 -0
- package/templates/rust/readme.hbs +77 -0
- package/templates/rust/transport.hbs +287 -0
- package/templates/rust/types.hbs +142 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module {{pascalCase meta.clientName}}
|
|
4
|
+
{{#each schemas}}
|
|
5
|
+
{{#if isEnum}}
|
|
6
|
+
# {{#if description}}{{description}}{{else}}Enum for {{name}} values.{{/if}}
|
|
7
|
+
module {{pascalCase name}}
|
|
8
|
+
{{#each enumValues}}
|
|
9
|
+
{{#if (isString this)}}
|
|
10
|
+
{{upperCase (snakeCase this)}} = "{{this}}"
|
|
11
|
+
{{else}}
|
|
12
|
+
{{upperCase name}}_{{this}} = {{this}}
|
|
13
|
+
{{/if}}
|
|
14
|
+
{{/each}}
|
|
15
|
+
|
|
16
|
+
# All valid enum values.
|
|
17
|
+
# @return [Array]
|
|
18
|
+
ALL = [
|
|
19
|
+
{{#each enumValues}}
|
|
20
|
+
{{#if (isString this)}}
|
|
21
|
+
{{upperCase (snakeCase this)}},
|
|
22
|
+
{{else}}
|
|
23
|
+
{{upperCase ../name}}_{{this}},
|
|
24
|
+
{{/if}}
|
|
25
|
+
{{/each}}
|
|
26
|
+
].freeze
|
|
27
|
+
|
|
28
|
+
# Check if a value is valid for this enum.
|
|
29
|
+
# @param value [String, Integer]
|
|
30
|
+
# @return [Boolean]
|
|
31
|
+
def self.valid?(value)
|
|
32
|
+
ALL.include?(value)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
{{else if isTypeAlias}}
|
|
37
|
+
{{#if unionMembers}}
|
|
38
|
+
# {{pascalCase name}} — type alias for: {{#each unionMembers}}{{this}}{{#unless @last}} | {{/unless}}{{/each}}
|
|
39
|
+
{{pascalCase name}} = Class.new
|
|
40
|
+
{{else}}
|
|
41
|
+
# {{pascalCase name}} — schema type alias
|
|
42
|
+
{{pascalCase name}} = Class.new
|
|
43
|
+
{{/if}}
|
|
44
|
+
|
|
45
|
+
{{else if isUnionType}}
|
|
46
|
+
# {{pascalCase name}} — union type: {{#each unionMembers}}{{this}}{{#unless @last}} | {{/unless}}{{/each}}
|
|
47
|
+
module {{pascalCase name}}
|
|
48
|
+
# Union members are typed schemas. Use `is_a?` or pattern matching at runtime.
|
|
49
|
+
{{#each unionMembers}}
|
|
50
|
+
# @see {{this}}
|
|
51
|
+
{{/each}}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
{{else}}
|
|
55
|
+
{{#if (and properties.length (not isUnionType))}}
|
|
56
|
+
# {{#if description}}{{description}}{{else}}Schema type: {{name}}{{/if}}
|
|
57
|
+
class {{pascalCase name}}
|
|
58
|
+
{{#each properties}}
|
|
59
|
+
# @return [{{type}}{{#if nullable}}, nil{{/if}}]{{#if description}} {{description}}{{/if}}
|
|
60
|
+
attr_accessor :{{snakeCase name}}
|
|
61
|
+
{{/each}}
|
|
62
|
+
|
|
63
|
+
# @param {{#each properties}}{{snakeCase name}} [{{type}}{{#if nullable}}, nil{{/if}}]{{#unless @last}}, {{/unless}}{{/each}}
|
|
64
|
+
def initialize({{#each properties}}{{snakeCase name}}: {{^required}}nil{{/required}}{{#unless @last}}, {{/unless}}{{/each}})
|
|
65
|
+
{{#each properties}}
|
|
66
|
+
@{{snakeCase name}} = {{snakeCase name}}
|
|
67
|
+
{{/each}}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @return [Hash] a hash representation of this object
|
|
71
|
+
def to_h
|
|
72
|
+
{
|
|
73
|
+
{{#each properties}}
|
|
74
|
+
{{#if (eq type "DateTime")}}
|
|
75
|
+
{{snakeCase name}}: @{{snakeCase name}}&.iso8601,
|
|
76
|
+
{{else}}
|
|
77
|
+
{{snakeCase name}}: @{{snakeCase name}},
|
|
78
|
+
{{/if}}
|
|
79
|
+
{{/each}}
|
|
80
|
+
}.compact
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Create an instance from a parsed JSON hash.
|
|
84
|
+
# @param attributes [Hash]
|
|
85
|
+
# @return [{{pascalCase name}}]
|
|
86
|
+
def self.from_json(attributes)
|
|
87
|
+
return nil unless attributes.is_a?(Hash)
|
|
88
|
+
|
|
89
|
+
new(
|
|
90
|
+
{{#each properties}}
|
|
91
|
+
{{snakeCase name}}: attributes["{{snakeCase name}}"] || attributes["{{originalName}}"] || attributes[:{{snakeCase name}}],
|
|
92
|
+
{{/each}}
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
{{else}}
|
|
98
|
+
# {{#if description}}{{description}}{{else}}Schema type without properties: {{name}}{{/if}}
|
|
99
|
+
class {{pascalCase name}}
|
|
100
|
+
# @return [Hash] raw attributes
|
|
101
|
+
attr_reader :attributes
|
|
102
|
+
|
|
103
|
+
# @param attributes [Hash]
|
|
104
|
+
def initialize(attributes = {})
|
|
105
|
+
@attributes = attributes
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# @return [Hash]
|
|
109
|
+
def to_h
|
|
110
|
+
@attributes.dup
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Create an instance from a parsed JSON hash.
|
|
114
|
+
# @param attributes [Hash]
|
|
115
|
+
# @return [{{pascalCase name}}]
|
|
116
|
+
def self.from_json(attributes)
|
|
117
|
+
return nil unless attributes.is_a?(Hash)
|
|
118
|
+
|
|
119
|
+
new(attributes)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
{{/if}}
|
|
124
|
+
{{/if}}
|
|
125
|
+
{{/each}}
|
|
126
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "{{crateName}}"
|
|
3
|
+
version = "{{#if packageVersion}}{{packageVersion}}{{else}}0.1.0{{/if}}"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
description = "{{#if description}}{{description}}{{else}}Rust SDK for {{title}}{{/if}}"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
repository = "https://github.com/{{#if packageName}}{{packageName}}{{else}}example/{{crateName}}{{/if}}"
|
|
8
|
+
|
|
9
|
+
[dependencies]
|
|
10
|
+
serde = { version = "1", features = ["derive"] }
|
|
11
|
+
serde_json = "1"
|
|
12
|
+
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
|
|
13
|
+
tokio = { version = "1", features = ["full"] }
|
|
14
|
+
thiserror = "2"
|
|
15
|
+
url = "2"
|
|
16
|
+
{{#if hasSSE}}
|
|
17
|
+
futures-core = "0.3"
|
|
18
|
+
tokio-stream = "0.1"
|
|
19
|
+
{{/if}}
|
|
20
|
+
|
|
21
|
+
[dev-dependencies]
|
|
22
|
+
tokio-test = "0.4"
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
use crate::transport::{Transport, TransportConfig};
|
|
2
|
+
{{#each groups}}
|
|
3
|
+
use crate::api::{{snakeCase fileName}}::{{interfaceName}};
|
|
4
|
+
{{/each}}
|
|
5
|
+
use std::time::Duration;
|
|
6
|
+
|
|
7
|
+
/// Configuration for the {{title}} API client.
|
|
8
|
+
#[derive(Debug, Clone)]
|
|
9
|
+
pub struct ClientConfig {
|
|
10
|
+
/// Base URL for the API.
|
|
11
|
+
pub base_url: String,
|
|
12
|
+
{{#each securitySchemes}}
|
|
13
|
+
{{#if (eq type "apiKey")}}
|
|
14
|
+
/// API key for the `{{name}}` security scheme.
|
|
15
|
+
pub {{snakeCase configKey}}: Option<String>,
|
|
16
|
+
{{/if}}
|
|
17
|
+
{{#if (and (eq type "http") (eq scheme "bearer"))}}
|
|
18
|
+
/// Bearer token for the `{{name}}` security scheme.
|
|
19
|
+
pub {{snakeCase configKey}}: Option<String>,
|
|
20
|
+
{{/if}}
|
|
21
|
+
{{#if (eq type "oauth2")}}
|
|
22
|
+
/// OAuth2 access token for the `{{name}}` security scheme.
|
|
23
|
+
pub {{snakeCase configKey}}: Option<String>,
|
|
24
|
+
{{/if}}
|
|
25
|
+
{{#if (eq type "openIdConnect")}}
|
|
26
|
+
/// OpenID Connect access token for the `{{name}}` security scheme.
|
|
27
|
+
pub {{snakeCase configKey}}: Option<String>,
|
|
28
|
+
{{/if}}
|
|
29
|
+
{{/each}}
|
|
30
|
+
/// Request timeout.
|
|
31
|
+
pub timeout: Duration,
|
|
32
|
+
/// Maximum number of retry attempts.
|
|
33
|
+
pub max_retries: u32,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
impl Default for ClientConfig {
|
|
37
|
+
fn default() -> Self {
|
|
38
|
+
Self {
|
|
39
|
+
base_url: "{{baseUrl}}".to_string(),
|
|
40
|
+
{{#each securitySchemes}}
|
|
41
|
+
{{snakeCase configKey}}: None,
|
|
42
|
+
{{/each}}
|
|
43
|
+
timeout: Duration::from_secs(15),
|
|
44
|
+
max_retries: 3,
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/// Primary API client for {{title}}.
|
|
50
|
+
///
|
|
51
|
+
/// Provides access to all domain-specific API groups.
|
|
52
|
+
pub struct Client {
|
|
53
|
+
transport: Transport,
|
|
54
|
+
{{#each groups}}
|
|
55
|
+
/// {{#if description}}{{description}}{{else}}{{interfaceName}} operations.{{/if}}
|
|
56
|
+
pub {{snakeCase name}}: {{interfaceName}},
|
|
57
|
+
{{/each}}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
impl Client {
|
|
61
|
+
/// Create a new {{title}} API client with the given configuration.
|
|
62
|
+
///
|
|
63
|
+
/// # Example
|
|
64
|
+
///
|
|
65
|
+
/// ```rust,no_run
|
|
66
|
+
/// use {{crateName}}::Client;
|
|
67
|
+
/// use {{crateName}}::ClientConfig;
|
|
68
|
+
///
|
|
69
|
+
/// let config = ClientConfig {
|
|
70
|
+
{{#each securitySchemes}}
|
|
71
|
+
{{#if (or (eq type "apiKey") (and (eq type "http") (eq scheme "bearer")))}}
|
|
72
|
+
/// {{snakeCase configKey}}: Some("your-key".to_string()),
|
|
73
|
+
{{/if}}
|
|
74
|
+
{{/each}}
|
|
75
|
+
/// ..Default::default()
|
|
76
|
+
/// };
|
|
77
|
+
/// let client = Client::new(config);
|
|
78
|
+
/// ```
|
|
79
|
+
pub fn new(config: ClientConfig) -> Self {
|
|
80
|
+
let mut transport_config = TransportConfig {
|
|
81
|
+
base_url: config.base_url,
|
|
82
|
+
{{#each securitySchemes}}
|
|
83
|
+
{{snakeCase configKey}}: config.{{snakeCase configKey}},
|
|
84
|
+
{{/each}}
|
|
85
|
+
timeout: config.timeout,
|
|
86
|
+
max_retries: config.max_retries,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
let transport = Transport::new(transport_config);
|
|
90
|
+
|
|
91
|
+
Self {
|
|
92
|
+
{{#each groups}}
|
|
93
|
+
{{snakeCase name}}: {{interfaceName}}::new(transport.clone()),
|
|
94
|
+
{{/each}}
|
|
95
|
+
transport,
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// Return a reference to the underlying transport layer.
|
|
100
|
+
pub fn transport(&self) -> &Transport {
|
|
101
|
+
&self.transport
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
impl std::fmt::Debug for Client {
|
|
106
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
107
|
+
f.debug_struct("Client")
|
|
108
|
+
.field("transport", &"<Transport>")
|
|
109
|
+
{{#each groups}}
|
|
110
|
+
.field("{{snakeCase name}}", &"<{{interfaceName}}>")
|
|
111
|
+
{{/each}}
|
|
112
|
+
.finish()
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
use crate::transport::Transport;
|
|
2
|
+
use crate::error::SdkError;
|
|
3
|
+
use reqwest::Method;
|
|
4
|
+
{{#if imports.length}}
|
|
5
|
+
use crate::types::{ {{join imports ", "}} };
|
|
6
|
+
{{/if}}
|
|
7
|
+
|
|
8
|
+
/// {{#if description}}{{description}}{{else}}{{interfaceName}} API operations.{{/if}}
|
|
9
|
+
pub struct {{interfaceName}} {
|
|
10
|
+
transport: Transport,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
impl {{interfaceName}} {
|
|
14
|
+
pub(crate) fn new(transport: Transport) -> Self {
|
|
15
|
+
Self { transport }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
{{#each operations}}
|
|
19
|
+
{{#if summary}}
|
|
20
|
+
/// {{summary}}{{#if description}}
|
|
21
|
+
///
|
|
22
|
+
/// {{description}}{{/if}}
|
|
23
|
+
{{/if}}
|
|
24
|
+
{{#if deprecated}}
|
|
25
|
+
#[deprecated{{#if deprecationMessage}}(note = "{{deprecationMessage}}"){{/if}}]
|
|
26
|
+
{{/if}}
|
|
27
|
+
pub async fn {{snakeCase name}}(
|
|
28
|
+
&self,
|
|
29
|
+
{{#each pathParams}}
|
|
30
|
+
{{snakeCase name}}: {{{rustParamType type}}},
|
|
31
|
+
{{/each}}
|
|
32
|
+
{{#if requestBody}}
|
|
33
|
+
body: &{{{requestBody.rustType}}},
|
|
34
|
+
{{/if}}
|
|
35
|
+
{{#if queryType}}
|
|
36
|
+
query: Option<&{{{rustQueryType queryType}}}>,
|
|
37
|
+
{{/if}}
|
|
38
|
+
) -> Result<{{#if isEventStream}}Vec<{{#if eventSchema}}{{{rustType eventSchema}}}{{else}}serde_json::Value{{/if}}>{{else}}{{{rustResponseType}}}{{/if}}, SdkError> {
|
|
39
|
+
let path = format!("{{path}}"{{#each pathParams}}, {{snakeCase name}} = {{#if (isRustCopyType type)}}{{snakeCase name}}{{else}}{{snakeCase name}}{{/if}}{{/each}});
|
|
40
|
+
{{#if (hasQueryParams this)}}
|
|
41
|
+
let mut query_params: Vec<(String, String)> = Vec::new();
|
|
42
|
+
if let Some(q) = query {
|
|
43
|
+
{{#each _queryParams}}
|
|
44
|
+
if let Some(ref v) = q.{{snakeCase name}} {
|
|
45
|
+
query_params.push(("{{originalName}}".to_string(), v.to_string()));
|
|
46
|
+
}
|
|
47
|
+
{{/each}}
|
|
48
|
+
}
|
|
49
|
+
let query_slice: Option<&[(String, String)]> = if query_params.is_empty() { None } else { Some(&query_params) };
|
|
50
|
+
{{else if queryType}}
|
|
51
|
+
// Query params from typed query object
|
|
52
|
+
let query_slice: Option<&[(String, String)]> = None; // TODO: serialize query type
|
|
53
|
+
{{else}}
|
|
54
|
+
let query_slice: Option<&[(String, String)]> = None;
|
|
55
|
+
{{/if}}
|
|
56
|
+
|
|
57
|
+
{{#if (or (hasRequestBody this) (needsRequestHeaders this))}}
|
|
58
|
+
let mut headers: Vec<(String, String)> = Vec::new();
|
|
59
|
+
{{#if (hasRequestBody this)}}
|
|
60
|
+
{{#if (and (neq requestBody.contentType "application/json") (neq requestBody.contentType "multipart/form-data"))}}
|
|
61
|
+
headers.push(("Content-Type".to_string(), "{{requestBody.contentType}}".to_string()));
|
|
62
|
+
{{/if}}
|
|
63
|
+
{{/if}}
|
|
64
|
+
{{#if (and headerParams.length headerType)}}
|
|
65
|
+
// Header params injected from header options
|
|
66
|
+
{{/if}}
|
|
67
|
+
{{#each headerParams}}
|
|
68
|
+
if let Some(ref h) = header_options.{{snakeCase name}} {
|
|
69
|
+
headers.push(("{{originalName}}".to_string(), h.to_string()));
|
|
70
|
+
}
|
|
71
|
+
{{/each}}
|
|
72
|
+
{{#if cookieParams}}
|
|
73
|
+
// Cookie params
|
|
74
|
+
{{/if}}
|
|
75
|
+
let headers_slice: Option<&[(String, String)]> = if headers.is_empty() { None } else { Some(&headers) };
|
|
76
|
+
{{else}}
|
|
77
|
+
let headers_slice: Option<&[(String, String)]> = None;
|
|
78
|
+
{{/if}}
|
|
79
|
+
|
|
80
|
+
self.transport.execute::<{{#if isEventStream}}Vec<{{#if eventSchema}}{{{rustType eventSchema}}}{{else}}serde_json::Value{{/if}}>{{else}}{{{rustResponseType}}}{{/if}}>(
|
|
81
|
+
Method::{{httpMethod}},
|
|
82
|
+
&path,
|
|
83
|
+
query_slice,
|
|
84
|
+
{{#if requestBody}}
|
|
85
|
+
Some(body),
|
|
86
|
+
{{else}}
|
|
87
|
+
None::<&serde_json::Value>,
|
|
88
|
+
{{/if}}
|
|
89
|
+
headers_slice,
|
|
90
|
+
).await
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
{{/each}}
|
|
94
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
use thiserror::Error;
|
|
2
|
+
|
|
3
|
+
/// Primary error type for the {{crateName}} SDK.
|
|
4
|
+
///
|
|
5
|
+
/// All API methods return `Result<T, SdkError>`.
|
|
6
|
+
#[derive(Error, Debug)]
|
|
7
|
+
pub enum SdkError {
|
|
8
|
+
/// The API returned an error response (4xx/5xx).
|
|
9
|
+
#[error("API error (status {status}): {message}")]
|
|
10
|
+
ApiError {
|
|
11
|
+
/// HTTP status code.
|
|
12
|
+
status: u16,
|
|
13
|
+
/// Machine-readable error code (if available).
|
|
14
|
+
code: Option<String>,
|
|
15
|
+
/// Human-readable error message.
|
|
16
|
+
message: String,
|
|
17
|
+
/// Raw response body for debugging.
|
|
18
|
+
body: String,
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
/// A network-level error occurred (DNS, TLS, connection refused, timeout).
|
|
22
|
+
#[error("network error: {0}")]
|
|
23
|
+
NetworkError(String),
|
|
24
|
+
|
|
25
|
+
/// Failed to deserialize the response body.
|
|
26
|
+
#[error("deserialization error: {0}")]
|
|
27
|
+
DeserializationError(String),
|
|
28
|
+
|
|
29
|
+
/// The request parameters failed client-side validation.
|
|
30
|
+
#[error("validation error: {0}")]
|
|
31
|
+
ValidationError(String),
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
impl SdkError {
|
|
35
|
+
/// Returns the HTTP status code, if this is an `ApiError`.
|
|
36
|
+
pub fn status(&self) -> Option<u16> {
|
|
37
|
+
match self {
|
|
38
|
+
Self::ApiError { status, .. } => Some(*status),
|
|
39
|
+
_ => None,
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// Returns `true` if this error was caused by the server (5xx).
|
|
44
|
+
pub fn is_server_error(&self) -> bool {
|
|
45
|
+
matches!(self, Self::ApiError { status, .. } if *status >= 500)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// Returns `true` if this error was caused by the client (4xx).
|
|
49
|
+
pub fn is_client_error(&self) -> bool {
|
|
50
|
+
matches!(self, Self::ApiError { status, .. } if *status >= 400 && *status < 500)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/// Returns `true` if this is a network error (should be retried safely).
|
|
54
|
+
pub fn is_retryable(&self) -> bool {
|
|
55
|
+
matches!(
|
|
56
|
+
self,
|
|
57
|
+
Self::NetworkError(_)
|
|
58
|
+
| Self::ApiError {
|
|
59
|
+
status: 429 | 502 | 503 | 504,
|
|
60
|
+
..
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// Returns the error message as a string.
|
|
66
|
+
pub fn message(&self) -> &str {
|
|
67
|
+
match self {
|
|
68
|
+
Self::ApiError { message, .. } => message.as_str(),
|
|
69
|
+
Self::NetworkError(msg) => msg.as_str(),
|
|
70
|
+
Self::DeserializationError(msg) => msg.as_str(),
|
|
71
|
+
Self::ValidationError(msg) => msg.as_str(),
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
//! {{title}}
|
|
2
|
+
//!
|
|
3
|
+
//! {{#if description}}{{description}}{{else}}Auto-generated Rust SDK for the {{title}} API.{{/if}}
|
|
4
|
+
//!
|
|
5
|
+
//! # Quick Start
|
|
6
|
+
//!
|
|
7
|
+
//! Add to your `Cargo.toml`:
|
|
8
|
+
//!
|
|
9
|
+
//! ```toml
|
|
10
|
+
//! [dependencies]
|
|
11
|
+
//! {{crateName}} = "{{#if packageVersion}}{{packageVersion}}{{else}}0.1.0{{/if}}"
|
|
12
|
+
//! ```
|
|
13
|
+
//!
|
|
14
|
+
//! Then use it:
|
|
15
|
+
//!
|
|
16
|
+
//! ```rust,no_run
|
|
17
|
+
//! use {{crateName}}::Client;
|
|
18
|
+
//! use {{crateName}}::ClientConfig;
|
|
19
|
+
//!
|
|
20
|
+
//! #[tokio::main]
|
|
21
|
+
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
22
|
+
//! let mut config = ClientConfig::default();
|
|
23
|
+
{{#each securitySchemes}}
|
|
24
|
+
{{#if (eq type "apiKey")}}
|
|
25
|
+
//! config.{{snakeCase configKey}} = Some("your-api-key".to_string());
|
|
26
|
+
{{/if}}
|
|
27
|
+
{{#if (and (eq type "http") (eq scheme "bearer"))}}
|
|
28
|
+
//! config.{{snakeCase configKey}} = Some("your-bearer-token".to_string());
|
|
29
|
+
{{/if}}
|
|
30
|
+
{{/each}}
|
|
31
|
+
//!
|
|
32
|
+
//! let client = Client::new(config);
|
|
33
|
+
//!
|
|
34
|
+
//! // Use domain clients
|
|
35
|
+
//! // let result = client.{{#each groups}}{{#if @first}}{{snakeCase name}}{{/if}}{{/each}}.some_method().await?;
|
|
36
|
+
//!
|
|
37
|
+
//! Ok(())
|
|
38
|
+
//! }
|
|
39
|
+
//! ```
|
|
40
|
+
//!
|
|
41
|
+
//! ## API Reference
|
|
42
|
+
//!
|
|
43
|
+
{{#each groups}}
|
|
44
|
+
//! ### `{{interfaceName}}`
|
|
45
|
+
//! {{#if description}}{{description}}{{/if}}
|
|
46
|
+
//!
|
|
47
|
+
{{#each operations}}
|
|
48
|
+
//! - `{{snakeCase name}}()` — {{#if summary}}{{summary}}{{else}}No summary{{/if}}
|
|
49
|
+
{{/each}}
|
|
50
|
+
//!
|
|
51
|
+
{{/each}}
|
|
52
|
+
//!
|
|
53
|
+
//! ## Error Handling
|
|
54
|
+
//!
|
|
55
|
+
//! All API methods return `Result<T, SdkError>`. The `SdkError` enum covers:
|
|
56
|
+
//!
|
|
57
|
+
//! - **ApiError** — server returned an error response (4xx/5xx)
|
|
58
|
+
//! - **NetworkError** — request failed due to network issues
|
|
59
|
+
//! - **DeserializationError** — response body could not be parsed
|
|
60
|
+
//! - **ValidationError** — invalid request parameters
|
|
61
|
+
//!
|
|
62
|
+
//! ```rust
|
|
63
|
+
//! match client.some_domain.some_method().await {
|
|
64
|
+
//! Ok(response) => println!("Success: {:?}", response),
|
|
65
|
+
//! Err(SdkError::ApiError { status, .. }) => eprintln!("API error ({}): {}", status, error),
|
|
66
|
+
//! Err(SdkError::NetworkError(e)) => eprintln!("Network error: {}", e),
|
|
67
|
+
//! Err(e) => eprintln!("Other error: {}", e),
|
|
68
|
+
//! }
|
|
69
|
+
//! ```
|
|
70
|
+
|
|
71
|
+
pub mod client;
|
|
72
|
+
pub mod transport;
|
|
73
|
+
pub mod error;
|
|
74
|
+
pub mod types;
|
|
75
|
+
pub mod api;
|
|
76
|
+
|
|
77
|
+
pub use client::*;
|
|
78
|
+
pub use error::SdkError;
|
|
79
|
+
|
|
80
|
+
/// Re-export API resource modules
|
|
81
|
+
pub mod resources {
|
|
82
|
+
{{#each groups}}
|
|
83
|
+
pub use super::api::{{snakeCase fileName}}::*;
|
|
84
|
+
{{/each}}
|
|
85
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# {{title}}
|
|
2
|
+
|
|
3
|
+
{{#if description}}{{description}}{{/if}}
|
|
4
|
+
|
|
5
|
+
{{#unless description}}An auto-generated Rust SDK for the {{title}} API.{{/unless}}
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Add this to your `Cargo.toml`:
|
|
10
|
+
|
|
11
|
+
```toml
|
|
12
|
+
[dependencies]
|
|
13
|
+
{{crateName}} = "{{#if packageVersion}}{{packageVersion}}{{else}}0.1.0{{/if}}"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```rust
|
|
19
|
+
use {{crateName}}::Client;
|
|
20
|
+
use {{crateName}}::ClientConfig;
|
|
21
|
+
|
|
22
|
+
#[tokio::main]
|
|
23
|
+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
24
|
+
let mut config = ClientConfig::default();
|
|
25
|
+
{{#each securitySchemes}}
|
|
26
|
+
{{#if (eq type "apiKey")}}
|
|
27
|
+
config.{{snakeCase configKey}} = Some("your-api-key".to_string());
|
|
28
|
+
{{/if}}
|
|
29
|
+
{{#if (and (eq type "http") (eq scheme "bearer"))}}
|
|
30
|
+
config.{{snakeCase configKey}} = Some("your-bearer-token".to_string());
|
|
31
|
+
{{/if}}
|
|
32
|
+
{{/each}}
|
|
33
|
+
|
|
34
|
+
let client = Client::new(config);
|
|
35
|
+
|
|
36
|
+
// Use domain clients
|
|
37
|
+
{{#each groups}}
|
|
38
|
+
{{#if @first}}
|
|
39
|
+
// let result = client.{{snakeCase name}}.some_operation().await?;
|
|
40
|
+
{{/if}}
|
|
41
|
+
{{/each}}
|
|
42
|
+
|
|
43
|
+
Ok(())
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## API Reference
|
|
48
|
+
|
|
49
|
+
{{#each groups}}
|
|
50
|
+
### {{interfaceName}}
|
|
51
|
+
|
|
52
|
+
{{#if description}}
|
|
53
|
+
{{description}}
|
|
54
|
+
{{/if}}
|
|
55
|
+
|
|
56
|
+
| Method | HTTP | Description |
|
|
57
|
+
|--------|------|-------------|
|
|
58
|
+
{{#each operations}}
|
|
59
|
+
| `{{snakeCase name}}()` | `{{httpMethod}}` | {{#if summary}}{{summary}}{{else}}—{{/if}} |
|
|
60
|
+
{{/each}}
|
|
61
|
+
|
|
62
|
+
{{/each}}
|
|
63
|
+
|
|
64
|
+
## Error Handling
|
|
65
|
+
|
|
66
|
+
All API methods return `Result<T, SdkError>`. The `SdkError` enum has these variants:
|
|
67
|
+
|
|
68
|
+
| Variant | Description |
|
|
69
|
+
|---------|-------------|
|
|
70
|
+
| `ApiError` | Server returned an error (4xx/5xx) |
|
|
71
|
+
| `NetworkError` | Request failed due to connectivity issues |
|
|
72
|
+
| `DeserializationError` | Response body could not be parsed |
|
|
73
|
+
| `ValidationError` | Invalid request parameters |
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
MIT
|