From a81147c59a843198a3cdb5bacc903ffd0605640b Mon Sep 17 00:00:00 2001 From: Chenjie Shi Date: Thu, 25 Jul 2024 13:36:58 +0800 Subject: [PATCH] [dpg] update spread doc (#1092) doc for the new behavior of spread, including one sample to show impact for azure core template. --------- Co-authored-by: Weidong Xu Co-authored-by: qiaozha Co-authored-by: Dapeng Zhang --- .../08methodInputs.mdx | 401 ++++++++++++++++-- 1 file changed, 372 insertions(+), 29 deletions(-) diff --git a/docs/howtos/DataPlane Generation - DPG/08methodInputs.mdx b/docs/howtos/DataPlane Generation - DPG/08methodInputs.mdx index 72489f1649..4d9d3f73ba 100644 --- a/docs/howtos/DataPlane Generation - DPG/08methodInputs.mdx +++ b/docs/howtos/DataPlane Generation - DPG/08methodInputs.mdx @@ -81,6 +81,13 @@ public User get(); ```go +type ClientGetOptions struct { +} + +type ClientGetResponse struct { +} + +func (client *Client) Get(ctx context.Context, options *ClientGetOptions) (ClientGetResponse, error) ``` @@ -171,7 +178,13 @@ public void post(User user); ```go +type ClientPostOptions struct { +} + +type ClientPostResponse struct { +} +func (client *Client) Post(ctx context.Context, user User, options *ClientPostOptions) (ClientPostResponse, error) ``` @@ -181,9 +194,9 @@ public void post(User user); Please use the _spread_ feature with caution. -- The anonymous model to be spread into operation should have less than 6 settable properties. See [simple methods](https://azure.github.io/azure-sdk/dotnet_introduction.html#dotnet-parameters). -- The anonymous model should be stable across api-versions. Adding an optional property across api-versions could result in one additional method overload in SDK client. -- The anonymous model should not be used in [JSON Merge Patch](https://datatracker.ietf.org/doc/html/rfc7386). +- The model to be spread should have less than 6 settable properties. See [simple methods](https://azure.github.io/azure-sdk/dotnet_introduction.html#dotnet-parameters). +- The model to be spread should be stable across api-versions. Adding an optional property across api-versions could result in one additional method overload in SDK client. +- The model to be spread should not be used in [JSON Merge Patch](https://datatracker.ietf.org/doc/html/rfc7386). ### Alias @@ -269,13 +282,20 @@ public void upload(String firstName, String lastName); ```go +type ClientUploadOptions struct { +} + +type ClientUploadResponse struct { +} + +func (client *Client) Upload(ctx context.Context, firstName string, lastName string, options *ClientUploadOptions) (ClientUploadResponse, error) ``` -### Alias with HTTP Parameters +### Alias with @header/@query/@path properties @@ -294,8 +314,10 @@ op upload(...User): void; +For Python, we will also generate the overloads described in the Http Post section, but omitting for brevity + ```python -def upload(id: str, first_name: str, last_name: str) -> None: +def upload(self, id: str, first_name: str, last_name: str, *, content_type: str = "application/json") -> None: ... ``` @@ -366,7 +388,13 @@ public void upload(String id, String firstName, String lastName); ```go +type ClientUploadOptions struct { +} +type ClientUploadResponse struct { +} + +func (client *Client) Upload(ctx context.Context, id string, firstName string, lastName string, options *ClientUploadOptions) (ClientUploadResponse, error) ``` @@ -392,7 +420,7 @@ op upload(...User): void; For Python, we will also generate the overloads described in the Http Post section, but omitting for brevity ```python -def upload(self, user: [User, JSON, IO[bytes]], *, content_type: str = "application/json") -> None: +def upload(self, first_name: str, last_name: str, *, content_type: str = "application/json") -> None: ... ``` @@ -402,7 +430,7 @@ def upload(self, user: [User, JSON, IO[bytes]], *, content_type: str = "applicat ```csharp public partial class User { - public User(string firstName, string lastName){} + public User(string firstName, string lastName) { } public string FirstName { get; } public string LastName { get; } } @@ -411,7 +439,7 @@ public virtual async Task UploadAsync(RequestContent content, RequestC public virtual Response Upload(RequestContent content, RequestContext context = null) //convenience method public virtual async Task UploadAsync(User user, CancellationToken cancellationToken = default) -public virtual Response Upload(User user, CancellationToken cancellationToken = default) +public virtual Response Upload(string firstName, string lastName, CancellationToken cancellationToken = default) ``` @@ -426,7 +454,10 @@ export type DemoServiceContext = Client & { (path: "/users"): { post( options: { - body: User; + body: { + firstName: string; + lastName: string; + }; } & RequestParameters ): StreamableMethod; }; @@ -434,11 +465,15 @@ export type DemoServiceContext = Client & { }; // Modular Api Layer -export async function upload(body: User, options: UploadOptionalParams): Promise; +export async function upload( + firstName: string, + lastName: string, + options: UploadOptionalParams +): Promise; // Modular classical client layer export class DemoServiceClient { - upload(body: User, options: UploadOptionalParams): Promise; + upload(firstName: string, lastName: string, options: UploadOptionalParams): Promise; } ``` @@ -446,29 +481,26 @@ export class DemoServiceClient { ```java -// Model class -@Immutable -public final class User implements JsonSerializable { - public User(String firstName, String lastName); - public String getFirstName(); - public String getLastName(); -} - -// Client API -public void upload(User user); +public void upload(String firstName, String lastName); ``` ```go +type ClientUploadOptions struct { +} + +type ClientUploadResponse struct { +} +func (client *Client) Upload(ctx context.Context, firstName string, lastName string, options *ClientUploadOptions) (ClientUploadResponse, error) ``` -### Model with `@body` Property +### Model with `@body` property @@ -493,7 +525,7 @@ op upload(...UserRequest): void; For Python, we will also generate the overloads described in the Http Post section, but omitting for brevity ```python -def upload(body: [User, JSON, IO[bytes]], **kwargs: Any) -> None: +def upload(self, body: [User, JSON, IO[bytes]], *, content_type: str = "application/json") -> None: ... ``` @@ -564,13 +596,24 @@ public void upload(User user); ```go +type User struct { + firstName *string + lastName *string +} + +type ClientUploadOptions struct { +} +type ClientUploadResponse struct { +} + +func (client *Client) Upload(ctx context.Context, user User, options *ClientUploadOptions) (ClientUploadResponse, error) ``` -### Model with Decorated Properties +### Model with @header/@query/@path properties @@ -594,7 +637,7 @@ For Python, we will also generate the overloads described in the Http Post secti ```python -def get_blob_properties(name: str, *, test_header: string, **kwargs: Any) -> None: +def get_blob_properties(self, name: str, *, test_header: string, content_type: str = "application/json") -> None: ... ``` @@ -657,13 +700,19 @@ public void getBlobProperties(String name, String testHeader); ```go +type ClientGetBlobPropertiesOptions struct { +} +type ClientGetBlobPropertiesResponse struct { +} + +func (client *Client) GetBlobProperties(ctx context.Context, name string, testHeader string, options *ClientGetBlobPropertiesOptions) (ClientGetBlobPropertiesResponse, error) ``` -### Model with Decorated and non-Decorated Properties +### Model mixed with normal and @header/@query/@path properties @@ -687,7 +736,7 @@ For Python, we will also generate the overloads described in the Http Post secti class Schema: schema: bytes -def register(body: [Schema, JSON, IO[bytes]], **kwargs: Any) -> None: +def register(self, body: [Schema, JSON, IO[bytes]], *, content_type: str = "application/json") -> None: ... ``` @@ -724,7 +773,7 @@ export type DemoServiceContext = Client & { "content-type": "application/json"; } & RawHttpHeaders; body: { - schema: string | Uint8Array | ReadableStream | NodeJS.ReadableStream; + schema: string; }; } & RequestParameters ): StreamableMethod; @@ -734,7 +783,7 @@ export type DemoServiceContext = Client & { // Modular model export interface Schema { - schema: string | Uint8Array | ReadableStream | NodeJS.ReadableStream; + schema: string; } // Modular api layer @@ -768,7 +817,301 @@ public void register(Schema schema); ```go +type ClientRegisterOptions struct { +} + +type ClientRegisterResponse struct { +} + +func (client *Client) Register(ctx context.Context, schema []byte, options *ClientRegisterOptions) (ClientRegisterResponse, error) +``` + + + + +### Using Azure.Core.ResourceOperations template + +Resource create and update operations are not impacted by spread since they all have explicit defined body parameter. +Only resource action operations are impacted by spread. + +If the action parameter is a model, then the model will be spread. + + + + +```typespec +@resource("widgets") +model Widget { + @key("widgetName") + name: string; +} + +model RepairInfo { + problem: string; + contact: string; +} + +model RepairResult { + reason: string; + info: string; +} + +alias Operations = Azure.Core.ResourceOperations<{}>; + +op scheduleRepairs is Operations.ResourceAction; +``` + + + + +For Python, we will also generate the overloads described in the Http Post section, but omitting for brevity + +```python +class RepairInfo: + problem: str + contact: str + +class RepairResult: + reason: str + info: str + +def scheduleRepairs(self, widget_name: str, problem: str, contact: str, *, content_type: str = "application/json") -> RepairResult: + ... +``` + + + + +```csharp + +``` + + + + +```typescript +// from user experience perspective + +export interface RepairInfo { + problem: string; + contact: string; +} + +export type WidgetServiceContext = Client & { + path: { + ( + path: "/widgets/{widgetName}:scheduleRepairs", + widgetName: string + ): { + post( + options: { + body: RepairInfo; + } & RequestParameters + ): StreamableMethod; + }; + }; +}; + +// Modular api layer +export async function scheduleRepairs( + context: Client, + widgetName: string, + problem: string, + contact: string, + options: ScheduleRepairsOptionalParams = { requestOptions: {} } +): Promise; + +// Modular classical client layer +export class WidgetServiceClient { + scheduleRepairs( + widgetName: string, + problem: string, + contact: string, + options: ScheduleRepairsOptionalParams = { requestOptions: {} } + ): Promise; +} +``` + + + + +```java +public RepairResult scheduleRepairs(String widgetName, String problem, String contact); +``` + + + + +```go +type ClientScheduleRepairsOptions struct { +} + +type RepairResult struct { + reason *string + info *string +} + +type ClientScheduleRepairsResponse struct { + RepairResult +} + +func (client *Client) ScheduleRepairs(ctx context.Context, widgetName string, problem string, contact string, options *ClientScheduleRepairsOptions) (ClientScheduleRepairsResponse, error) +``` + + + + +If you want to keep the model, you could use a wrapper to explicit set the body to prevent spread. + + + + +```typespec +alias BodyParameter< + T, + TName extends valueof string = "body", + TDoc extends valueof string = "Body parameter." +> = { + @doc(TDoc) + @friendlyName(TName) + @bodyRoot + body: T; +}; + +@resource("widgets") +model Widget { + @key("widgetName") + name: string; +} + +model RepairInfo { + problem: string; + contact: string; +} + +model RepairResult { + reason: string; + info: string; +} + +alias Operations = Azure.Core.ResourceOperations<{}>; + +op scheduleRepairs is Operations.ResourceAction, RepairResult>; +``` + + + + +For Python, we will also generate the overloads described in the Http Post section, but omitting for brevity + +```python +class RepairInfo: + problem: str + contact: str + +class RepairResult: + reason: str + info: str + +def scheduleRepairs(self, body: [Schema, JSON, IO[bytes]], *, content_type: str = "application/json") -> RepairResult: + ... +``` + + + + +```csharp + +``` + + + + +```typescript +// from user experience perspective + +export interface RepairInfo { + problem: string; + contact: string; +} + +export type WidgetServiceContext = Client & { + path: { + ( + path: "/widgets/{widgetName}:scheduleRepairs", + widgetName: string + ): { + post( + options: { + body: RepairInfo; + } & RequestParameters + ): StreamableMethod; + }; + }; +}; + +// Modular api layer +export async function scheduleRepairs( + context: Client, + widgetName: string, + body: RepairInfo, + options: ScheduleRepairsOptionalParams = { requestOptions: {} } +): Promise; + +// Modular classical client layer +export class WidgetServiceClient { + scheduleRepairs( + widgetName: string, + body: RepairInfo, + options: ScheduleRepairsOptionalParams = { requestOptions: {} } + ): Promise; +} +``` + + + + +```java +// Model class +@Immutable +public final class RepairInfo implements JsonSerializable { + public RepairInfo(String problem, String contact); + public String getProblem(); + public String getContact(); +} + +@Immutable +public final class RepairResult implements JsonSerializable { + public String getReason(); + public String getInfo(); +} + +// Client API +public RepairResult scheduleRepairs(String widgetName, RepairInfo body); +``` + + + + +```go +type RepairInfo struct { + problem *string + contact *string +} + +type ClientScheduleRepairsOptions struct { +} + +type RepairResult struct { + reason *string + info *string +} + +type ClientScheduleRepairsResponse struct { + RepairResult +} +func (client *Client) ScheduleRepairs(ctx context.Context, widgetName string, body RepairInfo, options *ClientScheduleRepairsOptions) (ClientScheduleRepairsResponse, error) ```