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.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

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

About this skill

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
Key
rest-call-from-json
Source
github.com/mendixlabs/mxcli