pact-net
pact-net copied to clipboard
Provider state parameters are serialised as numbers, causes errors in provider state middleware when using System.Text.Json
If the value of a provider state parameter is a number string, it is serialised in the pact file as a number. This is an issue if the provider state middleware in the provider tests uses System.Text.Json to deserialise a ProviderState value as System.Text.Json does not deserialise non-string values into string properties. https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft?pivots=dotnet-6-0#non-string-values-for-string-properties.
For example:
using System.Net;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using PactNet;
var config = new PactConfig
{
PactDir = Path.Join("..", "..", "..", "pacts"),
DefaultJsonSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
}
};
var pact = Pact.V3("consumer", "provider", config).WithHttpInteractions();
pact.UponReceiving("A valid request")
.Given("state with parameter", new Dictionary<string, string>() {["id"] = "10", ["name"] = "Fred"})
.WithRequest(HttpMethod.Get, "/api/endpoint")
.WillRespond()
.WithStatus(HttpStatusCode.OK);
await pact.VerifyAsync(async ctx =>
{
using var apiClient = new ApiClient(ctx.MockServerUri);
await apiClient.TestRequestAsync();
});
public class ApiClient: IDisposable
{
private readonly HttpClient _httpClient;
public ApiClient(Uri baseUri)
{
_httpClient = new HttpClient { BaseAddress = baseUri };
}
public async Task TestRequestAsync()
{
await _httpClient.GetAsync("api/endpoint");
}
public void Dispose()
{
_httpClient.Dispose();
}
}
generates this pact. Note that parameter "id" is serialised as 10 not "10".
{
"consumer": {
"name": "consumer"
},
"interactions": [
{
"description": "A valid request",
"providerStates": [
{
"name": "state with parameter",
"params": {
"id": 10,
"name": "Fred"
}
}
],
"request": {
"method": "GET",
"path": "/api/endpoint"
},
"response": {
"status": 200
}
}
],
"metadata": {
"pactRust": {
"ffi": "0.4.0",
"models": "1.0.4"
},
"pactSpecification": {
"version": "3.0.0"
}
},
"provider": {
"name": "provider"
}
}
Thanks for the report 👍 I'll check out whether the problem is happening in PactNet itself or whether it's after we've passed to the FFI library.
If it's the latter, and gut feel is that it is, then I'll raise an issue on the other repo and link here.
I've added a test which reproduces the issue, and confirms that this is an issue in pact-reference, not pact-net. We're passing a string value but a numeric value ends up getting written to the pact file.
I'll raise an upstream issue and link here.
Unfortunately the upstream maintainers closed the linked issue I created to change this as they believe it's working as expected, and so there's nothing I can do to change this issue.
I've added a comment saying I don't agree that's working as expected, but that's where we are unfortunately.
Added a comment here about a resolution from reading the linked issue, which appears to resolve the issue reproduction. (great things to have to hand!)
https://github.com/pact-foundation/pact-reference/issues/263#issuecomment-2134110690
question - how would you expect someone to pass in an integer value here if the signatures are strings for end users?
Unfortunately the upstream maintainers closed the linked issue I created to change this as they believe it's working as expected, and so there's nothing I can do to change this issue.
I've been reflecting on this overnight and I'm sorry you feel that there is nothing you can do to change this issue. I actually thought that when I read that comment that it was going to be something outside the Pact ecosystem, rather than from inside.
We definitely want to find the right, or most pragmatic solution, that works well for as many users, in as many consuming languages as possible!
Maybe the current direction isn't correct, but we are always happy to deliberate, and deliberate some more until we can get to a democratised solution :)
We are all part of one big (hopefully happy) family!