|
| 1 | +# REST Call from JSON Payload — End-to-End Skill |
| 2 | + |
| 3 | +Use this skill to generate the full stack of Mendix integration artifacts from a JSON payload: |
| 4 | +JSON Structure → Non-persistent entities → Import Mapping → REST CALL microflow. |
| 5 | + |
| 6 | +## Overview — Four Steps |
| 7 | + |
| 8 | +1. **CREATE JSON STRUCTURE** — store the raw payload and derive the element tree |
| 9 | +2. **CREATE ENTITY** (non-persistent) — one per JSON object type, with attributes per JSON field |
| 10 | +3. **CREATE IMPORT MAPPING** — link JSON structure elements to entities and attributes |
| 11 | +4. **CREATE MICROFLOW** — inline REST CALL that invokes the import mapping |
| 12 | + |
| 13 | +--- |
| 14 | + |
| 15 | +## Step 1 — JSON Structure |
| 16 | + |
| 17 | +```sql |
| 18 | +CREATE JSON STRUCTURE Module.JSON_MyStructure |
| 19 | + SNIPPET '{"key": "value", "count": 1}'; |
| 20 | +``` |
| 21 | + |
| 22 | +- The executor **formats** the snippet (pretty-print) then **refreshes** (derives element tree) automatically. |
| 23 | +- The snippet must be valid JSON; use single quotes around it in MDL. |
| 24 | +- Escape single quotes inside the snippet by doubling them: `''`. |
| 25 | +- The derived element tree must stay consistent with the snippet — the executor sorts JSON object keys alphabetically to match `json.MarshalIndent` output. |
| 26 | + |
| 27 | +**Verify** after creation: |
| 28 | +```sql |
| 29 | +DESCRIBE JSON STRUCTURE Module.JSON_MyStructure; |
| 30 | +-- Should show: element tree under "-- Element tree:" comment |
| 31 | +``` |
| 32 | + |
| 33 | +--- |
| 34 | + |
| 35 | +## Step 2 — Non-Persistent Entities |
| 36 | + |
| 37 | +Derive one entity per JSON object type. Name them after what they represent (not after JSON keys). |
| 38 | + |
| 39 | +```sql |
| 40 | +CREATE ENTITY Module.MyRootObject (NON_PERSISTENT) |
| 41 | + stringField : String |
| 42 | + intField : Integer |
| 43 | + decimalField : Decimal |
| 44 | + boolField : Boolean DEFAULT false; |
| 45 | + |
| 46 | +CREATE ENTITY Module.MyNestedObject (NON_PERSISTENT) |
| 47 | + name : String |
| 48 | + code : String; |
| 49 | + |
| 50 | +CREATE ASSOCIATION Module.MyRootObject_MyNestedObject |
| 51 | + FROM Module.MyRootObject |
| 52 | + TO Module.MyNestedObject; |
| 53 | +``` |
| 54 | + |
| 55 | +**Rules:** |
| 56 | +- All string fields: bare `String` (no length — unlimited) |
| 57 | +- All number fields: `Integer`, `Decimal`, or `Long` — remove defaults for optional fields |
| 58 | +- Boolean fields **require** `DEFAULT true|false` |
| 59 | +- `NON_PERSISTENT` — these entities are not stored in the database |
| 60 | +- One association per parent→child relationship; name it `Parent_Child` |
| 61 | + |
| 62 | +--- |
| 63 | + |
| 64 | +## Step 3 — Import Mapping |
| 65 | + |
| 66 | +```sql |
| 67 | +CREATE IMPORT MAPPING Module.IMM_MyMapping |
| 68 | + FROM JSON STRUCTURE Module.JSON_MyStructure |
| 69 | +{ |
| 70 | + "" AS Module.MyRootObject (Create) { |
| 71 | + nestedKey AS Module.MyNestedObject (Create) VIA Module.MyRootObject_MyNestedObject { |
| 72 | + name AS name (String) |
| 73 | + code AS code (String) |
| 74 | + } |
| 75 | + stringField AS stringField (String) |
| 76 | + intField AS intField (Integer) |
| 77 | + } |
| 78 | +}; |
| 79 | +``` |
| 80 | + |
| 81 | +**Syntax rules:** |
| 82 | +- Root element uses `""` (empty string) as the JSON key — it maps the top-level object |
| 83 | +- Object mappings: `jsonKey AS Module.Entity (Create|Find|FindOrCreate)` |
| 84 | +- Value mappings: `jsonKey AS attributeName (String|Integer|Long|Decimal|Boolean|DateTime)` |
| 85 | +- `VIA Module.Association` — required when mapping a nested object reachable via an association |
| 86 | +- No semicolons between child elements inside `{}` |
| 87 | + |
| 88 | +**Verify** after creation — check Schema elements are ticked in Studio Pro: |
| 89 | +- Open the import mapping in Studio Pro |
| 90 | +- All JSON structure elements should appear ticked in the Schema elements panel |
| 91 | +- If not ticked: JsonPath mismatch between import mapping and JSON structure elements |
| 92 | + |
| 93 | +--- |
| 94 | + |
| 95 | +## Step 4 — REST CALL Microflow |
| 96 | + |
| 97 | +Place the microflow in the `[Pages]/Operations/` folder or `Private/` depending on whether it is public. |
| 98 | + |
| 99 | +```sql |
| 100 | +CREATE MICROFLOW Module.GET_MyData () |
| 101 | +BEGIN |
| 102 | + @position(-5, 200) |
| 103 | + DECLARE $baseUrl String = 'https://api.example.com'; |
| 104 | + @position(185, 200) |
| 105 | + DECLARE $endpoint String = $baseUrl + '/path'; |
| 106 | + @position(375, 200) |
| 107 | + $Result = REST CALL GET '{1}' WITH ({1} = $endpoint) |
| 108 | + HEADER 'Accept' = 'application/json' |
| 109 | + TIMEOUT 300 |
| 110 | + RETURNS MAPPING Module.IMM_MyMapping AS Module.MyRootObject ON ERROR ROLLBACK; |
| 111 | + @position(565, 200) |
| 112 | + LOG INFO NODE 'Integration' 'Retrieved result' WITH (); |
| 113 | +END; |
| 114 | +/ |
| 115 | +``` |
| 116 | + |
| 117 | +**Key points:** |
| 118 | +- `@position` annotations control the canvas layout — StartEvent is auto-placed 150px to the left of the first annotated activity |
| 119 | +- The output variable name is **automatically derived** from the entity name in `AS Module.MyEntity` — do NOT hardcode it on the left side; the executor overrides it |
| 120 | +- Single vs list result is **automatically detected**: if the JSON structure's root element is an Object, the variable type is `ObjectType` (single); if Array, `ListType` (list) |
| 121 | +- `ON ERROR ROLLBACK` — standard error handling for integration calls |
| 122 | + |
| 123 | +**For list responses** (JSON root is an array): |
| 124 | +```sql |
| 125 | + $Results = REST CALL GET '{1}' WITH ({1} = $endpoint) |
| 126 | + HEADER 'Accept' = 'application/json' |
| 127 | + TIMEOUT 300 |
| 128 | + RETURNS MAPPING Module.IMM_MyMapping AS Module.MyItem ON ERROR ROLLBACK; |
| 129 | + @position(565, 200) |
| 130 | + $Count = COUNT($MyItem); |
| 131 | +``` |
| 132 | + |
| 133 | +--- |
| 134 | + |
| 135 | +## Complete Example — Bible Verse API |
| 136 | + |
| 137 | +```sql |
| 138 | +-- Step 1: JSON Structure |
| 139 | +CREATE JSON STRUCTURE Integrations.JSON_BibleVerse |
| 140 | + SNIPPET '{"translation":{"identifier":"web","name":"World English Bible","language":"English","language_code":"eng","license":"Public Domain"},"random_verse":{"book_id":"1SA","book":"1 Samuel","chapter":17,"verse":49,"text":"David put his hand in his bag, took a stone, and slung it."}}'; |
| 141 | + |
| 142 | +-- Step 2: Entities |
| 143 | +CREATE ENTITY Integrations.BibleApiResponse (NON_PERSISTENT); |
| 144 | + |
| 145 | +CREATE ENTITY Integrations.BibleTranslation (NON_PERSISTENT) |
| 146 | + identifier : String |
| 147 | + name : String |
| 148 | + language : String |
| 149 | + language_code : String |
| 150 | + license : String; |
| 151 | + |
| 152 | +CREATE ENTITY Integrations.BibleVerse (NON_PERSISTENT) |
| 153 | + book_id : String |
| 154 | + book : String |
| 155 | + chapter : Integer |
| 156 | + verse : Integer |
| 157 | + text : String; |
| 158 | + |
| 159 | +CREATE ASSOCIATION Integrations.BibleApiResponse_BibleTranslation |
| 160 | + FROM Integrations.BibleApiResponse |
| 161 | + TO Integrations.BibleTranslation; |
| 162 | + |
| 163 | +CREATE ASSOCIATION Integrations.BibleApiResponse_BibleVerse |
| 164 | + FROM Integrations.BibleApiResponse |
| 165 | + TO Integrations.BibleVerse; |
| 166 | + |
| 167 | +-- Step 3: Import Mapping |
| 168 | +CREATE IMPORT MAPPING Integrations.IMM_BibleVerse |
| 169 | + FROM JSON STRUCTURE Integrations.JSON_BibleVerse |
| 170 | +{ |
| 171 | + "" AS Integrations.BibleApiResponse (Create) { |
| 172 | + translation AS Integrations.BibleTranslation (Create) VIA Integrations.BibleApiResponse_BibleTranslation { |
| 173 | + identifier AS identifier (String) |
| 174 | + language AS language (String) |
| 175 | + language_code AS language_code (String) |
| 176 | + license AS license (String) |
| 177 | + name AS name (String) |
| 178 | + } |
| 179 | + random_verse AS Integrations.BibleVerse (Create) VIA Integrations.BibleApiResponse_BibleVerse { |
| 180 | + book AS book (String) |
| 181 | + book_id AS book_id (String) |
| 182 | + chapter AS chapter (Integer) |
| 183 | + text AS text (String) |
| 184 | + verse AS verse (Integer) |
| 185 | + } |
| 186 | + } |
| 187 | +}; |
| 188 | + |
| 189 | +-- Step 4: Microflow |
| 190 | +CREATE MICROFLOW Integrations.GET_BibleVerse_Random () |
| 191 | +BEGIN |
| 192 | + @position(-5, 200) |
| 193 | + DECLARE $baseUrl String = 'https://bible-api.com'; |
| 194 | + @position(185, 200) |
| 195 | + DECLARE $endpoint String = $baseUrl + '/data/web/random'; |
| 196 | + @position(375, 200) |
| 197 | + $Result = REST CALL GET '{1}' WITH ({1} = $endpoint) |
| 198 | + HEADER 'Accept' = 'application/json' |
| 199 | + TIMEOUT 300 |
| 200 | + RETURNS MAPPING Integrations.IMM_BibleVerse AS Integrations.BibleApiResponse ON ERROR ROLLBACK; |
| 201 | + @position(565, 200) |
| 202 | + LOG INFO NODE 'Integration' 'Retrieved Bible verse' WITH (); |
| 203 | +END; |
| 204 | +/ |
| 205 | +``` |
| 206 | + |
| 207 | +--- |
| 208 | + |
| 209 | +## Gotchas and Common Errors |
| 210 | + |
| 211 | +| Symptom | Cause | Fix | |
| 212 | +|---------|-------|-----| |
| 213 | +| Studio Pro "not consistent with snippet" | JSON element tree keys not in alphabetical order | Executor sorts keys; re-derive from snippet | |
| 214 | +| Schema elements not ticked in import mapping | JsonPath mismatch | Named object elements use `(Object)\|key`, NOT `(Object)\|key\|(Object)` | |
| 215 | +| Import mapping not linked in REST call | Wrong BSON field name | Use `ReturnValueMapping`, not `Mapping` | |
| 216 | +| Studio Pro shows "List of X" but mapping returns single X | `ForceSingleOccurrence` not set | Executor auto-detects from JSON structure root element type | |
| 217 | +| StartEvent behind first activities | Default posX=200 vs @position(-5,...) | Fixed: executor pre-scans for first @position and shifts StartEvent left | |
| 218 | +| `TypeCacheUnknownTypeException` | Wrong BSON `$Type` names | `ImportMappings$ObjectMappingElement` / `ImportMappings$ValueMappingElement` (no `Import` prefix) | |
| 219 | +| Attribute not found in Studio Pro | Attribute not fully qualified | Must be `Module.Entity.AttributeName` in the BSON | |
| 220 | + |
| 221 | +--- |
| 222 | + |
| 223 | +## Naming Conventions (MES) |
| 224 | + |
| 225 | +| Artifact | Pattern | Example | |
| 226 | +|----------|---------|---------| |
| 227 | +| JSON Structure | `JSON_<ApiName>` | `JSON_BibleVerse` | |
| 228 | +| Import Mapping | `IMM_<ApiName>` | `IMM_BibleVerse` | |
| 229 | +| Root entity | Describes the API response | `BibleApiResponse` | |
| 230 | +| Nested entities | Describes the domain concept | `BibleVerse`, `BibleTranslation` | |
| 231 | +| Microflow | `METHOD_Resource_Operation` | `GET_BibleVerse_Random` | |
| 232 | +| Folder | `Private/` for mappings/structures, `Operations/` for public microflows | — | |
0 commit comments