-
Notifications
You must be signed in to change notification settings - Fork 29
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
Support external schemas such as OAS/Swagger, JSON Schema, GraphQL or .proto #76
Comments
I would like to raise the concept of signing contracts as use case 3. I'm planning to do a full writeup in the future as part of my article series on contract-based testing. I'll quickly write up the main concept for now. For contract signing, we need both consumer-driven contracts (CDC) and a provider-driven contract (PDC). We can validate one contract with the other. For example, the provider uploads a new PDC to the contract signer. The signer grabs all accompanying CDCs. It grabs all interactions from the CDCs and validates them with the PDC. The PDC is rejected if during this validation any error is thrown. If no errors are thrown the PDC is signed and stored in the central contract repository. This also works when the consumer uploads a new contract: The consumer uploads a new CDC to the contract signer. The signer grabs the accompanying PCD and all interactions from the CDC. It validated the consumer's interactions against the PDC. The CDC is rejected if during this validation any error is thrown. If no errors are thrown the CDC is signed and stored in the central contract repository. Main advantages:
Main disadvantages:
|
I think this is a great idea, however, I think it needs a workflow to allow consumers to request functionality that doesn't yet exist. That's part of the "consumer driven" nature of "consumer driven contracts". |
I agree. There also has to be a way for the provider to mark things deprecated. This is already possible in OpenAPI Schema. Such a deprecation marker should raise a warning on the consumer-side. In any case, the pattern as described above is pretty bare bones. But I think the concept is sound. I'm sure we can find solutions to the things I haven't thought about. We probably can reuse concepts that already exist in Pact. For requesting functionality, I'm specifically thinking about tagged and/or pending Pacts. I already offered to @mefellows to talk about this with you folks. You're at +8 hours from me, but I'm sure we can find a moment to get into the nitty-gritty details :) |
Something else to throw into the mix, with implications for MessagePact, is AsyncAPI and any associated alternatives. It fulfils the same role as Open API Specifications/Swagger for events in a distributed system, and so has the same "making your own homework" caveats, but also probably many of the same benefits too. Update 14 September 2020 I've also come across the Cloud Events specification which supports HTTP transports as well as AMQP and MQTT. @mefellows how would an HTTP-based message-passing spec work with Pact? E.g. Azure Event Grid. |
Good call out @alastairs. I'll update the comment above, because it's been on my (a) list for ages. |
I'm just wondering. What are the next steps for this? Should we start expanding concepts? Which approach should we focus on? Do we need to implement a proof of concept? Or am I trying to go too fast? 😄 |
We should have something for you to try out in Pactflow in a few weeks. |
@alastairs sorry I missed your update, it doesn't send notifications for them. As for cloud events, thanks for the share - I wasn't actually aware of this. In my mind, this is almost a payload specific thing. The cloud events spec is fairly broad, so trying to do too much cloudevent specific stuff in Pact is probably a bad idea (there will be better tools for testing cloudevent-cy things over time). Where we do care about stuff is in the payload itself - Pact takes a fairly similar stance with respect to being protocol agnostic (although we don't currently have the concept of an "extension" - more on this in just a moment). What's missing is the ability to differentiate between request/response, request only, and streaming variations of our (see my proposal in #71). Being able to do this, across different protocols (HTTP, message and whatever else we come up with) I think will do enough to cover this case. More broadly, our issue is that we don't have a good mechanism to mix and match a Getting there is going to be a challenge, for various reasons, but i believe it's possible. I'm going to create a separate issue that tracks this, because whilst it overlaps with this, I believe the intent is different. |
FYI pactflow/roadmap#4 is ready for developer preview. You can find a link on https://github.com/pactflow/roadmap/ to join our developer preview program to get a briefing on an early version of this feature. |
Hello! I'll just chip in a use-case that I would like regarding provider driven contracts. In my ideal world, I would like a 3rd party service API to provide a contract (json file hosted somewhere) that they have verified against their API. I would like to be able to download this contract and then verify my application against it. Pretty much the consumer-driven approach but the other way around. We are trying to verify that our applications will work correctly with 3rd party services. Creating that contract file from a swagger/openai is also a step in the right dorection! |
Whilst not a Pact specific feature, we do have a workflow similar to described in Pactflow: https://docs.pactflow.io/docs/bi-directional-contract-testing. Upload OAS as a provider contract (ideally verified to be valid, but in the case of a 3rd party you'll just have to trust they have tested their API), generate a consumer contract and Pactflow will ensure they stay compatible. |
NOTE: this is a WIP request, but wanted to get my thoughts down and give the community an opportunity to view
This question is so common, we usually retort by linking to https://docs.pact.io/faq/#can-i-generate-my-pact-file-from-something-like-swagger.
That article gets to the essence of the problem ("marking your own exam").
I've gone back and forth on this a bit, alternating between solution and problem too many times, so I'm going to first pose it here as a "how might we".
How might we make it easier to use alternative schemas in contract testing, whilst providing the same guarantees as Pact does today?
Current challenges
The main one (which may simply be a perceived one) is duplication in defining a "contract". For RESTful APIs, many prefer to define a contract with OAS/Swagger and I'm seeing JSON Schema trending (using tools like ajv to validate the requests match. Pact has a good way of serialising HTTP interactions, but is it desirable to follow a similar approach for non-HTTP systems?
Potential solutions (currently focussed on the OAS use case but also applies for the JSONSchema case, and I think also GraphQL)
Use Case 1: Simplifying authoring of consumer tests
x-amples
to OAS)In JS this might look something like this. We can omit much of the additional detail in the request and response body/headers, assuming the request is easily disambiguated.
The mock server would be responsible for serving up an API that responds as defined in the OAS definition, and merge any Pact specific properties as discussed aboe.
For a provider test, it will look much the same as it does today, except that the matching rules will use the swagger definition.
Use Case 2: Provider driven contracts
Provider: OAS is authored with annotations for the example specifications (e.g. via x-examples or whatever the new extensions format is)
Provider: Pact reads the annotated swagger file and performs the verification much as it would if it instead had a Pact file
Provider: Publishes to the broker
Consumer: Writes a test that imports this OAS document
Test only passes if all of the requests the consumer makes are compatible with the OAS document
Publish results to broker
Additional benefits:
Further reading:
GraphQL Metadata/Decorators
JSON Schema
The text was updated successfully, but these errors were encountered: