Azure / Azure/typespec-azure

[typespec-ts] Empty resourceUri for tenant-scoped extension resources generates a double-slash URL

Open
#5,314 0 comments 0 reactions 0 assignees View on GitHub
emitter:typescript
Dominant language
TypeScript
Stars
27
Forks
90
Avg merge
1d 22h
Merged PRs (30d)
156

Description

## Describe the bug

The TypeScript emitter generates a URL template with a slash on both sides of the extension-resource scope parameter:

```ts
"/{+resourceUri}/providers/Azure.ResourceManager.Resources/extensionsResources/{extensionsResourceName}{?api%2Dversion}"
```

For tenant-scoped extension resources, `resourceUri` is correctly passed as an empty string. Expanding the template then produces a route beginning with two slashes:

```text
//providers/Azure.ResourceManager.Resources/extensionsResources/extension
```

The Spector server does not match this route and returns 404.

## Reproduction

Use the `azure/resource-manager/resources` Spector scenario and run:

```ts
await client.extensionsResources.get("", "extension");
```

The same problem affects all tenant-scoped extension-resource operations currently covered by `packages/typespec-ts/test/azure-modular-integration/azure-arm-resources.test.ts`:

- `get("", "extension")`
- `createOrUpdate("", "extension", resource)`
- `update("", "extension", resource)`
- `delete("", "extension")`
- `listByScope("")`

## Expected behavior

The request URL contains a single slash before `providers`:

```text
/providers/Azure.ResourceManager.Resources/extensionsResources/extension
```

An empty resource URI represents tenant scope. Callers should not need to pass `"."` or another placeholder to obtain the correct URL.

## Actual behavior

The generated requests contain `//providers/...` and receive 404 responses. For example:

```text
GET //providers/Azure.ResourceManager.Resources/extensionsResources/extension?api-version=2023-12-01-preview 404
```

The PUT, PATCH, DELETE, and list operations fail in the same way.

## Root cause

The generated `expandUrlTemplate` call expands this template:

```text
/{+resourceUri}/providers/...
```

With `resourceUri === ""`, the parameter contributes no characters while both literal slashes remain.

`@typespec/ts-http-runtime@0.3.7` intentionally preserves consecutive slashes inside a route path. Azure SDK for JS PR https://github.com/Azure/azure-sdk-for-js/pull/37302 removed the previous global slash normalization from `buildRequestUrl` and limits normalization to the endpoint/route boundary. Therefore, the runtime does not normalize this generated internal `//`.

## Suggested fix

Have the TypeScript emitter generate or expand the route so tenant scope produces `/providers/...` directly, without relying on runtime slash normalization. The fix should preserve the empty-string API for tenant scope and should not require the `"."` workaround.

## Environment

- `@azure-tools/typespec-ts`: 0.56.0
- `@typespec/ts-http-runtime`: 0.3.7
- `@azure-rest/core-client`: 2.8.0
- TypeSpec compiler: 1.14.0

Contributor guide

Open the contributing guide

Research direction

Start with the azure/resource-manager/resources Spector scenario and packages/typespec-ts/test/azure-modular-integration/azure-arm-resources.test.ts, running the tenant-scoped operations with an empty resource URI. Trace the TypeScript emitter's generated expandUrlTemplate call and verify that get, createOrUpdate, update, delete, and listByScope produce a single slash before providers and no longer receive 404 responses.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.