Skip to content

Commit e3c83de

Browse files
akoclaude
andcommitted
feat: implement SEND REST REQUEST and fix REST client BSON serialization
Add SEND REST REQUEST microflow action to call consumed REST service operations (Microflows$RestOperationCallAction). This is distinct from the existing REST CALL (inline HTTP) which remains fully supported. REST client serialization fixes: - Use Rest$JsonBody instead of Rest$ImplicitMappingBody (fixes CE7247) - Use Rest$NoResponseHandling with ContentType for JSON responses (fixes CE0061) - Auto-add Accept header when missing (fixes CE7062) - Auto-add empty body for POST/PUT/PATCH without explicit body (fixes CE7064) - Fix dynamic header values: don't create invalid {1} refs (fixes CE7056) - RestOperationCallAction does not support custom error handling (fixes CE6035) SEND REST REQUEST implementation: - Grammar: SEND token, sendRestRequestStatement parser rule - AST: SendRestRequestStmt node type - Model: RestOperationCallAction, RestOutputVar, RestBodyVar types - Full pipeline: visitor, executor, BSON parser/writer, formatter - Three-part operation reference: Module.ServiceName.OperationName Documents $latestHttpResponse system variable (System.HttpResponse) for checking call success after SEND REST REQUEST. Updated skills: rest-client.md (full rewrite), write-microflows.md (new REST Service Calls section). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent fab4662 commit e3c83de

30 files changed

Lines changed: 12789 additions & 11311 deletions
Lines changed: 192 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
# REST Client Skill
22

3-
Use this skill when working with Consumed REST Clients in MDL.
3+
Use this skill when creating, modifying, or calling Consumed REST Clients in MDL.
44

5-
## Quick Reference
5+
## When to Use
66

7-
### Create a REST Client
7+
- Creating consumed REST service definitions (`CREATE REST CLIENT`)
8+
- Calling REST service operations from microflows (`SEND REST REQUEST`)
9+
- Listing or inspecting REST clients (`SHOW REST CLIENTS`, `DESCRIBE REST CLIENT`)
10+
11+
## CREATE REST CLIENT
812

913
```sql
1014
CREATE REST CLIENT Module.ClientName
@@ -14,94 +18,200 @@ BEGIN
1418
OPERATION GetData
1519
METHOD GET
1620
PATH '/data'
17-
RESPONSE JSON AS $Result;
21+
HEADER 'Accept' = 'application/json'
22+
RESPONSE NONE;
1823
END;
1924
```
2025

21-
### Show/Describe REST Clients
26+
### Authentication
27+
28+
```sql
29+
-- No authentication
30+
AUTHENTICATION NONE
31+
32+
-- Basic auth with literal credentials
33+
AUTHENTICATION BASIC (USERNAME = 'user', PASSWORD = 'secret')
34+
```
35+
36+
**IMPORTANT**: `$Variable` references in authentication (e.g., `USERNAME = $MyConstant`) are serialized as `Rest$ConstantValue` and require the constant to exist in the project. Use literal strings in examples to avoid CE7073.
37+
38+
### Operations
39+
40+
Each operation defines one HTTP endpoint call:
41+
42+
```sql
43+
OPERATION OperationName
44+
METHOD GET|POST|PUT|PATCH|DELETE
45+
PATH '/path/{paramName}'
46+
[PARAMETER $paramName: Type] -- Path parameters
47+
[QUERY $queryParam: Type] -- Query parameters
48+
[HEADER 'Name' = 'value'] -- HTTP headers
49+
[BODY JSON FROM $Variable] -- Request body (POST/PUT/PATCH)
50+
[BODY FILE FROM $Variable] -- File upload
51+
[TIMEOUT seconds] -- Default: 300
52+
RESPONSE NONE|JSON AS $var|STRING AS $var|FILE AS $var|STATUS AS $var;
53+
```
54+
55+
### Mendix Validation Rules (mx check)
56+
57+
Follow these rules to avoid errors from `mx check`:
58+
59+
| Rule | Error | Fix |
60+
|------|-------|-----|
61+
| Every operation MUST have an Accept header | CE7062 | Auto-added by serializer (`Accept: */*`) if missing |
62+
| POST/PUT/PATCH MUST have a body | CE7064 | Auto-added by serializer (empty JSON body) |
63+
| Dynamic header values (`'Bearer ' + $Token`) are NOT supported | CE7056 | Use static literal values only |
64+
| Auth with `$Variable` requires the constant to exist | CE7073 | Use literal strings or create constants first |
65+
| RESPONSE JSON requires entity mapping for full functionality | CE0061 | Configure entity mapping in Studio Pro after creation |
66+
67+
### Response Handling
68+
69+
The serializer uses `Rest$NoResponseHandling` with ContentType for all response types to avoid CE0061 (entity mapping requirement). This means:
70+
71+
- **RESPONSE NONE**`Rest$NoResponseHandling` (no ContentType)
72+
- **RESPONSE JSON**`Rest$NoResponseHandling` with `ContentType: "application/json"`
73+
- **RESPONSE STRING**`Rest$NoResponseHandling` with `ContentType: "text/plain"`
74+
- **RESPONSE FILE**`Rest$NoResponseHandling` with `ContentType: "application/octet-stream"`
75+
76+
For full JSON-to-entity mapping (`Rest$ImplicitMappingResponseHandling`), configure the response mapping in Studio Pro. This requires:
77+
1. A non-persistent entity to hold the response data
78+
2. An `ImportMappings$ObjectMappingElement` mapping JSON fields to entity attributes
79+
80+
## SEND REST REQUEST (Microflow Activity)
81+
82+
Calls a consumed REST service operation from a microflow. This creates a `Microflows$RestOperationCallAction` in the BSON.
83+
84+
```sql
85+
-- Fire and forget (RESPONSE NONE operation)
86+
SEND REST REQUEST Module.ServiceName.OperationName;
87+
88+
-- With output variable (RESPONSE JSON — maps to entity)
89+
$Result = SEND REST REQUEST Module.ServiceName.OperationName;
90+
91+
-- With request body (POST/PUT operations)
92+
$Result = SEND REST REQUEST Module.ServiceName.CreateItem
93+
BODY $NewItem;
94+
```
95+
96+
### CRITICAL: `$latestHttpResponse` System Variable
97+
98+
After every `SEND REST REQUEST`, Mendix automatically populates `$latestHttpResponse` (type `System.HttpResponse`). **Always use this to check call success**:
99+
100+
```sql
101+
-- ✅ CORRECT: check $latestHttpResponse
102+
$RootResult = SEND REST REQUEST Module.Service.GetData;
103+
IF $latestHttpResponse/Content != empty THEN
104+
-- Process $RootResult
105+
END IF;
106+
107+
-- ❌ WRONG: causes CE0117 (expression error)
108+
IF $RootResult != empty THEN
109+
```
110+
111+
Key attributes on `$latestHttpResponse`:
112+
- `Content` (String) — response body
113+
- `StatusCode` (Integer) — HTTP status code (200, 404, etc.)
114+
115+
### Restrictions
116+
117+
- **No custom error handling**`ON ERROR CONTINUE` or `ON ERROR ROLLBACK` causes CE6035. The action always uses abort-on-error semantics.
118+
- Operation reference uses three-part qualified name: `Module.ServiceDocument.OperationName`
119+
120+
## REST CALL (Inline HTTP — Different Feature)
121+
122+
`REST CALL` is a separate feature for direct HTTP calls without a REST client document. URL, headers, auth, and body are specified inline in the microflow. See the write-microflows skill for full syntax.
123+
124+
Do NOT mix up:
125+
- `SEND REST REQUEST` → calls consumed REST service operation (`Microflows$RestOperationCallAction`)
126+
- `REST CALL` → inline HTTP call (`Microflows$RestCallAction`)
127+
128+
## Show / Describe
22129

23130
```sql
24-
-- List all REST clients
131+
-- List all consumed REST clients
25132
SHOW REST CLIENTS;
133+
SHOW REST CLIENTS IN ModuleName;
26134

27-
-- Show client source code
135+
-- Show client definition as MDL
28136
DESCRIBE REST CLIENT Module.ClientName;
137+
138+
-- Delete a client
139+
DROP REST CLIENT Module.ClientName;
140+
141+
-- Create or overwrite existing
142+
CREATE OR MODIFY REST CLIENT Module.ClientName ...
29143
```
30144

31-
## Key Components
32-
33-
### 1. Tokens (`src/parser/lexer/tokens.ts`)
34-
- `Rest`, `Client`, `Clients`
35-
- `Base`, `Url`
36-
- `Authentication`, `Basic`, `None`
37-
- `Operation`, `Method`, `Path`, `Timeout`
38-
- `Header`, `Parameter`, `Query`, `Body`
39-
- `Response`, `Json`, `Status`, `File`
40-
- `Get`, `Post`, `Put`, `Patch`, `Delete`
41-
42-
### 2. Parser Rules (`src/parser/grammar/MendixParser.ts`)
43-
- `createRestClient` - Main rule
44-
- `restAuthentication` - BASIC or NONE
45-
- `restOperation` - Operation definition
46-
- `restHeader` - Header with value
47-
- `restResponse` - Response handling
48-
49-
### 3. AST Types (`src/parser/ast/types.ts`)
50-
- `CreateRestClientAST`
51-
- `ShowRestClientsAST`
52-
- `DescribeRestClientAST`
53-
- `RestOperationDefinition`
54-
- `RestAuthentication`
55-
56-
### 4. Handlers (`src/repl/handlers/rest-client-handlers.ts`)
57-
- `ShowRestClientsHandler`
58-
- `CreateRestClientHandler`
59-
- `DescribeRestClientHandler`
60-
61-
### 5. Creator (`src/creators/RestClientCreator.ts`)
62-
Creates `rest.ConsumedRestService` in the Model SDK.
63-
64-
### 6. Generator (`src/generators/RestClientGenerator.ts`)
65-
Converts SDK objects back to MDL format.
66-
67-
## Testing
68-
69-
```bash
70-
# Test parser
71-
node /tmp/test-rest-parser.js
72-
73-
# Via REPL daemon
74-
pnpm run repl:exec -- "SHOW REST CLIENTS;"
145+
## Complete Example
146+
147+
```sql
148+
-- 1. Create the REST client with operations
149+
CREATE REST CLIENT MyModule.PetStoreAPI
150+
BASE URL 'https://petstore.swagger.io/v2'
151+
AUTHENTICATION NONE
152+
BEGIN
153+
OPERATION ListPets
154+
METHOD GET
155+
PATH '/pet/findByStatus'
156+
QUERY $status: String
157+
HEADER 'Accept' = 'application/json'
158+
TIMEOUT 30
159+
RESPONSE JSON AS $PetList;
160+
161+
OPERATION GetPet
162+
METHOD GET
163+
PATH '/pet/{petId}'
164+
PARAMETER $petId: Integer
165+
HEADER 'Accept' = 'application/json'
166+
RESPONSE JSON AS $Pet;
167+
168+
OPERATION AddPet
169+
METHOD POST
170+
PATH '/pet'
171+
HEADER 'Content-Type' = 'application/json'
172+
HEADER 'Accept' = 'application/json'
173+
BODY JSON FROM $NewPet
174+
RESPONSE JSON AS $CreatedPet;
175+
176+
OPERATION RemovePet
177+
METHOD DELETE
178+
PATH '/pet/{petId}'
179+
PARAMETER $petId: Integer
180+
RESPONSE NONE;
181+
END;
182+
183+
-- 2. Call an operation from a microflow
184+
CREATE MICROFLOW MyModule.ACT_TestPetStore ()
185+
RETURNS Boolean AS $Success
186+
BEGIN
187+
DECLARE $Success Boolean = false;
188+
189+
SEND REST REQUEST MyModule.PetStoreAPI.RemovePet;
190+
191+
IF $latestHttpResponse/StatusCode = 200 THEN
192+
SET $Success = true;
193+
END IF;
194+
195+
RETURN $Success;
196+
END;
75197
```
76198

77-
## SDK Classes Used
78-
79-
- `rest.ConsumedRestService` - Main client
80-
- `rest.RestOperation` - Operations
81-
- `rest.RestOperationMethod` / `RestOperationMethodWithBody` / `RestOperationMethodWithoutBody`
82-
- `rest.ValueTemplate` - URL/path templates
83-
- `rest.BasicAuthenticationScheme` - Basic auth
84-
- `rest.StringValue` - Auth credentials
85-
- `rest.HeaderWithValueTemplate` - Headers
86-
- `services.HttpMethod` - GET/POST/PUT/PATCH/DELETE
87-
88-
## Common Patterns
89-
90-
### Add a new operation type
91-
1. Add parser rule in `restOperation`
92-
2. Add AST type property in `RestOperationDefinition`
93-
3. Update visitor in `restOperation()`
94-
4. Update creator in `RestClientCreator`
95-
5. Update generator in `RestClientGenerator`
96-
97-
### Add authentication type
98-
1. Add token if needed
99-
2. Add alternative in `restAuthentication` rule
100-
3. Add AST type (e.g., `RestOAuth2Auth`)
101-
4. Update visitor
102-
5. Update creator with SDK class
103-
104-
## Documentation
105-
106-
- Implementation: `/docs/02-features/REST_CLIENT_SYNTAX.md`
107-
- Original Proposal: `/docs/06-future/rest-client-mdl-proposal.md`
199+
## BSON Types Reference
200+
201+
| MDL Concept | BSON Type |
202+
|-------------|-----------|
203+
| REST client document | `Rest$ConsumedRestService` |
204+
| Operation | `Rest$RestOperation` |
205+
| GET/DELETE method | `Rest$RestOperationMethodWithoutBody` |
206+
| POST/PUT/PATCH method | `Rest$RestOperationMethodWithBody` |
207+
| JSON body | `Rest$JsonBody` |
208+
| File body | `Rest$StringBody` |
209+
| No response | `Rest$NoResponseHandling` |
210+
| JSON response (with entity mapping) | `Rest$ImplicitMappingResponseHandling` |
211+
| Header | `Rest$HeaderWithValueTemplate` |
212+
| Path parameter | `Rest$OperationParameter` |
213+
| Query parameter | `Rest$QueryParameter` |
214+
| No auth | `null` (AuthenticationScheme field) |
215+
| Basic auth | `Rest$BasicAuthenticationScheme` |
216+
| Microflow action (send request) | `Microflows$RestOperationCallAction` |
217+
| Microflow action (inline HTTP) | `Microflows$RestCallAction` |

0 commit comments

Comments
 (0)