Skip to content

[Bug]: query params with nested objects are encoded wrong #10973

@sugiruu

Description

@sugiruu

Describe the bug

When a @query parameter uses @query(#{explode: true}) on a model type containing complex objects, the generated JS/C# client produces [object Object] in the URL instead of bracket-expanded key-value pairs.

Reproduction

TypeSpec

Playground link

import "@typespec/http";
using TypeSpec.Http;

model Condition {
  field: string;
  value: string;
}

model SearchFilter {
  items?: Condition[];
}

model ItemCollection { data: unknown[]; }

@service
@route("/api/v1")
namespace Example {
  @route("/items")
  interface Items {
    @get list(
      @query(#{explode: true}) filter?: SearchFilter,
    ): ItemCollection;
  }
}

Steps to reproduce

npx tsp compile main.tsp

Inspect the URI template expansion in the generated client:

import { parse } from "uri-template";

const filter = {
  items: [
    { field: "status", value: "active" },
    { field: "type",   value: "admin"  }
  ]
};

console.log(parse("/api/v1/items{?filter*}").expand({ filter }));
// Output: /api/v1/items?items=%5Bobject%20Object%5D&items=%5Bobject%20Object%5D

Expected behavior

The same output I would receive by using qs.stringify:

import qs from "qs";

const queryString = qs.stringify(
  { filter: { items: [{ field: "status", value: "active" }] } },
  { encode: false }
);
// filter[items][0][field]=status&filter[items][0][value]=active
GET /api/v1/items?filter[items][0][field]=status&filter[items][0][value]=active&filter[items][1][field]=type&filter[items][1][value]=admin

Actual behavior

GET /api/v1/items?items=%5Bobject%20Object%5D&items=%5Bobject%20Object%5D

http-client-csharp

The C# emitter has the same issue. The generated RestClient calls:

uri.AppendQuery("filter", TypeFormatters.ConvertToString(filter), true);

outputs

GET /api/v1/items?filter=Example.SearchFilter

Checklist

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingemitter:client:allGeneral issue for client emitters

    Type

    No type
    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