microsoft / microsoft/typespec
[http] buildPath() should not default empty path to '/' when no route segments exist
- Dominant language
- Java
- Stars
- 5.9k
- Forks
- 394
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 104
Description
## Bug Report
### Summary
When an operation has no explicit `@route` decorator and no parent route segments, the `buildPath()` function in `@typespec/http` defaults the path to `"/"`. This causes downstream consumers (TCGC, language emitters) to generate an unnecessary `"/"` in the request URL, which can cause mismatches with actual service endpoints.
**Related issue:** #10010 (reports the impact on Python SDK generation for Azure Storage)
### Root Cause
The issue is in `packages/http/src/route.ts`, lines 59-67:
```typescript
function buildPath(pathFragments: string[]) {
// Join all fragments with leading and trailing slashes trimmed
const path = pathFragments.length === 0 ? "/" : joinPathSegments(pathFragments);
// The final path must start with a '/', {/ (path expansion), or an allowed segment separator
return AllowedSegmentSeparators.includes(path[0]) || (path[0] === "{" && path[1] === "/")
? path
: /;
}
```
**Line 61:** When `pathFragments` is empty (no route segments at all), `buildPath` unconditionally returns `"/"`.
### How It Happens
1. `getUriTemplateAndParameters()` (line 197) calls `buildPath([result.uriTemplate])`
2. `DefaultRouteProducer` (lines 212-215) constructs the URI template from parent segments + route path
3. If there are no segments and no `@route` decorator, the joined path is empty
4. `buildPath` defaults empty path to `"/"`
5. The `HttpOperation.path` is then `"/"` and passed through to TCGC and emitters as-is
### Impact
- **TCGC** (`getSdkHttpOperation` in `http.ts`) passes `httpOperation.path` through without any normalization — it trusts the value from `@typespec/http`
- **Language emitters** (Python, Java, C#, etc.) generate `_url = "/"` in the request builder, which can cause URL mismatches with actual service endpoints
- **Azure Storage** and similar services that define operations at the root level (no explicit route) are affected — the generated SDK appends `"/"` to the base URL, causing test failures (see #10010)
### Reproduction
[TypeSpec Playground Link](https://typespec.io/playground/?options=%7B%22linterRuleSet%22%3A%7B%22extends%22%3A%5B%22%40typespec%2Fhttp%2Fall%22%5D%7D%7D&c=aW1wb3J0ICJAdHlwZXNwZWMvaHR0cCI7Cgp1c2luZyBIdHRwOwpAc2VydmljZSgjeyB0aXRsZTogIldpZGdldCBTxhoiIH0pCm5hbWVzcGFjZSBEZW1vxxo7Cgptb2RlbCDHMXsKICBAdmlzaWJpbGl0eShMaWZlY3ljbGUuUmVhZCkKICBpZDogc3RyaW5nOwoKICB3ZWlnaHQ6IGludDMyOwogIGNvbG9yOiAicmVkIiB8ICJibHVlIjsKfQoKQGVycm9yx3BFxAzFb2NvZGXLQG1lc3NhZ2XKZcQ6dGFnKOcA1HMiKQppbnRlcmbkAMvHFMVJLyoqIExpc3Qgd8cVKi%2FkAM7kANdsaXN0KCk6xy9bXSB85gCB5QDDxDhDcmVhdGUgYcc8xztwb3N0IGPFGyhAYm9keccfyEnJUtFQVXBk1FBhdGNoIHXFHCjEDmjlAU%2FGRC5pZCwgzmZNZXJnZVDENcZQPMYqPtp4RGVsZdJ4ZMYWxgfUeSk6IHZvaWTKT8ZOQW5hbHl60U9yb3V0ZSgie2lkfS9hxiMiKecBLscQ12XmAdTKZ30K&e=%40typespec%2Fopenapi3&vs=%7B%7D)
```typespec
import "@typespec/http";
using Http;
@service(#{ title: "Widget Service" })
namespace DemoService;
// These operations have no @route, so they get path: "/"
/** List widgets */
op list(): Widget[] | Error;
/** Create a widget */
@post op create(@body widget: Widget): Widget | Error;
```
In the generated OpenAPI spec, both `list` and `create` get path `"/"`.
### Expected Behavior
When no route segments exist, `buildPath()` should return `""` (empty string) instead of `"/"`, allowing downstream consumers to handle the empty path appropriately rather than injecting a spurious `"/"`.
### Actual Behavior
`buildPath()` returns `"/"` when `pathFragments` is empty, and this `"/"` propagates through TCGC to all language emitters.
### Existing Tests That Assert Current Behavior
The following tests in `packages/http/test/routes.test.ts` explicitly assert the current `"/"` behavior and would need updating:
- **"join empty route segments correctly"** (line ~275): asserts `@route("") + @route("") → path: "/"`
- **"interface at the document root are included"** (line ~39): asserts no-route interface → `"/"`
### Affected Packages
- `@typespec/http` (root cause)
- `@azure-tools/typespec-client-generator-core` (passes through)
- All language emitters (Python, Java, C#, JS)
Contributor guide
Assessment
This issue has not been assessed yet.