Skip to content

[Ballerina][MI] Resource Function Synapse Name Generation for MI Module Gen Tool #4540

@iamvirul

Description

@iamvirul

Description

The mi-module-gen tool currently supports generating synapse artifacts for:

  • Public functions: Regular Ballerina functions
  • Remote functions: Functions marked with the remote qualifier

Support for resource functions is being added as per GitHub Issue #4362.

Problem Statement

Current Behavior (Remote Functions)

For remote functions, the synapse template name can be directly derived from the function name:

remote function getUsers() returns User[]|error {
    // function implementation
}

Synapse Name: getUsers (uses function name directly)

This works because remote function names are simple identifiers that are:

  • Unique within the client class
  • Valid XML identifiers
  • Descriptive and meaningful

Issue with Resource Functions

Resource functions have a different structure:

resource isolated function get users/[string userId]/drafts(
    map<string|string[]> headers = {}, 
    *GmailUsersDraftsListQueries queries
) returns ListDraftsResponse|error {
    oas:ListDraftsResponse draftList = check self.genClient->/users/[userId]/drafts(headers, queries);
    return convertOASListDraftsResponseToListDraftsResponse(draftList);
}

Current Behavior: The tool extracts only the HTTP method name (get) from methodSymbol.getName().get(), which results in:

  • Synapse Name: get (not unique or descriptive)

Problems:

  1. Non-unique names: Multiple resource functions with the same HTTP method (e.g., get users/..., get posts/...) would all generate the same synapse name get, causing conflicts
  2. Not descriptive: The name doesn't reflect the resource path, making it difficult to identify which resource the synapse template represents
  3. Invalid XML names: Resource paths contain special characters like /, [, ] that are not valid in XML element names

Technical Details

Current Implementation

In BalConnectorAnalyzer.java (line 110):

String functionName = methodSymbol.getName().get();
// ...
Component component = new Component(functionName, ...);

For resource functions, methodSymbol.getName().get() returns only the HTTP method verb (e.g., "get", "post", "put", "delete"), not the full resource path.

Resource Function Structure in Ballerina

Resource functions in Ballerina have the following signature pattern:

resource [isolated] function <HTTP_METHOD> <resource_path>([parameters]) [returns <type>]

Where:

  • <HTTP_METHOD>: HTTP verb (get, post, put, delete, patch, head, options)
  • <resource_path>: Path segments with optional path parameters (e.g., users/[string userId]/drafts)
  • Path parameters are enclosed in square brackets: [string paramName]

Proposed Solution Approach

1. Extract Resource Path from Function Signature

Need to extract the complete resource path from the resource function signature. This may require:

  • Accessing the syntax tree node for the resource function
  • Parsing the resource path segments
  • Identifying path parameters

Investigation Needed:

  • How to access the resource path from MethodSymbol or FunctionSymbol?
  • Does the Ballerina Compiler API provide methods to extract resource paths?
  • Alternative: Parse the function signature string representation

2. Generate Synapse Name from HTTP Method + Resource Path

Combine the HTTP method with the resource path to create a unique, descriptive name:

Example Transformations:

get users/[string userId]/drafts
  → getUsersDrafts

post users/[string userId]/messages
  → postUsersMessages

get users/[string userId]/messages/[string messageId]
  → getUsersMessages

Naming Strategy Options:

CamelCase with Path Segments

  • Convert HTTP method to lowercase
  • Convert each path segment to PascalCase
  • Remove path parameter brackets and types
  • Concatenate: get + Users + Drafts = getUsersDrafts

3. Handle Edge Cases

Duplicate Names:
If two resource functions generate the same synapse name:

get users/drafts
get users/drafts

Solution: Append a numeric suffix: getUsersDrafts, getUsersDrafts2

Special Characters:

  • Path segments may contain hyphens: user-profilesUserProfiles
  • Path segments may be numeric: v1/usersV1Users or getV1Users

Path Parameters:

  • Remove type information: [string userId] → use only userId for naming context
  • Multiple parameters: users/[string userId]/messages/[string msgId]getUsersMessages

Empty Path Segments:

  • Root resource: get /getRoot or get

4. XML Name Validation

Ensure generated names are valid XML identifiers:

  • Must start with a letter or underscore
  • Can contain letters, digits, underscores, hyphens, periods
  • Cannot contain spaces or special characters like /, [, ]

Sanitization Rules:

  • Replace invalid characters with underscores or remove them
  • Ensure first character is valid
  • Handle consecutive special characters

Implementation Tasks

  1. Research Ballerina Compiler API

    • Identify how to extract resource path from MethodSymbol/FunctionSymbol
    • Check if ResourceMethodSymbol or similar specialized symbol exists
    • Explore syntax tree access for resource functions
  2. Create Resource Path Extraction Utility

    • Implement method to extract HTTP method and resource path
    • Handle different resource function signatures
    • Support both isolated and non-isolated resource functions
  3. Implement Synapse Name Generation

    • Create utility method: generateSynapseNameForResource(String httpMethod, String resourcePath)
    • Apply naming strategy (CamelCase recommended)
    • Handle path parameter extraction and removal
    • Sanitize for XML validity
  4. Update Component Creation Logic

    • Modify BalConnectorAnalyzer.java to use new naming logic for resource functions
    • Keep existing logic for remote and public functions
    • Add validation to ensure unique names within a connection
  5. Add Tests

    • Test various resource path patterns
    • Test edge cases (special characters, duplicates, etc.)
    • Verify XML name validity
    • Ensure backward compatibility with remote functions

Example Scenarios

Scenario 1: Simple Resource Path

resource isolated function get users/drafts() returns Draft[]|error

Generated Synapse Name: getUsersDrafts

Scenario 2: Resource Path with Parameters

resource isolated function get users/[string userId]/drafts(...) returns Draft[]|error

Generated Synapse Name: getUsersDrafts
(Path parameter [string userId] is used for parameter extraction but removed from name)

Scenario 3: Multiple Path Segments

resource isolated function post users/[string userId]/messages/[string messageId]/replies(...) returns Reply|error

Generated Synapse Name: postUsersMessagesReplies

Scenario 4: Root Resource

resource isolated function get /() returns RootResource|error

Generated Synapse Name: getRoot or get

Scenario 5: Conflicting Names

resource isolated function get users/drafts(...) returns Draft[]|error
resource isolated function get users/drafts(...) returns Draft[]|error  // Different signature but same path

Generated Synapse Names: getUsersDrafts, getUsersDrafts2

References

  • GitHub Issue #4362 - Support for resource functions in mi-module-gen tool
  • Ballerina Language Specification - Resource Functions
  • Apache Synapse XML Template Naming Conventions

Notes

  • The current implementation in BalConnectorAnalyzer.java line 120 creates components with functionName directly
  • The synapse template XML uses {{name}} from the component (see functions_template.xml line 19)
  • Need to ensure the generated name is compatible with Synapse template naming requirements
  • Consider impact on existing connectors that may already use resource functions (if any)

Version

No response

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions