Greg Tyler

Weeknotes: 24th February 2020

Published on 1st March 2020

(Last week I created a Pact file, but missed weeknotes).

This week I started moving some big changes forwad.

In Complete the deputy report, we have a few big changes in the pipeline. I’ve discussed before that having multiple significant strands at once isn’t my preferred approach, but here we are in the real world where things can’t move at the pace I’d like.

This week I’ve worked on a range of stories that set the groundwork for these big changes: moving more emails to GOV.UK Notify, creating a new permissions structure for administrators, rewriting tests in a standalone format, and making changes to database tables which will be necessary for our upcoming integrations.

That means the next few weeks will be chasing down the middle or tail ends of these projects: deprecating our old email service, redesigning the admin portal, rewriting more tests, and building an integration. Hopefully not too simultaneously.

Making a Pact

The update that I would have written last week.

I spent a lot of the week working with Pact and planning how we might integrate it into our projects and workflows. Pact is a kind of all-in-one contract testing tool, which provides mocking for contracted services and keeps track of tests to ensure their contract (or “pact”) is being met.

From a consumer (consumer = app using API) perspective you write out some expectations of how API requests should go (pseudocode follows):

pact
  .onRequest('GET', '/users')
  .willReturn(arrayOf(objectWith(
    id: /[0-9]+/,
    username: /[a-z0-9-_]{8,16}
  ))
  .suchAs([
    { id: 4, username: 'toddsmith' },
    { id: 353953, username: 'lithiumrogue' },
  ]);

Pact then runs a mock server with these responses baked in, and you can run unit tests against code which calls it:

const users = api.getUsers();

expect(users).toHaveLength(2);
expect(users[0].id).toBe(4);

pact.verify();

This way you ensure that you’re code is making API requests as anticipated, and handling the response correctly, alongside your existing unit tests.

At the end of the tests, Pact generates a JSON file containing all of your expectations (so a more formal and language-independent version of my pseudocode above) to provide a concrete document of how the consumer expects the API to behave.

Finally, there’s a tool call Pact Broker which collates these JSON files and tests them against the API (in a test environment). This completes the validation of the end-to-end service, with each end being tested independently and without developers needing to both services.

This may seem like a lot of effort for minimal gain (I suggest, as someone who’s spent a week grappling with this), but it should shine when we have multiple APIs, consumers and endpoints. We could have a large number of consumer apps, all using different parts of the API and producing Pact JSON files for the bits they need. Then the Broker checks all of these automatically and provides realtime feedback about the overall health of our (and our associates’) services.

I’m sure this is just the start of our Pact journey, particularly because our scale is currently miniscule (one API, one consumer, two endpoints). Hopefully I’ll post an update in a few months to see how it’s going.

Summary