Invental/Review lessons/Writes that span systems

Writes that span systems

Dry runs inherit every side effect

A “dry run” endpoint inherits every side effect of the real path unless hooks can tell it's a dry run, and it can still say “valid” for data the database will reject (unique constraints). Design both into the API on day one.

01 · Before and afterThe pattern

Make the operation visible to hooks, and check uniqueness without treating the check as a guarantee.

TypeScript
// before: hook can't tell a dry run from a save
beforeChange: [async ({ data }) => { data.stripeId = await createCustomer(data) }]
// after
beforeChange: [async ({ data, operation }) => {
  if (operation === 'validate') return data          // no external calls on a dry run
  data.stripeId ??= await createCustomer(data)
}]
// validate(): also query for an existing row with the same unique value,
// but still handle the unique-violation error on the real insert (no lock between the two).

02 · Run it on your appThe check

If your app has a “preview / validate / dry run” mode, do your side-effecting hooks know they're in it?

If the honest answer is no or not sure, this is worth a look before it reaches production.

Want this checked on your code?

Tell us what you are building and what worries you. We match a senior reviewer to your code and confirm scope before anything starts.

— Get in touch
hi@invental.co ↗
— Or
— What to include

A link or short description of the code or system, what you want checked, your stack, and when you need the answer. No repository access is needed until scope is agreed.

— Or leave a note
We reply within one business day.