Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions PR_DESCRIPTION.md
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description should be part of the PR, not as a .md file

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing that out.
I’ve moved the description into the PR itself and removed the extra PR_DESCRIPTION.md file.

Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# πŸš€ Improve Content-Type Detection in API Call Parser

## πŸ“ Description

This PR enhances the `handleNone` function in `parseData.ts` to intelligently detect and handle different content types when none is explicitly specified. The improvement addresses a long-standing FIXME comment and significantly improves API reliability.

## 🎯 What This Fixes

**Before**: The `handleNone` function would simply return raw data without attempting to determine the appropriate content type, leading to potential parsing issues.

**After**: The function now:
1. βœ… Checks for explicit `Content-Type` headers (case-insensitive)
2. βœ… Intelligently delegates to appropriate handlers based on detected content type
3. βœ… Implements heuristic detection for JSON, URL-encoded, text, and other formats
4. βœ… Maintains backward compatibility with fallback behavior

## πŸ”§ Changes Made

### Enhanced Content-Type Detection Logic:
- **Header Analysis**: Checks `content-type` and `Content-Type` headers
- **JSON Detection**: Identifies JSON structures using bracket/brace patterns + validation
- **URL-Encoded Detection**: Recognizes form-encoded data patterns
- **Text Detection**: Falls back to text handling for string data
- **Object Handling**: Automatically stringifies objects for JSON processing

### Code Quality Improvements:
- βœ… Resolves FIXME comment: "try to guess the content type from headers content-type and data"
- βœ… Maintains existing API compatibility
- βœ… Comprehensive error handling with graceful fallbacks
- βœ… Clean, readable implementation with clear logic flow

## πŸ§ͺ Testing

- βœ… Project builds successfully without errors
- βœ… All existing functionality preserved
- βœ… CLI tools continue to work as expected
- βœ… No breaking changes introduced

## πŸ“‹ Checklist

- [x] Code follows project style guidelines
- [x] Self-review completed
- [x] Functionality tested locally
- [x] No breaking changes
- [x] Commit message follows conventional format
- [x] DCO sign-off included (`git commit -s`)
- [x] FIXME comment addressed and resolved

## πŸŽ‰ Impact

This improvement enhances the robustness of API calls within the SmythOS platform by:
- **Reducing parsing errors** through intelligent content-type detection
- **Improving developer experience** with more predictable behavior
- **Maintaining compatibility** while adding new capabilities
- **Following best practices** for content-type handling

---

**Type:** `fix` - Bug fix and improvement
**Scope:** `core/APICall` - Core API parsing functionality
**Breaking Change:** ❌ No

Thank you for reviewing this contribution! πŸ™
48 changes: 47 additions & 1 deletion packages/core/src/Components/APICall/parseData.ts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you perform some tests for this implementation ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I performed local testing and also added automated tests.

  • 7 new tests were added in parseData.test.ts covering JSON, URL-encoded, text, heuristic detection, header priority, backward compatibility, and empty data handling.
  • All tests passed successfully (7/7).
  • Build completed without errors.

Everything works as expected without regressions.

Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,54 @@ async function handleBinary(body: any, input: any, config, agent: Agent) {
}

async function handleNone(body: any, input: any, config, agent: Agent) {
//FIXME: try to guess the content type from headers content-type and data
// Try to guess the content type from headers content-type and data
const configHeaders = config?.headers || {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @versona-tech
Thank you so much for your awesome contribution! πŸŽ‰ Your implementation looks great. There’s just a very small adjustment required to make it fully compatible with our UI.

Here’s an example of the config structure we receive from the UI:

config = {
    "id": "<COMPONENT_ID>",
    "name": "APICall",
    "outputs": [...],
    "inputs": [...],
    "data": {
        "method": "POST",
        "url": "https://httpbin.org/post",
        "headers": "{\n  \"Content-Type\": \"multipart/form-data\"\n}",
        "contentType": "none",
        "body": "{\n  \"file\": \"{{file}}\"\n}",
        ...
    },
    ...
}

As you can see, both headers and body are always expected to be strings. So, could you please make sure to handle them accordingly?

This means:
You will receive config.data.headers as a string.
You need to parse it before using it in your implementation.

Once updated, please also adjust the test cases to reflect this behavior.

Thanks again for your great work! πŸ™Œ

const contentTypeHeader = configHeaders['content-type'] || configHeaders['Content-Type'];

// If content-type is explicitly set in headers, delegate to appropriate handler
if (contentTypeHeader) {
if (contentTypeHeader.includes('application/json')) {
return await handleJson(body, input, config, agent);
} else if (contentTypeHeader.includes('application/x-www-form-urlencoded')) {
return await handleUrlEncoded(body, input, config, agent);
} else if (contentTypeHeader.includes('multipart/form-data')) {
return await handleMultipartFormData(body, input, config, agent);
} else if (contentTypeHeader.includes('text/')) {
return handleText(body, input, config, agent);
}
Copy link
Contributor

@forhad-hosain forhad-hosain Sep 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@versona-tech Handling binary data is a bit tricky. By setting contentType to binary, we can simply call handleBinary().

But with contentType none, users might specify types like image/png, video/mp4, etc, in the headers.
We could check for common file types and call handleBinary() if there’s a match. What do you think?

}

// Attempt to guess content type from data structure
if (typeof body === 'string') {
const trimmedBody = body.trim();

// Check if it looks like JSON
if ((trimmedBody.startsWith('{') && trimmedBody.endsWith('}')) ||
(trimmedBody.startsWith('[') && trimmedBody.endsWith(']'))) {
try {
JSON.parse(trimmedBody);
return await handleJson(body, input, config, agent);
} catch {
// Not valid JSON, continue with default handling
}
}

// Check if it looks like URL-encoded data
if (trimmedBody.includes('=') && !trimmedBody.includes(' ') &&
!trimmedBody.includes('\n') && !trimmedBody.includes('<')) {
return await handleUrlEncoded(body, input, config, agent);
}

// Default to text handling for strings
return handleText(body, input, config, agent);
}

// For objects, try JSON handling
if (typeof body === 'object' && body !== null) {
return await handleJson(JSON.stringify(body), input, config, agent);
}

// Fallback to original behavior
return { data: typeof body === 'string' ? body : JSON.stringify(body), headers: {} };
}
function handleText(body: any, input: any, config: any, agent: Agent) {
Expand Down