You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
By default, the schema is not explicitly checked by Windmill. For example, when triggering a script via [webhook](../4_webhooks/index.mdx), it is possible to pass an arbitrary JSON payload for the arguments, and Windmill [workers](../9_worker_groups/index.mdx) will just try to execute the script with it.
306
+
307
+
In some cases, you might want the job to fail if the payload does not follow the defined schema. For this, just add the `schema_validation` annotation as a comment to the top of your script. The logs should tell you if schema validation is taking place.
308
+
309
+
For example in [TypeScript](../../getting_started/0_scripts_quickstart/1_typescript_quickstart/index.mdx):
310
+
311
+
```ts
312
+
// schema_validation
313
+
314
+
exportasyncfunction main(
315
+
a:number,
316
+
b:"my"|"enum",
317
+
e="inferred type string from default arg",
318
+
f= { nested: "object" },
319
+
g: {
320
+
label:"Variant 1",
321
+
foo:string
322
+
} | {
323
+
label:"Variant 2",
324
+
bar:number
325
+
}
326
+
) {
327
+
return { foo: a };
328
+
}
329
+
```
330
+
331
+
Here, if we were to pass a string to `a` instead of a number, or pass `"something else"` to `b` instead of `"my"` or `"enum"`, or even if the shape of `g` does not correspond to one of the OneOf variants, the job will fail.
332
+
333
+
This was an example in TypeScript but backend schema validation is available on all [languages](../../getting_started/0_scripts_quickstart/index.mdx), in particular for [SQL safe interpolated arguments](../../getting_started/0_scripts_quickstart/5_sql_quickstart/index.mdx#safe-interpolated-arguments).
334
+
335
+
Note that this validation is not a fully JSON schema compliant. The checks you can expect are type and shape, required fields, strict enums. One thing that is not supported yet for instance is matching regex patterns on strings. When in doubt, it's best to test it out or provide your own checks.
Copy file name to clipboardExpand all lines: docs/getting_started/0_scripts_quickstart/5_sql_quickstart/index.mdx
+37-3
Original file line number
Diff line number
Diff line change
@@ -523,9 +523,43 @@ You can then write your prepared statement.
523
523
524
524
## Raw queries
525
525
526
-
A more convenient but less secure option is to execute raw queries with a TypeScript, Deno or Python client. This enables you more flexibility than SQL prepared statement. You can for instance do string interpolation to make the name of the table a parameter of your script: `SELECT * FROM ${table}`. However this is dangerous since the string is directly interpolated and this open the door for [SQL injections](https://en.wikipedia.org/wiki/SQL_injection). Use with care and only in trusted environment.
526
+
### Safe interpolated arguments
527
527
528
-
### PostgreSQL
528
+
To allow more flexibility than with prepared statements, Windmill offers the possibility to do safe string interpolation in your queries thanks to [backend schema validation](../../../core_concepts/13_json_schema_and_parsing/index.mdx#backend-schema-validation). This allows you to use script parameters for elements you would usually not be able to, such as table or column names. In order to avoid SQL injections however, these parameters are checked at runtime and the job will fail if any of these rules is not followed:
529
+
530
+
- The parameter is a non-empty string.
531
+
- The characters are all either alphabetical (ASCII only), numeric, or an underscore (`_`). Meaning no whitespace or symbol is allowed.
532
+
- The string does not start with a number.
533
+
- If the parameter is an enum, it must be one of the defined variants.
534
+
535
+
These rules are strict enough to protect from any kind of unexpected injection, but lenient enough to have some powerful use cases. Let's look at an example:
536
+
537
+
```sql
538
+
-- :daily_minimum_calories (int)
539
+
-- %%table_name%% fruits/vegetables/cereals
540
+
541
+
SELECT name, calories FROM %%table_name%% WHERE calories > daily_minimum_calories
542
+
```
543
+
544
+
In this example the argument `table_name` is defined as a string that can be either `"fruits"`, `"vegetables"` or `"cereals"`, and the user of the script can then choose which table to query by setting this argument. If the user of the script tries to query a different table, the job will fail before making a connection to the DB, and thus protecting potentially sensitive data.
545
+
546
+
It the enum variants are ommited, the field is considered to be a regular string and only the other rules apply:
547
+
548
+
```sql
549
+
-- :daily_minimum_calories (int)
550
+
-- %%table_name%%
551
+
552
+
SELECT name, calories FROM %%table_name%% WHERE calories > daily_minimum_calories
553
+
```
554
+
555
+
Keep in mind that this means users of this script can try this query against all existant and non-existant tables of the database.
556
+
557
+
558
+
### Unsafe interpolation on a REST script
559
+
560
+
A more convenient but less secure option is to execute raw queries with a TypeScript, Deno or Python client. You can for instance do string interpolation to make the name of the table a parameter of your script: `SELECT * FROM ${table}`. However this is dangerous since the string is directly interpolated and this open the door for [SQL injections](https://en.wikipedia.org/wiki/SQL_injection). Use with care and only in trusted environment.
561
+
562
+
#### PostgreSQL
529
563
530
564
<TabsclassName="unique-tabs">
531
565
@@ -684,7 +718,7 @@ You can find more Script examples related to PostgreSQL on
0 commit comments