2. Make sure you have these installed (or similar):
https://www.jetbrains.com/idea/download/
https://www.postman.com/downloads/
https://github.com/PierreVincent/pact-workshop/
Clone the workshop repository:
https://pactflow.io/
Sign-up for free Pactflow account:
4. Agenda for the day
Contract testing fundamentals
Implementing contract tests with Pact
Scaling contract tests with Pactflow
Designing APIs with contracts
Q&A / Open discussions
Contracts in your architecture
Breaks
Morning
10:30 - 11:00
Lunch
12:30 - 13:30
Afternoon
15:00 - 15:30
12. What’s in a contract?
Request Headers
HTTP MethodAPI Endpoint
Query Parameters Request Body
Response HeadersStatus Code Response Body
e.g. /api/users e.g. POST
e.g. ?fields=name e.g. Authorization
e.g. Content-Typee.g. 200
15. Consumer
Provider
Provider State
Request
Expected
Response
Login Service
User Service
Given that user 'pierre' exists
Method GET
Path /users/pierre
Headers
Accept: application/json
Status 200
Headers
Content-Type: application/json
Body
{
"user": "pierre",
"name": "Pierre Vincent",
"role": "publisher"
}
Interaction
16. User
Service
A
P
I
1. Set Provider State
2. Send Request
3. Verify Response
Interaction Verification Test
INSERT INTO users [...]
GET /users/pierre
Accept: application/json
{
"user": "pierre",
...
}
{
"user": "pierre",
...
}
?
20. Provider pipeline
Implement changes Get Pacts from Broker
Replay & Verify
Interactions
Deploy Service
Build
Deploy to EU
PROD-EU
Get Pacts from Broker
Replay & Verify
Interactions
Stop deployment of
incompatible Provider
Stop introduction of
breaking change
PROD-US
PROD-EU
23. Our running example for the workshop
Game
Service
Leaderboard
Service
APIAPI
Play a game
Return result &
current win-rate
Record game result
Return updated
win-rate
Contract
24. POST /play
{
"username": "pierre",
"game": "headsOrTails",
"choice": "heads"
}
Game
Service
API
200 OK
Content-Type: application/json; charset=UTF-8
{
"won": true,
"message": "You won!",
"totalPlays": 120,
"totalWins": 71,
"winRate": 59
}
26. Game
Service
Leaderboard
Service
API
Record game result:
Game played, User
playing, Won/Lost
Return win-rate:
Games played,
Games won,
Win-Loss Ratio
“Consumer” Teams
- Document what API you need to send
game results
“Provider” Teams
- Document what API you will
implement to receive game results
27. Game
Service
Leaderboard
Service
API
Record game result:
Game played, User
playing, Won/Lost
Return win-rate:
Games played,
Games won,
Win-Loss Ratio
“Consumer” & “Provider” Teams
- Meet to compare your API designs
- Discuss differences and come to agreement on the API interaction
- Have you thought of “unhappy” paths? (API errors)
29. RecordScore API (or write your own)
Game
Service
Leaderboard
Service
POST /recordScore
{
“username”: “anna”,
“game”: “headOrTails”,
“won”: true
}
{
“gamesPlayed”: 123,
“gamesWon”: 55
}
Request
Response
30. API
Implement API client in Consumer
- In LeaderboardClient.java:
- API endpoint (recordScoreUrl)
- Request Body (RecordScoreRequestBody)
- Response Body (RecordScoreResponseBody)
- In LeaderBoardClientTest.java:
- Implement MockServer unit test
./gradlew test
Run the service unit tests (in game-service dir)
curl -X POST -H "Content-Type: application/json" --data '{"username":
"pierre", "game":"headsortails", "choice": "tails"}'
http://localhost:8080/play
Try your API (curl or Postman)
Game
Service
Why doesn’t this work?
31. API
Creating the Pact
- In LeaderboardClientPactTest.java:
- Complete the PACT definition (RequestResponsePact)
- Update expected response (expectedResponse)
- Update expected request (client.recordScore)
./gradlew test
Run the pact test (in game-service dir)
cat build/pacts/game-service-leaderboard-service.json
Find the generated PACT
Contract
Does the contract match
what you defined?
32. Leaderboard
Service
API
Implement the Provider API
- In ScoreController.java:
- API endpoint (@PostMapping)
- Request Body (RecordScoreRequestBody)
- Response Body (RecordScoreResponseBody)
./gradlew run
Run the service (in leaderboard-service dir)
curl -X POST -H "Content-Type: application/json" --data
'YOUR_JSON_PAYLOAD' http://localhost:8081/your/api/endpoint
Try your API (curl of Postman)
33. Verifying the pact
- Copy the generated PACT file (game-service/build/pacts/*.json)
to the Provider test resources (leaderboard-service/pacts)
./gradlew pactVerify
Run the verification test (in leaderboard-service dir)
Contract
✓