Skip to content

Commit 16ca223

Browse files
committed
Added Worker documentation.
1 parent c176892 commit 16ca223

File tree

7 files changed

+162
-101
lines changed

7 files changed

+162
-101
lines changed

00-docs/src/docs/functionalityDsls/worker.md

Lines changed: 137 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,40 @@ The implementation of an **_External Task_** is done by a _**Worker**_.
33

44
So for each _External Task_ type we have a DSL for an according _Worker_.
55

6+
@:callout(info)
7+
In the future, it is possible to have more than the Worker types, that are described here.
8+
@:@
9+
10+
## General
11+
Let's start with functions that are provided for all Workers.
12+
13+
### validate
14+
In every _Worker_, the input `In` is validated automatically (it is decoded from JSON to a `In` object).
15+
However, you can override the `validate` method to add more sophisticated validation logic.
16+
17+
Example:
18+
```scala
19+
override def validate(in: In): Either[ValidatorError, In] =
20+
for
21+
_ <- Try(in.accountTypeFilterAsSeq).toEither.left.map: _ =>
22+
ValidatorError(
23+
"accountTypeFilter must be a single Int or a comma separated String of Ints"
24+
)
25+
//_ <- moreValidation(in)
26+
yield in
27+
```
28+
629
## Custom Worker
730
The _Custom Worker_ is a general _Worker_ that can used for any business logic or integration.
831

9-
It automatically does:
10-
- validate the input variables
11-
1232
You can create:
1333
- business logic that can't be handled by the expression language in the BPMN itself
34+
- complex mappings
1435
- a service integration that is not covered by the _Service Worker_
1536
- whatever you want
1637

38+
Use this [Generator](../development/projectDev.md#customtask) to create a new _Custom Worker_
39+
1740
```scala
1841
import mycompany.myproject.bpmn.myprocess.v1.MyCustomTask.*
1942

@@ -25,25 +48,25 @@ class MyCustomTaskWorker extends CompanyCustomWorkerDsl[In, Out]:
2548
def runWork(in: In): Either[CamundalaWorkerError.CustomError, Out] =
2649
// your business logic
2750
???
28-
override def validate(in: In): Either[CamundalaWorkerError.ValidatorError, In] =
29-
??? // custom validation logic here
3051
```
31-
- `lazy val customTask` is just needed for the compiler to check the correctness of the types.
52+
- `lazy val customTask` is just needed for the compiler to check the correctness of the types (_Prototype_ pattern).
3253
- `runWork` is the method that is called by the _Worker_ to execute the business logic.
3354
- The code can either:
3455
- complete the task successfully with a result -> `Right[Out]`
3556
- fail the task with an error -> `Left[CamundalaWorkerError.CustomError]`
36-
- `override def validate(in: In)` is optional and can be used to add more sophisticated validation logic.
37-
If the validation fails, the process will fail.
3857

39-
Examples:
40-
41-
### runWork
42-
TODO
43-
### validate
44-
This is the same in every worker type.
45-
TODO
58+
Example:
4659

60+
```scala
61+
def runWork(in: In): Either[CamundalaWorkerError.CustomError, Out] =
62+
doSomethingThatCanFail(in)
63+
.left.map: e =>
64+
CamundalaWorkerError.CustomError("Problem in Worker: " + e.getMessage)
65+
66+
private def doSomethingThatCanFail(in: In): Either[Throwable, In] = ???
67+
```
68+
`doSomethingThatCanFail` does some mapping or business logic that can fail.
69+
If it fails, it returns a `Left` with an error message, that you wrap with a _CamundalaWorkerError.CustomError_.
4770

4871
## Init Process Worker
4972
The _Init Process Worker_ is a special _Worker_ that is used to start a process.
@@ -57,8 +80,6 @@ You can:
5780
- init process variables used to control the process flow,
5881
like counters, variables that may not be on the process.
5982
- create simplified process variables to simplify the process flow.
60-
- validate the input variables, if you need more sophisticated validation logic,
61-
than you can do with the type definition.
6283

6384
```scala
6485
import mycompany.myproject.bpmn.myprocess.v1.MyProcess.*
@@ -70,27 +91,29 @@ class MyProcessWorker extends CompanyInitWorkerDsl[In, Out, InitIn, InConfig]:
7091

7192
def customInit(in: In): InitIn =
7293
??? // init logic here
73-
override def validate(in: In): Either[CamundalaWorkerError.ValidatorError, In] =
74-
??? // custom validation logic here
7594
```
7695
- `lazy val inOutExample` is just needed for the compiler to check the correctness of the types.
7796
- `customInit` is the method that is called by the _Worker_ to execute the init logic.
7897
- The method sets the process variables according the _InitIn_ object.
7998
Be aware that this can not fail, as the input variables are already validated.
80-
- `override def validate(in: In)` is optional and can be used to add more sophisticated validation logic.
81-
If the validation fails, the process will fail.
8299

83100
Examples:
84101

85102
### customInit
86-
TODO
103+
104+
```scala
105+
def customInit(in: In): InitIn =
106+
InitIn(
107+
currency = in.currency.getOrElse(Currency.EUR), // set optional value with default value
108+
requestCounter = 0, // init process variables used to control the process flow
109+
iban = in.person.iban, // simplify process variables
110+
//...
111+
)
112+
```
87113

88114
## Service Worker
89115
The _Service Worker_ is a special _Worker_ that is used to call a REST API service.
90116

91-
It automatically does:
92-
- validate the input variables
93-
94117
You can provide:
95118
- the method and the path of the service
96119
- the query parameters
@@ -106,9 +129,9 @@ class MyServiceTaskWorker extends CompanyServiceWorkerDsl[In, Out]:
106129
lazy val serviceTask = example
107130

108131
def apiUri(in: In) = uri"$serviceBasePath/myService"
109-
override protected lazy val method: Method = Method.POST
132+
override lazy val method: Method = Method.POST
110133

111-
override protected def inputHeaders(in: In): Map[String, String] =
134+
override def inputHeaders(in: In): Map[String, String] =
112135
??? // map the input variables to the headers
113136
override def querySegments(in: In) =
114137
??? // map the input variables to the query parameters
@@ -119,8 +142,6 @@ class MyServiceTaskWorker extends CompanyServiceWorkerDsl[In, Out]:
119142
in: In
120143
): Either[ServiceMappingError, Out] =
121144
??? // map the service response body and header to the output variables
122-
override def validate(in: In): Either[CamundalaWorkerError.ValidatorError, In] =
123-
??? // custom validation logic here
124145
```
125146
- `lazy val serviceTask` is just needed for the compiler to check the correctness of the types.
126147
- `def apiUri(in: In)` the path of the service, with the path parameters from the `in` object.
@@ -130,17 +151,97 @@ class MyServiceTaskWorker extends CompanyServiceWorkerDsl[In, Out]:
130151
- `override def inputHeaders(in: In)` is optional and can be used to add headers to the request.
131152
- `override def inputMapper(in: In)` is optional and can be used to map the input variables to the request body.
132153
- `override def outputMapper(out: ServiceResponse[ServiceOut], in: In)` is optional and can be used to map the response body and -headers to the output variables.
133-
- `override def validate(in: In)` is optional and can be used to add more sophisticated validation logic.
134-
If the validation fails, the process will fail.
135154

136155
Examples:
137156

138157
### apiUri
139-
TODO
140-
### querySegments
141-
TODO
158+
```scala
159+
def apiUri(in: In) = uri"$serviceBasePath/myService/account/${in.accountId}"
160+
```
161+
The only required function. It returns the path of the service, with the path parameters from the `in` object.
162+
163+
### method
164+
```scala
165+
override lazy val method: Method = Method.POST
166+
```
167+
Override the HTTP method. Default is `Method.GET`.
168+
142169
### inputHeaders
143-
TODO
170+
```scala
171+
override def inputHeaders(in: In): Map[String, String] =
172+
Map("Correlation-ID" -> in.userId)
173+
```
174+
175+
### querySegments
176+
We support three ways to provide query parameters:
177+
178+
#### queryKeys
179+
```scala
180+
override def querySegments(in: In) =
181+
queryKeys("limitSelection", "accountType")
182+
```
183+
A list of optional `In` fields that are mapped to query parameters.
184+
So in this example you need to have `limitSelection` and `accountType` in your `In` object.
185+
```scala
186+
case class In(limitSelection: Option[Int], accountType: Option[String])
187+
```
188+
189+
#### queryKeyValues
190+
```scala
191+
override def querySegments(in: In) =
192+
queryKeyValues(
193+
"limitSelection" -> in.limitSelection,
194+
"accountType" -> adjust(in.accountType)
195+
)
196+
```
197+
If you need to adjust an `In` value, you can use this way of explicit listing the key-value pairs.
198+
199+
#### queryValues
200+
```scala
201+
override def querySegments(in: In) =
202+
queryValues(
203+
s"eq(username,string:${in.user})"
204+
)
205+
```
206+
If you have a query language, you can use this way to provide the query parameters.
207+
208+
#### a combination of the above
209+
```scala
210+
override def querySegments(in: In) =
211+
queryKeys("limitSelection") ++
212+
queryKeyValues("accountType" -> adjust(in.accountType))
213+
```
214+
And you can combine them as you like.
215+
144216
### inputMapper
145-
TODO
217+
```scala
218+
override def inputMapper(in: In): Option[ServiceIn] =
219+
Some(ServiceIn(in.accountType, in.accountId))
220+
```
221+
Mapping the input variables to the request body.
222+
146223
### outputMapper
224+
225+
```scala
226+
override def outputMapper(
227+
out: ServiceResponse[ServiceOut],
228+
in: In
229+
): Either[ServiceMappingError, Out] =
230+
out.outputBody
231+
.collect:
232+
case b if b.nonEmpty =>
233+
Right(Out(
234+
creditCardDetail = b.head,
235+
creditCardDetails = b
236+
))
237+
.getOrElse(Left(ServiceMappingError("There is at least one CreditCardDetail expected.")))
238+
```
239+
240+
Mapping the response body and -headers to the output variables.
241+
242+
@:callout(info)
243+
As you can see there are only two methods that can fail:
244+
- `validate` -> For the input, use this methode to validate the input and return any possible error.
245+
- `outputMapper` -> For the output, we do not have an extra 'validate' method.
246+
So if the service response is not as expected, you can return an error here.
247+
@:@

00-docs/src/docs/projectSetup.md

Lines changed: 0 additions & 43 deletions
This file was deleted.

04-helper/src/main/scala/camundala/helper/dev/company/CompanyGenerator.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ case class CompanyGenerator()(using config: DevConfig):
77
lazy val generate: Unit =
88
generateDirectories
99
DirectoryGenerator().generate // generates myCompany-camundala project
10-
10+
GenericFileGenerator().createScalaFmt
11+
GenericFileGenerator().createGitIgnore
1112
// needed helper classes
1213
CompanyWrapperGenerator().generate
1314
// override helperCompany.scala

04-helper/src/main/scala/camundala/helper/dev/update/ApiGenerator.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ case class ApiGenerator()(using config: DevConfig):
1717
s"""package ${config.projectPackage}
1818
|package api
1919
|
20-
|import bpmn.*
20+
|//import bpmn.*
2121
|
2222
|object ApiProjectCreator extends CompanyApiCreator:
2323
|
@@ -31,15 +31,17 @@ case class ApiGenerator()(using config: DevConfig):
3131
| val version = "0.1.0-SNAPSHOT"
3232
|
3333
| document(
34-
| myProcessApi,
34+
| //myProcessApi,
3535
| //..
3636
| )
3737
|
38+
| /* example:
3839
| private lazy val myProcessApi =
3940
| import myProcess.v1.*
4041
| api(MyProcess.example)(
4142
| // userTasks / workers etc.
4243
| )
44+
| */
4345
|end ApiProjectCreator
4446
|""".stripMargin
4547
end api

04-helper/src/main/scala/camundala/helper/dev/update/DmnGenerator.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ case class DmnGenerator()(using config: DevConfig):
77
createIfNotExists(dmnPath() / "ProjectDmnTester.scala", dmnTester)
88

99
lazy val dmnTester: String =
10-
s"""package ${config.projectPackage}.dmn
10+
s"""package ${config.projectPackage}
11+
|package dmn
1112
|
12-
|import ${config.projectPackage}.bpmn.*
13+
|//import bpmn.*
1314
|
1415
|// dmn/run
1516
|object ProjectDmnTester extends CompanyDmnTester:

04-helper/src/main/scala/camundala/helper/dev/update/GenericFileGenerator.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import camundala.helper.util.VersionHelper
55
case class GenericFileGenerator()(using config: DevConfig):
66

77
lazy val generate: Unit =
8-
createOrUpdate(config.projectDir / ".scalafmt.conf", scalafmt)
9-
createOrUpdate(config.projectDir / ".gitignore", gitignore)
8+
createScalaFmt
9+
createGitIgnore
1010
createOrUpdate(config.projectDir / "helper.scala", helperScala)
1111
os.proc("chmod", "+x", config.projectDir / "helper.scala").call()
1212
createIfNotExists(config.projectDir / "CHANGELOG.md", changeLog)
@@ -16,6 +16,11 @@ case class GenericFileGenerator()(using config: DevConfig):
1616
createOrUpdate(config.projectDir / ".vscode" / "launch.json", workerTestAppVsCode)
1717
end generate
1818

19+
lazy val createScalaFmt =
20+
createOrUpdate(config.projectDir / ".scalafmt.conf", scalafmt)
21+
lazy val createGitIgnore =
22+
createOrUpdate(config.projectDir / ".gitignore", gitignore)
23+
1924
private lazy val scalafmt =
2025
s"""# $helperDoNotAdjustText
2126
|

0 commit comments

Comments
 (0)