eugenk
eugenk

Reputation: 472

pact.io: Select specific endpoints for provider test

We are running a microservice architecture and want to set up contract testing in our project. Our consumers do not know which request is handled by which microservice. We want our microservices to select the interactions from the pacts that they should participate in.

Example:

We want to put provider tests next to the Microservices. Each microservice should only test the endpoints that it is capable of handling. In this scenario, Microservice A would test all of the POST /users contracts. Microservice B would select the GET /users/$userId contracts and so on.

Is there a way to do so with pactflow.io and nodejs bindings for pact?

Edit: Added the architecture diagram: Architecture Diagram

Upvotes: 0

Views: 348

Answers (2)

eugenk
eugenk

Reputation: 472

We have found a solution to our particular problem:

  • The consumer does not know which service acts as a provider, but it knows the (HTTP method, URL) tuple that it calls.
  • The microservice knows every (HTTP method, URL) that it is responsible for.

We define a provider as the tuple (HTTP method, URL). As a result, a consumer contains many tests for many providers and a microservice also contains many tests for many providers.

Something like this in node.js for the consumer:

const consumer = "MyConsumer";

const providerGetArticles = new Pact({ consumer, provider: 'GET-articles', ...  });

const providerGetArticlesArticleId = new Pact({ consumer, provider: 'GET-articles-:articleId', ...  });

const providerPostUsers = new Pact({ consumer, provider: 'POST-users', ...  });

const providerGetUsers = new Pact({ consumer, provider: 'GET-users', ...  });

const providerGetUsersUserId = new Pact({ consumer, provider: 'GET-users-:userId', ...  });

providerGetArticles.setup().then(() => {
  providerGetArticles.addInteraction(
    {
      withRequest: { method: 'GET', path: '/articles' },
      ...


providerGetArticlesArticleId.setup().then(() => {
  providerGetArticlesArticleId.addInteraction(
    {
      withRequest: { method: 'GET', path: '/articles/12345' },
      ...

providerPostUsers.setup().then(() => {
  providerPostUsers.addInteraction(
    {
      withRequest: { method: 'POST', path: '/users' },
      ...

And like this for a microservice that handles GET /articles and GET /articles/:articleId

new Verifier({ provider: 'GET-articles', ... }).verifyProvider()...

new Verifier({ provider: 'GET-articles-:articleId', ... }).verifyProvider()...

We can now start the single microservice in isolation and run the provider tests.

Upvotes: 0

Matthew Fellows
Matthew Fellows

Reputation: 4065

No, there is no such in-built feature in Pact that supports that use case.

We've discussed the possibility of publishing expectations for messages this way, but not HTTP (because this is a bit more unusual, unlike message queues like Kafka where there is usually more indirection).

Are you using some form of dynamic API gateway or something?

One challenge you'll face is reverse engineering out the requests themselves in a reliable manner.

Ideas

The only suggestion I have would be to have a proxy on the provider side test that was aware of the different endpoints, and would redirect the requests to the correct provider. But then state handling gets difficult.

You can of course also manually fetch the pacts, and split them, but you'll lose a lot of value that pact has.

I'm not sure if the consumers not knowing about the providers is more of a philosophical thing, a practical thing or otherwise, but obviously the simplest solution is probably making the consumers aware of their providers.

Raise a Feature Request

Perhaps stating your use case more clearly and requesting a feature at https://pact.canny.io/ might be worthwhile, to see how relevant your use case is to the broader community and if it would be worth implementing.

Upvotes: 1

Related Questions