GRPC mappings are not created correctly when created through Admin API #663

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

Originally created by @misiek150 on GitHub (Jan 8, 2025).

Originally assigned to: @StefH on GitHub.

Describe the bug

It looks like mappings for GRPC call are not created correctly when created through __admin/mappings endpoint. It doesn't matter if we register proto at server level or pass its content to mapping response and request, directly. Created mapping miss some parts which causes requests to fail (returning 404 status code).

When proto is registered at server level following parts are not created despite the fact they are included in the JSON request for creating mappings:

  • Mapping.ProtoDefinition
  • Response.TrailingHeaders
  • Response.ProtoBufMessageType

When proto is passed as text directly (for request and response) following parts are not created despite the fact they are included in the JSON request for creating mappings:

  • Response.ProtoDefinition
  • Response.TrailingHeaders
  • Response.ProtoBufMessageType

Expected behavior:

Above parts of the mapping are created thus mapping works correctly and the same way as if they were created through code at server start.

Test to reproduce

Start server with below code, register attached proto, don't add any mappings, e.g.:

var urlGrpc = "grpc://*:9093/";
var urlGrpcSecure = "grpcs://*:9094/";
var urlHttp = "http://*:80/";
var urlHttpSecure = "https://*:443/";

        WireMockServerSettings settings = new WireMockServerSettings
        {
            UseHttp2 = true,
            Urls = [urlGrpc, urlGrpcSecure, urlHttp, urlHttpSecure],
            Logger = new WireMockConsoleLogger(),
            StartAdminInterface = true
        };

        _server = WireMockServer.Start(settings);
        
        string protosFolder = args[0];
        string[] filePaths = Directory.GetFiles(protosFolder);
        foreach (string filePath in filePaths)
        {
            _server.AddProtoDefinition(Path.GetFileNameWithoutExtension(filePath), File.ReadAllText(filePath));
        }
       
        Console.Out.WriteLine($"{DateTime.UtcNow} Press Ctrl+C to shut down");

Proto definition:

syntax = "proto3";
 
package greet;
 
// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}
 
// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}
 
// The response message containing the greetings
message HelloReply {
  string message = 1;
}

Register following mapping through __admin/mappings endpoint:

[
  {
    "Guid": "3c16e119-fe92-43cf-a006-260514569e06",
    "UpdatedAt": "2025-01-08T11:50:01.3475097Z",
    "Request": {
      "Methods": [
        "POST"
      ],
      "Body": {
        "Matcher": {
          "Name": "ProtoBufMatcher",
          "ProtoBufMessageType": "greet.HelloRequest"
        }
      }
    },
    "Response": {
      "BodyAsJson": {
        "message": "hello {{request.BodyAsJson.name}} {{request.method}}"
      },
      "UseTransformer": true,
      "TransformerType": "Handlebars",
      "TransformerReplaceNodeOptions": "EvaluateAndTryToConvert",
      "Headers": {
        "Content-Type": "application/grpc"
      },
      "TrailingHeaders": {
        "grpc-status": "0"
      },
      "ProtoBufMessageType": "greet.HelloReply"
    },
    "ProtoDefinition": "greet"
  }
]

Inspect mapping using __admin/mappings endpoint for missing parts of the mapping.

Sample code to get server working correctly (i.e. return proper response to client):

        _server
            .Given(Request.Create()
            .UsingPost()
            .WithBodyAsProtoBuf("greet.HelloRequest")
            .WithProtoDefinition("greet")
            .RespondWith(Response.Create()
            .WithHeader("Content-Type", "application/grpc")
            .WithTrailingHeader("grpc-status", "0")
            .WithBodyAsProtoBuf("greet.HelloReply", new { message = "hello {{request.BodyAsJson.name}} {{request.method}}" })
            .WithBodyAsProtoBuf(File.ReadAllText(filePaths.Where(x => Path.GetFileNameWithoutExtension(x).Equals("greet")).First()), "greet.HelloReply", new { message = "hello {{request.BodyAsJson.name}} {{request.method}}" })
             .WithTransformer());

__admin/mappings endpoint may be used to obtain JSON mappings, posted earlier in this post.

In case there is any problem with the approach I take, or maybe there is some specific convention required in terms of JSON mapping I tried I am more than happy to be corrected.

Originally created by @misiek150 on GitHub (Jan 8, 2025). Originally assigned to: @StefH on GitHub. ### Describe the bug It looks like mappings for GRPC call are not created correctly when created through __admin/mappings endpoint. It doesn't matter if we register proto at server level or pass its content to mapping response and request, directly. Created mapping miss some parts which causes requests to fail (returning 404 status code). When proto is registered at server level following parts are not created despite the fact they are included in the JSON request for creating mappings: - Mapping.ProtoDefinition - Response.TrailingHeaders - Response.ProtoBufMessageType When proto is passed as text directly (for request and response) following parts are not created despite the fact they are included in the JSON request for creating mappings: - Response.ProtoDefinition - Response.TrailingHeaders - Response.ProtoBufMessageType ### Expected behavior: Above parts of the mapping are created thus mapping works correctly and the same way as if they were created through code at server start. ### Test to reproduce Start server with below code, register attached proto, don't add any mappings, e.g.: ```csharp var urlGrpc = "grpc://*:9093/"; var urlGrpcSecure = "grpcs://*:9094/"; var urlHttp = "http://*:80/"; var urlHttpSecure = "https://*:443/"; WireMockServerSettings settings = new WireMockServerSettings { UseHttp2 = true, Urls = [urlGrpc, urlGrpcSecure, urlHttp, urlHttpSecure], Logger = new WireMockConsoleLogger(), StartAdminInterface = true }; _server = WireMockServer.Start(settings); string protosFolder = args[0]; string[] filePaths = Directory.GetFiles(protosFolder); foreach (string filePath in filePaths) { _server.AddProtoDefinition(Path.GetFileNameWithoutExtension(filePath), File.ReadAllText(filePath)); } Console.Out.WriteLine($"{DateTime.UtcNow} Press Ctrl+C to shut down"); ``` Proto definition: ```proto syntax = "proto3"; package greet; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply); } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; } ``` Register following mapping through __admin/mappings endpoint: ```json [ { "Guid": "3c16e119-fe92-43cf-a006-260514569e06", "UpdatedAt": "2025-01-08T11:50:01.3475097Z", "Request": { "Methods": [ "POST" ], "Body": { "Matcher": { "Name": "ProtoBufMatcher", "ProtoBufMessageType": "greet.HelloRequest" } } }, "Response": { "BodyAsJson": { "message": "hello {{request.BodyAsJson.name}} {{request.method}}" }, "UseTransformer": true, "TransformerType": "Handlebars", "TransformerReplaceNodeOptions": "EvaluateAndTryToConvert", "Headers": { "Content-Type": "application/grpc" }, "TrailingHeaders": { "grpc-status": "0" }, "ProtoBufMessageType": "greet.HelloReply" }, "ProtoDefinition": "greet" } ] ``` Inspect mapping using __admin/mappings endpoint for missing parts of the mapping. Sample code to get server working correctly (i.e. return proper response to client): ```csharp _server .Given(Request.Create() .UsingPost() .WithBodyAsProtoBuf("greet.HelloRequest") .WithProtoDefinition("greet") .RespondWith(Response.Create() .WithHeader("Content-Type", "application/grpc") .WithTrailingHeader("grpc-status", "0") .WithBodyAsProtoBuf("greet.HelloReply", new { message = "hello {{request.BodyAsJson.name}} {{request.method}}" }) .WithBodyAsProtoBuf(File.ReadAllText(filePaths.Where(x => Path.GetFileNameWithoutExtension(x).Equals("greet")).First()), "greet.HelloReply", new { message = "hello {{request.BodyAsJson.name}} {{request.method}}" }) .WithTransformer()); ``` __admin/mappings endpoint may be used to obtain JSON mappings, posted earlier in this post. ### Other related info In case there is any problem with the approach I take, or maybe there is some specific convention required in terms of JSON mapping I tried I am more than happy to be corrected.
adam added the bug label 2025-12-29 15:30:07 +01:00
adam closed this issue 2025-12-29 15:30:07 +01:00
Author
Owner

@StefH commented on GitHub (Jan 9, 2025):

@misiek150

Can you try preview 1.6.11-ci-19563 ?

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

@StefH commented on GitHub (Jan 9, 2025): @misiek150 Can you try preview `1.6.11-ci-19563` ? https://github.com/WireMock-Net/WireMock.Net/wiki/MyGet-preview-versions
Author
Owner

@misiek150 commented on GitHub (Jan 11, 2025):

Hmm I am not sure if there is still an issue or I am doing something wrong.

I switched to 1.6.11-ci-19563. I am using below proto:

syntax = "proto3";
 
package greet;
 
// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}
 
// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}
 
// The response message containing the greetings
message HelloReply {
  string message = 1;
}

and load it with "greet" ID like:

string protosFolder = args[0];
        string[] filePaths = Directory.GetFiles(protosFolder);
        foreach (string filePath in filePaths)
        {
            _server.AddProtoDefinition(Path.GetFileNameWithoutExtension(filePath), File.ReadAllText(filePath));
        }

Server configuration:

        _server
            .Given(Request.Create()
                .UsingPost()
                .WithBodyAsProtoBuf("greet.HelloRequest")
                )
            .WithProtoDefinition("greet")
            .RespondWith(Response.Create()
                .WithHeader("Content-Type", "application/grpc")
                .WithTrailingHeader("grpc-status", "0")
                .WithBodyAsProtoBuf("greet.HelloReply", new { message = "hello {{request.BodyAsJson.name}} {{request.method}}" })
                .WithTransformer());

I run it and I am able to get successful response from the servier using postman. Now, I am getting mapping via __admin/mappings:

[
  {
    "Guid": "e7154d4b-cd5e-4d6b-9383-c15e058c0535",
    "UpdatedAt": "2025-01-11T17:30:32.1365012Z",
    "Request": {
      "Methods": [
        "POST"
      ],
      "Body": {
        "Matcher": {
          "Name": "ProtoBufMatcher",
          "ProtoBufMessageType": "greet.HelloRequest"
        }
      }
    },
    "Response": {
      "BodyAsJson": {
        "message": "hello {{request.BodyAsJson.name}} {{request.method}}"
      },
      "UseTransformer": true,
      "TransformerType": "Handlebars",
      "TransformerReplaceNodeOptions": "EvaluateAndTryToConvert",
      "Headers": {
        "Content-Type": "application/grpc"
      },
      "TrailingHeaders": {
        "grpc-status": "0"
      },
      "ProtoBufMessageType": "greet.HelloReply"
    },
    "ProtoDefinition": "greet"
  }
]

I delete all the mappings, paste above JSON into file, then post it back to the server via __admin/mappings with curl curl -X POST --header "Content-Type: application/json" --data @C:\temp\WiremockMappings2.json http://localhost:80/__admin/mappings.

If I get mapping again using curl http://localhost:80/__admin/mappings I do see all the fields so the problem I initially described seems to be fixed. However, if I call server again using postman, I am constantly getting 404 error.

Can you try replicating above situation? Maybe I am doing some dumb mistake on my side. Hard to say as mapping itself looks fine.

@misiek150 commented on GitHub (Jan 11, 2025): Hmm I am not sure if there is still an issue or I am doing something wrong. I switched to 1.6.11-ci-19563. I am using below proto: ```proto syntax = "proto3"; package greet; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply); } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; } ``` and load it with "greet" ID like: ```csharp string protosFolder = args[0]; string[] filePaths = Directory.GetFiles(protosFolder); foreach (string filePath in filePaths) { _server.AddProtoDefinition(Path.GetFileNameWithoutExtension(filePath), File.ReadAllText(filePath)); } ``` Server configuration: ```csharp _server .Given(Request.Create() .UsingPost() .WithBodyAsProtoBuf("greet.HelloRequest") ) .WithProtoDefinition("greet") .RespondWith(Response.Create() .WithHeader("Content-Type", "application/grpc") .WithTrailingHeader("grpc-status", "0") .WithBodyAsProtoBuf("greet.HelloReply", new { message = "hello {{request.BodyAsJson.name}} {{request.method}}" }) .WithTransformer()); ``` I run it and I am able to get successful response from the servier using postman. Now, I am getting mapping via __admin/mappings: ```json [ { "Guid": "e7154d4b-cd5e-4d6b-9383-c15e058c0535", "UpdatedAt": "2025-01-11T17:30:32.1365012Z", "Request": { "Methods": [ "POST" ], "Body": { "Matcher": { "Name": "ProtoBufMatcher", "ProtoBufMessageType": "greet.HelloRequest" } } }, "Response": { "BodyAsJson": { "message": "hello {{request.BodyAsJson.name}} {{request.method}}" }, "UseTransformer": true, "TransformerType": "Handlebars", "TransformerReplaceNodeOptions": "EvaluateAndTryToConvert", "Headers": { "Content-Type": "application/grpc" }, "TrailingHeaders": { "grpc-status": "0" }, "ProtoBufMessageType": "greet.HelloReply" }, "ProtoDefinition": "greet" } ] ``` I delete all the mappings, paste above JSON into file, then post it back to the server via __admin/mappings with curl `curl -X POST --header "Content-Type: application/json" --data @C:\temp\WiremockMappings2.json http://localhost:80/__admin/mappings`. If I get mapping again using `curl http://localhost:80/__admin/mappings` I do see all the fields so the problem I initially described seems to be fixed. However, if I call server again using postman, I am constantly getting 404 error. Can you try replicating above situation? Maybe I am doing some dumb mistake on my side. Hard to say as mapping itself looks fine.
Author
Owner

@StefH commented on GitHub (Jan 13, 2025):

@misiek150
I can replicate this error and it's fixed and I've added an extra unit test.

Can you test preview version 1.6.11-ci-19569 ?

@StefH commented on GitHub (Jan 13, 2025): @misiek150 I can replicate this error and it's fixed and I've added an extra unit test. Can you test preview version `1.6.11-ci-19569` ?
Author
Owner

@StefH commented on GitHub (Jan 17, 2025):

@misiek150
Can you please try to check?

@StefH commented on GitHub (Jan 17, 2025): @misiek150 Can you please try to check?
Author
Owner

@misiek150 commented on GitHub (Jan 26, 2025):

Sorry I've been unavailable, I should be able to check next week

@misiek150 commented on GitHub (Jan 26, 2025): Sorry I've been unavailable, I should be able to check next week
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/WireMock.Net-wiremock#663