Skip to content

Commit d1528a2

Browse files
authored
feat: Upgrade apis to v2 & allow to select apis via feature flag for optimized compile times (#565)
This is achieved by the following steps: * generate clients including feature flag * guard individual apis with features flags * switch from v2beta to v2 apis
1 parent 1fc3513 commit d1528a2

File tree

6 files changed

+143
-27
lines changed

6 files changed

+143
-27
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
Cargo.lock
33
temp*
44
src/api/generated
5+
.idea

Cargo.toml

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,38 @@ default = []
2121
## Feature that enables support for the [actix framework](https://actix.rs/).
2222
actix = ["credentials", "oidc", "dep:actix-web"]
2323

24-
## The API feature enables the gRPC service clients to access the ZITADEL API.
25-
api = ["dep:prost", "dep:prost-types", "dep:tonic", "dep:tonic-types", "dep:pbjson-types"]
24+
## The API feature enables all gRPC service clients to access the ZITADEL API.
25+
api = [
26+
"api-admin-v1",
27+
"api-auth-v1",
28+
"api-management-v1",
29+
"api-system-v1",
30+
"api-oidc-v2",
31+
"api-org-v2",
32+
"api-session-v2",
33+
"api-settings-v2",
34+
"api-user-v2"
35+
]
36+
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
37+
api-admin-v1 = ["api-common", "zitadel-admin-v1" ]
38+
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
39+
api-auth-v1 = ["api-common", "zitadel-auth-v1" ]
40+
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
41+
api-management-v1 = ["api-common", "zitadel-v1-v1" ]
42+
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
43+
api-system-v1 = ["api-common", "zitadel-system-v1", "zitadel-authn-v1" ]
44+
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
45+
api-oidc-v2 = ["api-common", "zitadel-oidc-v2" ]
46+
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
47+
api-org-v2 = ["api-common", "zitadel-org-v2", "zitadel-user-v2" ]
48+
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
49+
api-session-v2 = ["api-common", "zitadel-session-v2" ]
50+
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
51+
api-settings-v2 = ["api-common", "zitadel-settings-v2" ]
52+
## The API feature enables all gRPC service clients to access the respective ZITADEL API.
53+
api-user-v2 = ["api-common", "zitadel-user-v2" ]
54+
api-common = ["dep:prost", "dep:prost-types", "dep:tonic", "dep:tonic-types", "dep:pbjson-types" ]
55+
2656

2757
## Feature that enables support for the [axum framework](https://docs.rs/axum/latest/axum/).
2858
axum = ["credentials", "oidc", "dep:axum", "dep:axum-extra"]
@@ -36,7 +66,7 @@ credentials = ["dep:jsonwebtoken", "dep:openidconnect", "dep:reqwest", "dep:serd
3666
## new convenience functions to create a gRPC client with interceptors.
3767
## The interceptors provide easy access to an authenticated ZITADEL API client.
3868
## The interceptors work with the credentials from this crate.
39-
interceptors = ["api", "credentials", "dep:time", "dep:tokio"]
69+
interceptors = ["credentials", "dep:time", "dep:tokio"]
4070

4171
## This feature enables caching of the OIDC discovery and introspection results.
4272
## By default, only the in-memory cache is available. To use a different cache,
@@ -54,6 +84,59 @@ oidc = ["credentials", "dep:base64-compat"]
5484
## Refer to the rocket module for more information.
5585
rocket = ["credentials", "oidc", "dep:rocket"]
5686

87+
# @@protoc_deletion_point(features)
88+
# This section is automatically generated by protoc-gen-prost-crate.
89+
# Changes in this area may be lost on regeneration.
90+
proto_full = ["zitadel-action-v1","zitadel-admin-v1","zitadel-app-v1","zitadel-auth-v1","zitadel-authn-v1","zitadel-change-v1","zitadel-event-v1","zitadel-feature-v1","zitadel-feature-v2","zitadel-feature-v2beta","zitadel-idp-v1","zitadel-idp-v2","zitadel-instance-v1","zitadel-management-v1","zitadel-member-v1","zitadel-metadata-v1","zitadel-milestone-v1","zitadel-object-v2","zitadel-object-v2beta","zitadel-object-v3alpha","zitadel-oidc-v2","zitadel-oidc-v2beta","zitadel-org-v1","zitadel-org-v2","zitadel-org-v2beta","zitadel-policy-v1","zitadel-project-v1","zitadel-protoc_gen_zitadel-v2","zitadel-quota-v1","zitadel-resources-action-v3alpha","zitadel-resources-object-v3alpha","zitadel-resources-webkey-v3alpha","zitadel-session-v2","zitadel-session-v2beta","zitadel-settings-object-v3alpha","zitadel-settings-v1","zitadel-settings-v2","zitadel-settings-v2beta","zitadel-system-v1","zitadel-text-v1","zitadel-user-schema-v3alpha","zitadel-user-v1","zitadel-user-v2","zitadel-user-v2beta","zitadel-user-v3alpha","zitadel-v1","zitadel-v1-v1"]
91+
"zitadel-action-v1" = ["zitadel-v1"]
92+
"zitadel-admin-v1" = ["zitadel-event-v1","zitadel-idp-v1","zitadel-instance-v1","zitadel-management-v1","zitadel-member-v1","zitadel-milestone-v1","zitadel-org-v1","zitadel-policy-v1","zitadel-settings-v1","zitadel-text-v1","zitadel-v1","zitadel-v1-v1"]
93+
"zitadel-app-v1" = ["zitadel-v1"]
94+
"zitadel-auth-v1" = ["zitadel-change-v1","zitadel-idp-v1","zitadel-metadata-v1","zitadel-org-v1","zitadel-policy-v1","zitadel-user-v1","zitadel-v1"]
95+
"zitadel-authn-v1" = ["zitadel-v1"]
96+
"zitadel-change-v1" = ["zitadel-v1"]
97+
"zitadel-event-v1" = ["zitadel-v1"]
98+
"zitadel-feature-v1" = []
99+
"zitadel-feature-v2" = ["zitadel-object-v2"]
100+
"zitadel-feature-v2beta" = ["zitadel-object-v2beta"]
101+
"zitadel-idp-v1" = ["zitadel-v1"]
102+
"zitadel-idp-v2" = ["zitadel-object-v2"]
103+
"zitadel-instance-v1" = ["zitadel-v1"]
104+
"zitadel-management-v1" = ["zitadel-action-v1","zitadel-app-v1","zitadel-authn-v1","zitadel-change-v1","zitadel-idp-v1","zitadel-member-v1","zitadel-metadata-v1","zitadel-org-v1","zitadel-policy-v1","zitadel-project-v1","zitadel-text-v1","zitadel-user-v1","zitadel-v1"]
105+
"zitadel-member-v1" = ["zitadel-user-v1","zitadel-v1"]
106+
"zitadel-metadata-v1" = ["zitadel-v1"]
107+
"zitadel-milestone-v1" = []
108+
"zitadel-object-v2" = []
109+
"zitadel-object-v2beta" = []
110+
"zitadel-object-v3alpha" = []
111+
"zitadel-oidc-v2" = ["zitadel-object-v2"]
112+
"zitadel-oidc-v2beta" = ["zitadel-object-v2beta"]
113+
"zitadel-org-v1" = ["zitadel-v1"]
114+
"zitadel-org-v2" = ["zitadel-object-v2"]
115+
"zitadel-org-v2beta" = ["zitadel-object-v2beta"]
116+
"zitadel-policy-v1" = ["zitadel-idp-v1","zitadel-v1"]
117+
"zitadel-project-v1" = ["zitadel-v1"]
118+
"zitadel-protoc_gen_zitadel-v2" = []
119+
"zitadel-quota-v1" = []
120+
"zitadel-resources-action-v3alpha" = ["zitadel-object-v3alpha","zitadel-resources-object-v3alpha"]
121+
"zitadel-resources-object-v3alpha" = ["zitadel-object-v3alpha"]
122+
"zitadel-resources-webkey-v3alpha" = ["zitadel-object-v3alpha","zitadel-resources-object-v3alpha"]
123+
"zitadel-session-v2" = ["zitadel-object-v2","zitadel-v1"]
124+
"zitadel-session-v2beta" = ["zitadel-object-v2beta","zitadel-v1"]
125+
"zitadel-settings-object-v3alpha" = ["zitadel-object-v3alpha"]
126+
"zitadel-settings-v1" = ["zitadel-v1"]
127+
"zitadel-settings-v2" = ["zitadel-object-v2"]
128+
"zitadel-settings-v2beta" = ["zitadel-object-v2beta"]
129+
"zitadel-system-v1" = ["zitadel-feature-v1","zitadel-instance-v1","zitadel-member-v1","zitadel-quota-v1","zitadel-v1"]
130+
"zitadel-text-v1" = ["zitadel-v1"]
131+
"zitadel-user-schema-v3alpha" = ["zitadel-object-v2"]
132+
"zitadel-user-v1" = ["zitadel-v1"]
133+
"zitadel-user-v2" = ["zitadel-object-v2"]
134+
"zitadel-user-v2beta" = ["zitadel-object-v2beta"]
135+
"zitadel-user-v3alpha" = ["zitadel-object-v2"]
136+
"zitadel-v1" = []
137+
"zitadel-v1-v1" = ["zitadel-authn-v1","zitadel-idp-v1","zitadel-management-v1","zitadel-org-v1","zitadel-v1"]
138+
# @@protoc_insertion_point(features)
139+
57140
[dependencies]
58141
actix-web = { version = "4.5.1", optional = true }
59142
async-trait = { version = "0.1.80", optional = true }
@@ -64,9 +147,9 @@ custom_error = "1.9.2"
64147
document-features = { version = "0.2.8", optional = true }
65148
jsonwebtoken = { version = "9.3.0", optional = true }
66149
openidconnect = { version = "3.5.0", optional = true }
67-
pbjson-types = { version = "0.6", optional = true }
68-
prost = { version = "0.12.4", optional = true }
69-
prost-types = { version = "0.12.4", optional = true }
150+
pbjson-types = { version = "0.7.0", optional = true }
151+
prost = { version = "0.13.1", optional = true }
152+
prost-types = { version = "0.13.1", optional = true }
70153
reqwest = { version = "0.11.27", features = ["json", "rustls-tls"], default-features = false, optional = true }
71154
rocket = { version = "0.5.0", optional = true }
72155
serde = { version = "1.0.200", features = ["derive"], optional = true }
@@ -77,17 +160,16 @@ tokio = { version = "1.37.0", optional = true, features = [
77160
"macros",
78161
"rt-multi-thread",
79162
] }
80-
tonic = { version = "0.11", features = [
163+
tonic = { version = "0.12.1", features = [
81164
"tls",
82165
"tls-roots",
83-
"tls-roots-common",
84166
], optional = true }
85-
tonic-types = { version = "0.11", optional = true }
167+
tonic-types = { version = "0.12.1", optional = true }
86168

87169
[dev-dependencies]
88170
chrono = "0.4.38"
89171
tokio = { version = "1.37.0", features = ["macros", "rt-multi-thread"] }
90172
tower = { version = "0.4.13" }
91173

92174
[package.metadata.docs.rs]
93-
all-features = true
175+
all-features = true

buf.gen.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ plugins:
1515
- extern_path=.google.protobuf=::pbjson_types
1616
- no_server
1717
- name: prost-crate
18-
out: src/api/generated
18+
out: .
1919
strategy: all
2020
opt:
21-
- no_features
22-
- include_file=mod.rs
21+
- gen_crate
22+
- include_file=src/api/generated/mod.rs

src/api/clients.rs

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,44 @@ use std::error::Error;
88
use custom_error::custom_error;
99
use tonic::codegen::InterceptedService;
1010
use tonic::service::Interceptor;
11-
use tonic::transport::{Channel, Endpoint};
11+
use tonic::transport::{Channel, ClientTlsConfig, Endpoint};
1212
use tonic::{Request, Status};
1313

14+
#[cfg(feature = "interceptors")]
1415
use crate::api::interceptors::{AccessTokenInterceptor, ServiceAccountInterceptor};
15-
use crate::api::zitadel::oidc::v2beta::oidc_service_client::OidcServiceClient;
16-
use crate::api::zitadel::org::v2beta::organization_service_client::OrganizationServiceClient;
17-
use crate::api::zitadel::session::v2beta::session_service_client::SessionServiceClient;
18-
use crate::api::zitadel::settings::v2beta::settings_service_client::SettingsServiceClient;
16+
17+
#[cfg(feature = "api-oidc-v2")]
18+
use crate::api::zitadel::oidc::v2::oidc_service_client::OidcServiceClient;
19+
#[cfg(feature = "api-org-v2")]
20+
use crate::api::zitadel::org::v2::organization_service_client::OrganizationServiceClient;
21+
#[cfg(feature = "api-session-v2")]
22+
use crate::api::zitadel::session::v2::session_service_client::SessionServiceClient;
23+
#[cfg(feature = "api-settings-v2")]
24+
use crate::api::zitadel::settings::v2::settings_service_client::SettingsServiceClient;
25+
#[cfg(feature = "api-user-v2")]
26+
use crate::api::zitadel::user::v2::user_service_client::UserServiceClient;
27+
28+
#[cfg(feature = "api-admin-v1")]
29+
use crate::api::zitadel::admin::v1::admin_service_client::AdminServiceClient;
30+
#[cfg(feature = "api-auth-v1")]
31+
use crate::api::zitadel::auth::v1::auth_service_client::AuthServiceClient;
32+
#[cfg(feature = "api-management-v1")]
33+
use crate::api::zitadel::management::v1::management_service_client::ManagementServiceClient;
34+
#[cfg(feature = "api-system-v1")]
1935
use crate::api::zitadel::system::v1::system_service_client::SystemServiceClient;
20-
use crate::api::zitadel::user::v2beta::user_service_client::UserServiceClient;
21-
use crate::credentials::{AuthenticationOptions, ServiceAccount};
2236

23-
use super::zitadel::{
24-
admin::v1::admin_service_client::AdminServiceClient,
25-
auth::v1::auth_service_client::AuthServiceClient,
26-
management::v1::management_service_client::ManagementServiceClient,
27-
};
37+
#[cfg(feature = "interceptors")]
38+
use crate::credentials::{AuthenticationOptions, ServiceAccount};
2839

2940
custom_error! {
3041
/// Errors that may occur when creating a client.
3142
pub ClientError
3243
InvalidUrl = "the provided url is invalid",
3344
ConnectionError = "could not connect to provided endpoint",
45+
TlsInitializationError = "could not setup tls connection",
3446
}
3547

48+
#[cfg(feature = "interceptors")]
3649
enum AuthType {
3750
None,
3851
AccessToken(String),
@@ -56,6 +69,7 @@ impl ChainedInterceptor {
5669
}
5770
}
5871

72+
#[cfg(feature = "interceptors")]
5973
pub(crate) fn add_interceptor(mut self, interceptor: Box<dyn Interceptor + Send>) -> Self {
6074
self.interceptors.push(interceptor);
6175
self
@@ -77,6 +91,7 @@ impl Interceptor for ChainedInterceptor {
7791
/// an authentication method.
7892
pub struct ClientBuilder {
7993
api_endpoint: String,
94+
#[cfg(feature = "interceptors")]
8095
auth_type: AuthType,
8196
}
8297

@@ -85,6 +100,7 @@ impl ClientBuilder {
85100
pub fn new(api_endpoint: &str) -> Self {
86101
Self {
87102
api_endpoint: api_endpoint.to_string(),
103+
#[cfg(feature = "interceptors")]
88104
auth_type: AuthType::None,
89105
}
90106
}
@@ -127,6 +143,7 @@ impl ClientBuilder {
127143
/// This function returns a [`ClientError`] if the provided API endpoint
128144
/// cannot be parsed into a valid URL or if the connection to the endpoint
129145
/// is not possible.
146+
#[cfg(feature = "api-admin-v1")]
130147
pub async fn build_admin_client(
131148
&self,
132149
) -> Result<AdminServiceClient<InterceptedService<Channel, ChainedInterceptor>>, Box<dyn Error>>
@@ -148,6 +165,7 @@ impl ClientBuilder {
148165
/// This function returns a [`ClientError`] if the provided API endpoint
149166
/// cannot be parsed into a valid URL or if the connection to the endpoint
150167
/// is not possible.
168+
#[cfg(feature = "api-auth-v1")]
151169
pub async fn build_auth_client(
152170
&self,
153171
) -> Result<AuthServiceClient<InterceptedService<Channel, ChainedInterceptor>>, Box<dyn Error>>
@@ -169,6 +187,7 @@ impl ClientBuilder {
169187
/// This function returns a [`ClientError`] if the provided API endpoint
170188
/// cannot be parsed into a valid URL or if the connection to the endpoint
171189
/// is not possible.
190+
#[cfg(feature = "api-management-v1")]
172191
pub async fn build_management_client(
173192
&self,
174193
) -> Result<
@@ -192,6 +211,7 @@ impl ClientBuilder {
192211
/// This function returns a [`ClientError`] if the provided API endpoint
193212
/// cannot be parsed into a valid URL or if the connection to the endpoint
194213
/// is not possible.
214+
#[cfg(feature = "api-oidc-v2")]
195215
pub async fn build_oidc_client(
196216
&self,
197217
) -> Result<OidcServiceClient<InterceptedService<Channel, ChainedInterceptor>>, Box<dyn Error>>
@@ -213,6 +233,7 @@ impl ClientBuilder {
213233
/// This function returns a [`ClientError`] if the provided API endpoint
214234
/// cannot be parsed into a valid URL or if the connection to the endpoint
215235
/// is not possible.
236+
#[cfg(feature = "api-org-v2")]
216237
pub async fn build_organization_client(
217238
&self,
218239
) -> Result<
@@ -236,6 +257,7 @@ impl ClientBuilder {
236257
/// This function returns a [`ClientError`] if the provided API endpoint
237258
/// cannot be parsed into a valid URL or if the connection to the endpoint
238259
/// is not possible.
260+
#[cfg(feature = "api-session-v2")]
239261
pub async fn build_session_client(
240262
&self,
241263
) -> Result<SessionServiceClient<InterceptedService<Channel, ChainedInterceptor>>, Box<dyn Error>>
@@ -257,6 +279,7 @@ impl ClientBuilder {
257279
/// This function returns a [`ClientError`] if the provided API endpoint
258280
/// cannot be parsed into a valid URL or if the connection to the endpoint
259281
/// is not possible.
282+
#[cfg(feature = "api-settings-v2")]
260283
pub async fn build_settings_client(
261284
&self,
262285
) -> Result<
@@ -280,6 +303,7 @@ impl ClientBuilder {
280303
/// This function returns a [`ClientError`] if the provided API endpoint
281304
/// cannot be parsed into a valid URL or if the connection to the endpoint
282305
/// is not possible.
306+
#[cfg(feature = "api-system-v1")]
283307
pub async fn build_system_client(
284308
&self,
285309
) -> Result<SystemServiceClient<InterceptedService<Channel, ChainedInterceptor>>, Box<dyn Error>>
@@ -301,6 +325,7 @@ impl ClientBuilder {
301325
/// This function returns a [`ClientError`] if the provided API endpoint
302326
/// cannot be parsed into a valid URL or if the connection to the endpoint
303327
/// is not possible.
328+
#[cfg(feature = "api-user-v2")]
304329
pub async fn build_user_client(
305330
&self,
306331
) -> Result<UserServiceClient<InterceptedService<Channel, ChainedInterceptor>>, Box<dyn Error>>
@@ -313,7 +338,9 @@ impl ClientBuilder {
313338
}
314339

315340
fn get_chained_interceptor(&self) -> ChainedInterceptor {
341+
#[allow(unused_mut)]
316342
let mut interceptor = ChainedInterceptor::new();
343+
#[cfg(feature = "interceptors")]
317344
match &self.auth_type {
318345
AuthType::AccessToken(token) => {
319346
interceptor =
@@ -337,6 +364,12 @@ impl ClientBuilder {
337364
async fn get_channel(api_endpoint: &str) -> Result<Channel, ClientError> {
338365
Endpoint::from_shared(api_endpoint.to_string())
339366
.map_err(|_| ClientError::InvalidUrl)?
367+
.tls_config(
368+
ClientTlsConfig::default()
369+
.assume_http2(true)
370+
.with_native_roots(),
371+
)
372+
.map_err(|_| ClientError::TlsInitializationError)?
340373
.connect()
341374
.await
342375
.map_err(|_| ClientError::ConnectionError)

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
#[cfg(feature = "actix")]
3939
pub mod actix;
40-
#[cfg(feature = "api")]
40+
#[cfg(feature = "api-common")]
4141
pub mod api;
4242
#[cfg(feature = "axum")]
4343
pub mod axum;

src/oidc/introspection/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ custom_error! {
3636
/// by default and [additional claims](https://zitadel.com/docs/apis/openidoauth/claims)
3737
/// if requested by scope:
3838
/// - When scope contains `urn:zitadel:iam:user:resourceowner`, the fields prefixed with
39-
/// `resource_owner_` are set.
39+
/// `resource_owner_` are set.
4040
/// - When scope contains `urn:zitadel:iam:user:metadata`, the metadata hashmap will be
4141
/// filled with the user metadata.
4242
#[derive(Clone, Debug, Serialize, Deserialize, Default)]

0 commit comments

Comments
 (0)