Skip to content

parity(functions): honor caller's Content-Type header regardless of casing [from supabase-js] #265

Description

@grdsdev

Warning

Auto-generated parity issue — may be a false positive.

This issue was created automatically by /sync-sdk-parity from a heuristic
analysis of recent supabase-js commits. The tooling has limited insight
into language-specific idioms and may have:

  • misidentified a JS-only change as cross-language relevant,
  • missed an existing implementation in this SDK under a different name,
  • or proposed an API shape that doesn't fit this language's conventions.

It is the SDK author's responsibility to validate the need before
implementing.
If this change does not apply to this SDK, please close the
issue with a short note explaining why.


SDK Parity: C# implementation needed

A change was made in supabase-js that may need to be implemented in this repository for SDK parity. Please confirm applicability before starting work.

Reference Implementation (supabase-js)

What Changed

When a caller passes a custom Content-Type header to invoke(), the SDK was checking with a case-sensitive key lookup. If the caller used lowercase content-type, the check failed and a conflicting Content-Type was injected. The fix uses a case-insensitive check.

Code Reference

// Before (JS) — case-sensitive check missed lowercase 'content-type'
if (
  functionArgs &&
  ((headers && !Object.prototype.hasOwnProperty.call(headers, 'Content-Type')) || !headers)
) { ... inject Content-Type ... }

// After (JS) — case-insensitive check
const hasContentTypeHeader =
  !!headers && Object.keys(headers).some((key) => key.toLowerCase() === 'content-type')
if (functionArgs && !hasContentTypeHeader) { ... inject Content-Type ... }

Current C# behavior (architectural limitation)

In modules/functions-csharp/Functions/Client.cs, HandleRequest() builds the request as:

requestMessage.Content = new StringContent(
    JsonConvert.SerializeObject(options.Body),
    Encoding.UTF8,
    "application/json"   // hardcoded Content-Type on the HttpContent object
);

foreach (var kvp in options.Headers)
{
    requestMessage.Headers.TryAddWithoutValidation(kvp.Key, kvp.Value);  // adds to request headers, NOT content headers
}

In .NET, Content-Type is a content header (on requestMessage.Content.Headers), not a request header. User-provided headers go to requestMessage.Headers and are ignored for Content-Type. There is currently no way for callers to override the Content-Type.

Additionally, InvokeFunctionOptions.Body is typed as Dictionary<string, object>, preventing users from passing raw strings or byte arrays.

Implementation Guidance

Expected fix

Allow callers to specify a custom Content-Type (and body type), and respect it when building the request:

// Option: check if caller provided content-type in headers (case-insensitive)
var callerContentType = options.Headers
    .FirstOrDefault(kvp => kvp.Key.Equals("Content-Type", StringComparison.OrdinalIgnoreCase))
    .Value;

if (callerContentType != null)
{
    requestMessage.Content = new StringContent(
        JsonConvert.SerializeObject(options.Body),
        Encoding.UTF8,
        callerContentType
    );
    // Remove from headers to avoid duplicate
    options.Headers.Remove(options.Headers.Keys
        .First(k => k.Equals("Content-Type", StringComparison.OrdinalIgnoreCase)));
}
else
{
    requestMessage.Content = new StringContent(
        JsonConvert.SerializeObject(options.Body),
        Encoding.UTF8,
        "application/json"
    );
}

Key Behaviors to Match

  • Caller-provided Content-Type (any casing) should be used for the request
  • Default application/json is used when no Content-Type is specified
  • Existing behavior for calls without custom headers is unchanged

Files Likely Affected

  • modules/functions-csharp/Functions/Client.cs
  • modules/functions-csharp/Functions/InvokeFunctionOptions.cs (may need Body type flexibility)

Acceptance Criteria

  • Caller can override Content-Type via InvokeFunctionOptions.Headers (case-insensitive)
  • Default Content-Type: application/json still applies when not provided
  • Unit tests cover custom Content-Type override
  • No breaking changes to existing API

Context

  • supabase-js version: v3.0.0-next.29
  • Parity tracking: This issue was auto-generated by SDK parity analysis
  • Related parity issues: SDK-1087 (dart), SDK-1088 (py)

Generated with Claude Code /sync-sdk-parity

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions