diff --git a/cspell.yaml b/cspell.yaml index 16efe6871a..5c7741356f 100644 --- a/cspell.yaml +++ b/cspell.yaml @@ -89,6 +89,7 @@ words: - SERVICERP - seti - stac + - strconv - tcgc - tsmv - userrp diff --git a/website/src/content/docs/docs/howtos/Generate client libraries/02package.mdx b/website/src/content/docs/docs/howtos/Generate client libraries/02package.mdx index de8ecdecd0..70c43d1f14 100644 --- a/website/src/content/docs/docs/howtos/Generate client libraries/02package.mdx +++ b/website/src/content/docs/docs/howtos/Generate client libraries/02package.mdx @@ -85,7 +85,27 @@ client.feed(Food(name="pork", "quantity="1")) ``` ```csharp -// TODO +namespace PetStore +{ + public partial class Food + { + public Food(string name, int quantity); + public string Name { get; } + public int Quantity { get; } + } + + public partial class PetStoreClient + { + public PetStoreClient(Uri endpoint); + public PetStoreClient(Uri endpoint, PetStoreClientOptions options); + // protocol method + public virtual Response Feed(RequestContent content, RequestContext context = null); + public virtual Task FeedAsync(RequestContent content, RequestContext context = null); + // convenience method + public virtual Response Feed(Food food, CancellationToken cancellationToken = default); + public virtual Task FeedAsync(Food food, CancellationToken cancellationToken = default); + } +} ``` ```typescript @@ -189,7 +209,26 @@ namespace Customization; ``` ```csharp -// TODO +// Food is generated in the PetStore.Models namespace. +namespace PetStore.Models +{ + public partial class Food + { + public Food(string name, int quantity); + public string Name { get; } + public int Quantity { get; } + } +} + +namespace PetStore +{ + public partial class PetStoreClient + { + public PetStoreClient(Uri endpoint); + public virtual Response Feed(Food food, CancellationToken cancellationToken = default); + public virtual Task FeedAsync(Food food, CancellationToken cancellationToken = default); + } +} ``` ```typescript diff --git a/website/src/content/docs/docs/howtos/Generate client libraries/03client.mdx b/website/src/content/docs/docs/howtos/Generate client libraries/03client.mdx index 5942d94823..35ebdbb1eb 100644 --- a/website/src/content/docs/docs/howtos/Generate client libraries/03client.mdx +++ b/website/src/content/docs/docs/howtos/Generate client libraries/03client.mdx @@ -1342,7 +1342,25 @@ client2.pet() ``` ```csharp -// TODO +namespace NewPetStore.Food +{ + public partial class FoodClient + { + public FoodClient(Uri endpoint); + public virtual Response Feed(CancellationToken cancellationToken = default); + public virtual Task FeedAsync(CancellationToken cancellationToken = default); + } +} + +namespace NewPetStore.PetAction +{ + public partial class PetActionClient + { + public PetActionClient(Uri endpoint); + public virtual Response Pet(CancellationToken cancellationToken = default); + public virtual Task PetAsync(CancellationToken cancellationToken = default); + } +} ``` ```typescript @@ -1948,7 +1966,9 @@ With `@clientInitialization`, you can change the initialization way, by passing @service namespace Storage; -op download(@path blobName: string): void; +namespace Blob { + op download(@path blobName: string): void; +} ``` ```typespec title="client.tsp" @@ -1959,12 +1979,8 @@ using Azure.ClientGenerator.Core; namespace Customizations; -model StorageClientOptions { - blobName: string; -} - @@clientInitialization( - Storage, + Storage.Blob, { initializedBy: InitializedBy.individually | InitializedBy.parent, } @@ -1980,19 +1996,25 @@ NOT_SUPPORTED ``` ```typescript -export class StorageClient { - download( - blobName: string, - options: DownloadOptionalParams = { requestOptions: {} }, - ): Promise; -} - -const client = new StorageClient(); -client.download("blobName"); +// TODO ``` ```java -// TODO +// Java requires `enable-subclient: true` option in "tspconfig.yaml" + +public final class StorageClientBuilder { + public StorageClient buildClient(); +} + +// via ClientBuilder +public final class BlobBuilder { + public BlobClient buildClient(); +} + +// via parent Client +public final class StorageClient { + public BlobClient getBlobClient() +} ``` ```go diff --git a/website/src/content/docs/docs/howtos/Generate client libraries/04method.mdx b/website/src/content/docs/docs/howtos/Generate client libraries/04method.mdx index 4f60afc00f..c1a261a9c2 100644 --- a/website/src/content/docs/docs/howtos/Generate client libraries/04method.mdx +++ b/website/src/content/docs/docs/howtos/Generate client libraries/04method.mdx @@ -241,7 +241,14 @@ public final class PetStoreNamespaceClient { ``` ```go -// NOT_SUPPORTED +// Go generates the model and method as `outputModel` / `getModel` (unexported), +// so they are not part of the package's public API. +type outputModel struct { + // READ-ONLY + Name *string +} + +func (client *PetStoreNamespaceClient) getModel(ctx context.Context, apiVersion string, name string, options *petStoreNamespaceClientgetModelOptions) (petStoreNamespaceClientgetModelResponse, error) ``` @@ -340,7 +347,9 @@ public final class ImageGenerations { ``` ```go -// NOT_SUPPORTED +// Go does not generate different code based on usage. +// However, the model may not be generated if it's never used. +// In that case, set a usage for the model. ``` @@ -1606,7 +1615,24 @@ def get(self, *, etag: Optional[str] = None, match_condition: Optional[MatchCond ``` ```csharp -# TODO +namespace TestService +{ + public partial class Response + { + public string Name { get; } + } + + public partial class TestServiceClient + { + public TestServiceClient(Uri endpoint); + // protocol method + public virtual Response Get(MatchConditions matchConditions, RequestContext context); + public virtual Task GetAsync(MatchConditions matchConditions, RequestContext context); + // convenience method + public virtual Response Get(MatchConditions matchConditions = default, CancellationToken cancellationToken = default); + public virtual Task> GetAsync(MatchConditions matchConditions = default, CancellationToken cancellationToken = default); + } +} ``` ```typescript @@ -1747,7 +1773,12 @@ public final class ContosoProviderHubClient { ``` ```go -// NOT_SUPPORTED +// subscriptionID is moved from the client to the operation level. +type ContosoProviderHubClient struct { ... } + +func (c *ClientFactory) NewContosoProviderHubClient() *ContosoProviderHubClient + +func (client *ContosoProviderHubClient) Get(ctx context.Context, subscriptionID string, extendedZoneName string, options *ContosoProviderHubClientGetOptions) (ContosoProviderHubClientGetResponse, error) ``` @@ -1835,7 +1866,8 @@ public void getSecrets(int maxResults); ```go -// NOT_SUPPORTED +// maxResults is now required, exposed as a positional parameter. +func (client *MyServiceClient) GetSecrets(ctx context.Context, maxResults int32, options *MyServiceClientGetSecretsOptions) (MyServiceClientGetSecretsResponse, error) ``` @@ -1927,7 +1959,8 @@ public void getSecrets(int maxResults); ```go -// NOT_SUPPORTED +// maxResults is now required, exposed as a positional parameter. +func (client *MyServiceClient) GetSecrets(ctx context.Context, maxResults int32, options *MyServiceClientGetSecretsOptions) (MyServiceClientGetSecretsResponse, error) ``` @@ -2003,7 +2036,8 @@ public void getSecrets(); ```go -// NOT_SUPPORTED +// maxResults parameter is removed. +func (client *MyServiceClient) GetSecrets(ctx context.Context, options *MyServiceClientGetSecretsOptions) (MyServiceClientGetSecretsResponse, error) ``` @@ -2142,7 +2176,8 @@ public void myOp(boolean c, String a, int b); ```go -// NOT_SUPPORTED +// Parameters are now in the order: c, a, b. +func (client *MyServiceClient) MyOp(ctx context.Context, c bool, a string, b int32, options *MyServiceClientMyOpOptions) (MyServiceClientMyOpResponse, error) ``` @@ -2270,7 +2305,8 @@ export async function exists( ``` ```java -// NOT_SUPPORTED +public boolean exists(String name); +public Response existsWithResponse(String name, RequestOptions requestOptions); ``` ```go diff --git a/website/src/content/docs/docs/howtos/Generate client libraries/05pagingOperations.mdx b/website/src/content/docs/docs/howtos/Generate client libraries/05pagingOperations.mdx index 1bbffb92d3..9eb91448ab 100644 --- a/website/src/content/docs/docs/howtos/Generate client libraries/05pagingOperations.mdx +++ b/website/src/content/docs/docs/howtos/Generate client libraries/05pagingOperations.mdx @@ -195,7 +195,21 @@ def list_with_page(self, **kwargs: Any) -> ItemPaged["_models.User"]: ``` ```csharp -// TODO +namespace TestService +{ + public partial class User + { + public string Id { get; } + public string Name { get; } + } + + public partial class TestServiceClient + { + public TestServiceClient(Uri endpoint); + public virtual Pageable GetWithPage(string continuationToken = default, CancellationToken cancellationToken = default); + public virtual AsyncPageable GetWithPageAsync(string continuationToken = default, CancellationToken cancellationToken = default); + } +} ``` ```typescript @@ -218,7 +232,11 @@ NOT_SUPPORTED ``` ```go -// NOT_SUPPORTED +func (client *MyServiceClient) NewListWithPagePager(options *MyServiceClientListWithPageOptions) *runtime.Pager[MyServiceClientListWithPageResponse] + +type MyServiceClientListWithPageOptions struct { + ContinuationToken *string +} ``` @@ -255,7 +273,21 @@ def list_with_page(self, **kwargs: Any) -> ItemPaged["_models.User"]: ``` ```csharp -// TODO +namespace TestService +{ + public partial class User + { + public string Id { get; } + public string Name { get; } + } + + public partial class TestServiceClient + { + public TestServiceClient(Uri endpoint); + public virtual Pageable GetWithPage(string continuationToken = default, CancellationToken cancellationToken = default); + public virtual AsyncPageable GetWithPageAsync(string continuationToken = default, CancellationToken cancellationToken = default); + } +} ``` ```typescript @@ -278,7 +310,11 @@ NOT_SUPPORTED ``` ```go -// NOT_SUPPORTED +func (client *MyServiceClient) NewListWithPagePager(options *MyServiceClientListWithPageOptions) *runtime.Pager[MyServiceClientListWithPageResponse] + +type MyServiceClientListWithPageOptions struct { + ContinuationToken *string +} ``` @@ -314,7 +350,21 @@ def list_with_page(self, **kwargs: Any) -> ItemPaged["_models.User"]: ``` ```csharp -// TODO +namespace TestService +{ + public partial class User + { + public string Id { get; } + public string Name { get; } + } + + public partial class TestServiceClient + { + public TestServiceClient(Uri endpoint); + public virtual Pageable GetWithPage(string continuationToken = default, CancellationToken cancellationToken = default); + public virtual AsyncPageable GetWithPageAsync(string continuationToken = default, CancellationToken cancellationToken = default); + } +} ``` ```typescript @@ -337,7 +387,11 @@ NOT_SUPPORTED ``` ```go -// NOT_SUPPORTED +func (client *MyServiceClient) NewListWithPagePager(options *MyServiceClientListWithPageOptions) *runtime.Pager[MyServiceClientListWithPageResponse] + +type MyServiceClientListWithPageOptions struct { + ContinuationToken *string +} ``` @@ -373,7 +427,21 @@ def list_with_page(self, **kwargs: Any) -> ItemPaged["_models.User"]: ``` ```csharp -// TODO +namespace TestService +{ + public partial class User + { + public string Id { get; } + public string Name { get; } + } + + public partial class TestServiceClient + { + public TestServiceClient(Uri endpoint); + public virtual Pageable GetWithPage(string continuationToken = default, CancellationToken cancellationToken = default); + public virtual AsyncPageable GetWithPageAsync(string continuationToken = default, CancellationToken cancellationToken = default); + } +} ``` ```typescript @@ -396,7 +464,11 @@ NOT_SUPPORTED ``` ```go -// NOT_SUPPORTED +func (client *MyServiceClient) NewListWithPagePager(options *MyServiceClientListWithPageOptions) *runtime.Pager[MyServiceClientListWithPageResponse] + +type MyServiceClientListWithPageOptions struct { + ContinuationToken *string +} ``` diff --git a/website/src/content/docs/docs/howtos/Generate client libraries/07multipart.mdx b/website/src/content/docs/docs/howtos/Generate client libraries/07multipart.mdx index 233a6cda27..f4a95f12a4 100644 --- a/website/src/content/docs/docs/howtos/Generate client libraries/07multipart.mdx +++ b/website/src/content/docs/docs/howtos/Generate client libraries/07multipart.mdx @@ -47,7 +47,18 @@ def upload( ``` ```csharp -# TODO +namespace TestService +{ + // The C# emitter currently generates only the protocol method (RequestContent) for + // multipart operations; no convenience overload or `MultipartRequest` model class + // is produced. + public partial class TestServiceClient + { + public TestServiceClient(Uri endpoint); + public virtual Response Upload(RequestContent content, string contentType, RequestContext context = null); + public virtual Task UploadAsync(RequestContent content, string contentType, RequestContext context = null); + } +} ``` ```typescript diff --git a/website/src/content/docs/docs/howtos/Generate client libraries/08types.mdx b/website/src/content/docs/docs/howtos/Generate client libraries/08types.mdx index f62ac503c3..0ada7c99ff 100644 --- a/website/src/content/docs/docs/howtos/Generate client libraries/08types.mdx +++ b/website/src/content/docs/docs/howtos/Generate client libraries/08types.mdx @@ -38,7 +38,13 @@ foo = Foo(prop="hello") ```csharp -// TODO +namespace Service +{ + public partial class Foo + { + public string Prop { get; } + } +} ``` @@ -107,7 +113,13 @@ foo = Foo(prop="hello") ```csharp -// TODO +namespace Service.Container +{ + public partial class Foo + { + public string Prop { get; } + } +} ``` @@ -177,7 +189,13 @@ foo = Foo(prop="hello") ```csharp -// TODO +namespace Service.Container +{ + public partial class Foo + { + public string Prop { get; } + } +} ``` @@ -1085,7 +1103,13 @@ public final class Animal implements JsonSerializable { ```go -// NOT_SUPPORTED +type Animal struct { + // REQUIRED + Kind *string + // REQUIRED + Name *string + AdditionalProperties map[string]*string +} ``` @@ -1333,7 +1357,28 @@ class Foo(_model_base.Model): -TODO +```csharp +namespace TestService +{ + public partial class Foo + { + public string BasicNullableProperty { get; } + public Bar ModelNullableProperty { get; } + public LR? EnumNullableProperty { get; } + } + + public partial class Bar + { + public string Prop { get; } + } + + public enum LR + { + Left, + Right + } +} +``` @@ -1353,7 +1398,23 @@ export type LR = "left" | "right"; -TODO +```java +// All Java reference type is nullable. +public final class Foo implements JsonSerializable { + public String getBasicNullableProperty(); + public Bar getModelNullableProperty(); + public LR getEnumNullableProperty(); +} + +public final class Bar implements JsonSerializable { + public String getProp(); +} + +public enum LR { + LEFT("left"), + RIGHT("right"); +} +``` @@ -2591,10 +2652,21 @@ serialized_prop = json.dumps(prop, cls=SdkJSONEncoder, format="string") ```csharp -TODO +// The property is exposed as `long`; serialization writes it as a JSON string. +namespace TestService +{ + public partial class Test + { + public long Prop { get; } + } +} + +// Internal implementation +writer.WriteStringValue(Prop.ToString()); ``` + ```typescript @@ -2623,8 +2695,20 @@ jsonWriter.writeStringField("prop", Objects.toString(this.value, null)); + ```go -// NOT_SUPPORTED +type Test struct { + // REQUIRED + Prop *int64 +} + +// Custom MarshalJSON converts int64 to a JSON string. +func (t Test) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "prop", to.Ptr(strconv.FormatInt(*t.Prop, 10))) + return json.Marshal(objectMap) +} ``` + diff --git a/website/src/content/docs/docs/howtos/Generate client libraries/10versioning.mdx b/website/src/content/docs/docs/howtos/Generate client libraries/10versioning.mdx index aa482f3871..83c6a0c1d9 100644 --- a/website/src/content/docs/docs/howtos/Generate client libraries/10versioning.mdx +++ b/website/src/content/docs/docs/howtos/Generate client libraries/10versioning.mdx @@ -534,7 +534,43 @@ def create_user_profile( ``` ```csharp -// TODO +// The C# emitter generates both operations and a ServiceVersion enum, but does not +// emit version guards on the newly added operation. +namespace My.Service +{ + public partial class UserInfo + { + public UserInfo(string username); + public string Username { get; } + } + + public partial class UserProfile + { + public UserProfile(string profileName); + public string ProfileName { get; } + } + + public partial class ServiceClient + { + public ServiceClient(Uri endpoint); + public ServiceClient(Uri endpoint, ServiceClientOptions options); + public virtual Response GetUserInfo(UserInfo userInfo, CancellationToken cancellationToken = default); + public virtual Task GetUserInfoAsync(UserInfo userInfo, CancellationToken cancellationToken = default); + public virtual Response CreateUserProfile(UserProfile userProfile, CancellationToken cancellationToken = default); + public virtual Task CreateUserProfileAsync(UserProfile userProfile, CancellationToken cancellationToken = default); + } + + public partial class ServiceClientOptions : ClientOptions + { + public ServiceClientOptions(ServiceVersion version = ServiceVersion.V2024_02_01); + + public enum ServiceVersion + { + V2024_01_01 = 1, + V2024_02_01 = 2 + } + } +} ``` ```typescript @@ -697,7 +733,37 @@ def create_user_profile( ``` ```csharp -// TODO +// The C# emitter generates the new model and property as plain members; it does not +// emit version guards or per-version conditional shapes. +namespace My.Service +{ + public partial class UserInfo + { + public UserInfo(string username); + public string Username { get; } + } + + public partial class UserProfile + { + public UserProfile(string profileName, ProfileDetails profileDetails); + public string ProfileName { get; } + public ProfileDetails ProfileDetails { get; } + } + + public partial class ProfileDetails + { + public ProfileDetails(string detailDescription); + public string DetailDescription { get; } + } + + public partial class ServiceClient + { + public ServiceClient(Uri endpoint); + public ServiceClient(Uri endpoint, ServiceClientOptions options); + public virtual Response GetUserInfo(UserInfo userInfo, CancellationToken cancellationToken = default); + public virtual Response CreateUserProfile(UserProfile userProfile, CancellationToken cancellationToken = default); + } +} ``` ```typescript