diff --git a/Uno.Extensions-packageonly.slnf b/Uno.Extensions-packageonly.slnf index 07b26d4c30..31161e14a9 100644 --- a/Uno.Extensions-packageonly.slnf +++ b/Uno.Extensions-packageonly.slnf @@ -13,6 +13,7 @@ "src\\Uno.Extensions.Core\\Uno.Extensions.Core.csproj", "src\\Uno.Extensions.Hosting.UI\\Uno.Extensions.Hosting.WinUI.csproj", "src\\Uno.Extensions.Hosting\\Uno.Extensions.Hosting.csproj", + "src\\Uno.Extensions.Http.Kiota\\Uno.Extensions.Http.Kiota.csproj", "src\\Uno.Extensions.Http.Refit\\Uno.Extensions.Http.Refit.csproj", "src\\Uno.Extensions.Http.UI\\Uno.Extensions.Http.WinUI.csproj", "src\\Uno.Extensions.Http\\Uno.Extensions.Http.csproj", diff --git a/Uno.Extensions.sln b/Uno.Extensions.sln index 756d16be46..8367d69f77 100644 --- a/Uno.Extensions.sln +++ b/Uno.Extensions.sln @@ -137,6 +137,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.Extensions.RuntimeTests EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.Extensions.RuntimeTests.Core", "src\Uno.Extensions.RuntimeTests\Uno.Extensions.RuntimeTests.Core\Uno.Extensions.RuntimeTests.Core.csproj", "{869C9E5B-0F85-4316-BC4B-CB6CBFCC02A3}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.Extensions.Http.Kiota", "src\Uno.Extensions.Http.Kiota\Uno.Extensions.Http.Kiota.csproj", "{C9827C80-312B-4E81-B539-2D305D893A6C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -733,6 +735,22 @@ Global {869C9E5B-0F85-4316-BC4B-CB6CBFCC02A3}.Release|x64.Build.0 = Release|Any CPU {869C9E5B-0F85-4316-BC4B-CB6CBFCC02A3}.Release|x86.ActiveCfg = Release|Any CPU {869C9E5B-0F85-4316-BC4B-CB6CBFCC02A3}.Release|x86.Build.0 = Release|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Debug|arm64.ActiveCfg = Debug|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Debug|arm64.Build.0 = Debug|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Debug|x64.ActiveCfg = Debug|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Debug|x64.Build.0 = Debug|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Debug|x86.ActiveCfg = Debug|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Debug|x86.Build.0 = Debug|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Release|Any CPU.Build.0 = Release|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Release|arm64.ActiveCfg = Release|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Release|arm64.Build.0 = Release|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Release|x64.ActiveCfg = Release|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Release|x64.Build.0 = Release|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Release|x86.ActiveCfg = Release|Any CPU + {C9827C80-312B-4E81-B539-2D305D893A6C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -779,6 +797,7 @@ Global {B72698C5-6706-4275-8A2B-A1D39FE9B13E} = {2197ADCE-59C4-465A-B380-0B06BF68BBBC} {A42362AF-8A61-4BBA-AA8A-E43323D5A063} = {FB399485-A0B1-4416-A494-E19AC7F5A665} {869C9E5B-0F85-4316-BC4B-CB6CBFCC02A3} = {FB399485-A0B1-4416-A494-E19AC7F5A665} + {C9827C80-312B-4E81-B539-2D305D893A6C} = {45179294-70DC-47E8-AD22-1296F897B594} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6E7B035D-9A64-4D95-89AA-9D4653F17C42} diff --git a/doc/Learn/Http/HowTo-Kiota.md b/doc/Learn/Http/HowTo-Kiota.md new file mode 100644 index 0000000000..556e841a31 --- /dev/null +++ b/doc/Learn/Http/HowTo-Kiota.md @@ -0,0 +1,114 @@ +--- +uid: Uno.Extensions.Http.HowToKiota +--- +# How-To: Quickly create and register a Kiota Client for an API + +When working with APIs in your application, having a strongly-typed client can simplify communication and reduce boilerplate code. **Kiota** is a tool that generates strongly-typed API clients from Swagger/OpenAPI definitions. With Uno.Extensions, you can easily register and use Kiota clients in your Uno Platform app without additional setup. + +## Step-by-Step Guide + +> [!IMPORTANT] +> This guide assumes you used the template wizard or `dotnet new unoapp` to create your solution. If not, it is recommended that you follow the [**Creating an application with Uno.Extensions** documentation](xref:Uno.Extensions.HowToGettingStarted) to create an application from the template. + +### 1. Installation + +* Add `Http` to the `` property in the Class Library (`.csproj`) file: + + ```diff + + Material; + Extensions; + + Http; + Toolkit; + MVUX; + + ``` + +### 2. Enable Http in Host Builder + +* Add the UseHttp method to the `IHostBuilder`: + + ```csharp + protected override void OnLaunched(LaunchActivatedEventArgs args) + { + var appBuilder = this.CreateBuilder(args) + .Configure(hostBuilder => + { + hostBuilder.UseHttp(); + }); + ... + } + ``` + +### 3. Generate the Kiota Client + +* Install the Kiota tool: + + ```xml + dotnet tool install --global Microsoft.OpenApi.Kiota + ``` + +* Generate the Client using the OpenAPI specification URL: + + ```xml + kiota generate -l CSharp -c MyApiClient -n MyApp.Client -d PATH_TO_YOUR_API_SPEC.json -o ./Client + ``` + + This will create a client named `MyApiClient` in the Client folder. + +### 4. Register the Kiota Client + +* Register the generated client in the IHostBuilder using `AddKiotaClient` from `Uno.Extensions`: + + ```csharp + + protected override void OnLaunched(LaunchActivatedEventArgs args) + { + var appBuilder = this.CreateBuilder(args) + .Configure(hostBuilder => + { + hostBuilder.UseHttp((context, services) => + services.AddKiotaClient( + context, + options: new EndpointOptions { Url = "https://localhost:5002" } + ) + ); + }); + } + ``` + +### 5. Use the Kiota Client in Your Code + +* Inject the ChefsApiClient into your view model or service and make API requests: + +```csharp +public class MyViewModel +{ + private readonly MyApiClient _apiClient; + + public MyViewModel(MyApiClient apiClient) + { + _apiClient = apiClient; + } + + public async Task GetAll() + { + var something = await _apiClient.Api.GetAsync(); + Console.WriteLine($"Retrieved {something?.Count}."); + } +} + +``` + +## Important Considerations + +* With `Uno.Extensions.Authentication`, the HttpClient automatically includes the **Authorization** header. You don't need to manually handle token injection. The middleware ensures the access token is included in each request. + +* Ensure your server is running and the swagger.json file is accessible at the specified URL when generating the Kiota client. + +## See also + +* [Overview: What is Kiota?](https://learn.microsoft.com/en-us/openapi/kiota/) +* [Overview: HTTP](xref:Uno.Extensions.Http.Overview) +* [How-To: Consume a web API with HttpClient](xref:Uno.Development.ConsumeWebApi) +* [How-To: Register an Endpoint for HTTP Requests](xref:Uno.Extensions.Http.HowToHttp) diff --git a/doc/Learn/Http/toc.yml b/doc/Learn/Http/toc.yml index 633126698b..077d78b560 100644 --- a/doc/Learn/Http/toc.yml +++ b/doc/Learn/Http/toc.yml @@ -6,3 +6,5 @@ href: xref:Uno.Extensions.Http.HowToRefit - name: "How-To: Configure with endpoint options" href: xref:Uno.Extensions.Http.HowToEndpointOptions +- name: "How-To: Use create Kiota Client" + href: Uno.Extensions.Http.HowToKiota diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 4a6f9cad4e..878f8ae6f5 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -7,6 +7,13 @@ + + + + + + + diff --git a/src/Uno.Extensions.Http.Kiota/ServiceCollectionExtensions.cs b/src/Uno.Extensions.Http.Kiota/ServiceCollectionExtensions.cs new file mode 100644 index 0000000000..7be34f0f4c --- /dev/null +++ b/src/Uno.Extensions.Http.Kiota/ServiceCollectionExtensions.cs @@ -0,0 +1,127 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Kiota.Abstractions; +using Microsoft.Kiota.Abstractions.Authentication; +using Microsoft.Kiota.Http.HttpClientLibrary; + +namespace Uno.Extensions.Http.Kiota; + +/// +/// Provides extension methods for registering Kiota clients within the . +/// +public static class ServiceCollectionExtensions +{ + /// + /// Registers a Kiota client with the specified and endpoint options. + /// + /// The Kiota client type to register. + /// The to register the client with. + /// The providing the hosting context. + /// [Optional] The endpoint options for the client (loaded from appsettings if not specified). + /// [Optional] The name for locating endpoint information in appsettings. + /// [Optional] A callback for configuring the endpoint. + /// The updated with the registered Kiota client. + public static IServiceCollection AddKiotaClient( + this IServiceCollection services, + HostBuilderContext context, + EndpointOptions? options = null, + string? name = null, + Func? configure = null + ) + where TClient : class => + services.AddKiotaClientWithEndpoint(context, options, name, configure); + + /// + /// Registers a Kiota client with the specified and supports additional endpoint options. + /// + /// The Kiota client type to register. + /// The type of endpoint to register. + /// The to register the client with. + /// The providing the hosting context. + /// [Optional] The endpoint options for the client (loaded from appsettings if not specified). + /// [Optional] The name for locating endpoint information in appsettings. + /// [Optional] A callback for configuring the endpoint. + /// The updated with the registered Kiota client. + public static IServiceCollection AddKiotaClientWithEndpoint( + this IServiceCollection services, + HostBuilderContext context, + TEndpoint? options = null, + string? name = null, + Func? configure = null +) + where TClient : class + where TEndpoint : EndpointOptions, new() + { + services.AddKiotaHandlers(); + + return services.AddClientWithEndpoint( + context, + options, + name: name ?? typeof(TClient).FullName ?? "DefaultClient", + httpClientFactory: (s, c) => s.AddHttpClient(name ?? typeof(TClient).FullName ?? "DefaultClient") + .AttachKiotaHandlers() + .ConfigureHttpClient(client => + { + if (options?.Url != null) + { + client.BaseAddress = new Uri(options.Url); + } + }), + configure: configure + ) + .AddSingleton(sp => + { + var httpClient = sp.GetRequiredService(); + var authProvider = new AnonymousAuthenticationProvider(); + + var parseNodeFactory = new Microsoft.Kiota.Serialization.Json.JsonParseNodeFactory(); + var serializationWriterFactory = new Microsoft.Kiota.Serialization.Json.JsonSerializationWriterFactory(); + + var requestAdapter = new HttpClientRequestAdapter(authProvider, parseNodeFactory, serializationWriterFactory, httpClient); + + if (options?.Url != null) + { + requestAdapter.BaseUrl = options.Url; + } + + return requestAdapter; + }) + .AddSingleton(sp => + { + var requestAdapter = sp.GetRequiredService(); + return (TClient)Activator.CreateInstance(typeof(TClient), requestAdapter)!; + }); + } + /// + /// Dynamically adds Kiota handlers to the service collection. + /// + /// The to register the handlers with. + /// The updated with the registered Kiota handlers. + private static IServiceCollection AddKiotaHandlers(this IServiceCollection services) + { + var kiotaHandlers = KiotaClientFactory.GetDefaultHandlerTypes(); + foreach (var handler in kiotaHandlers) + { + services.AddTransient(handler); + } + + return services; + } + + /// + /// Attaches Kiota handlers to the . + /// + /// The to attach the handlers to. + /// The updated with the attached Kiota handlers. + private static IHttpClientBuilder AttachKiotaHandlers(this IHttpClientBuilder builder) + { + var kiotaHandlers = KiotaClientFactory.GetDefaultHandlerTypes(); + foreach (var handler in kiotaHandlers) + { + builder.AddHttpMessageHandler((sp) => (DelegatingHandler)sp.GetRequiredService(handler)); + } + + return builder; + } + +} diff --git a/src/Uno.Extensions.Http.Kiota/Uno.Extensions.Http.Kiota.csproj b/src/Uno.Extensions.Http.Kiota/Uno.Extensions.Http.Kiota.csproj new file mode 100644 index 0000000000..44e92dcdab --- /dev/null +++ b/src/Uno.Extensions.Http.Kiota/Uno.Extensions.Http.Kiota.csproj @@ -0,0 +1,28 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + + + + + + + + + + diff --git a/testing/TestHarness/TestHarness.Core/TestSections.cs b/testing/TestHarness/TestHarness.Core/TestSections.cs index f4edf27f92..1d32a405ea 100644 --- a/testing/TestHarness/TestHarness.Core/TestSections.cs +++ b/testing/TestHarness/TestHarness.Core/TestSections.cs @@ -33,6 +33,7 @@ public enum TestSections Localization, Http_Endpoints, Http_Refit, + Http_Kiota, Toolkit_ThemeService, Validation } diff --git a/testing/TestHarness/TestHarness.UITest/Ext/Kiota/Given_Kiota.cs b/testing/TestHarness/TestHarness.UITest/Ext/Kiota/Given_Kiota.cs new file mode 100644 index 0000000000..e8943b3fa6 --- /dev/null +++ b/testing/TestHarness/TestHarness.UITest/Ext/Kiota/Given_Kiota.cs @@ -0,0 +1,24 @@ +namespace TestHarness.UITest; + +public class Given_Kiota : NavigationTestBase +{ + [Test] + public async Task When_KiotaClient_Registered() + { + InitTestSection(TestSections.Http_Kiota); + + App.WaitThenTap("ShowAppButton"); + + App.WaitElement("KiotaHomeNavigationBar"); + + var initializationStatus = App.GetText("InitializationStatusTextBlock"); + initializationStatus.Should().Contain("Kiota Client initialized successfully."); + + App.WaitThenTap("FetchPostsButton"); + + await Task.Delay(1000); + + var fetchResult = App.GetText("FetchPostsResultTextBlock"); + fetchResult.Should().Contain("Retrieved").And.Contain("posts"); + } +} diff --git a/testing/TestHarness/TestHarness.sln b/testing/TestHarness/TestHarness.sln index 4bd4e11961..2ab94fb4a6 100644 --- a/testing/TestHarness/TestHarness.sln +++ b/testing/TestHarness/TestHarness.sln @@ -123,6 +123,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestHarness", "TestHarness\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.Extensions.Reactive.Tests", "..\..\src\Uno.Extensions.Reactive.Tests\Uno.Extensions.Reactive.Tests.csproj", "{A39E9AEC-4F8B-4B6F-A4DD-16201F427948}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Uno.Extensions.Http.Kiota", "..\..\src\Uno.Extensions.Http.Kiota\Uno.Extensions.Http.Kiota.csproj", "{49716A71-0D2A-4EB2-83C0-3A7CDD9549B5}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.Extensions.Reactive.Testing", "..\..\src\Uno.Extensions.Reactive.Testing\Uno.Extensions.Reactive.Testing.csproj", "{1A90701A-FE5D-478A-9D5E-E264D5D0287F}" EndProject Global diff --git a/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/Models/Post.cs b/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/Models/Post.cs new file mode 100644 index 0000000000..0ae79bc715 --- /dev/null +++ b/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/Models/Post.cs @@ -0,0 +1,81 @@ +// +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace TestHarness.Ext.Http.Kiota.Client.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.16.0")] + #pragma warning disable CS1591 + public partial class Post : IAdditionalDataHolder, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData { get; set; } + /// The body property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Body { get; set; } +#nullable restore +#else + public string Body { get; set; } +#endif + /// The id property + public int? Id { get; set; } + /// The title property +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public string? Title { get; set; } +#nullable restore +#else + public string Title { get; set; } +#endif + /// The userId property + public int? UserId { get; set; } + /// + /// Instantiates a new and sets the default values. + /// + public Post() + { + AdditionalData = new Dictionary(); + } + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::TestHarness.Ext.Http.Kiota.Client.Models.Post CreateFromDiscriminatorValue(IParseNode parseNode) + { + _ = parseNode ?? throw new ArgumentNullException(nameof(parseNode)); + return new global::TestHarness.Ext.Http.Kiota.Client.Models.Post(); + } + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "body", n => { Body = n.GetStringValue(); } }, + { "id", n => { Id = n.GetIntValue(); } }, + { "title", n => { Title = n.GetStringValue(); } }, + { "userId", n => { UserId = n.GetIntValue(); } }, + }; + } + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + _ = writer ?? throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("body", Body); + writer.WriteIntValue("id", Id); + writer.WriteStringValue("title", Title); + writer.WriteIntValue("userId", UserId); + writer.WriteAdditionalData(AdditionalData); + } + } +} diff --git a/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/Posts/Item/PostItemRequestBuilder.cs b/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/Posts/Item/PostItemRequestBuilder.cs new file mode 100644 index 0000000000..e4bcd372d7 --- /dev/null +++ b/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/Posts/Item/PostItemRequestBuilder.cs @@ -0,0 +1,184 @@ +// +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +using TestHarness.Ext.Http.Kiota.Client.Models; +namespace TestHarness.Ext.Http.Kiota.Client.Posts.Item +{ + /// + /// Builds and executes requests for operations under \posts\{post-id} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.16.0")] + public partial class PostItemRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public PostItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/posts/{post%2Did}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public PostItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/posts/{post%2Did}", rawUrl) + { + } + /// + /// Delete post + /// + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task DeleteAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task DeleteAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToDeleteRequestInformation(requestConfiguration); + return await RequestAdapter.SendPrimitiveAsync(requestInfo, default, cancellationToken).ConfigureAwait(false); + } + /// + /// Get post by ID + /// + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToGetRequestInformation(requestConfiguration); + return await RequestAdapter.SendAsync(requestInfo, global::TestHarness.Ext.Http.Kiota.Client.Models.Post.CreateFromDiscriminatorValue, default, cancellationToken).ConfigureAwait(false); + } + /// + /// Update post + /// + /// A + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PatchAsync(global::TestHarness.Ext.Http.Kiota.Client.Models.Post body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PatchAsync(global::TestHarness.Ext.Http.Kiota.Client.Models.Post body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + _ = body ?? throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPatchRequestInformation(body, requestConfiguration); + return await RequestAdapter.SendAsync(requestInfo, global::TestHarness.Ext.Http.Kiota.Client.Models.Post.CreateFromDiscriminatorValue, default, cancellationToken).ConfigureAwait(false); + } + /// + /// Delete post + /// + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToDeleteRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToDeleteRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.DELETE, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + return requestInfo; + } + /// + /// Get post by ID + /// + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + return requestInfo; + } + /// + /// Update post + /// + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPatchRequestInformation(global::TestHarness.Ext.Http.Kiota.Client.Models.Post body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPatchRequestInformation(global::TestHarness.Ext.Http.Kiota.Client.Models.Post body, Action> requestConfiguration = default) + { +#endif + _ = body ?? throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.PATCH, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::TestHarness.Ext.Http.Kiota.Client.Posts.Item.PostItemRequestBuilder WithUrl(string rawUrl) + { + return new global::TestHarness.Ext.Http.Kiota.Client.Posts.Item.PostItemRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.16.0")] + public partial class PostItemRequestBuilderDeleteRequestConfiguration : RequestConfiguration + { + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.16.0")] + public partial class PostItemRequestBuilderGetRequestConfiguration : RequestConfiguration + { + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.16.0")] + public partial class PostItemRequestBuilderPatchRequestConfiguration : RequestConfiguration + { + } + } +} diff --git a/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/Posts/PostsRequestBuilder.cs b/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/Posts/PostsRequestBuilder.cs new file mode 100644 index 0000000000..1291eec093 --- /dev/null +++ b/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/Posts/PostsRequestBuilder.cs @@ -0,0 +1,187 @@ +// +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +using TestHarness.Ext.Http.Kiota.Client.Models; +using TestHarness.Ext.Http.Kiota.Client.Posts.Item; +namespace TestHarness.Ext.Http.Kiota.Client.Posts +{ + /// + /// Builds and executes requests for operations under \posts + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.16.0")] + public partial class PostsRequestBuilder : BaseRequestBuilder + { + /// Gets an item from the TestHarness.Ext.Http.Kiota.Client.posts.item collection + /// key: id of post + /// A + public global::TestHarness.Ext.Http.Kiota.Client.Posts.Item.PostItemRequestBuilder this[int position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("post%2Did", position); + return new global::TestHarness.Ext.Http.Kiota.Client.Posts.Item.PostItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// Gets an item from the TestHarness.Ext.Http.Kiota.Client.posts.item collection + /// key: id of post + /// A + [Obsolete("This indexer is deprecated and will be removed in the next major version. Use the one with the typed parameter instead.")] + public global::TestHarness.Ext.Http.Kiota.Client.Posts.Item.PostItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + if (!string.IsNullOrWhiteSpace(position)) urlTplParams.Add("post%2Did", position); + return new global::TestHarness.Ext.Http.Kiota.Client.Posts.Item.PostItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public PostsRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/posts{?title*,userId*}", pathParameters) + { + } + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public PostsRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/posts{?title*,userId*}", rawUrl) + { + } + /// + /// Get posts + /// + /// A List<global::TestHarness.Ext.Http.Kiota.Client.Models.Post> + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task?> GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task> GetAsync(Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + var requestInfo = ToGetRequestInformation(requestConfiguration); + var collectionResult = await RequestAdapter.SendCollectionAsync(requestInfo, global::TestHarness.Ext.Http.Kiota.Client.Models.Post.CreateFromDiscriminatorValue, default, cancellationToken).ConfigureAwait(false); + return collectionResult?.AsList(); + } + /// + /// Create post + /// + /// A + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public async Task PostAsync(global::TestHarness.Ext.Http.Kiota.Client.Models.Post body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { +#nullable restore +#else + public async Task PostAsync(global::TestHarness.Ext.Http.Kiota.Client.Models.Post body, Action> requestConfiguration = default, CancellationToken cancellationToken = default) + { +#endif + _ = body ?? throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPostRequestInformation(body, requestConfiguration); + return await RequestAdapter.SendAsync(requestInfo, global::TestHarness.Ext.Http.Kiota.Client.Models.Post.CreateFromDiscriminatorValue, default, cancellationToken).ConfigureAwait(false); + } + /// + /// Get posts + /// + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToGetRequestInformation(Action> requestConfiguration = default) + { +#endif + var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + return requestInfo; + } + /// + /// Create post + /// + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + public RequestInformation ToPostRequestInformation(global::TestHarness.Ext.Http.Kiota.Client.Models.Post body, Action>? requestConfiguration = default) + { +#nullable restore +#else + public RequestInformation ToPostRequestInformation(global::TestHarness.Ext.Http.Kiota.Client.Models.Post body, Action> requestConfiguration = default) + { +#endif + _ = body ?? throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/json"); + requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body); + return requestInfo; + } + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::TestHarness.Ext.Http.Kiota.Client.Posts.PostsRequestBuilder WithUrl(string rawUrl) + { + return new global::TestHarness.Ext.Http.Kiota.Client.Posts.PostsRequestBuilder(rawUrl, RequestAdapter); + } + /// + /// Get posts + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.16.0")] + public partial class PostsRequestBuilderGetQueryParameters + { + /// Filter results by title +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER +#nullable enable + [QueryParameter("title")] + public string? Title { get; set; } +#nullable restore +#else + [QueryParameter("title")] + public string Title { get; set; } +#endif + /// Filter results by user ID + [QueryParameter("userId")] + public int? UserId { get; set; } + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.16.0")] + public partial class PostsRequestBuilderGetRequestConfiguration : RequestConfiguration + { + } + /// + /// Configuration for the request such as headers, query parameters, and middleware options. + /// + [Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")] + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.16.0")] + public partial class PostsRequestBuilderPostRequestConfiguration : RequestConfiguration + { + } + } +} diff --git a/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/PostsApiClient.cs b/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/PostsApiClient.cs new file mode 100644 index 0000000000..eb6adb2584 --- /dev/null +++ b/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/PostsApiClient.cs @@ -0,0 +1,46 @@ +// +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions; +using Microsoft.Kiota.Serialization.Form; +using Microsoft.Kiota.Serialization.Json; +using Microsoft.Kiota.Serialization.Multipart; +using Microsoft.Kiota.Serialization.Text; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +using TestHarness.Ext.Http.Kiota.Client.Posts; +namespace TestHarness.Ext.Http.Kiota.Client +{ + /// + /// The main entry point of the SDK, exposes the configuration and the fluent API. + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.16.0")] + public partial class PostsApiClient : BaseRequestBuilder + { + /// The posts property + public global::TestHarness.Ext.Http.Kiota.Client.Posts.PostsRequestBuilder Posts + { + get => new global::TestHarness.Ext.Http.Kiota.Client.Posts.PostsRequestBuilder(PathParameters, RequestAdapter); + } + /// + /// Instantiates a new and sets the default values. + /// + /// The request adapter to use to execute the requests. + public PostsApiClient(IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}", new Dictionary()) + { + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + if (string.IsNullOrEmpty(RequestAdapter.BaseUrl)) + { + RequestAdapter.BaseUrl = "https://jsonplaceholder.typicode.com"; + } + PathParameters.TryAdd("baseurl", RequestAdapter.BaseUrl); + } + } +} diff --git a/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/kiota-lock.json b/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/kiota-lock.json new file mode 100644 index 0000000000..764ed34a5d --- /dev/null +++ b/testing/TestHarness/TestHarness/Ext/Http/Kiota/Client/kiota-lock.json @@ -0,0 +1,33 @@ +{ + "descriptionHash": "37FE8D63AB108F248AAA5632A5D37D625F8B9E3A6C439952B4029B0AF49579F337028FE07768B89D6F9210460D77E116F312CB505A43E8EB877131E772464F3B", + "descriptionLocation": "../posts-api.yml", + "lockFileVersion": "1.0.0", + "kiotaVersion": "1.16.0", + "clientClassName": "PostsApiClient", + "clientNamespaceName": "TestHarness.Ext.Http.Kiota.Client", + "language": "CSharp", + "usesBackingStore": false, + "excludeBackwardCompatible": false, + "includeAdditionalData": true, + "disableSSLValidation": false, + "serializers": [ + "Microsoft.Kiota.Serialization.Json.JsonSerializationWriterFactory", + "Microsoft.Kiota.Serialization.Text.TextSerializationWriterFactory", + "Microsoft.Kiota.Serialization.Form.FormSerializationWriterFactory", + "Microsoft.Kiota.Serialization.Multipart.MultipartSerializationWriterFactory" + ], + "deserializers": [ + "Microsoft.Kiota.Serialization.Json.JsonParseNodeFactory", + "Microsoft.Kiota.Serialization.Text.TextParseNodeFactory", + "Microsoft.Kiota.Serialization.Form.FormParseNodeFactory" + ], + "structuredMimeTypes": [ + "application/json", + "text/plain;q=0.9", + "application/x-www-form-urlencoded;q=0.2", + "multipart/form-data;q=0.1" + ], + "includePatterns": [], + "excludePatterns": [], + "disabledValidationRules": [] +} \ No newline at end of file diff --git a/testing/TestHarness/TestHarness/Ext/Http/Kiota/KiotaHomePage.xaml b/testing/TestHarness/TestHarness/Ext/Http/Kiota/KiotaHomePage.xaml new file mode 100644 index 0000000000..93d215e9fc --- /dev/null +++ b/testing/TestHarness/TestHarness/Ext/Http/Kiota/KiotaHomePage.xaml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + +