Code reuse (DRY principle) for recurring and ad hoc script execution

Greetins!

I am starting a new project where in which I will write a script that needs to be triggered…

  1. at regular intervals (eg. daily)
  2. ad hoc, manually by a user

Automations work well for the first case, and scripting app for the second case. However, I wont sleep well at night if I have to maintain two copies of the script, one in Automations, one in the scripting app. What would be the best approach to not duplicating the code here?

For now I am thinking of…

  • a first automation with an incoming webhook trigger that runs the actual script
  • a second automation with a scheduled trigger that runs a one liner script to call the webhook (and this covers my first use case)
  • a scripting app with the same one line script that calls the webhook (which covers my second use case).

Any better idea way of doing this?

Thanks in advance!

Welcome to the Airtable community!

The system you described will work, assuming that the script has no inputs, such as a triggering record. However, is the extra complexity of having a two layer system really worth it?

I am a fan of trying to balance DRY and WET code, and in this particular situation, I think I would lean WET. I’d have the code exactly the same in both scripting app and in the action script, but have a maintenance workflow that says to copy/paste it to both places whenever updating it.

Of course, your ability to sleep well at night is far more important than my humble opinion, and I recommend doing whatever will help you sleep at night. Whatever you choose, I recommend documenting it!

1 Like

Thanks @kuovonne for your feedback. I am also generally comfortable with WET code when it is short… so I may start with duplicates and adjust based on how long/complicated this gets!

(I may have slightly exaggerated the impact of WET code on my sleep… :sweat_smile:)

1 Like

So just to keep track of the idea, for those people who may be interested… I coded a quick proof of concept involving:

  • The actual script in an automation triggered by a webhook
  • A scripting app posting go the webhook for manual triggers
  • An automation based on a recurring trigger with a script posting to the webhook as the action

It works! But there are caveats…

  • Using fetch to post from the scripting app to the automation webhook does not work. Use remoteFetchAsync instead.

  • My script needs to call an external API using Bearer authentication… My goto solution for Base64 encoding was using the btoa() function, which works in a scripting app, but not in automations (I guess scripts run in the browser and automations on the server). Since using libraries (Buffer.from...) is not possible, I had to find a “replacement” for btoa()

  • Debugging is harder, mainly because the triggering scripts only get the response of their post action to the webhook, which is not an indicator of whether or not the script succeeded

  • As the idea is to make something easily reusable in multiple contexts (eg. call the script for table, or a specific view in another table), there will be quite a few parameters that need to be passed from the triggering scripts, to the main script. That involves a lot of mapping to config variables (I can think of at least a workaround for this…)

I will keep posting here if I find anything else of interest…

1 Like

Thanks for coming back and posting your findings.

It sounds like your use case hits upon a lot of the differences between scripting app and automation action scripts.

Just curious, but what was your replacement? When I’ve been in this situation, I have hardcoded the encoded string.

You may have found out that an Airtable automation that receives a webhook cannot access the body as a whole object, only individual keys. One workaround is to reduce the entire body to a JSON string assigned to a single key. Note that you would end up JSON encoding/deciding twice.

I was just about to hardcode the encoded string instead of using btoa() when I found this: ATOB/BTOA Perfect Alternative/Replacement - JSFiddle - Code Playground (I just blindly copy-pasted the b2a() function).

Yeah, that is what I had in mind, although I haven’t had the time to test it yet.