Skip to content

Commit

Permalink
Implement Response abstraction for Azure (Azure#46530)
Browse files Browse the repository at this point in the history
  • Loading branch information
live1206 authored Oct 23, 2024
1 parent 8236e8d commit 47f3c9b
Show file tree
Hide file tree
Showing 38 changed files with 1,083 additions and 631 deletions.
2 changes: 1 addition & 1 deletion eng/Packages.Data.props
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@
</ItemGroup>

<ItemGroup Condition="'$(IsGeneratorLibrary)' == 'true'">
<PackageReference Update="Microsoft.Generator.CSharp.ClientModel" Version="1.0.0-alpha.20241010.1" />
<PackageReference Update="Microsoft.Generator.CSharp.ClientModel" Version="1.0.0-alpha.20241022.3" />
</ItemGroup>

<!--
Expand Down
6 changes: 6 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,8 @@ 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}") = "BasicTypeSpec", "TestProjects\Local\Basic-TypeSpec\src\BasicTypeSpec.csproj", "{F8386530-1166-438C-99DC-AE855036A37C}"
EndProject
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 +19,10 @@ 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
{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 @@ -9,8 +9,8 @@
</PropertyGroup>

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

<!-- Copy output to package dist path for local execution -->
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,48 @@
// 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(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,38 @@
// 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(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,47 @@
// 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(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,51 @@
// 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(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,35 @@
// 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(Empty);

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

public override CSharpType HttpRequestOptionsType => typeof(RequestContext);

public override string ParameterName => "context";

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,40 @@
// 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(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

0 comments on commit 47f3c9b

Please sign in to comment.