pact-foundation / pact-reference

Reference implementations for the pact specifications
https://pact.io
MIT License
91 stars 46 forks source link

Interaction response body with only a String value #193

Closed surpher closed 1 year ago

surpher commented 2 years ago

When preparing a Pact test using PactSwift (which uses pact-ffi under the hood) a test that expects only a single String value in the response body fails to prepare a valid response body.

The response expectation In a consumer test:

.willRespondWith(status: 410,
                        headers: [HttpHeaders.contentType: "application/json"],
                        body: Matcher.EqualTo("\"EXPIRED\"")

Expected response written in Pact file:

"response": {
        "body": "\"EXPIRED\"",
        "headers": {
          "Content-Type": "application/json"
        },
        "matchingRules": {
          "body": {
            "$": {
              "combine": "AND",
              "matchers": [
                {
                  "match": "equality"
                }
              ]
            }
          }
        },
        "status": 410
      }

Actual:

"response": {
        "body": "EXPIRED",
        "headers": {
          "Content-Type": "application/json"
        },
        "matchingRules": {
          "body": {
            "$": {
              "combine": "AND",
              "matchers": [
                {
                  "match": "equality"
                }
              ]
            }
          }
        },
        "status": 410
      }

Enabling PactSwift logging shows that PactSwift sends the following data to pact-ffi:

{"metadata":{"pactSpecification":{"version":"3.0.0"},"pactSwift":{"version":"0.12.0"}},
"interactions":[
  { 
    "response": {
      "status": 410,
      "body": "\"EXPIRED\""
    },
    "providerState": "elements exist",
    "request":{"path":"\/elements","method":"get"},
"description":"Request for a list"}],"provider":{"name":"unit-test-api-provider"},
"consumer":{"name":"pactswift-unit-tests"}}

Initially raised at https://github.com/surpher/PactSwift/issues/89#issue-1230776527

rholshausen commented 1 year ago

What is happening here, because the Pact file is JSON and the content is JSON, it renders the body as a string value. When the Pact file is used, it knows the content type is JSON, so it creates a JSON String body (i.e. adds the quotes back). It will do the same thing with an empty object {}. It will write the JSON as "body": {} and not "body": "{}".

Is there a reason that the body has to have the quotes in the Pact file? This behavior goes all the way back to the original Pact implementation.

surpher commented 1 year ago

This was reported a while back here -> https://github.com/surpher/PactSwift/issues/89#issue-1230776527

If I understand this correctly, the issue here was that the body's content is not JSON, but a single String value in " which the reporter's provider was providing. libpact is removing redundant "?

imo a bit of an edge case.

rholshausen commented 1 year ago

But the content type is being set, so it is JSON

surpher commented 1 year ago

Will file it under "misusing".