zeebe_rs/process_instance/
create.rs

1use crate::Client;
2use crate::ClientError;
3use crate::proto;
4use serde::Serialize;
5use serde::de::DeserializeOwned;
6
7const LATEST_VERSION: i32 = -1;
8
9#[derive(Debug, Clone)]
10pub struct Initial;
11
12#[derive(Debug, Clone)]
13pub struct WithProcess;
14
15#[derive(Debug, Clone)]
16pub struct WithVariables;
17
18#[derive(Debug, Clone)]
19pub struct WithResult;
20
21pub trait CreateProcessInstanceState {}
22impl CreateProcessInstanceState for Initial {}
23impl CreateProcessInstanceState for WithProcess {}
24impl CreateProcessInstanceState for WithVariables {}
25impl CreateProcessInstanceState for WithResult {}
26
27/// Request to create a process instance in Zeebe
28///
29/// This builder-like struct allows you to configure and send a request to create a new process instance
30/// in the Zeebe workflow engine. The request goes through several states to ensure all required parameters
31/// are set before sending.
32///
33/// # Examples
34///
35/// ```ignore
36/// // Create a process instance with a BPMN process ID and no input variables
37/// client
38///     .create_process_instance()
39///     .with_bpmn_process_id(String::from("order-process"))
40///     .without_input()
41///     .send()
42///     .await?;
43///
44/// // Create a process instance with a process definition key and input variables
45/// client
46///     .create_process_instance()
47///     .with_process_definition_key(12345)
48///     .with_variables(json!({"orderId": 123}))
49///     .unwrap()
50///     .send()
51///     .await?;
52/// ```
53#[derive(Debug, Clone)]
54pub struct CreateProcessInstanceRequest<T: CreateProcessInstanceState> {
55    client: Client,
56    process_definition_key: Option<i64>,
57    bpmn_process_id: Option<String>,
58    version: Option<i32>,
59    input: Option<serde_json::Value>,
60    start_instructions: Vec<String>,
61    tenant_id: String,
62    operation_reference: Option<u64>,
63    fetch_variables: Option<Vec<String>>,
64    request_timeout: i64,
65    _state: std::marker::PhantomData<T>,
66}
67
68impl<T: CreateProcessInstanceState> CreateProcessInstanceRequest<T> {
69    pub(crate) fn new(client: Client) -> CreateProcessInstanceRequest<Initial> {
70        CreateProcessInstanceRequest {
71            client,
72            process_definition_key: None,
73            bpmn_process_id: None,
74            version: None,
75            input: None,
76            start_instructions: vec![],
77            tenant_id: String::default(),
78            operation_reference: None,
79            fetch_variables: None,
80            request_timeout: 0,
81            _state: std::marker::PhantomData,
82        }
83    }
84
85    fn transition<NewState: CreateProcessInstanceState>(
86        self,
87    ) -> CreateProcessInstanceRequest<NewState> {
88        CreateProcessInstanceRequest {
89            client: self.client,
90            process_definition_key: self.process_definition_key,
91            bpmn_process_id: self.bpmn_process_id,
92            version: self.version,
93            input: self.input,
94            start_instructions: self.start_instructions,
95            tenant_id: self.tenant_id,
96            operation_reference: self.operation_reference,
97            fetch_variables: self.fetch_variables,
98            request_timeout: self.request_timeout,
99            _state: std::marker::PhantomData,
100        }
101    }
102}
103
104impl CreateProcessInstanceRequest<Initial> {
105    /// Sets the BPMN process ID to identify in which process to instantiate.
106    ///
107    /// # Arguments
108    ///
109    /// * `bpmn_process_id` - The BPMN process ID of the instance to create.
110    ///
111    /// # Returns
112    ///
113    /// A `CreateProcessInstanceRequest<WithProcess>` to continue the request building.
114    pub fn with_bpmn_process_id(
115        mut self,
116        bpmn_process_id: String,
117    ) -> CreateProcessInstanceRequest<WithProcess> {
118        self.bpmn_process_id = Some(bpmn_process_id);
119        self.transition()
120    }
121
122    /// Sets the process definition key to identify in which process to instantiate.
123    ///
124    /// # Arguments
125    ///
126    /// * `process_definition_key` - The unique key identifying the process definition.
127    ///
128    /// # Returns
129    ///
130    /// A `CreateProcessInstanceRequest<WithProcess>` to continue the request building.
131    pub fn with_process_definition_key(
132        mut self,
133        process_definition_key: i64,
134    ) -> CreateProcessInstanceRequest<WithProcess> {
135        self.process_definition_key = Some(process_definition_key);
136        self.transition()
137    }
138}
139
140impl CreateProcessInstanceRequest<WithProcess> {
141    /// Sets the variables to instantiate the process with.
142    ///
143    /// # Arguments
144    ///
145    /// * `variables` - Variables that will be used as instance payload.
146    ///
147    /// # Errors
148    ///
149    /// Returns `ClientError` if variables cannot be serialized to JSON.
150    ///
151    /// # Returns
152    ///
153    /// A `Result` containing either a `CreateProcessInstanceRequest<WithVariables>` if successful, or a `ClientError` if serialization fails.
154    pub fn with_variables<T: Serialize>(
155        mut self,
156        variables: T,
157    ) -> Result<CreateProcessInstanceRequest<WithVariables>, ClientError> {
158        self.input = Some(
159            serde_json::to_value(variables)
160                .map_err(|e| ClientError::SerializationFailed { source: e })?,
161        );
162        Ok(self.transition())
163    }
164
165    /// Creates the process instance without any input variables
166    ///
167    /// # Returns
168    ///
169    /// A `CreateProcessInstanceRequest<WithVariables>` to continue the request building.
170    pub fn without_input(self) -> CreateProcessInstanceRequest<WithVariables> {
171        self.transition()
172    }
173}
174
175impl CreateProcessInstanceRequest<WithVariables> {
176    /// Sends the process instance creation request to the Zeebe workflow engine.
177    ///
178    /// # Errors
179    ///
180    /// Returns `ClientError` if the request fails.
181    pub async fn send(mut self) -> Result<CreateProcessInstanceResponse, ClientError> {
182        let res = self
183            .client
184            .gateway_client
185            .create_process_instance(proto::CreateProcessInstanceRequest {
186                process_definition_key: self.process_definition_key.unwrap_or(0),
187                bpmn_process_id: self.bpmn_process_id.unwrap_or_default(),
188                version: self.version.unwrap_or(LATEST_VERSION),
189                variables: self
190                    .input
191                    .map_or(String::new(), |variables| variables.to_string()),
192                start_instructions: self
193                    .start_instructions
194                    .into_iter()
195                    .map(|s| proto::ProcessInstanceCreationStartInstruction { element_id: s })
196                    .collect(),
197                tenant_id: self.tenant_id,
198                operation_reference: self.operation_reference,
199            })
200            .await?;
201
202        Ok(res.into_inner().into())
203    }
204
205    /// Configures which variables to fetch when the process completes
206    ///
207    /// # Arguments
208    /// * `fetch_variables` - Optional list of variable names to fetch, or None to fetch all
209    ///
210    /// # Returns
211    ///
212    /// A `CreateProcessInstanceRequest<WithResult>` to continue the request building.
213    pub fn with_result(
214        mut self,
215        fetch_variables: Option<Vec<String>>,
216    ) -> CreateProcessInstanceRequest<WithResult> {
217        self.fetch_variables = fetch_variables;
218        self.transition()
219    }
220
221    /// Sets the version of the process definition to use.
222    ///
223    /// Use `-1` to select the latest deployed version.
224    ///
225    /// # Arguments
226    ///
227    /// * `version` - The version of the process definition.
228    ///
229    /// # Returns
230    ///
231    /// A `CreateProcessInstanceRequest<WithVariables>` to continue the request building.
232    pub fn with_version(mut self, version: i32) -> Self {
233        self.version = Some(version);
234        self
235    }
236
237    /// Sets the tenant ID for the process instance.
238    ///
239    /// # Arguments
240    ///
241    /// * `tenant_id` - The tenant ID.
242    ///
243    /// # Returns
244    ///
245    /// A `CreateProcessInstanceRequest<WithVariables>` to continue the request building.
246    pub fn with_tenant_id(mut self, tenant_id: String) -> Self {
247        self.tenant_id = tenant_id;
248        self
249    }
250
251    /// Sets a reference key for tracking this operation.
252    ///
253    /// # Arguments
254    ///
255    /// * `operation_reference` - The reference key.
256    ///
257    /// # Returns
258    ///
259    /// A `CreateProcessInstanceRequest<WithVariables>` to continue the request building.
260    pub fn with_operation_reference(mut self, operation_reference: u64) -> Self {
261        self.operation_reference = Some(operation_reference);
262        self
263    }
264}
265
266impl CreateProcessInstanceRequest<WithResult> {
267    async fn send(mut self) -> Result<proto::CreateProcessInstanceWithResultResponse, ClientError> {
268        let res = self
269            .client
270            .gateway_client
271            .create_process_instance_with_result(proto::CreateProcessInstanceWithResultRequest {
272                request: Some(proto::CreateProcessInstanceRequest {
273                    process_definition_key: self.process_definition_key.unwrap_or(0),
274                    bpmn_process_id: self.bpmn_process_id.unwrap_or_default(),
275                    version: self.version.unwrap_or(LATEST_VERSION),
276                    variables: self
277                        .input
278                        .map_or(String::new(), |variables| variables.to_string()),
279                    start_instructions: self
280                        .start_instructions
281                        .into_iter()
282                        .map(|s| proto::ProcessInstanceCreationStartInstruction { element_id: s })
283                        .collect(),
284                    tenant_id: self.tenant_id,
285                    operation_reference: self.operation_reference,
286                }),
287                request_timeout: self.request_timeout,
288                fetch_variables: self.fetch_variables.unwrap_or_default(),
289            })
290            .await?;
291
292        Ok(res.into_inner())
293    }
294
295    /// Sends the request and returns serialized result variables as JSON.
296    ///
297    /// # Errors
298    ///
299    /// Returns `ClientError` if the request fails.
300    pub async fn send_with_serialized_result(
301        self,
302    ) -> Result<CreateProcessInstanceWithResultSerialized, ClientError> {
303        let res = self.send().await?;
304        Ok(res.into())
305    }
306
307    /// Sends the request and deserializes result variables into the specified type.
308    ///
309    /// # Errors
310    ///
311    /// Returns `ClientError` if the request fails or deserialization fails.
312    pub async fn send_with_result<T: DeserializeOwned>(
313        self,
314    ) -> Result<CreateProcessInstanceWithResult<T>, ClientError> {
315        let res = self.send().await?;
316        res.try_into()
317    }
318}
319
320#[derive(Debug, Clone)]
321/// Response from creating a process instance
322pub struct CreateProcessInstanceResponse {
323    process_definition_key: i64,
324    bpmn_process_id: String,
325    version: i32,
326    process_instance_key: i64,
327    tenant_id: String,
328}
329
330impl CreateProcessInstanceResponse {
331    /// Returns the unique key identifying the process definition.
332    ///
333    /// # Returns
334    ///
335    /// The unique key as an `i64`.
336    pub fn process_definition_key(&self) -> i64 {
337        self.process_definition_key
338    }
339
340    /// Returns the BPMN process ID of the created instance.
341    ///
342    /// # Returns
343    ///
344    /// A string slice representing the BPMN process ID.
345    pub fn bpmn_process_id(&self) -> &str {
346        &self.bpmn_process_id
347    }
348
349    /// Returns the version of the process that was used.
350    ///
351    /// # Returns
352    ///
353    /// The version as an `i32`.
354    pub fn version(&self) -> i32 {
355        self.version
356    }
357
358    /// Returns the unique key identifying the created process instance.
359    ///
360    /// # Returns
361    ///
362    /// The unique key as an `i64`.
363    pub fn process_instance_key(&self) -> i64 {
364        self.process_instance_key
365    }
366
367    /// Returns the tenant ID of the process instance.
368    ///
369    /// # Returns
370    ///
371    /// A string slice representing the tenant ID.
372    pub fn tenant_id(&self) -> &str {
373        &self.tenant_id
374    }
375}
376
377impl From<proto::CreateProcessInstanceResponse> for CreateProcessInstanceResponse {
378    fn from(value: proto::CreateProcessInstanceResponse) -> CreateProcessInstanceResponse {
379        CreateProcessInstanceResponse {
380            process_definition_key: value.process_definition_key,
381            bpmn_process_id: value.bpmn_process_id,
382            version: value.version,
383            process_instance_key: value.process_instance_key,
384            tenant_id: value.tenant_id,
385        }
386    }
387}
388
389/// Response from creating a process instance with serialized result variables
390#[derive(Debug, Clone)]
391pub struct CreateProcessInstanceWithResultSerialized {
392    response: CreateProcessInstanceResponse,
393    variables: String,
394}
395
396/// A response type for process instance creation with serialized variables
397impl CreateProcessInstanceWithResultSerialized {
398    /// Returns a reference to the underlying process instance creation response
399    /// containing basic information about the created process instance such as
400    /// process definition key, version, and instance key.
401    ///
402    /// # Returns
403    /// * `&CreateProcessInstanceResponse` - A reference to the base process instance response
404    pub fn response(&self) -> &CreateProcessInstanceResponse {
405        &self.response
406    }
407
408    /// Returns the process instance result variables as a JSON-formatted string.
409    /// These variables represent the final state of the process instance after completion.
410    ///
411    /// # Returns
412    /// * `&str` - A reference to the JSON string containing the result variables
413    pub fn variables(&self) -> &str {
414        &self.variables
415    }
416}
417
418impl From<proto::CreateProcessInstanceWithResultResponse>
419    for CreateProcessInstanceWithResultSerialized
420{
421    fn from(
422        value: proto::CreateProcessInstanceWithResultResponse,
423    ) -> CreateProcessInstanceWithResultSerialized {
424        CreateProcessInstanceWithResultSerialized {
425            response: CreateProcessInstanceResponse {
426                process_definition_key: value.process_definition_key,
427                bpmn_process_id: value.bpmn_process_id,
428                version: value.version,
429                process_instance_key: value.process_instance_key,
430                tenant_id: value.tenant_id,
431            },
432            variables: value.variables,
433        }
434    }
435}
436
437/// Response from creating a process instance with deserialized result variables
438///
439/// # Type Parameters
440/// - `T`: The type of the deserialized result variables, which must implement `DeserializeOwned`.
441#[derive(Debug, Clone)]
442pub struct CreateProcessInstanceWithResult<T: DeserializeOwned> {
443    response: CreateProcessInstanceResponse,
444    data: T,
445}
446
447impl<T: DeserializeOwned> CreateProcessInstanceWithResult<T> {
448    /// Returns a reference to the base process instance creation response.
449    ///
450    /// # Returns
451    /// A reference to a `CreateProcessInstanceResponse` containing the details of the process instance creation.
452    pub fn response(&self) -> &CreateProcessInstanceResponse {
453        &self.response
454    }
455
456    /// Returns a reference to the deserialized result variables.
457    ///
458    /// # Returns
459    /// A reference to the deserialized result variables of type `T`.
460    pub fn data(&self) -> &T {
461        &self.data
462    }
463}
464
465impl<T: DeserializeOwned> TryFrom<proto::CreateProcessInstanceWithResultResponse>
466    for CreateProcessInstanceWithResult<T>
467{
468    type Error = ClientError;
469    fn try_from(
470        value: proto::CreateProcessInstanceWithResultResponse,
471    ) -> Result<CreateProcessInstanceWithResult<T>, Self::Error> {
472        Ok(CreateProcessInstanceWithResult {
473            response: CreateProcessInstanceResponse {
474                process_definition_key: value.process_definition_key,
475                bpmn_process_id: value.bpmn_process_id,
476                version: value.version,
477                process_instance_key: value.process_instance_key,
478                tenant_id: value.tenant_id,
479            },
480            data: serde_json::from_str(&value.variables).map_err(|e| {
481                ClientError::DeserializationFailed {
482                    value: value.variables.clone(),
483                    source: e,
484                }
485            })?,
486        })
487    }
488}