-
Notifications
You must be signed in to change notification settings - Fork 70
[TCGC] Support multiple service #3617
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
46 commits
Select commit
Hold shift + click to select a range
9c0ca78
Revert "[tcgc] one client multiple services (#3460)"
6fcd55f
wip
3f87b75
Merge branch 'main' of https://github.com/Azure/typespec-azure into t…
624da25
lint
356bc60
closer to passing tests
1284236
Merge https://github.com/Azure/typespec-azure into tcgc-multiple-service
1d920c0
versioning mutation not fully working
1ac3a67
tests passing
7b0ade8
add decorator
df25ca8
switch to multi service decoraotr
a2d4cec
Revert "switch to multi service decoraotr"
5946c5c
Revert "add decorator"
d3b150d
try new client design
79586df
most tests passing
e909e63
fix some versioning
24f8e9b
update logic
6ec8462
Merge branch 'main' of https://github.com/Azure/typespec-azure into t…
2811a69
Merge branch 'tcgc-multiple-service' of https://github.com/Azure/type…
12d867a
tests besides versioning working
8488f67
Merge branch 'main' of https://github.com/Azure/typespec-azure into t…
b8df586
fix return type of getPackageVersions so tests don't hang
afc95a5
change return types of functions
1400b13
Merge remote-tracking branch 'origin/main' into tcgc-multiple-service
8295613
remove automerge
2653bb3
update
c5f773f
Finish most logics for multiple services case
22e4c18
add tests
7dedcd9
add diagnostic tests
3937de8
add docs
1e85565
add changeset
738a592
add examples tests
e6ac719
support `@clientLocation` to new og for multiple services scenario
b57c80a
add test and fix realm
07610f5
auto apply version dependency
c338da9
fix example mapping problem and direct ops under service for multiple…
3cf322d
enhance robust
200d92f
fix multiple service client api version param
c020dcd
update docs
134d01a
update
611515b
update doc
b4d9cb5
add lint to validate endpoint and auth
8788e81
Update website/src/content/docs/docs/libraries/typespec-client-genera…
tadelesh ba43dfe
update docs
43ad8df
fix
ecc5332
update doc
206d497
fix mutation issue
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| --- | ||
| changeKind: feature | ||
| packages: | ||
| - "@azure-tools/typespec-client-generator-core" | ||
| --- | ||
|
|
||
| Add support for a single client from multiple services |
176 changes: 176 additions & 0 deletions
176
packages/typespec-client-generator-core/design-docs/multiple-services.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| # Multiple Service Support in TypeSpec Client Generator Core | ||
|
|
||
| ## Background | ||
|
|
||
| Previously, TCGC [client](./client.md) only supported generating a client from a single service. However, in real-world scenarios, a single package often contains multiple services. TCGC must support multiple services within one package to address these needs. | ||
|
|
||
| ## User Scenario | ||
|
|
||
| 1. Merging multiple services' namespaces into one client | ||
tadelesh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| This scenario is common in Azure management services. For example, the compute team maintains several services: `Compute`, `Disk`, `Gallery`, and `Sku`. These services share the same endpoint and credential but have different versioning. When migrating these services into TypeSpec, services team wants to follow the existing way to generate SDK: geneate one SDK with a single client that could manage all these services with different versioning, instead of generate multiple SDKs for these multiple services. Therefore, TCGC must support auto-merging operations and nested namespaces/interfaces from multiple services with different versioning into one client. | ||
tadelesh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| For example, given two services `Disk` and `Gallery`, with Python SDK, the generated client code should look like: | ||
|
|
||
lirenhe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ```python | ||
| client = ComputeManagementClient(credential=DefaultAzureCredential(), subscription_id="{subscription-id}") | ||
| client.disks.list_by_resource_group(resource_group_name="myResourceGroup") # this operation will use API version defined in Disk service | ||
| client.galleries.list(location="eastus") # this operation will use API version defined in Gallery service | ||
| ``` | ||
|
|
||
| ## First Step Design | ||
|
|
||
| The initial design focuses on the scenario of auto-merging multiple services into a single client. For other scenarios, such as redefining client hierarchy for multiple services, we will consider them in future iterations. | ||
|
|
||
| ### Syntax Proposal | ||
|
|
||
| Previously, the `service` property of the `@client` option only supported a single service. We propose extending it to accept an array of services. | ||
|
|
||
| For example, given two services, the original service specs are: | ||
|
|
||
| ```typespec title="ServiceA/main.tsp" | ||
| @service | ||
| @versioned(VersionsA) | ||
| namespace ServiceA; | ||
|
|
||
| enum VersionsA { | ||
| av1, | ||
| av2, | ||
| } | ||
| interface AI { | ||
| @route("/aTest") | ||
| aTest(@query("api-version") apiVersion: VersionsA): void; | ||
| } | ||
| ``` | ||
|
|
||
| ```typespec title="ServiceB/main.tsp" | ||
| @service | ||
| @versioned(VersionsB) | ||
| namespace ServiceB; | ||
|
|
||
| enum VersionsB { | ||
| bv1, | ||
| bv2, | ||
| } | ||
| interface BI { | ||
| @route("/bTest") | ||
| bTest(@query("api-version") apiVersion: VersionsB): void; | ||
| } | ||
| ``` | ||
|
|
||
| To define a combined client: | ||
|
|
||
| ```typespec title="client.tsp" | ||
| import "./ServiceA/main.tsp"; | ||
| import "./ServiceB/main.tsp"; | ||
| import "@azure-tools/typespec-client-generator-core"; | ||
|
|
||
| using Azure.ClientGenerator.Core; | ||
|
|
||
| @client({ | ||
| name: "CombineClient", | ||
| service: [ServiceA, ServiceB], | ||
iscai-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }) | ||
| @useDependency(ServiceA.VersionsA.av2, ServiceB.VersionsB.bv2) // optional | ||
iscai-msft marked this conversation as resolved.
Show resolved
Hide resolved
MaryGao marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| namespace CombineClient; | ||
tadelesh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ``` | ||
|
|
||
| **Explanation:** | ||
|
|
||
| - `@client` with the `service` property as an array indicates a combined client. | ||
| - `@useDependency` specifies the version for each service: | ||
| - If all services are unversioned, `@useDependency` can be omitted. | ||
| - If any service is versioned and `@useDependency` is not set, TCGC will use the latest version for each service by default. | ||
| - Only one `@client` with multiple services can be defined per package. Defining multiple such clients or mixing with `@operationGroup` is not supported. | ||
|
|
||
| ### TCGC Behavior | ||
|
|
||
| When TCGC detects multiple services in one client, it will: | ||
|
|
||
| 1. Create the root client for the combined client. If any service is versioned, the root client's initialization method will have an `apiVersion` parameter with no default value. The `apiVersions` property and the `apiVersion` parameter for the root client will be empty (since multiple services' API versions cannot be combined). The root client's endpoint and credential parameters will be created based on the first sub-service, which means all sub-services must share the same endpoint and credential. | ||
tadelesh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 2. Create sub-clients for each service's nested namespaces or interfaces. Each sub-client will have its own `apiVersion` property and initialization method if the service is versioned. | ||
| 3. Operations directly under each service's namespace are placed under the root client. Operations under nested namespaces or interfaces are placed under the corresponding sub-clients. | ||
iscai-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 4. Decorators such as `@clientLocation`, `@convenientAPI`, `@protocolAPI`, `@moveTo`, and `@scope` work as usual. | ||
| 5. All other TCGC logic remains unchanged. | ||
lirenhe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 6. Since TCGC does not check if merging multiple services will cause sub-clients, models, operations, or other name conflicts, emitters must handle these conflicts appropriately. | ||
iscai-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| For the example above, TCGC will generate types like: | ||
|
|
||
| ```yaml | ||
| clients: | ||
tadelesh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| - &a1 | ||
| kind: client | ||
| name: CombineClient | ||
| apiVersions: [] | ||
| clientInitialization: | ||
| kind: clientinitialization | ||
| parameters: | ||
| - kind: endpoint | ||
| name: endpoint | ||
| isGeneratedName: true | ||
| onClient: true | ||
| - kind: method | ||
| name: apiVersion | ||
| apiVersions: [] | ||
| clientDefaultValue: undefined | ||
| isGeneratedName: false | ||
| onClient: true | ||
| name: CombineClientOptions | ||
| isGeneratedName: true | ||
| initializedBy: individually | ||
| children: | ||
| - kind: client | ||
| name: AI | ||
| parent: *a1 | ||
| apiVersions: | ||
| - av1 | ||
| - av2 | ||
| initialization: | ||
| kind: clientinitialization | ||
| parameters: | ||
| - kind: endpoint | ||
| name: endpoint | ||
| isGeneratedName: true | ||
| onClient: true | ||
| - kind: method | ||
| name: apiVersion | ||
| apiVersions: | ||
| - av1 | ||
| - av2 | ||
| clientDefaultValue: av2 | ||
| isGeneratedName: false | ||
| onClient: true | ||
| name: AIOptions | ||
| isGeneratedName: true | ||
| initializedBy: parent | ||
MaryGao marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| methods: | ||
| - kind: basic | ||
| name: aTest | ||
| - kind: client | ||
| name: BI | ||
| parent: *a1 | ||
| apiVersions: | ||
| - bv1 | ||
| - bv2 | ||
| initialization: | ||
| kind: clientinitialization | ||
| parameters: | ||
| - kind: endpoint | ||
| name: endpoint | ||
| isGeneratedName: true | ||
| onClient: true | ||
| - kind: method | ||
| name: apiVersion | ||
| apiVersions: | ||
| - bv1 | ||
| - bv2 | ||
| clientDefaultValue: bv2 | ||
| isGeneratedName: false | ||
| onClient: true | ||
| name: BIOptions | ||
| isGeneratedName: true | ||
| initializedBy: parent | ||
| methods: | ||
| - kind: basic | ||
| name: bTest | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.