Skip to content
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

Implement Response abstraction for Azure #46530

Merged
merged 18 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions eng/packages/http-client-csharp/generator/Azure.Generator.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ VisualStudioVersion = 17.10.35201.131
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Generator", "Azure.Generator\src\Azure.Generator.csproj", "{8DDB0B72-B3F6-4F87-8B04-163EB4880FC8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Generator.CSharp.ClientModel", "..\..\..\..\..\..\work\typespec\packages\http-client-csharp\generator\Microsoft.Generator.CSharp.ClientModel\src\Microsoft.Generator.CSharp.ClientModel.csproj", "{9B280BB0-0A82-4635-A8F7-A44FDF7EF316}"
live1206 marked this conversation as resolved.
Show resolved Hide resolved
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BasicTypeSpec", "TestProjects\Local\Basic-TypeSpec\src\BasicTypeSpec.csproj", "{F8386530-1166-438C-99DC-AE855036A37C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Generator.Tests", "Azure.Generator\test\Azure.Generator.Tests.csproj", "{A05E6873-DD18-44B2-88A8-DEE3AA103EC4}"
EndProject
Global
Expand All @@ -17,6 +20,14 @@ Global
{8DDB0B72-B3F6-4F87-8B04-163EB4880FC8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8DDB0B72-B3F6-4F87-8B04-163EB4880FC8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8DDB0B72-B3F6-4F87-8B04-163EB4880FC8}.Release|Any CPU.Build.0 = Release|Any CPU
{9B280BB0-0A82-4635-A8F7-A44FDF7EF316}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9B280BB0-0A82-4635-A8F7-A44FDF7EF316}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9B280BB0-0A82-4635-A8F7-A44FDF7EF316}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9B280BB0-0A82-4635-A8F7-A44FDF7EF316}.Release|Any CPU.Build.0 = Release|Any CPU
{F8386530-1166-438C-99DC-AE855036A37C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8386530-1166-438C-99DC-AE855036A37C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8386530-1166-438C-99DC-AE855036A37C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8386530-1166-438C-99DC-AE855036A37C}.Release|Any CPU.Build.0 = Release|Any CPU
{A05E6873-DD18-44B2-88A8-DEE3AA103EC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A05E6873-DD18-44B2-88A8-DEE3AA103EC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A05E6873-DD18-44B2-88A8-DEE3AA103EC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@
<PackageId>Azure.Generator</PackageId>
<Version>1.0.0-beta.1</Version>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<NoWarn>CS8002</NoWarn>
<NoWarn>CS8002</NoWarn>
<LangVersion>latest</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Generator.CSharp.ClientModel" />
<PackageReference Include="Azure.Core" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\..\..\..\..\work\typespec\packages\http-client-csharp\generator\Microsoft.Generator.CSharp.ClientModel\src\Microsoft.Generator.CSharp.ClientModel.csproj" />
live1206 marked this conversation as resolved.
Show resolved Hide resolved
</ItemGroup>

<!-- Copy output to package dist path for local execution -->
<Target Name="CopyForNpmPackage" AfterTargets="Build">
<Message Text="Copying output to dist path" Importance="high" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.CodeAnalysis;
using Microsoft.Generator.CSharp;
using Microsoft.Generator.CSharp.ClientModel;
using System;
using System.ClientModel;
using System.Collections.Generic;
using System.ComponentModel.Composition;

namespace Azure.Generator;
Expand Down Expand Up @@ -38,6 +41,7 @@ public AzureClientPlugin(GeneratorContext context) : base(context)
public override void Configure()
{
base.Configure();
AddMetadataReference(MetadataReference.CreateFromFile(typeof(Response).Assembly.Location));
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Azure.Core;
using Azure.Generator.Primitives;
using Azure.Generator.Providers;
using Azure.Generator.Providers.Abstraction;
using Microsoft.Generator.CSharp.ClientModel;
using Microsoft.Generator.CSharp.ClientModel.Providers;
using Microsoft.Generator.CSharp.Input;
using Microsoft.Generator.CSharp.Primitives;

Expand All @@ -11,6 +15,33 @@ namespace Azure.Generator
/// <inheritdoc/>
public class AzureTypeFactory : ScmTypeFactory
{
/// <inheritdoc/>
public override CSharpType ClientUriBuilderBaseType => typeof(RequestUriBuilder);

/// <inheritdoc/>
public override IClientResponseApi ClientResponseApi => AzureClientResponseProvider.Instance;

/// <inheritdoc/>
public override IHttpResponseApi HttpResponseApi => AzureResponseProvider.Instance;

/// <inheritdoc/>
public override IClientPipelineApi ClientPipelineApi => HttpPipelineProvider.Instance;

/// <inheritdoc/>
public override IHttpMessageApi HttpMessageApi => HttpMessageProvider.Instance;

/// <inheritdoc/>
public override IExpressionApi<HttpRequestApi> HttpRequestApi => HttpRequestProvider.Instance;

/// <inheritdoc/>
public override IStatusCodeClassifierApi StatusCodeClassifierApi => StatusCodeClassifierProvider.Instance;

/// <inheritdoc/>
public override IRequestContentApi RequestContentApi => RequestContentProvider.Instance;

/// <inheritdoc/>
public override IHttpRequestOptionsApi HttpRequestOptionsApi => HttpRequestOptionsProvider.Instance;

/// <inheritdoc/>
protected override CSharpType? CreateCSharpTypeCore(InputType inputType)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.Generator.CSharp.ClientModel.Providers;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Primitives;
using Microsoft.Generator.CSharp.Snippets;
using static Microsoft.Generator.CSharp.Snippets.Snippet;

namespace Azure.Generator.Providers
{
internal record AzureClientResponseProvider : ClientResponseApi
{
private static ClientResponseApi? _instance;
internal static ClientResponseApi Instance => _instance ??= new AzureClientResponseProvider();
private AzureClientResponseProvider() : base(typeof(Response), Empty)
{
}

public AzureClientResponseProvider(ValueExpression original) : base(typeof(Response), original)
{
}

public override CSharpType ClientResponseType => typeof(Response);

public override CSharpType ClientResponseOfTType => typeof(Response<>);

public override CSharpType ClientResponseExceptionType => typeof(RequestFailedException);

public override ValueExpression CreateAsync(HttpResponseApi response)
=> New.Instance(ClientResponseExceptionType, [response]);

public override ClientResponseApi FromExpression(ValueExpression original)
=> new AzureClientResponseProvider(original);

public override ValueExpression FromResponse(ValueExpression valueExpression) => valueExpression;

public override ValueExpression FromValue(ValueExpression valueExpression, HttpResponseApi response)
=> Static(ClientResponseType).Invoke(nameof(FromValue), [valueExpression, response]);

public override ValueExpression FromValue<ValueType>(ValueExpression valueExpression, HttpResponseApi response)
=> Static(ClientResponseType).Invoke(nameof(FromValue), [valueExpression, response], [typeof(ValueType)], false);

public override HttpResponseApi GetRawResponse()
=> new AzureResponseProvider(GetRawResponseExpression());

public override ClientResponseApi ToExpression() => this;

private ScopedApi<Response> GetRawResponseExpression() => Original.As<Response>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.Generator.CSharp.ClientModel.Providers;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Primitives;
using Microsoft.Generator.CSharp.Snippets;
using System;
using System.IO;

namespace Azure.Generator.Providers
{
internal record AzureResponseProvider : HttpResponseApi
{
private static HttpResponseApi? _instance;
internal static HttpResponseApi Instance => _instance ??= new AzureResponseProvider();
private AzureResponseProvider() : base(typeof(Response), Empty)
{
}

public AzureResponseProvider(ValueExpression original) : base(typeof(Response), original)
{
}

public override CSharpType HttpResponseType => typeof(Response);

public override ScopedApi<BinaryData> Content()
=> Original.Property(nameof(Response.Content)).As<BinaryData>();

public override ScopedApi<Stream> ContentStream()
=> Original.Property(nameof(Response.ContentStream)).As<Stream>();

public override HttpResponseApi FromExpression(ValueExpression original)
=> new AzureResponseProvider(original);

public override ScopedApi<bool> IsError()
=> Original.Property(nameof(Response.IsError)).As<bool>();

public override HttpResponseApi ToExpression() => this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Azure.Core;
using Microsoft.Generator.CSharp.ClientModel.Providers;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Primitives;
using Microsoft.Generator.CSharp.Statements;
using static Microsoft.Generator.CSharp.Snippets.Snippet;

namespace Azure.Generator.Providers
{
internal record HttpMessageProvider : HttpMessageApi
{
private static HttpMessageApi? _instance;
internal static HttpMessageApi Instance => _instance ??= new HttpMessageProvider();
private HttpMessageProvider() : base(typeof(HttpMessage), Empty)
{
}

public HttpMessageProvider(ValueExpression original) : base(typeof(HttpMessage), original)
{
}

public override CSharpType HttpMessageType => typeof(HttpMessage);

public override MethodBodyStatement Apply(ValueExpression options)
=> MethodBodyStatement.Empty;

public override ValueExpression BufferResponse()
=> Original.Property(nameof(HttpMessage.BufferResponse));

public override MethodBodyStatement[] ExtractResponse()
=> [Original.Invoke(nameof(HttpMessage.ExtractResponseContent)).Terminate(), Return(Original.Property(nameof(HttpMessage.Response)))];

public override HttpMessageApi FromExpression(ValueExpression original)
=> new HttpMessageProvider(original);

public override HttpRequestApi Request()
=> new HttpRequestProvider(Original.Property(nameof(HttpMessage.Request)));

public override HttpResponseApi Response()
=> new AzureResponseProvider(Original.Property(nameof(HttpMessage.Response)));

public override ValueExpression ResponseClassifier()
=> Original.Property(nameof(HttpMessage.ResponseClassifier));

public override HttpMessageApi ToExpression() => this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Azure.Core;
using Azure.Core.Pipeline;
using Microsoft.Generator.CSharp.ClientModel.Providers;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Primitives;
using static Microsoft.Generator.CSharp.Snippets.Snippet;

namespace Azure.Generator.Providers.Abstraction
{
internal record HttpPipelineProvider : ClientPipelineApi
{
private static ClientPipelineApi? _instance;
internal static ClientPipelineApi Instance => _instance ??= new HttpPipelineProvider();
private HttpPipelineProvider() : base(typeof(HttpPipeline), Empty)
{
}

public HttpPipelineProvider(ValueExpression original) : base(typeof(HttpPipeline), original)
{
}

public override CSharpType ClientPipelineType => typeof(HttpPipeline);

public override CSharpType ClientPipelineOptionsType => typeof(ClientOptions);

public override CSharpType PipelinePolicyType => typeof(HttpPipelinePolicy);

public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies)
=> Static(typeof(HttpPipelineBuilder)).Invoke(nameof(HttpPipelineBuilder.Build), [options, perRetryPolicies]);

public override HttpMessageApi CreateMessage()
=> new HttpMessageProvider(Original.Invoke(nameof(HttpPipeline.CreateMessage)));

public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier)
=> Original.Invoke(nameof(HttpPipeline.CreateMessage), requestOptions, responseClassifier).As<HttpMessage>();

public override ClientPipelineApi FromExpression(ValueExpression expression)
=> new HttpPipelineProvider(expression);

public override ValueExpression PerRetryPolicy(params ValueExpression[] arguments)
=> Empty; // TODO: implement with default retry policy for Azure

public override InvokeMethodExpression Send(HttpMessageApi message)
=> Original.Invoke(nameof(HttpPipeline.Send), [message, Default]);

public override InvokeMethodExpression SendAsync(HttpMessageApi message)
=> Original.Invoke(nameof(HttpPipeline.SendAsync), [message, Default], true);

public override ClientPipelineApi ToExpression() => this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.Generator.CSharp.ClientModel.Providers;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Primitives;
using static Microsoft.Generator.CSharp.Snippets.Snippet;

namespace Azure.Generator.Providers.Abstraction
{
internal record HttpRequestOptionsProvider : HttpRequestOptionsApi
{
private static HttpRequestOptionsApi? _instance;
internal static HttpRequestOptionsApi Instance => _instance ??= new HttpRequestOptionsProvider();
private HttpRequestOptionsProvider() : base(typeof(RequestContext), Empty)
{
}

public HttpRequestOptionsProvider(ValueExpression original) : base(typeof(RequestContext), original)
{
}

public override CSharpType HttpRequestOptionsType => typeof(RequestContext);

public override ValueExpression ErrorOptions()
=> Original.NullConditional().Property(nameof(RequestContext.ErrorOptions));

public override HttpRequestOptionsApi FromExpression(ValueExpression original)
=> new HttpRequestOptionsProvider(original);

public override ValueExpression NoThrow()
=> FrameworkEnumValue(Azure.ErrorOptions.NoThrow);

public override HttpRequestOptionsApi ToExpression() => this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Azure.Core;
using Microsoft.Generator.CSharp.ClientModel.Providers;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Snippets;
using System.ClientModel.Primitives;
using System.Collections.Generic;
using static Microsoft.Generator.CSharp.Snippets.Snippet;

namespace Azure.Generator.Providers
{
internal record HttpRequestProvider : HttpRequestApi
{
private static HttpRequestApi? _instance;
internal static HttpRequestApi Instance => _instance ??= new HttpRequestProvider();
private HttpRequestProvider() : base(typeof(Request), Empty)
{
}

public HttpRequestProvider(ValueExpression original) : base(typeof(Request), original)
{
}

public override ValueExpression Content()
=> Original.Property(nameof(Request.Content));

public override HttpRequestApi FromExpression(ValueExpression original)
=> new HttpRequestProvider(original);

public override InvokeMethodExpression SetHeaders(IReadOnlyList<ValueExpression> arguments)
=> Original.Property(nameof(PipelineRequest.Headers)).Invoke(nameof(RequestHeaders.Add), arguments);

public override AssignmentExpression SetMethod(string httpMethod)
=> Original.Property(nameof(PipelineRequest.Method)).Assign(New.Instance(typeof(RequestMethod), [Literal(httpMethod)]));

public override AssignmentExpression SetUri(ValueExpression value)
=> Original.Property("Uri").Assign(value);

public override HttpRequestApi ToExpression() => this;
}
}
Loading
Loading