Replacing Low Code with PureScript and Temporal (Dev Journal)

31 July 2023 20:30 I like to use Make (formerly Integromat) to avoid writing code, but after a few attempts at implementing data deserialization and reserialization, and parsing, I gave up. It's too primitive, and they no longer allow me to write custom functions. So, I'm porting my partial solution to Temporal, which is similar to what I have in Make, but with code. It basically allows me to manage tasks and workflows through a predefined communication protocol using gRPC. My task is simple: I need to receive data from the Evo API (through webhooks) and push it to the Siigo API. Both solutions are similar to CRMs, but Evo is the user-facing solution. I have a workflow in Make called "processSales" that takes the Evo sale ID through a webhook. I need to POST to a Siigo endpoint when this event occurs. The first step is to fetch the Evo sale using its ID. To do that, I need to create a workflow that dispatches a single activity (so far) to fetch the sale. I'm working on that using PureScript on top of the Temporal TypeScript SDK. https://github.com/klarkc/evo-siigo 20:33 The first version isn't working yet. I managed to dispatch the request, but the JSON isn't parsing for some reason. Also, this first attempt is bloated with unsafe code because I'm still trying to figure out how Temporal works. However, I have a general understanding of it. It's pretty powerful and safe because it isolates the context of each activity and workflow from each other. 1 August 2023 13:52 Today, I fixed the Evo authentication issue. The reason it wasn't working was that I was trying to parse an undefined body due to the lack of HTTP authentication. I had to build base64 encodings for the headers and made small changes to the API to adopt this dependency. I successfully got a response from the Evo API. Now, I'll try to parse the response to a PureScript type. 3 August 2023 10:34 I managed to parse the data into the Sale type, and it's working nicely now. The code still isn't perfect, but I'm more concerned with delivering the task right now. Today, I'll continue with other endpoints and maybe add Siigo endpoints. 21:58 I reworked the solution by creating a monad stack and internal state to store context information in the workflow. With that in place, I could use the loaded sale to fetch the customer. 11 August 2023 00:43 The monad stack has become too limited to manage environment dependencies. I'm building free monads (I extracted a common functor for both workflows and activities). Now, I want to build a way to proxy the dependencies in the free monad. 12 August 2023 21:17 I struggled a bit to deal with the Promise type. It took a few refactorings until I figured out how to fit things together. I'm composing WorkflowBuilder and Builder (lifting from Builder to WorkflowBuilder). I wrote a minimal example of parsing and encoding in "processSale". Now, I'll return to the proxy problem and see how I'll create ActivityBuilder. 21:21 After that, the next step is to encode environment things as commands, maybe in an EnvF. 12 August 2023 00:03 I finally finished the proxy. I did a rework on the underlying monad to Aff (because Promise is really hard to work with). Now, it's time to return to the environment. 22:43 Oh yeah, today I built a few more activities, and we're moving forward. I had a problem with functions in workflows (I forgot that workflows can only be pure functions, except for console logs), so our "env monad" becomes a little less useful. But it's there; I called it Temporal.Platform.OperationF.

Feb 19, 2025 - 18:21
 0
Replacing Low Code with PureScript and Temporal (Dev Journal)

31 July 2023

20:30

I like to use Make (formerly Integromat) to avoid writing code, but after a few attempts at implementing data deserialization and reserialization, and parsing, I gave up. It's too primitive, and they no longer allow me to write custom functions. So, I'm porting my partial solution to Temporal, which is similar to what I have in Make, but with code. It basically allows me to manage tasks and workflows through a predefined communication protocol using gRPC.

My task is simple: I need to receive data from the Evo API (through webhooks) and push it to the Siigo API. Both solutions are similar to CRMs, but Evo is the user-facing solution.

I have a workflow in Make called "processSales" that takes the Evo sale ID through a webhook. I need to POST to a Siigo endpoint when this event occurs.

The first step is to fetch the Evo sale using its ID. To do that, I need to create a workflow that dispatches a single activity (so far) to fetch the sale. I'm working on that using PureScript on top of the Temporal TypeScript SDK.

https://github.com/klarkc/evo-siigo

20:33

The first version isn't working yet. I managed to dispatch the request, but the JSON isn't parsing for some reason. Also, this first attempt is bloated with unsafe code because I'm still trying to figure out how Temporal works. However, I have a general understanding of it. It's pretty powerful and safe because it isolates the context of each activity and workflow from each other.

1 August 2023

13:52

Today, I fixed the Evo authentication issue. The reason it wasn't working was that I was trying to parse an undefined body due to the lack of HTTP authentication. I had to build base64 encodings for the headers and made small changes to the API to adopt this dependency. I successfully got a response from the Evo API. Now, I'll try to parse the response to a PureScript type.

Image description

3 August 2023

10:34

I managed to parse the data into the Sale type, and it's working nicely now. The code still isn't perfect, but I'm more concerned with delivering the task right now. Today, I'll continue with other endpoints and maybe add Siigo endpoints.

21:58

I reworked the solution by creating a monad stack and internal state to store context information in the workflow. With that in place, I could use the loaded sale to fetch the customer.

Image description

11 August 2023

00:43

The monad stack has become too limited to manage environment dependencies. I'm building free monads (I extracted a common functor for both workflows and activities). Now, I want to build a way to proxy the dependencies in the free monad.

12 August 2023

21:17

I struggled a bit to deal with the Promise type. It took a few refactorings until I figured out how to fit things together. I'm composing WorkflowBuilder and Builder (lifting from Builder to WorkflowBuilder). I wrote a minimal example of parsing and encoding in "processSale". Now, I'll return to the proxy problem and see how I'll create ActivityBuilder.

21:21

After that, the next step is to encode environment things as commands, maybe in an EnvF.

12 August 2023

00:03

I finally finished the proxy. I did a rework on the underlying monad to Aff (because Promise is really hard to work with). Now, it's time to return to the environment.

Image description

Image description

22:43

Oh yeah, today I built a few more activities, and we're moving forward. I had a problem with functions in workflows (I forgot that workflows can only be pure functions, except for console logs), so our "env monad" becomes a little less useful. But it's there; I called it Temporal.Platform.OperationF.

Image description

Image description