-
Notifications
You must be signed in to change notification settings - Fork 76
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
Support for clientlets (partial application of common parameters in operation groups) #1133
Comments
@xirzec In the above example, I have added 2 more APIs below: interface OperationGroup {
doFoo(param1: string, param2: string, options?: FooOptions): Promise<ReturnShape>;
doBar(param1: string, param2: string, options?: BarOptions): Promise<ReturnShape>;
doBaz(param1: string, param2: string, options?: BazOptions): Promise<ReturnShape>;
doXyz(param3: string, options?: XyzOptions): Promise<ReturnShape>;
doAbc(options?: AbcOptions): Promise<ReturnShape>;
} const clientlet = client.operationGroup(param1, param2, param3);
await clientlet.doBar();
await clientlet.doXyz();
await clientlet.doAbc(); With the above design, I agree the code to call Also, let me take a specific example of createOrUpdate(skillsetName: string, skillset: SearchIndexerSkillset, options?: SkillsetsCreateOrUpdateOptionalParams): Promise<SkillsetsCreateOrUpdateResponse>;
delete(skillsetName: string, options?: SkillsetsDeleteOptionalParams): Promise<coreHttp.RestResponse>;
get(skillsetName: string, options?: SkillsetsGetOptionalParams): Promise<SkillsetsGetResponse>;
list(options?: SkillsetsListOptionalParams): Promise<SkillsetsListResponse>;
create(skillset: SearchIndexerSkillset, options?: SkillsetsCreateOptionalParams): Promise<SkillsetsCreateResponse>; const skillset_og = searchServiceClient.skillsets(
skillsetName, //For createOrUpdate/delete/get APIs
skillset, //For createOrUpdate/create APIs
)
skillset_og.create();
skillset_og.list();
skillset_og.delete(); In the above code, the |
I agree that this doesn't help much for listing/manipulating resources. I think I see it more as a way to bind state for operations that are all scoped to a particular resource. So to me a better analogue would be if say const client = new SearchClient(endpoint, credentials);
const index = client.index("MySearchIndex");
const results = await index.search("some search text"); So instead of splitting operation groups into multiple clients, we simply parameterize them into dynamic ones. |
Also, with the latest suggestion from Brian and Michael Nash in the Arch Board review, We could achieve the same functionality that Jeff mentioned in his last comment. But, in order to achieve this, we should do the code changes in in Modelerfour. I am working with autorest crew and will provide updates on the expected timelines soon. |
I like the idea of having these Do we expect these I think having this explicitly called out in the swagger is a better approach as it takes out a lot of guessing and would allow us to achieve more consistent results. |
This is cool! If there are methods in the operation group that don't need any of the "common" parameters, we could have a clientlet override that takes no parameters and only has the methods that don't take those parameters, when passing common parameters you get all. for example: interface OperationGroup {
doFoo(param1: string, param2: string, options?: FooOptions): Promise<ReturnShape>;
doBar(param1: string, param2: string, options?: BarOptions): Promise<ReturnShape>;
doBaz(param1: string, param2: string, options?: BazOptions): Promise<ReturnShape>;
doXyz(param3: string, options?: XyzOptions): Promise<ReturnShape>;
doAbc(options?: AbcOptions): Promise<ReturnShape>;
} would turn into: Typescript Playground (link) interface Client {
foo(param1: string, param2: string): {
doFoo(options?: FooOptions): Promise<ReturnShape>;
doBar(options?: BarOptions): Promise<ReturnShape>;
doBaz(options?: BazOptions): Promise<ReturnShape>;
doXyz(param3: string, options?: XyzOptions): Promise<ReturnShape>;
doAbc(options?: AbcOptions): Promise<ReturnShape>;
},
foo(): {
doXyz(param3: string, options?: XyzOptions): Promise<ReturnShape>;
doAbc(options?: AbcOptions): Promise<ReturnShape>;
}
}
declare const client: Client;
client.foo("a", "b").doBar();
client.foo("a", "b").doAbc();
client.foo().doAbc(); |
I think we definitely need configurability in any case, so we should have good x-ms properties to support it. Out of the box I think we could maybe default to using the operation group pattern with this and do a simple greedy algorithm like:
|
The above will at worst give us what we have today (an operation group with no parameters) and at best give us some easy wins. We can construct overloads like you show above by using special directives |
I agree that we will likely want overrides, but I believe C# is being successful inferring this kind of thing based on parameters. I think their algorithm is similar to what Jeff suggests. For the overall shape, for:
IIUC the C# approach is something like:
The drawback of this approach is that, when these are subresources, the operations like
I like the second one a lot, and it has precedence in Cosmos which gets pretty good user feedback. |
+1 on the second more nuanced approach |
Today when we create operation groups, it might look something like
Often, it would be more convenient to allow the consumer to pass
param1
andparam2
when retrieving the operation group, such as:The text was updated successfully, but these errors were encountered: