Skip to content

feat: import consumed REST client from OpenAPI 3.0 spec#268

Open
khode-mx wants to merge 3 commits intomendixlabs:mainfrom
khode-mx:feature/207-openapi-import-rest-client
Open

feat: import consumed REST client from OpenAPI 3.0 spec#268
khode-mx wants to merge 3 commits intomendixlabs:mainfrom
khode-mx:feature/207-openapi-import-rest-client

Conversation

@khode-mx
Copy link
Copy Markdown
Contributor

@khode-mx khode-mx commented Apr 22, 2026

Summary

  • Closes feat: Add OpenAPI contract import for Consumed Rest Services #207
  • CREATE REST CLIENT Module.Name (OpenAPI: 'path/or/url') auto-generates a consumed REST service document from an OpenAPI 3.0 spec (JSON or YAML)
  • Operations, path/query parameters, headers, request body, response type, resource groups (tags), and Basic auth are all derived automatically
  • Spec content stored in OpenApiFile for Studio Pro parity (matching what Studio Pro's own OpenAPI import produces)
  • DESCRIBE CONTRACT OPERATION FROM OPENAPI 'path' for previewing the import without writing to the project
  • Both local file paths (relative to the .mpr file) and HTTP/HTTPS URLs are supported

Testing

  • make build
  • make test ✅ (all tests pass)
  • make fmt + make vet
  • mxcli check mdl-examples/doctype-tests/20-openapi-import-examples.mdl

Mendix Studio Pro Validation

Tested imports verified in Mendix Studio Pro — mx check returns 0 errors:

  • CapitalOpenAPI module — JSON spec from a real-world API
  • PolarionOpenAPI module — JSON spec from a real-world API
  • PetStoreOpenAPI module — YAML spec from public swagger.io/petstore
  • Verified resource groups (from OpenAPI tags) match what Studio Pro's built-in OpenAPI import produces
  • Verified OpenApiFile/Content PascalCase BSON field names match Studio Pro serialization

Mendix version tested: 10.21.0

Agentic Code Testing

  • Tested with Claude Code in dev container
  • Claude can generate correct MDL for this feature (used to implement and test the feature)
  • Skills updated (rest-client.md — new Approach 0: OpenAPI Import section)
  • Error messages are helpful for debugging (warnings surfaced for unsupported auth schemes, non-JSON bodies)

Documentation

  • docs/01-project/MDL_QUICK_REFERENCE.md — new OpenAPI Import section under Consumed REST Services
  • docs-site/src/examples/rest-integration.md — OpenAPI import as the recommended first step
  • docs-site/src/reference/capabilities.md — new capability row
  • .claude/skills/mendix/rest-client.md — Approach 0 section added
  • CHANGELOG.md — entry under [Unreleased]

🤖 Generated with Claude Code

…xlabs#207)

Add `OpenAPI: 'path/or/url'` property to `CREATE REST CLIENT` that
auto-generates a consumed REST service document from an OpenAPI 3.0
spec (JSON or YAML). Operations, path/query parameters, request bodies,
response types, resource groups (tags), and Basic auth are all derived
from the spec. The spec content is stored in OpenApiFile for Studio Pro
parity. Also adds `DESCRIBE CONTRACT OPERATION FROM OPENAPI` for
previewing the import without writing to the project.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

AI Code Review

Let me review this pull request against the checklist provided in the CLAUDE.md file.

First, I'll summarize what this PR does based on the description:

  • Adds support for importing consumed REST clients from OpenAPI 3.0 spec
  • New syntax: CREATE REST CLIENT Module.Name (OpenAPI: 'path/or/url')
  • Also adds DESCRIBE CONTRACT OPERATION FROM OPENAPI 'path' for previewing imports
  • Supports both local file paths and HTTP/HTTPS URLs
  • Generated REST client includes operations, parameters, headers, request/response types, resource groups (tags), and Basic auth
  • Stores the OpenAPI spec content in OpenApiFile for Studio Pro parity
  • Includes documentation updates, tests, and changelog entry

Now I'll go through the checklist items:

Overlap & duplication

  • Checked proposals list: No proposals directory mentioned, so nothing to check
  • Checked for duplicate implementations: The PR adds new functionality for OpenAPI import, which doesn't appear to duplicate existing REST client functionality (which was manual definition)
  • Checked doctype test files: Added new test file mdl-examples/doctype-tests/20-openapi-import-examples.mdl for this feature
  • The PR doesn't re-document already-shipped features as new - it's adding genuinely new functionality

MDL syntax design

Let me check if the new MDL syntax follows the design guidelines:

  1. Follows standard CREATE/ALTER/DROP/SHOW/DESCRIBE pattern:

    • Uses CREATE REST CLIENT (standard CREATE verb)
    • Uses DESCRIBE CONTRACT OPERATION FROM OPENAPI (standard DESCRIBE verb)
    • No custom verbs for CRUD operations ✓
  2. Uses Module.Element qualified names everywhere:

    • Examples show ClaudeKhodeLab.PetStoreMinimal which follows QualifiedName pattern ✓
    • No bare names or implicit module context ✓
  3. Property lists use ( Key: value, ... ) format:

    • Examples show (OpenAPI: 'path/or/url') and (OpenAPI: '...', BaseUrl: '...')
    • Uses colon separators as required ✓
    • One per line in examples ✓
  4. Colon for property definitions, AS for name-to-name mappings:

    • The PR correctly uses colon for property definitions (OpenAPI: '...')
    • No inappropriate use of AS in property contexts ✓
    • AS is only used in mapping contexts where appropriate (not shown in this diff but mentioned in guidelines)
  5. Keywords are full English words:

    • Uses OpenAPI which is an acronym but treated as a full word ✓
    • No abbreviations or symbols for domain operations ✓
  6. Statement reads as English:

    • CREATE REST CLIENT Module.Name (OpenAPI: 'path/or/url') reads as English ✓
    • DESCRIBE CONTRACT OPERATION FROM OPENAPI 'path' reads as English ✓
  7. No keyword overloading:

    • OpenAPI is used specifically for specifying the OpenAPI source ✓
    • No evidence of overloading existing keywords ✓
  8. Diff-friendly:

    • Adding the OpenAPI property is a one-line diff in the examples ✓
  9. Consistent with existing MDL patterns:

    • Compared to existing REST client syntax in docs/01-project/MDL_QUICK_REFERENCE.md
    • Follows the same pattern: create rest client Module.Name ( property: value, ... )
    • Consistent with other property-based MDL statements ✓

Full-stack consistency

For the new MDL feature, I need to check if it's wired through the full pipeline:

  1. Grammar rule added to MDLParser.g4 (and MDLLexer.g4 if new tokens):

    • MDLLexer.g4: Added OPENAPI: O P E N A P I;
    • MDLParser.g4:
      • Added DESCRIBE CONTRACT OPERATION FROM OPENAPI STRING_LITERAL to describeStatement ✓
      • Modified createRestClientStatement to make the operation block optional: (LBRACE restClientOperation* RBRACE)?
      • Added restClientProperty rule that includes OpenAPI: STRING_LITERAL
    • Parser regenerated: The diff shows changes to parser files, but the instructions say to note but skip generated ANTLR parser files as noise. However, the grammar files were modified correctly. ✓
  2. AST node type added in mdl/ast/:

    • mdl/ast/ast_rest.go:
      • Added OpenApiPath string field to CreateRestClientStmt
      • Added DescribeContractFromOpenAPIStmt struct ✓
    • These are the new AST node types needed ✓
  3. Visitor handler in mdl/visitor/:

    • The diff doesn't show changes to mdl/visitor/, but let me think...
    • Actually, looking at the executor changes, it seems like the visitor might not need modification if the AST structure was already capable of handling the new syntax through existing mechanisms.
    • Wait, I need to check if visitor changes were made. The diff doesn't show visitor folder changes, but let me reconsider...
    • Looking at the AST changes:
      • CreateRestClientStmt got a new OpenApiPath field
      • DescribeContractFromOpenAPIStmt is entirely new
    • For these to be populated, the visitor would need to be updated to set these fields during parsing.
    • However, the diff doesn't show changes to mdl/visitor/. This is a potential issue.
    • Let me double-check: The PR description mentions "New MDL features MUST be wired through the full pipeline (grammar → AST → visitor → executor → LSP → DESCRIBE roundtrip)"
    • I don't see visitor changes in the diff. This might be missing.
  4. Executor handler in mdl/executor/:

    • mdl/executor/cmd_rest_clients.go:
      • Added significant new code for handling OpenAPI import:
        • createRestClientFromSpec function ✓
        • describeContractFromOpenAPI function ✓
        • Helper functions like convertOpenAPIToModel, sanitizeModuleName, fetchSpecBytes
      • Modified createRestClient to delegate to spec-driven path when OpenApiPath is set ✓
      • Added imports for needed packages (net/http, os, path/filepath, time, internal/pathutil, mdl/openapi) ✓
    • This looks correct ✓
  5. LSP wiring (cmd/mxcli/lsp.go):

    • cmd/mxcli/lsp_completions_gen.go: Added {Label: "OPENAPI", Kind: protocol.CompletionItemKindKeyword, Detail: "REST keyword"}
    • This adds OPENAPI to LSP completions ✓
    • No other LSP changes needed for this feature (no new formatting, diagnostics, or navigation targets) ✓
  6. DESCRIBE roundtrip:

    • The feature includes DESCRIBE CONTRACT OPERATION FROM OPENAPI 'path' for previewing imports ✓
    • The test file shows examples of this ✓
    • When a REST client is created via OpenAPI import, DESCRIBE REST CLIENT should show the properties including OpenAPI: '...' ✓
    • This appears to be implemented correctly ✓
  7. VS Code extension (vscode-mdl/package.json):

    • The diff doesn't show changes to vscode-mdl/package.json ✓
    • Since no new LSP capabilities were added (just a new keyword for completion), this might be okay
    • But let me check: The LSP completion was updated, so if the VS Code extension pulls completions from the mxcli binary, it might not need a package.json change
    • However, if the VS Code extension has its own hardcoded list of keywords, it might need updating
    • Looking at the guidelines: "VS Code extension (vscode-mdl/package.json) updated if new LSP capabilities added"
    • Since we only added a completion item (not a new capability like formatting/diagnostics/navigation), this might not be required ✓

Wait, I need to go back to the visitor concern. Let me re-examine...

Actually, looking more carefully at the executor code in cmd_rest_clients.go, I see:

// createRestClient handles CREATE REST CLIENT statement.
func createRestClient(ctx *ExecContext, stmt *ast.CreateRestClientStmt) error {
	// Spec-driven path: OpenAPI: property present
	if stmt.OpenApiPath != "" {
		return createRestClientFromSpec(ctx, stmt)
	}

This suggests that the AST's CreateRestClientStmt now has an OpenApiPath field, which would be set by the visitor.

But I don't see changes to the visitor in the diff. Let me check if the visitor changes might be in a part of the diff that wasn't shown due to truncation...

The diff shows changes to:

  • .claude/skills/mendix/rest-client.md
  • CHANGELOG.md
  • cmd/mxcli/lsp_completions_gen.go
  • cmd/mxcli/syntax/features_integration.go
  • mdl-examples/doctype-tests/20-openapi-import-examples.mdl
  • mdl/ast/ast_rest.go
  • mdl/executor/cmd_misc_mock_test.go
  • mdl/executor/cmd_rest_clients.go
  • mdl/executor/register_stubs.go
  • mdl/executor/registry_test.go
  • mdl/grammar/MDLLexer.g4
  • mdl/grammar/MDLParser.g4
  • (and some generated parser files which we're told to skip)

I don't see any changes to mdl/visitor/ in the diff. This is concerning because for the AST nodes to be properly populated with the OpenApiPath field, the visitor would need to be updated.

However, let me think about how ANTLR works. When you modify the grammar, you sometimes don't need to change the visitor if:

  1. The new rule fits into an existing visitor method pattern
  2. Or if the visitor uses a generic approach

Looking at the grammar changes:

  • In MDLParser.g4, the restClientProperty rule was likely modified to handle OpenAPI
  • The createRestClientStatement was modified to make the operation block optional

If the visitor was already using a generic approach to handle restClientProperty (like iterating through properties and setting them based on name), then it might not need changes.

Let me check if there were visitor changes that got truncated... Actually, no, the diff doesn't show any visitor folder changes at all.

This is a potential issue. Without visitor changes, how would the OpenApiPath field in CreateRestClientStmt get populated?

Actually, let me look at the AST again:

type CreateRestClientStmt struct {
 	Documentation  string
 	Folder         string // Folder path within module
 	CreateOrModify bool   // True if CREATE OR MODIFY was used
+	OpenApiPath    string // Non-empty = spec-driven; operations come from spec not OPERATION blocks
 }

For this field to be set, the visitor would need to recognize when an OpenAPI property is encountered and set this field.

Since I don't see visitor changes in the diff, this might be missing.

But wait - let me check if the visitor changes might be in a part that was not included in the visible diff due to the 80k character limit... The total size is mentioned as 2884407 bytes, so it's possible the visitor changes are there but not shown.

However, as a reviewer, I can only go by what's visible. And I don't see visitor changes.

Let me check one more thing: the mdl/executor/cmd_misc_mock_test.go shows:

+	"github.com/mendixlabs/mxcli/mdl/ast"

This suggests they're importing ast for some reason in the test, possibly related to new statement types.

And mdl/executor/register_stubs.go shows:

+	r.Register(&ast.DescribeContractFromOpenAPIStmt{}, func(ctx *ExecContext, stmt ast.Statement) error {
+		return describeContractFromOpenAPI(ctx, stmt.(*ast.DescribeContractFromOpenAPIStmt))
+	})

This confirms they added handling for the new statement type.

And mdl/executor/registry_test.go shows:

+		&ast.DescribeContractFromOpenAPIStmt{},

in the allKnownStatements() function.

So the executor side is definitely handled for both statement types.

But for the CreateRestClientStmt, if the OpenApiPath field isn't being set by the visitor, then createRestClientFromSpec wouldn't be called even when OpenAPI: is specified.

Let me think differently: maybe the visitor doesn't need to change because the OpenAPI property is handled like other properties through a generic mechanism.

Looking at the existing CreateRestClientStmt, it has Documentation, Folder, CreateOrModify fields. How are THOSE set?

If there's a generic visitor method that handles all restClientProperties by name, then it might automatically handle OpenAPI as well.

For example, if the visitor has something like:

func (v *MDLVisitor) VisitRestClientProperty(ctx *RestClientPropertyContext) interface{} {
	// handle property by name
}

And then in the createRestClientStatement handler, it iterates through properties and sets fields based on property names.

If that's the case, then adding OpenAPI to the grammar would automatically work without visitor changes.

Let me check if I can infer this from the existing code...

Actually, I don't have the visitor code in front of me, but given that:

  1. The AST was updated with the OpenApiPath field
  2. The executor checks stmt.OpenApiPath != "" to decide the path
  3. The grammar was modified to accept OpenAPI as a restClientProperty

It's plausible that the visitor already had generic property handling that would set this field.

Without seeing the visitor code, I can't be 100% sure, but given the patterns in this codebase, it's likely that the visitor uses a reflective or map-based approach to set AST fields based on property names.

Let me assume for now that the visitor handling is implicit through existing mechanisms, since:

  • The PR author would likely have noticed if visitor changes were needed and didn't make them
  • The code compiles and tests pass (as stated in the PR: make build ✅, make test ✅)
  • If the visitor wasn't setting OpenApiPath, then stmt.OpenApiPath would always be empty, and the spec-driven path wouldn't be taken, causing failures

Since tests pass, it's likely working correctly.

Test coverage

  • New packages: The PR doesn't appear to add new Go packages, just modifies existing ones ✓
  • New executor commands: Added MDL examples in mdl-examples/doctype-tests/20-openapi-import-examples.mdl
  • Integration paths tested: The PR mentions testing with mx check returning 0 errors for sample projects ✓
  • No time.Sleep for synchronization: No evidence of this in the visible diff ✓

Security & robustness

  • Command injection: The spec path is used in fetchSpecBytes which uses pathutil.NormalizeURL and then either os.ReadFile or http.Client.Get - seems safe ✓
  • XSS: Not applicable to this CLI tool ✓
  • SQL injection: Not relevant to this feature ✓
  • Temp file issues: No temporary files created in the visible code ✓
  • Unix sockets: Not relevant ✓
  • File I/O in hot paths: This is CLI tool code, not in event loops ✓
  • Silent side effects on typos: The code validates module existence and checks for existing rest clients ✓
  • Method receivers: The executor functions use pointer to ExecContext, which is correct for mutations ✓

Scope & atomicity

  • Each commit: The PR appears to be a single feature (OpenAPI import for REST clients) ✓
  • PR scope: Focused on a single feature ✓
  • Independent features: Not mixing unrelated items ✓
  • Refactors: No large refactors visible ✓

Code quality

  • Refactors applied consistently: No evidence of inconsistent refactors ✓
  • Manually maintained lists:
    • The lsp_completions_gen.go file shows a manually maintained list of keywords
    • This is flagged as a maintenance risk in the checklist: "Manually maintained lists (keyword lists, type mappings) should be flagged as maintenance risks"
    • However, this file is generated (as indicated by _gen.go suffix), so the manual maintenance risk is mitigated ✓
  • Design docs matching implementation:
    • Documentation updated in multiple places ✓
    • CHANGELOG entry added ✓
    • Skills updated ✓

Bugs & correctness

  • Logic errors: No obvious logic errors visible ✓
  • Race conditions: Not applicable to this single-threaded CLI tool ✓
  • Resource leaks:
    • In fetchSpecBytes: http.Client.Get response body is deferred closed ✓
    • os.ReadFile doesn't need explicit close ✓
    • Seems correct ✓
  • Error handling:
    • Errors are wrapped with context ✓
    • User-facing errors are provided ✓
    • Warnings are surfaced for unsupported auth schemes ✓

Let me double-check the visitor concern one more time...

Actually, looking at the mdl/ast/ast_rest.go changes again, I notice:

type CreateRestClientStmt struct {
 	Documentation  string
 	Folder         string // Folder path within module
 	CreateOrModify bool   // True if CREATE OR MODIFY was used
+	OpenApiPath    string // Non-empty = spec-driven; operations come from spec not OPERATION blocks
 }

And in the executor:

// createRestClient handles CREATE REST CLIENT statement.
func createRestClient(ctx *ExecContext, stmt *ast.CreateRestClientStmt) error {
	// Spec-driven path: OpenAPI: property present
	if stmt

---
*Automated review via OpenRouter (Nemotron Super 120B) — [workflow source](https://github.com/mendixlabs/mxcli/blob/main/.github/workflows/ai-review.yml)*

@ako
Copy link
Copy Markdown
Collaborator

ako commented Apr 22, 2026

Code Review — feat: import consumed REST client from OpenAPI 3.0 spec

Overview

This PR adds two new capabilities:

  1. CREATE [OR MODIFY] REST CLIENT Module.Name (OpenAPI: 'path/or/url') — auto-generate a consumed REST service document from an OpenAPI 3.0 spec
  2. DESCRIBE CONTRACT OPERATION FROM OPENAPI 'path' — preview without writing

The core architecture is clean: a new mdl/openapi package with its own intermediate types (avoiding a model import), full-stack wiring from grammar to BSON, deterministic path ordering, and a 30-second HTTP timeout. The TestHelp_Mock compile error that has been blocking #254#256 is also fixed here.


Issues

[BLOCKER] doc["OpenApiFile"] = nil corrupts existing REST clients

writer_rest.go now writes OpenApiFile = nil on every REST client that wasn't created from a spec:

} else {
    doc["OpenApiFile"] = nil
}

Studio Pro-created REST clients don't have this field at all. Adding an explicit null may cause errors when Studio Pro opens a project that was previously saved by mxcli. The else branch should be removed — only write OpenApiFile when svc.OpenApiContent != "".

[BLOCKER] OR MODIFY loses UnitID — same bug as #258

createRestClientFromSpec does a DeleteConsumedRestService + CreateConsumedRestService without preserving the original UnitID. Any microflows that reference this REST service by SEND REST REQUEST will have stale IDs after an OR MODIFY. PR #258 fixed exactly this issue for microflows; the same pattern (store the dropped ID, reuse it on recreate) needs to apply here.

[NEEDS VALIDATION] Tags → resource groups BSON assumption

The PR stores operation tags as a versioned BSON array on each RestClientOperation: [1, "tag1", ...]. But in Studio Pro, resource groups are a property of the REST client container (service-level), not per-operation metadata. If Studio Pro does not read Tags from individual operations to derive resource group assignments, this feature is a no-op. Before merge, validate this by creating a spec-imported REST client in Studio Pro and comparing the BSON with what mxcli writes.


Medium concerns

convert.go not updated

model.ConsumedRestService gained OpenApiContent and model.RestClientOperation gained Tags. If there is a conversion layer in mdl/types/ or convert.go that mirrors these structs, TestFieldCountDrift will fail on merge.

No unit tests for new executor functions

createRestClientFromSpec and describeContractFromOpenAPI have no mock-based executor tests. The doctype example (20-openapi-import-examples.mdl) hits petstore3.swagger.io — this won't work in offline CI. A local fixture (embedded minimal JSON spec) would let the executor path be tested without network access.

Unbounded io.ReadAll

fetchSpecBytes has a 30s HTTP timeout but no response-body size limit. A large or malicious URL could exhaust memory. Suggest io.LimitReader(resp.Body, 10<<20) (10 MB) before ReadAll.


Minor

sanitizeModuleName (executor) vs sanitizeIdent (openapi package) duplication

describeContractFromOpenAPI calls sanitizeModuleName(spec.Info.Title) (PascalCase converter in the executor) while convertOperation calls sanitizeIdent (underscore-based, in the openapi package). The same spec title produces different results for the service name vs operation names. Either expose sanitizeIdent from the openapi package or consolidate to one function.


What works well

  • mdl/openapi package is cleanly isolated (no model import, own intermediate types)
  • Paths iterated in sorted order — deterministic BSON output
  • Grammar is properly extended: DESCRIBE CONTRACT OPERATION FROM OPENAPI as a dedicated alternative, operation block made optional in createRestClientStatement
  • OPENAPI correctly added to the keyword escape list so it can appear in qualified names
  • pathutil.NormalizeURL correctly resolves relative paths against the .mpr directory
  • resolveAuthentication emits actionable warnings for unsupported schemes (apiKey, OAuth2) rather than silently dropping them
  • Full pipeline wired: grammar → visitor → AST → executor → backend → registry test
  • TestHelp\_Mock compile error from test: expand mock tests for 28 executor handler files #254 fixed (execHelp(ctx, &ast.HelpStmt{}))

…OR MODIFY

- writer_rest.go: drop the else-branch that wrote OpenApiFile=nil for
  manually-created REST clients; Studio Pro omits this field entirely for
  non-spec services, so writing an explicit null can corrupt existing projects
- cmd_rest_clients.go: preserve the existing UnitID on CREATE OR MODIFY so
  any SEND REST REQUEST microflows that reference the service by ID remain
  valid after a re-import; applies to both the spec-driven and manual paths

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@khode-mx
Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review, @ako.

[BLOCKER] doc["OpenApiFile"] = nil — Fixed in 362e5ca. Removed the else branch entirely; OpenApiFile is now only written when svc.OpenApiContent != "", matching Studio Pro's omit-when-absent behaviour.

[BLOCKER] OR MODIFY loses UnitID — Fixed in 362e5ca. Both the spec-driven path (createRestClientFromSpec) and the manual path (createRestClient) now capture the existing ID before deletion and pass it into CreateConsumedRestService, so the new document inherits the original UnitID. The CreateConsumedRestService writer already skips ID generation when svc.ID is non-empty.

[NEEDS VALIDATION] Tags → resource groups BSON assumption — Validated before this PR was submitted. Python-dumping the Example_Consumed_REST_service unit from the OpenAPI-MxCLI project (the reference project used throughout development) shows Studio Pro stores tags per-operation exactly as we do:

Op 'getBuildLists': Tags = [1, 'Build Lists']       # Example_Consumed_REST_service
Op 'addPet': Tags = [1, 'pet']                      # PetstoreAPI
Op 'branchDocuments': Tags = [1, 'Documents']       # PolarionAPI
Op 'getAuditTrails': Tags = [1, 'Audit Trail', 'Filtering']  # CapitalAPI

All four entries are Studio Pro-created imports. The [versionInt, tagString, ...] array is at the operation level, not the service container level. Our implementation matches.


Medium/minor items — I'll address the unbounded io.ReadAll and the sanitizeModuleName vs sanitizeIdent duplication in a follow-up commit shortly.

…tizeIdent

- fetchSpecBytes: wrap resp.Body in io.LimitReader(10 MiB) before ReadAll
  to prevent memory exhaustion from oversized or malicious spec URLs
- sanitizeModuleName: add comment explaining intentional PascalCase vs
  snake_case difference relative to openapi.sanitizeIdent (service names
  vs operation names follow different Mendix naming conventions)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@khode-mx
Copy link
Copy Markdown
Contributor Author

khode-mx commented Apr 22, 2026

Re: Two distinct refresh operations (item 3 from @ako's review in #207 )

Actually, after going over these remarks, I don't believe they're applicable to this scenario. In Studio Pro the OpenAPI import results in a generated Consumed REST Service document with no option to change the input file afterwards — the spec and the service are decoupled after creation, and there is no "refresh from spec" or "update source" operation exposed anywhere in the Studio Pro UI.

Given that, CREATE OR MODIFY REST CLIENT Module.Name (OpenAPI: '...') already covers the refresh use case — it re-imports from any source (same path, new path, or URL) and replaces all operations while preserving the UnitID. This is actually more capable than Studio Pro, which offers no equivalent mechanism at all.

A dedicated REFRESH FROM OPENAPI command and SET OpenAPI: would introduce behaviour with no Studio Pro equivalent to validate against. We're considering not to pursue them — do you agree with this observation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Add OpenAPI contract import for Consumed Rest Services

2 participants