mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-22 09:09:02 +01:00
Add new package WireMock.Net.Extensions.Routing which provides minimal-API-style routing for WireMock.Net (#1344)
* Add new package WireMock.Net.Extensions.Routing * Update documentation for WireMock.Net.Extensions.Routing * Cleanup imports * Add header to all source files inside WireMock.Net.Extensions.Routing * Add header to all source files inside WireMock.Net.Extensions.Routing.Tests * Revert unintended changes * Remove redundant build configurations * Remove incorrect links from documentation * Update nuget package references * Revert unintended changes * Migrate to AwesomeAssertions * Remove redundant project reference * Adjust formatting * Migrate to primary constructor * Refactoring: rename delegate parameter * Abstract over JSON converter * Replace WireMock with WireMock.Net in comments * Move local functions to the bottom of the methods
This commit is contained in:
committed by
GitHub
parent
60eb519ae2
commit
be2ea67b89
@@ -0,0 +1,19 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace WireMock.Net.Extensions.Routing.Extensions;
|
||||
|
||||
internal static class DictionaryExtensions
|
||||
{
|
||||
public static IDictionary<TKey, TValue> AddIf<TKey, TValue>(
|
||||
this IDictionary<TKey, TValue> source,
|
||||
bool condition,
|
||||
TKey key,
|
||||
TValue value,
|
||||
IEqualityComparer<TKey>? keyComparer = null)
|
||||
where TKey : notnull =>
|
||||
condition
|
||||
? source.ToImmutableDictionary(keyComparer).Add(key, value)
|
||||
: source;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.Net.Extensions.Routing.Extensions;
|
||||
|
||||
internal static class HttpResponseExtensions
|
||||
{
|
||||
public static async Task<ResponseMessage> ToResponseMessageAsync(
|
||||
this HttpResponse response)
|
||||
{
|
||||
var headers = response.Headers.ToDictionary(
|
||||
header => header.Key, header => new WireMockList<string?>(header.Value.ToArray()));
|
||||
return new()
|
||||
{
|
||||
Headers = headers!,
|
||||
BodyData = new BodyData
|
||||
{
|
||||
DetectedBodyType = BodyType.String,
|
||||
BodyAsString = await response.ReadBodyAsStringAsync(),
|
||||
},
|
||||
StatusCode = response.StatusCode,
|
||||
};
|
||||
}
|
||||
|
||||
public static async Task<string> ReadBodyAsStringAsync(this HttpResponse response)
|
||||
{
|
||||
response.Body.Seek(0, SeekOrigin.Begin);
|
||||
using var reader = new StreamReader(response.Body);
|
||||
return await reader.ReadToEndAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using JsonConverter.Abstractions;
|
||||
|
||||
namespace WireMock.Net.Extensions.Routing.Extensions;
|
||||
|
||||
internal static class RequestMessageExtensions
|
||||
{
|
||||
public static T? GetBodyAsJson<T>(
|
||||
this IRequestMessage requestMessage,
|
||||
IJsonConverter jsonConverter,
|
||||
JsonConverterOptions? jsonOptions = null) =>
|
||||
requestMessage.Body is not null
|
||||
? jsonConverter.Deserialize<T>(requestMessage.Body, jsonOptions)
|
||||
: default;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
namespace WireMock.Net.Extensions.Routing.Extensions;
|
||||
|
||||
internal static class StringExtensions
|
||||
{
|
||||
public static string ToMatchFullStringRegex(this string regex) =>
|
||||
$"^{regex}$";
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
namespace WireMock.Net.Extensions.Routing.Extensions;
|
||||
|
||||
internal static class TaskExtensions
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage(
|
||||
"Usage",
|
||||
"VSTHRD003:Avoid awaiting foreign Tasks",
|
||||
Justification = "Await is required here to transform base task to generic one.")]
|
||||
public static async Task<object?> ToGenericTaskAsync(this Task task)
|
||||
{
|
||||
await task;
|
||||
var taskType = task.GetType();
|
||||
if (!IsAssignableToGenericTaskType(taskType))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return task
|
||||
.GetType()
|
||||
.GetProperty("Result", BindingFlags.Instance | BindingFlags.Public)!
|
||||
.GetValue(task);
|
||||
}
|
||||
|
||||
private static bool IsAssignableToGenericTaskType(Type type)
|
||||
{
|
||||
if (type.IsGenericType &&
|
||||
type.GetGenericTypeDefinition() == typeof(Task<>) &&
|
||||
type.GetGenericArguments()[0] != Type.GetType("System.Threading.Tasks.VoidTaskResult"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return type.BaseType is not null && IsAssignableToGenericTaskType(type.BaseType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using WireMock.Net.Extensions.Routing.Delegates;
|
||||
|
||||
namespace WireMock.Net.Extensions.Routing.Extensions;
|
||||
|
||||
internal static class WireMockHttpRequestHandlerExtensions
|
||||
{
|
||||
public static WireMockHttpRequestHandler UseMiddleware(
|
||||
this WireMockHttpRequestHandler handler, WireMockMiddleware middleware) =>
|
||||
middleware(handler);
|
||||
|
||||
public static WireMockHttpRequestHandler UseMiddlewareCollection(
|
||||
this WireMockHttpRequestHandler handler,
|
||||
IReadOnlyCollection<WireMockMiddleware> middlewareCollection) =>
|
||||
middlewareCollection.Aggregate(handler, UseMiddleware);
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using JsonConverter.Abstractions;
|
||||
using WireMock.Net.Extensions.Routing.Models;
|
||||
|
||||
namespace WireMock.Net.Extensions.Routing.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for mapping HTTP routes to handlers in <see cref="WireMockRouter"/>.
|
||||
/// </summary>
|
||||
public static class WireMockRouterExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps a GET request to a synchronous request handler.
|
||||
/// </summary>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The request handler function.</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapGet(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo, object?> requestHandler) =>
|
||||
source.Map(HttpMethod.Get.Method, pattern, requestHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a GET request to an asynchronous request handler.
|
||||
/// </summary>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The asynchronous request handler function.</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapGet(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo, Task<object?>> requestHandler) =>
|
||||
source.Map(HttpMethod.Get.Method, pattern, requestHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a POST request to a synchronous request handler.
|
||||
/// </summary>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The request handler function.</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapPost(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo, object?> requestHandler) =>
|
||||
source.Map(HttpMethod.Post.Method, pattern, requestHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a POST request to an asynchronous request handler.
|
||||
/// </summary>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The asynchronous request handler function.</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapPost(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo, Task<object?>> requestHandler) =>
|
||||
source.Map(HttpMethod.Post.Method, pattern, requestHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a POST request to a synchronous request handler with a typed body.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRequest">The type of the request body.</typeparam>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The request handler function.</param>
|
||||
/// <param name="jsonConverter">The <see cref="IJsonConverter"/> [optional]. Default value is NewtonsoftJsonConverter.</param>
|
||||
/// <param name="jsonOptions">The <see cref="JsonConverterOptions"/> [optional].</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapPost<TRequest>(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo<TRequest>, object?> requestHandler,
|
||||
IJsonConverter? jsonConverter = null,
|
||||
JsonConverterOptions? jsonOptions = null) =>
|
||||
source.Map(HttpMethod.Post.Method, pattern, requestHandler, jsonConverter, jsonOptions);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a POST request to an asynchronous request handler with a typed body.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRequest">The type of the request body.</typeparam>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The asynchronous request handler function.</param>
|
||||
/// <param name="jsonConverter">The <see cref="IJsonConverter"/> [optional]. Default value is NewtonsoftJsonConverter.</param>
|
||||
/// <param name="jsonOptions">The <see cref="JsonConverterOptions"/> [optional].</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapPost<TRequest>(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo<TRequest>, Task<object?>> requestHandler,
|
||||
IJsonConverter? jsonConverter = null,
|
||||
JsonConverterOptions? jsonOptions = null) =>
|
||||
source.Map(HttpMethod.Post.Method, pattern, requestHandler, jsonConverter, jsonOptions);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a PUT request to a synchronous request handler.
|
||||
/// </summary>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The request handler function.</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapPut(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo, object?> requestHandler) =>
|
||||
source.Map(HttpMethod.Put.Method, pattern, requestHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a PUT request to an asynchronous request handler.
|
||||
/// </summary>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The asynchronous request handler function.</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapPut(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo, Task<object?>> requestHandler) =>
|
||||
source.Map(HttpMethod.Put.Method, pattern, requestHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a PUT request to a synchronous request handler with a typed body.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRequest">The type of the request body.</typeparam>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The request handler function.</param>
|
||||
/// <param name="jsonConverter">The <see cref="IJsonConverter"/> [optional]. Default value is NewtonsoftJsonConverter.</param>
|
||||
/// <param name="jsonOptions">The <see cref="JsonConverterOptions"/> [optional].</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapPut<TRequest>(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo<TRequest>, object?> requestHandler,
|
||||
IJsonConverter? jsonConverter = null,
|
||||
JsonConverterOptions? jsonOptions = null) =>
|
||||
source.Map(HttpMethod.Put.Method, pattern, requestHandler, jsonConverter, jsonOptions);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a PUT request to an asynchronous request handler with a typed body.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRequest">The type of the request body.</typeparam>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The asynchronous request handler function.</param>
|
||||
/// <param name="jsonConverter">The <see cref="IJsonConverter"/> [optional]. Default value is NewtonsoftJsonConverter.</param>
|
||||
/// <param name="jsonOptions">The <see cref="JsonConverterOptions"/> [optional].</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapPut<TRequest>(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo<TRequest>, Task<object?>> requestHandler,
|
||||
IJsonConverter? jsonConverter = null,
|
||||
JsonConverterOptions? jsonOptions = null) =>
|
||||
source.Map(HttpMethod.Put.Method, pattern, requestHandler, jsonConverter, jsonOptions);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a DELETE request to a synchronous request handler.
|
||||
/// </summary>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The request handler function.</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapDelete(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo, object?> requestHandler) =>
|
||||
source.Map(HttpMethod.Delete.Method, pattern, requestHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a DELETE request to an asynchronous request handler.
|
||||
/// </summary>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The asynchronous request handler function.</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapDelete(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo, Task<object?>> requestHandler) =>
|
||||
source.Map(HttpMethod.Delete.Method, pattern, requestHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a DELETE request to a synchronous request handler with a typed body.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRequest">The type of the request body.</typeparam>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The request handler function.</param>
|
||||
/// <param name="jsonConverter">The <see cref="IJsonConverter"/> [optional]. Default value is NewtonsoftJsonConverter.</param>
|
||||
/// <param name="jsonOptions">The <see cref="JsonConverterOptions"/> [optional].</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapDelete<TRequest>(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo<TRequest>, object?> requestHandler,
|
||||
IJsonConverter? jsonConverter = null,
|
||||
JsonConverterOptions? jsonOptions = null) =>
|
||||
source.Map(HttpMethod.Delete.Method, pattern, requestHandler, jsonConverter, jsonOptions);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a DELETE request to an asynchronous request handler with a typed body.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRequest">The type of the request body.</typeparam>
|
||||
/// <param name="source">The router to extend.</param>
|
||||
/// <param name="pattern">The route pattern.</param>
|
||||
/// <param name="requestHandler">The asynchronous request handler function.</param>
|
||||
/// <param name="jsonConverter">The <see cref="IJsonConverter"/> [optional]. Default value is NewtonsoftJsonConverter.</param>
|
||||
/// <param name="jsonOptions">The <see cref="JsonConverterOptions"/> [optional].</param>
|
||||
/// <returns>The current <see cref="WireMockRouter"/> instance.</returns>
|
||||
public static WireMockRouter MapDelete<TRequest>(
|
||||
this WireMockRouter source,
|
||||
string pattern,
|
||||
Func<WireMockRequestInfo<TRequest>, Task<object?>> requestHandler,
|
||||
IJsonConverter? jsonConverter = null,
|
||||
JsonConverterOptions? jsonOptions = null) =>
|
||||
source.Map(HttpMethod.Delete.Method, pattern, requestHandler, jsonConverter, jsonOptions);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright © WireMock.Net
|
||||
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Net.Extensions.Routing.Delegates;
|
||||
using WireMock.RequestBuilders;
|
||||
using WireMock.ResponseBuilders;
|
||||
using WireMock.Server;
|
||||
|
||||
namespace WireMock.Net.Extensions.Routing.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for mapping HTTP requests to handlers in <see cref="WireMockServer"/>.
|
||||
/// </summary>
|
||||
public static class WireMockServerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps a request to a WireMock.Net server using the specified method, path matcher, and request handler.
|
||||
/// </summary>
|
||||
/// <param name="source">The WireMock.Net server to extend.</param>
|
||||
/// <param name="method">The HTTP method to match.</param>
|
||||
/// <param name="pathMatcher">The matcher for the request path.</param>
|
||||
/// <param name="httpRequestHandler">The handler to process the request.</param>
|
||||
/// <returns>The current <see cref="WireMockServer"/> instance.</returns>
|
||||
public static WireMockServer Map(
|
||||
this WireMockServer source,
|
||||
string method,
|
||||
IStringMatcher pathMatcher,
|
||||
WireMockHttpRequestHandler httpRequestHandler)
|
||||
{
|
||||
source
|
||||
.Given(Request.Create().WithPath(pathMatcher).UsingMethod(method))
|
||||
.RespondWith(Response.Create().WithCallback(req => httpRequestHandler(req)));
|
||||
return source;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user