Wikipage Update for Admin REST Api + Fluent Model Builder #485

Closed
opened 2025-12-29 15:24:54 +01:00 by adam · 5 comments
Owner

Originally created by @R0boC0p on GitHub (Feb 16, 2023).

Hi @StefH , I already approach you using Gitter, but I cannot reply on there anymore for whatever reasons.
I must have formulated my question oddly and caused some confusion, so here I go again...

Former Question:

Can I use the Fluent Api to build a request and send it over to the IWireMockAdminApi instance as my WireMock is running remotely inside another docker container?

Self-Answer:

You answered me to use the RestApi. Yes, but it's about the fluent bit.
I have seen that there are already several questions, which are relating to what I have asked. So I apologize if I am bugging you with this over again. Example
You recently exposed the MappingModelBuilder https://github.com/WireMock-Net/WireMock.Net/issues/867 which is what I was trying to leverage, to create an interface which replicates what the WireMockServer is currently able to do using Given() call.

I tried to be helpful, fork your repository, and provide a solution to ship an extension along the WireMock.Net.RestClient Nuget package. I ended up pulling too much interfaces and abstractions from the WireMock Project into the Wiremock Abstractions Project. It wasn't a simple change anymore, which you presumingly wouldn't have accepted, as it was just too invasive.

Suggestion:

Maybe I still have just overseen something, but I ended up writing an extension, which you could propose on your WikiPage if you like?
It supposed to replicate the same usage as the WireMockServer.Given():

/// <summary>
/// Builder instance to create a mapping model request.
/// </summary>
public interface IAdminMappingRequestBuilder
{
    IEnumerable<MappingModel> GetMappingModels();

    IRespondWithAProvider Given(IRequestBuilder request);
    IAdminMappingRequestBuilder Given(
        Action<IRequestBuilder> request,
        Action<IResponseBuilder> response,
        Action<IRespondWithAProvider> provider = null);

    Task<StatusModel> BuildAndSendAsync();
}

public static class WireMockAdminApiExtension
{
    /// <summary>
    /// Creates a mapping request that can be send to a <see cref="IAdminMappingRequestBuilder"/> instance
    /// </summary>
    /// <param name="api">Instance to send the build request to.</param>
    /// <returns><see cref="IAdminMappingRequestBuilder"/></returns>
    public static IAdminMappingRequestBuilder MappingBuilder(this IWireMockAdminApi api)
        => new AdminMappingRequest(api, new MappingBuilder());

    private class AdminMappingRequest : IAdminMappingRequestBuilder
    {
        private readonly IWireMockAdminApi _api;
        private readonly MappingBuilder _mappingBuilder;

        public AdminMappingRequest(
            IWireMockAdminApi api,
            MappingBuilder mappingBuilder
            )
        {
            _api = api;
            _mappingBuilder = mappingBuilder;
        }

        public IEnumerable<MappingModel> GetMappingModels() => _mappingBuilder.GetMappings();
        public IRespondWithAProvider Given(IRequestBuilder request)
            => _mappingBuilder.Given(request);

        public IAdminMappingRequestBuilder Given(
            Action<IRequestBuilder> request,
            Action<IResponseBuilder> response,
            Action<IRespondWithAProvider> provider = null
            )
        {
            var requestBuilder = Request.Create();
            request(requestBuilder);

            var responseBuilder = Response.Create();
            response(responseBuilder);

            var providerBuilder = Given(requestBuilder);
            provider?.Invoke(providerBuilder);

            providerBuilder.RespondWith(responseBuilder);
            return this;
        }

        public async Task<StatusModel> BuildAndSendAsync()
            => await _api.PostMappingsAsync(GetMappingModels().ToList());
    }
}

Usage:

var api = RestClient.For<IWireMockAdminApi>($"http://localhost:{WireMockPort}");
var builder = api.MappingBuilder();
        builder.Given(Request.Create().UsingGet().WithPath("/bla"))
               .WithTitle("This is my title")
               .RespondWith(Response.Create().WithBody("This is my body")
                    .WithStatusCode(HttpStatusCode.OK));
        await builder.BuildAndSendAsync();

Usage 2:

var api = RestClient.For<IWireMockAdminApi>($"http://localhost:{WireMockPort}");
await api.MappingBuilder()
              .Given(request: r => r
                    .UsingGet()
                    .WithPath("/bla"),
                response: r => r
                    .WithStatusCode(HttpStatusCode.OK)
                    .WithBody("This is my body"),
                provider: p => p.WithTitle("Search for a location"))
             .BuildAndSendAsync();

Final Thought:

Please excuse my approach if it is a bit blue-eyed or I found a solution for a non existent issue. It really took me some time to figure how to do it. Perhaps if there is an explicit example on the Wiki how to properly handle FluentApi using the ResClient, using whatever approach, people will stop asking/looking for it. Potential time saver.
Thanks for your great work!

All the best.

Originally created by @R0boC0p on GitHub (Feb 16, 2023). Hi @StefH , I already approach you using Gitter, but I cannot reply on there anymore for whatever reasons. I must have formulated my question oddly and caused some confusion, so here I go again... ### Former Question: Can I use the `Fluent Api` to build a request and send it over to the `IWireMockAdminApi` instance as my WireMock is running remotely inside another docker container? ### Self-Answer: You answered me to use the RestApi. Yes, but it's about the fluent bit. I have seen that there are already several questions, which are relating to what I have asked. So I apologize if I am bugging you with this over again. [Example](https://github.com/WireMock-Net/WireMock.Net/issues/172) You recently exposed the `MappingModelBuilder` https://github.com/WireMock-Net/WireMock.Net/issues/867 which is what I was trying to leverage, to create an interface which replicates what the `WireMockServer` is currently able to do using `Given()` call. I tried to be helpful, fork your repository, and provide a solution to ship an extension along the `WireMock.Net.RestClient` Nuget package. I ended up pulling too much interfaces and abstractions from the `WireMock Project` into the `Wiremock Abstractions Project`. It wasn't a simple change anymore, which you presumingly wouldn't have accepted, as it was just too invasive. ### Suggestion: Maybe I still have just overseen something, but I ended up writing an extension, which you could propose on your [WikiPage](https://github.com/WireMock-Net/WireMock.Net/wiki/Admin-API-Reference) if you like? It supposed to replicate the same usage as the `WireMockServer.Given()`: ```c# /// <summary> /// Builder instance to create a mapping model request. /// </summary> public interface IAdminMappingRequestBuilder { IEnumerable<MappingModel> GetMappingModels(); IRespondWithAProvider Given(IRequestBuilder request); IAdminMappingRequestBuilder Given( Action<IRequestBuilder> request, Action<IResponseBuilder> response, Action<IRespondWithAProvider> provider = null); Task<StatusModel> BuildAndSendAsync(); } public static class WireMockAdminApiExtension { /// <summary> /// Creates a mapping request that can be send to a <see cref="IAdminMappingRequestBuilder"/> instance /// </summary> /// <param name="api">Instance to send the build request to.</param> /// <returns><see cref="IAdminMappingRequestBuilder"/></returns> public static IAdminMappingRequestBuilder MappingBuilder(this IWireMockAdminApi api) => new AdminMappingRequest(api, new MappingBuilder()); private class AdminMappingRequest : IAdminMappingRequestBuilder { private readonly IWireMockAdminApi _api; private readonly MappingBuilder _mappingBuilder; public AdminMappingRequest( IWireMockAdminApi api, MappingBuilder mappingBuilder ) { _api = api; _mappingBuilder = mappingBuilder; } public IEnumerable<MappingModel> GetMappingModels() => _mappingBuilder.GetMappings(); public IRespondWithAProvider Given(IRequestBuilder request) => _mappingBuilder.Given(request); public IAdminMappingRequestBuilder Given( Action<IRequestBuilder> request, Action<IResponseBuilder> response, Action<IRespondWithAProvider> provider = null ) { var requestBuilder = Request.Create(); request(requestBuilder); var responseBuilder = Response.Create(); response(responseBuilder); var providerBuilder = Given(requestBuilder); provider?.Invoke(providerBuilder); providerBuilder.RespondWith(responseBuilder); return this; } public async Task<StatusModel> BuildAndSendAsync() => await _api.PostMappingsAsync(GetMappingModels().ToList()); } } ``` Usage: ```c# var api = RestClient.For<IWireMockAdminApi>($"http://localhost:{WireMockPort}"); var builder = api.MappingBuilder(); builder.Given(Request.Create().UsingGet().WithPath("/bla")) .WithTitle("This is my title") .RespondWith(Response.Create().WithBody("This is my body") .WithStatusCode(HttpStatusCode.OK)); await builder.BuildAndSendAsync(); ``` Usage 2: ```c# var api = RestClient.For<IWireMockAdminApi>($"http://localhost:{WireMockPort}"); await api.MappingBuilder() .Given(request: r => r .UsingGet() .WithPath("/bla"), response: r => r .WithStatusCode(HttpStatusCode.OK) .WithBody("This is my body"), provider: p => p.WithTitle("Search for a location")) .BuildAndSendAsync(); ``` ### Final Thought: Please excuse my approach if it is a bit blue-eyed or I found a solution for a non existent issue. It really took me some time to figure how to do it. Perhaps if there is an explicit example on the Wiki how to properly handle FluentApi using the ResClient, using whatever approach, people will stop asking/looking for it. Potential time saver. Thanks for your great work! All the best.
adam added the question label 2025-12-29 15:24:54 +01:00
adam closed this issue 2025-12-29 15:24:54 +01:00
Author
Owner

@StefH commented on GitHub (Feb 16, 2023):

@R0boC0p
I understand your question.

You actually want to have a Fluent interface which mimics the same builder pattern for WireMockServer for the JSON Rest ClientModels.

This functionality is not yet present.

However, there are some auto-generated builders present in WireMock.Net.Abstractions which use https://github.com/StefH/FluentBuilder and can be used to create the models in a fluent way.


I think it should be possible to create a builder for the WireMock.Net.Abstractions project.

In basic, your interface looks ok:

public interface IAdminMappingRequestBuilder
{
    IEnumerable<MappingModel> GetMappingModels();

    IRespondWithAProvider Given(IRequestBuilder request);
    IAdminMappingRequestBuilder Given(
        Action<IRequestBuilder> request,
        Action<IResponseBuilder> response,
        Action<IRespondWithAProvider> provider = null);

    Task<StatusModel> BuildAndSendAsync();
}

However for the implementation you cannot use the "MappingBuilder" because that one is server-side only.

So if you build an extension /new project this should only reference the WireMock.Net.Abstractions project

@StefH commented on GitHub (Feb 16, 2023): @R0boC0p I understand your question. You actually want to have a Fluent interface which mimics the same builder pattern for WireMockServer for the JSON Rest ClientModels. This functionality is not yet present. However, there are some auto-generated builders present in WireMock.Net.Abstractions which use https://github.com/StefH/FluentBuilder and can be used to create the models in a fluent way. --- I think it should be possible to create a builder for the WireMock.Net.Abstractions project. In basic, your interface looks ok: ``` c# public interface IAdminMappingRequestBuilder { IEnumerable<MappingModel> GetMappingModels(); IRespondWithAProvider Given(IRequestBuilder request); IAdminMappingRequestBuilder Given( Action<IRequestBuilder> request, Action<IResponseBuilder> response, Action<IRespondWithAProvider> provider = null); Task<StatusModel> BuildAndSendAsync(); } ``` However for the implementation you cannot use the "MappingBuilder" because that one is server-side only. So if you build an extension /new project this should only reference the WireMock.Net.Abstractions project
Author
Owner

@StefH commented on GitHub (Feb 18, 2023):

@R0boC0p

I started with an implementation.
See PR https://github.com/WireMock-Net/WireMock.Net/pull/890

This can be used like:

        var api = RestClient.For<IWireMockAdminApi>("http://localhost:9091");

        var mappingBuilder = api.GetMappingBuilder();
        mappingBuilder.Given(m => m
            .WithTitle("This is my title 1")
            .WithRequest(req => req
                .UsingGet()
                .WithPath("/bla1")
            )
            .WithResponse(rsp => rsp
                .WithBody("x1")
                .WithHeaders(h => h.Add("h1", "v1"))
            )
        );

        mappingBuilder.Given(m => m
            .WithTitle("This is my title 2")
            .WithRequest(req => req
                .UsingGet()
                .WithPath("/bla2")
            )
            .WithResponse(rsp => rsp
                .WithBody("x2")
                .WithHeaders(h => h.Add("h2", "v2"))
            )
        );

        var result = await mappingBuilder.BuildAndPostAsync().ConfigureAwait(false);

Preview version (1.5.16-ci-17023) can be tested.

(https://github.com/WireMock-Net/WireMock.Net/wiki/MyGet-preview-versions)

@StefH commented on GitHub (Feb 18, 2023): @R0boC0p I started with an implementation. See PR https://github.com/WireMock-Net/WireMock.Net/pull/890 This can be used like: ``` c# var api = RestClient.For<IWireMockAdminApi>("http://localhost:9091"); var mappingBuilder = api.GetMappingBuilder(); mappingBuilder.Given(m => m .WithTitle("This is my title 1") .WithRequest(req => req .UsingGet() .WithPath("/bla1") ) .WithResponse(rsp => rsp .WithBody("x1") .WithHeaders(h => h.Add("h1", "v1")) ) ); mappingBuilder.Given(m => m .WithTitle("This is my title 2") .WithRequest(req => req .UsingGet() .WithPath("/bla2") ) .WithResponse(rsp => rsp .WithBody("x2") .WithHeaders(h => h.Add("h2", "v2")) ) ); var result = await mappingBuilder.BuildAndPostAsync().ConfigureAwait(false); ``` Preview version (`1.5.16-ci-17023`) can be tested. (https://github.com/WireMock-Net/WireMock.Net/wiki/MyGet-preview-versions)
Author
Owner

@StefH commented on GitHub (Feb 20, 2023):

@R0boC0p Did you have time to test this preview version?

@StefH commented on GitHub (Feb 20, 2023): @R0boC0p Did you have time to test this preview version?
Author
Owner

@R0boC0p commented on GitHub (Feb 23, 2023):

@StefH Hi, sorry for the late reply. Been off work for a couple of days.

However, there are some auto-generated builders present in WireMock.Net.Abstractions which use https://github.com/StefH/FluentBuilder and can be used to create the models in a fluent way.

I have seen these builders but did not use them, as there was a lack of like UsingGet/UsingPost methods, and all parameters seem to have accepted object and string only. Also the WithStatusCode was missing a type. Would have preferred some strong typing there, as it's too easy to get something wrong by accident.

So if you build an extension /new project this should only reference the WireMock.Net.Abstractions project
That's what I have thought, but like I explained failed on doing so.

I have just checked your preview version and from what I can tell it works as expected. Thank you for that. I think there is just a lack of some types like HttpStatusCode that could be easily added to the RequestModelBuilder like you did with the Usingxxx() I guess?

Btw, are the nugets of this branch to be targeted against net7.0 only? I had some troubles there, as I am still using net6.0 and found that I couldn't use them without jumping through some hoops.

@R0boC0p commented on GitHub (Feb 23, 2023): @StefH Hi, sorry for the late reply. Been off work for a couple of days. > However, there are some auto-generated builders present in WireMock.Net.Abstractions which use https://github.com/StefH/FluentBuilder and can be used to create the models in a fluent way. I have seen these builders but did not use them, as there was a lack of like `UsingGet/UsingPost` methods, and all parameters seem to have accepted `object` and `string` only. Also the `WithStatusCode` was missing a type. Would have preferred some strong typing there, as it's too easy to get something wrong by accident. > So if you build an extension /new project this should only reference the WireMock.Net.Abstractions project That's what I have thought, but like I explained failed on doing so. I have just checked your preview version and from what I can tell it works as expected. Thank you for that. I think there is just a lack of some types like `HttpStatusCode` that could be easily added to the `RequestModelBuilder` like you did with the `Usingxxx()` I guess? Btw, are the nugets of this branch to be targeted against `net7.0` only? I had some troubles there, as I am still using net6.0 and found that I couldn't use them without jumping through some hoops.
Author
Owner

@StefH commented on GitHub (Feb 23, 2023):

Preview version (1.5.16-ci-17054) can be tested which includes some more methods.
I'll merge to master and create a new NuGet release.

(You can always create a PR to add more methods.)

@StefH commented on GitHub (Feb 23, 2023): Preview version (1.5.16-ci-17054) can be tested which includes some more methods. I'll merge to master and create a new NuGet release. (You can always create a PR to add more methods.)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/WireMock.Net-wiremock#485