// Copyright © WireMock.Net using JsonConverter.Abstractions; using JsonConverter.Newtonsoft.Json; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using WireMock.Matchers; using WireMock.Net.Extensions.Routing.Delegates; using WireMock.Net.Extensions.Routing.Extensions; using WireMock.Net.Extensions.Routing.Models; using WireMock.Net.Extensions.Routing.Utils; using WireMock.Server; namespace WireMock.Net.Extensions.Routing; /// /// Provides routing and request mapping functionality for WireMock.Net, /// mimicking ASP.NET Core Minimal APIs routing style. /// /// /// Initializes a new instance of the class. /// /// The WireMock.Net server instance. public sealed class WireMockRouter(WireMockServer server) { private readonly WireMockServer _server = server; /// /// Gets or initializes the collection of middleware for the router. /// public IReadOnlyCollection MiddlewareCollection { get; init; } = []; /// /// Gets or initializes the default [optional]. /// public IJsonConverter? DefaultJsonConverter { get; init; } /// /// Gets or initializes the default [optional]. /// public JsonConverterOptions? DefaultJsonOptions { get; init; } /// /// Maps a route to a synchronous request handler. /// /// The HTTP method. /// The route pattern. /// The request handler function. /// The current instance. public WireMockRouter Map( string method, string pattern, Func requestHandler) { return Map(method, pattern, CreateResponse); object? CreateResponse(IRequestMessage request) => requestHandler(CreateRequestInfo(request, pattern)); } /// /// Maps a route to an asynchronous request handler. /// /// The HTTP method. /// The route pattern. /// The asynchronous request handler function. /// The current instance. public WireMockRouter Map( string method, string pattern, Func> requestHandler) { return Map(method, pattern, CreateResponseAsync); Task CreateResponseAsync(IRequestMessage request) => requestHandler(CreateRequestInfo(request, pattern)); } /// /// Maps a route to a request handler with a typed body. /// /// The type of the request body. /// The HTTP method. /// The route pattern. /// The request handler function. /// The [optional]. Default value is NewtonsoftJsonConverter. /// The [optional]. /// The current instance. public WireMockRouter Map( string method, string pattern, Func, object?> requestHandler, IJsonConverter? jsonConverter = null, JsonConverterOptions? jsonOptions = null) { return Map(method, pattern, CreateBody); object? CreateBody(IRequestMessage request) => requestHandler(CreateRequestInfo(request, pattern, jsonConverter, jsonOptions)); } private static WireMockRequestInfo CreateRequestInfo(IRequestMessage request, string pattern) => new(request) { RouteArgs = RoutePattern.GetArgs(pattern, request.Path), }; private static WireMockHttpRequestHandler CreateHttpRequestHandler( Func requestHandler) => request => CreateResponseMessageAsync(requestHandler(request)); private static async Task CreateResponseMessageAsync(object? response) { var awaitedResponse = response is Task task ? await task.ToGenericTaskAsync() : response; var result = awaitedResponse as IResult ?? Results.Ok(awaitedResponse); var httpContext = CreateHttpContext(); await result.ExecuteAsync(httpContext); return await httpContext.Response.ToResponseMessageAsync(); } private static HttpContext CreateHttpContext() => new DefaultHttpContext { RequestServices = new ServiceCollection().AddLogging().BuildServiceProvider(), Response = { Body = new MemoryStream() }, }; private WireMockRequestInfo CreateRequestInfo( IRequestMessage request, string pattern, IJsonConverter? jsonConverter = null, JsonConverterOptions? jsonOptions = null) { var requestInfo = CreateRequestInfo(request, pattern); var establishedJsonConverter = jsonConverter ?? DefaultJsonConverter ?? new NewtonsoftJsonConverter(); var establishedJsonOptions = jsonOptions ?? DefaultJsonOptions; return new WireMockRequestInfo(requestInfo.Request) { RouteArgs = requestInfo.RouteArgs, Body = requestInfo.Request.GetBodyAsJson( establishedJsonConverter, establishedJsonOptions), }; } private WireMockRouter Map( string method, string pattern, Func requestHandler) { var matcher = new RegexMatcher(RoutePattern.ToRegex(pattern), ignoreCase: true); var httpRequestHandler = CreateHttpRequestHandler(requestHandler).UseMiddlewareCollection(MiddlewareCollection); _server.Map(method, matcher, httpRequestHandler); return this; } }