Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Best approach for supporting non-JSON serialization formats in pact #62

Open
mcon-gr opened this issue Dec 2, 2018 · 5 comments
Open

Comments

@mcon-gr
Copy link

mcon-gr commented Dec 2, 2018

The below is a Request For Comment on the idea of adding support for non-JSON serialization in pact - before I do any work on trying to add this support for pact, I'd like to get thoughts and suggestions from the community on whether such a change to pact would be likely to be accepted, and feedback on the best way to go about it.

Motivation

JSON isn't a schema based serialization format, and so having some sort of contract or integration test is essential - without it, there would be no guarantee that producers and consumers were in sync at all. To my mind, pact tests cover the following bases:

  • The (implicit) schema that both producer and consumer are consistent.
    • This covers any API versioning concerns that might exist between producer and consumer.
  • A given route that a consumer service is expecting the producer to have exists and has the expected schema.
  • Particular types of requests / responses interact with the consumer / producer in expected ways (e.g. an invalid request produces a bad HTTP status code of some kind).

All of the above points also apply to protobuf (and other non-JSON encodings): admittedly protobuf does encourage patterns which support versioning (which I won't go into here), and there is a data schema that's shared between producer / consumer, but there's nothing forcing schemas to be in sync between services or to stop developers breaking backwards compatibility.

In a world in which services are loosely coupled, producers and consumers live in separate repositories - with the data schema living in a third repository - there's ample potential for services to find themselves out of sync with each other. To ensure services stay in sync, either an integration test or a contract test is required.

Currently there exists no tooling for contract testing with HTTP + protobuf, but from what I can work out, adding support to pact is both a desirable and tractable thing to do.

Suggested approach

Given protobuf, isn't the only non-JSON encoding that users might want to contract test using pact, my proposal to implement this functionality is encoding agnostic (there are lots of other encodings out there: flatbuffers, msgpack, SBE, thrift to name a few).

Suggested flow for non-JSON pacts

When generating a consumer contract and validating consumer code, the test code POSTs to the /interactions endpoint on the pact mock_service the details of the expected response when a given request is received. I suggest that when new interactions are being configured, that two fields are added: 1) encoding type, and 2) an opaque representation containing details of how to encode/decode the given request/response. Request and response matching / requests / responses would still be sent in JSON.

For every additional encoding (in addition to JSON), a new module in the mock_service and provider_verifier would be required, which would contain encoding-specific logic that uses opaque representation. This module translates the native format to a JSON representation, which can then be fed through to the standard mock_service matching logic - thereby keeping most of the code paths the same for JSON/non-JSON.

In terms of the consumer contract, in addition to the current JSON which specifies the contract, the following would be required: 1) the expected encoding type, 2) the opaque representation as mentioned at the start of this section. Given the opaque representation would likely obfuscate the rest of the contract, this would likely be stored in a seperate file to the JSON contract and referenced with a unique identifier.

The new consumer contract could then be used by an implementation of provider_verifier which supports the additional encoding in order to validate the producer.

Protobuf specifics

In terms of protobuf, the opaque representation of the message encoding is the MessageDescriptor, which is programming language agnostic, and thus straightforward to pass between pact test clients and the Ruby-based mock server.

Proof of concept

Given I'm at the point of having an idea of how to go about adding support for protobuf to pact, it's something I'm going to have a go at over the next few weeks once I have time. The main purpose of the proof of concept would be to gain more insight on the nicest way to add protobuf support, ahead of attempting to add support in a way which would be amenable to the community.

@mefellows
Copy link
Member

but there's nothing forcing schemas to be in sync between services or to stop developers breaking backwards compatibility.

I've never used protobufs in anger, and I always expected this was the case. I'm glad to get some form of confirmation that this is was possible / is the case.

The question is how would matchers work from a consumer client code, could you put together a gist/pseudocode of how you see it looking in your head?

@bethesque
Copy link
Member

Just letting you know I've seen this, I just haven't had time to sit down and devote the attention it deserves. I will as soon as I can.

@mcon-gr
Copy link
Author

mcon-gr commented Dec 6, 2018

Thanks folks, @mefellows I'll put something together on how I vaguely expect this to work in the mock_service once I manage to carve out some time.

@mcon-gr
Copy link
Author

mcon-gr commented Dec 10, 2018

Hi @mefellows @bethesque I've just knocked together a quick gist that illustrates a rough outline how I see this working. Based on the outline in the gist I've got a very bare-bones implementation working locally - please let me know what you think. I'm happy to add more detail, or code up a firmer implementation as you prefer.

https://gist.github.com/mcon-gr/348232a3d2e64df544858b5491bb9d30

@mefellows
Copy link
Member

Minor update note - progress on this issue has started, thanks Matt!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants