REST Call from JSON Payload — End-to-End Skill

SkillDev tools

Lets your agent generate a REST call microflow, mappings, and entities from an example JSON response.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the REST Call from JSON Payload — End-to-End Skill skill

About this capability

Generate the whole integration stack from a JSON payload: JSON structure, non-persistent entities, import mapping, and the REST CALL microflow. Use when starting from an example response and needing everything between it and a working microflow.

What this skill tells your AI

The instructions your AI receives, as published by mendixlabs/mxcli in .claude/skills/mendix/rest-call-from-json/SKILL.md and read by ahel’s review.

Use this skill to generate the full stack of Mendix integration artifacts from a JSON payload: JSON Structure → Non-persistent entities → Import Mapping → microflow.

Two approaches: This skill uses the inline REST CALL approach (good for one-off calls and quick prototyping). For structured APIs with reusable operations, use the REST Client approach instead — see rest-client for create rest client + send rest request

  • optional transform with JSLT data transformers.

Overview — Four Steps

  1. CREATE JSON STRUCTURE — store the raw payload and derive the element tree
  2. CREATE ENTITY (non-persistent) — one per JSON object type, with attributes per JSON field
  3. CREATE IMPORT MAPPING — link JSON structure elements to entities and attributes
  4. CREATE MICROFLOW — inline REST CALL that invokes the import mapping (or use REST Client + SEND REST REQUEST)

Step 1 — JSON Structure

create json structure Module.JSON_MyStructure
  snippet '{"key": "value", "count": 1}';
  • The executor formats the snippet (pretty-print) then refreshes (derives element tree) automatically.
  • The snippet must be valid JSON; use single quotes around it in MDL.
  • Escape single quotes inside the snippet by doubling them: ''.
  • The derived element tree must stay consistent with the snippet — the executor sorts JSON object keys alphabetically to match json.MarshalIndent output.

Verify after creation:

describe json structure Module.JSON_MyStructure;
-- Should show: element tree under "-- Element tree:" comment

Step 2 — Non-Persistent Entities

Derive one entity per JSON object type. Name them after what they represent (not after JSON keys).

create non-persistent entity Module.MyRootObject (
  stringField   : string,
  intField      : integer,
  decimalField  : decimal,
  boolField     : boolean default false
);

create non-persistent entity Module.MyNestedObject (
  name : string,
  code : string
);

create association Module.MyRootObject_MyNestedObject
  from Module.MyRootObject
  to Module.MyNestedObject;

Rules:

  • All string fields: bare string (no length — unlimited)
  • All number fields: integer, decimal, or long — remove defaults for optional fields
  • Boolean fields require default true|false
  • non-persistent — these entities are not stored in the database. The keyword is hyphenated and goes before entity: create non-persistent entity Mod.X (...). NON_PERSISTENT, and a (NON_PERSISTENT) inside the body, are both parse errors
  • One association per parent→child relationship; name it Parent_Child

Step 3 — Import Mapping

Full reference: See json-structures-and-mappings for complete import/export mapping syntax, domain model patterns, and common mistakes.

create import mapping Module.IMM_MyMapping
  with json structure Module.JSON_MyStructure
{
  create Module.MyRootObject {
    stringField = stringField,
    intField    = intField,
    create Module.MyRootObject_MyNestedObject/Module.MyNestedObject = nestedKey {
      name = name,
      code = code
    }
  }
};

Syntax rules:

  • Root object: create Module.Entity { ... } — always starts with handling keyword
  • Value mappings: attributename = jsonFieldName — entity attribute on the left, JSON field on the right
  • Nested objects: create association/entity = jsonKey { ... } — association path + JSON key
  • Object handling: create (default), find (requires KEY), find or create
  • KEY marker: attr = jsonField key — marks the attribute as a matching key
  • Value transforms: attr = Module.Microflow(jsonField) — call a microflow to transform the value

Verify after creation — check Schema elements are ticked in Studio Pro:

  • Open the import mapping in Studio Pro
  • All JSON structure elements should appear ticked in the Schema elements panel
  • If not ticked: JsonPath mismatch between import mapping and JSON structure elements

Step 4 — REST CALL Microflow

Place the microflow in the [pages]/Operations/ folder or Private/ depending on whether it is public.

create microflow Module.GET_MyData ()
begin
  @position(-5, 200)
  declare $baseUrl string = 'https://api.example.com';
  @position(185, 200)
  declare $endpoint string = $baseUrl + '/path';
  @position(375, 200)
  $Result = rest call get '{1}' with ({1} = $endpoint)
    header 'Accept' = 'application/json'
    timeout 300
    returns mapping Module.IMM_MyMapping as Module.MyRootObject on error rollback;
  @position(565, 200)
  log info node 'Integration' 'Retrieved result' with ();
end;
/

Key points:

  • @position annotations control the canvas layout — StartEvent is auto-placed 150px to the left of the first annotated activity
  • 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
  • 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)
  • on error rollback — standard error handling for integration calls

For list responses (JSON root is an array):

  $Results = rest call get '{1}' with ({1} = $endpoint)
    header 'Accept' = 'application/json'
    timeout 300
    returns mapping Module.IMM_MyMapping as Module.MyItem on error rollback;
  @position(565, 200)
  $count = count($MyItem);

Step 5 — Import/Export Mapping in Microflows (Optional)

Instead of using returns mapping on a REST CALL, you can use standalone import/export mapping actions. This is useful when you already have a JSON string and want to map it to entities, or when you want to serialize entities back to JSON.

Import from mapping

Applies an import mapping to a string variable (JSON content) to produce entity objects:

-- With assignment (non-persistent entities, need the result in the flow)
$PetResponse = import from mapping Module.IMM_Pet($JsonContent);

-- Without assignment (persistent entities, just stores to DB)
import from mapping Module.IMM_Pet($JsonContent);

Export to mapping

Applies an export mapping to an entity object to produce a JSON string:

$JsonOutput = export to mapping Module.EMM_Pet($PetResponse);

Complete import → process → export microflow

create microflow Module.ProcessPetData ()
begin
  declare $ResponseContent string = $latestHttpResponse/content;
  $PetResponse = import from mapping Module.IMM_Pet($ResponseContent);
  -- Process the imported data...
  $JsonOutput = export to mapping Module.EMM_Pet($PetResponse);
  log info node 'Integration' 'Exported: ' + $JsonOutput;
end;
/

Step 6 — Sending a Request Body (Optional)

Everything above receives data. To send it, an inline REST CALL takes one of four body forms:

-- 1. String template with placeholders
body '{{"name": "{1}", "qty": {2}}' with ({1} = $Name, {2} = toString($Qty))

-- 2. An expression that already yields the payload
body $JsonPayload

-- 3. An export mapping (entity -> JSON)
body mapping Module.EMM_Item from $Item

-- 4. Raw bytes — a file document's CONTENTS member
body binary $Doc/Contents

Uploading a file

The expression is the file document's Contents member, not the document, and the content type goes on a header — the body clause carries only the bytes:

create or modify microflow Module.POST_Document_Upload (
  $Doc: Module.UploadedFile
)
returns boolean as $Ok
begin
  declare $Ok boolean = false;
  $Response = rest call post 'https://api.example.com/documents'
    header 'ContentType' = 'application/pdf'
    body binary $Doc/Contents
    timeout 300
    returns response;
  set $Ok = $Response/StatusCode = 200;
  return $Ok;
end;
/

$Doc must be a specialization of System.FileDocument. Downloading is the mirror image — returns Module.UploadedFile stores the response body in a new file document.

A consumed REST CLIENT document cannot do this. Its body is one of Rest$JsonBody, Rest$StringBody or Rest$ImplicitMappingBody — all textual — so Body: file from $Doc in a create rest client operation is refused as MDL-REST02. Binary uploads belong in a microflow. (Response: file as $Doc on an operation is fine; downloads work either way.)


Complete Example — Bible Verse API

-- Step 1: JSON Structure
create json structure Integrations.JSON_BibleVerse
  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."}}';

-- Step 2: Entities
create non-persistent entity Integrations.BibleApiResponse ();

create non-persistent entity Integrations.BibleTranslation (
  identifier    : string,
  name          : string,
  language      : string,
  language_code : string,
  license       : string
);

create non-persistent entity Integrations.BibleVerse (
  book_id : string,
  book    : string,
  chapter : integer,
  verse   : integer,
  text    : string
);

create association Integrations.BibleApiResponse_BibleTranslation
  from Integrations.BibleApiResponse
  to Integrations.BibleTranslation;

create association Integrations.BibleApiResponse_BibleVerse
  from Integrations.BibleApiResponse
  to Integrations.BibleVerse;

-- Step 3: Import Mapping
create import mapping Integrations.IMM_BibleVerse
  with json structure Integrations.JSON_BibleVerse
{
  create Integrations.BibleApiResponse {
    create Integrations.BibleApiResponse_BibleTranslation/Integrations.BibleTranslation = translation {
      identifier    = identifier,
      language      = language,
      language_code = language_code,
      license       = license,
      name          = name
    },
    create Integrations.BibleApiResponse_BibleVerse/Integrations.BibleVerse = random_verse {
      book    = book,
      book_id = book_id,
      chapter = chapter,
      text    = text,
      verse   = verse
    }
  }
};

-- Step 4: Microflow
create microflow Integrations.GET_BibleVerse_Random ()
begin
  @position(-5, 200)
  declare $baseUrl string = 'https://bible-api.com';
  @position(185, 200)
  declare $endpoint string = $baseUrl + '/data/web/random';
  @position(375, 200)
  $Result = rest call get '{1}' with ({1} = $endpoint)
    header 'Accept' = 'application/json'
    timeout 300
    returns mapping Integrations.IMM_BibleVerse as Integrations.BibleApiResponse on error rollback;
  @position(565, 200)
  log info node 'Integration' 'Retrieved Bible verse' with ();
end;
/

Gotchas and Common Errors

SymptomCauseFix
Studio Pro "not consistent with snippet"JSON element tree keys not in alphabetical orderExecutor sorts keys; re-derive from snippet
Schema elements not ticked in import mappingJsonPath mismatchNamed object elements use (object)|key, NOT (object)|key|(object)
Import mapping not linked in REST callWrong BSON field nameUse ReturnValueMapping, not mapping
Studio Pro shows "List of X" but mapping returns single XForceSingleOccurrence not setExecutor auto-detects from JSON structure root element type
StartEvent behind first activitiesDefault posX=200 vs @position(-5,...)Fixed: executor pre-scans for first @position and shifts StartEvent left
TypeCacheUnknownTypeExceptionWrong BSON $type namesImportMappings$ObjectMappingElement / ImportMappings$ValueMappingElement (no import prefix)
Attribute not found in Studio ProAttribute not fully qualifiedMust be Module.Entity.AttributeName in the BSON
CE0117 "Error(s) in expression." at the end event after a REST callreturns response binds a System.HttpResponse, so returning it from a returns string microflow is a type errorMatch the microflow's return type to what you do with the response — e.g. returns boolean and set $Ok = $Response/StatusCode = 200
Upload returns HTTP 200 but the server received a few bytesBody: file from $Doc on a REST CLIENT document used to be written as the literal text $DocNow refused as MDL-REST02 — upload from a microflow with body binary $Doc/Contents

Naming Conventions (MES)

ArtifactPatternExample
JSON StructureJSON_<ApiName>JSON_BibleVerse
Import MappingIMM_<ApiName>IMM_BibleVerse
Root entityDescribes the API responseBibleApiResponse
Nested entitiesDescribes the domain conceptBibleVerse, BibleTranslation
MicroflowMETHOD_Resource_OperationGET_BibleVerse_Random
FolderPrivate/ for mappings/structures, Operations/ for public microflows—

Signals

GitHub stars
122
Forks
49
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
rest-call-from-json
Source
github.com/mendixlabs/mxcli