Skip to content

Commit 2ffe9f7

Browse files
akoclaude
andcommitted
feat: add parameter support to SEND REST REQUEST (#193)
SEND REST REQUEST now supports passing parameter values via WITH: SEND REST REQUEST Module.API.GetForecast WITH ($latitude = toString(52.52), $longitude = toString(13.41)); Full pipeline: BSON parser reads ParameterMappings and QueryParameterMappings arrays, DESCRIBE strips the fully-qualified prefix and emits the WITH clause, grammar adds sendRestRequestWithClause, writer serializes parameter bindings with correct $Type and qualified names. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2d88bed commit 2ffe9f7

12 files changed

+9993
-9444
lines changed

mdl/ast/ast_microflow.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,11 +619,18 @@ func (s *RestCallStmt) isMicroflowStatement() {}
619619
type SendRestRequestStmt struct {
620620
OutputVariable string // Optional output variable (without $)
621621
Operation QualifiedName // Consumed REST service operation (Module.Service.Operation)
622+
Parameters []SendRestParamDef // Parameter bindings from WITH clause
622623
BodyVariable string // Optional body variable name (without $)
623624
ErrorHandling *ErrorHandlingClause // Optional ON ERROR clause
624625
Annotations *ActivityAnnotations // Optional @position, @caption, @color, @annotation
625626
}
626627

628+
// SendRestParamDef represents a parameter binding: $paramName = expression
629+
type SendRestParamDef struct {
630+
Name string // parameter name (without $)
631+
Expression string // Mendix expression
632+
}
633+
627634
func (s *SendRestRequestStmt) isMicroflowStatement() {}
628635

629636
// ImportFromMappingStmt represents: [$Var =] IMPORT FROM MAPPING Module.IMM($SourceVar)

mdl/executor/cmd_microflows_builder_calls.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -787,13 +787,30 @@ func (fb *flowBuilder) addSendRestRequestAction(s *ast.SendRestRequestStmt) mode
787787
}
788788
}
789789

790+
// Build parameter mappings from WITH clause
791+
var paramMappings []*microflows.RestParameterMapping
792+
var queryParamMappings []*microflows.RestQueryParameterMapping
793+
for _, p := range s.Parameters {
794+
// Determine if path or query param by convention:
795+
// the executor can't distinguish at this level, so we emit both
796+
// and let the BSON field names sort it out. For now, emit as
797+
// query parameter mappings (most common use case).
798+
queryParamMappings = append(queryParamMappings, &microflows.RestQueryParameterMapping{
799+
Parameter: operationQN + "." + p.Name,
800+
Value: p.Expression,
801+
Included: "Yes",
802+
})
803+
}
804+
790805
// RestOperationCallAction does not support custom error handling (CE6035).
791806
// ON ERROR clauses in the MDL are silently ignored for this action type.
792807
action := &microflows.RestOperationCallAction{
793-
BaseElement: model.BaseElement{ID: model.ID(mpr.GenerateID())},
794-
Operation: operationQN,
795-
OutputVariable: outputVar,
796-
BodyVariable: bodyVar,
808+
BaseElement: model.BaseElement{ID: model.ID(mpr.GenerateID())},
809+
Operation: operationQN,
810+
OutputVariable: outputVar,
811+
BodyVariable: bodyVar,
812+
ParameterMappings: paramMappings,
813+
QueryParameterMappings: queryParamMappings,
797814
}
798815

799816
activity := &microflows.ActionActivity{

mdl/executor/cmd_microflows_format_action.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,37 @@ func (e *Executor) formatRestOperationCallAction(a *microflows.RestOperationCall
915915
sb.WriteString("SEND REST REQUEST ")
916916
sb.WriteString(a.Operation)
917917

918+
// WITH clause for parameter mappings
919+
allParams := make([]struct{ name, value string }, 0)
920+
for _, pm := range a.ParameterMappings {
921+
// Strip operation prefix from parameter name
922+
name := pm.Parameter
923+
if idx := strings.LastIndex(name, "."); idx >= 0 {
924+
name = name[idx+1:]
925+
}
926+
allParams = append(allParams, struct{ name, value string }{name, pm.Value})
927+
}
928+
for _, qm := range a.QueryParameterMappings {
929+
name := qm.Parameter
930+
if idx := strings.LastIndex(name, "."); idx >= 0 {
931+
name = name[idx+1:]
932+
}
933+
allParams = append(allParams, struct{ name, value string }{name, qm.Value})
934+
}
935+
if len(allParams) > 0 {
936+
sb.WriteString("\n WITH (")
937+
for i, p := range allParams {
938+
if i > 0 {
939+
sb.WriteString(", ")
940+
}
941+
sb.WriteString("$")
942+
sb.WriteString(p.name)
943+
sb.WriteString(" = ")
944+
sb.WriteString(p.value)
945+
}
946+
sb.WriteString(")")
947+
}
948+
918949
if a.BodyVariable != nil && a.BodyVariable.VariableName != "" {
919950
sb.WriteString("\n BODY $")
920951
sb.WriteString(a.BodyVariable.VariableName)

mdl/grammar/MDLParser.g4

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,10 +1596,19 @@ restCallReturnsClause
15961596
*/
15971597
sendRestRequestStatement
15981598
: (VARIABLE EQUALS)? SEND REST REQUEST qualifiedName
1599+
sendRestRequestWithClause?
15991600
sendRestRequestBodyClause?
16001601
onErrorClause?
16011602
;
16021603

1604+
sendRestRequestWithClause
1605+
: WITH LPAREN sendRestRequestParam (COMMA sendRestRequestParam)* RPAREN
1606+
;
1607+
1608+
sendRestRequestParam
1609+
: VARIABLE EQUALS expression
1610+
;
1611+
16031612
sendRestRequestBodyClause
16041613
: BODY VARIABLE
16051614
;

mdl/grammar/parser/MDLParser.interp

Lines changed: 3 additions & 1 deletion
Large diffs are not rendered by default.

mdl/grammar/parser/mdl_parser.go

Lines changed: 9815 additions & 9433 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mdl/grammar/parser/mdlparser_base_listener.go

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mdl/grammar/parser/mdlparser_listener.go

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mdl/visitor/visitor_microflow_actions.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,22 @@ func buildSendRestRequestStatement(ctx parser.ISendRestRequestStatementContext)
10271027
stmt.Operation = buildQualifiedName(qn)
10281028
}
10291029

1030+
// WITH clause (parameter bindings)
1031+
if withClause := sendCtx.SendRestRequestWithClause(); withClause != nil {
1032+
wc := withClause.(*parser.SendRestRequestWithClauseContext)
1033+
for _, paramCtx := range wc.AllSendRestRequestParam() {
1034+
pc := paramCtx.(*parser.SendRestRequestParamContext)
1035+
param := ast.SendRestParamDef{}
1036+
if v := pc.VARIABLE(); v != nil {
1037+
param.Name = strings.TrimPrefix(v.GetText(), "$")
1038+
}
1039+
if expr := pc.Expression(); expr != nil {
1040+
param.Expression = expr.GetText()
1041+
}
1042+
stmt.Parameters = append(stmt.Parameters, param)
1043+
}
1044+
}
1045+
10301046
// Body clause
10311047
if bodyClause := sendCtx.SendRestRequestBodyClause(); bodyClause != nil {
10321048
bc := bodyClause.(*parser.SendRestRequestBodyClauseContext)

sdk/microflows/microflows_actions.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -595,10 +595,25 @@ func (RestCallAction) isMicroflowAction() {}
595595
// BSON type: Microflows$RestOperationCallAction
596596
type RestOperationCallAction struct {
597597
model.BaseElement
598-
ErrorHandlingType ErrorHandlingType `json:"errorHandlingType,omitempty"`
599-
Operation string `json:"operation,omitempty"` // BY_NAME: Module.Service.Operation
600-
OutputVariable *RestOutputVar `json:"outputVariable,omitempty"` // null or Microflows$OutputVariable
601-
BodyVariable *RestBodyVar `json:"bodyVariable,omitempty"` // null or nested object
598+
ErrorHandlingType ErrorHandlingType `json:"errorHandlingType,omitempty"`
599+
Operation string `json:"operation,omitempty"` // BY_NAME: Module.Service.Operation
600+
OutputVariable *RestOutputVar `json:"outputVariable,omitempty"` // null or Microflows$OutputVariable
601+
BodyVariable *RestBodyVar `json:"bodyVariable,omitempty"` // null or nested object
602+
ParameterMappings []*RestParameterMapping `json:"parameterMappings,omitempty"` // path parameter bindings
603+
QueryParameterMappings []*RestQueryParameterMapping `json:"queryParameterMappings,omitempty"` // query parameter bindings
604+
}
605+
606+
// RestParameterMapping maps an operation path parameter to a Mendix expression.
607+
type RestParameterMapping struct {
608+
Parameter string `json:"parameter"` // fully qualified: Module.Client.Op.paramName
609+
Value string `json:"value"` // Mendix expression
610+
}
611+
612+
// RestQueryParameterMapping maps an operation query parameter to a Mendix expression.
613+
type RestQueryParameterMapping struct {
614+
Parameter string `json:"parameter"` // fully qualified: Module.Client.Op.paramName
615+
Value string `json:"value"` // Mendix expression
616+
Included string `json:"included"` // "Yes" or "No"
602617
}
603618

604619
func (RestOperationCallAction) isMicroflowAction() {}

0 commit comments

Comments
 (0)