Stick to the rules!
Consumer Driven Contracts
04.07.2015 - Confitura PL
Marcin Grzejszczak @mgrzejszczak
@confiturapl @mgrzejszczak / @4financeit
Swim for a dream
http://swimforadream.com/
Adam will swim 18.5 km from Hel to Gdynia
Money for 3 charity organizations
@confiturapl @mgrzejszczak / @4financeit
Marcin Grzejszczak
● Software Architect at 4financeIT
● Author of "Mockito Instant", "Mockito Cookbook"
● Co-author of "micro-infra-spring",
“spring-cloud-zookeeper”, “spring-cloud-sleuth”
Twitter: @MGrzejszczak
Blog: http://toomuchcoding.blogspot.com
Homepage: http://marcin.grzejszczak.pl
@confiturapl @mgrzejszczak / @4financeit
Agenda
● Short introduction
● Real life scenario with a hilarious joke
● How does it work?
● Live (hopefully) coding
● Summary
@confiturapl @mgrzejszczak / @4financeit
Consumer Driven Contracts
● TDD on architectural level
○ mistakes occur both in implementation and design
● Try to use API before implementing it
@confiturapl @mgrzejszczak / @4financeit
Real life scenario...
@confiturapl @mgrzejszczak / @4financeit
Real life scenario...
Hi! I’m team
X and we
have spent
weeks to
tweak our
code to use
your API!
@confiturapl @mgrzejszczak / @4financeit
Real life scenario...
That’s so
sweet… But
we’ve just
changed our
API because
well, it’s ours.
@confiturapl @mgrzejszczak / @4financeit
Real life scenario...
You’ve got to
be shitting
me! (however
it sounds)
@confiturapl @mgrzejszczak / @4financeit
Real life scenario...
@confiturapl @mgrzejszczak / @4financeit
CDC building blocks
● Server
● Consumer
● Contract
@confiturapl @mgrzejszczak / @4financeit
CDC building blocks
@confiturapl @mgrzejszczak / @4financeit
How to make life easier?
Use common contract
@confiturapl @mgrzejszczak / @4financeit
Contract definition
@confiturapl @mgrzejszczak / @4financeit
What is a contract?
io.codearte.accurest.dsl.GroovyDsl.make {
request {
method "PUT"
url "/fraudcheck"
body(''' { “clientPesel":"12345678901", "loanAmount":123.123 } ''' )
headers { header("Content-Type", "application/fraud+json") }
}
response {
status 200
body( """{ "fraudCheckStatus": "OK"}""")
headers { header('Content-Type': 'application/fraud+json') }
}
}
@confiturapl @mgrzejszczak / @4financeit
What is a contract?
io.codearte.accurest.dsl.GroovyDsl.make {
request {
method "PUT"
url "/fraudcheck"
body(''' { “clientPesel":"12345678901", "loanAmount":123.123 } ''' )
headers { header("Content-Type", "application/fraud+json") }
}
response {
status 200
body( """{ "fraudCheckStatus": "OK"}""")
headers { header('Content-Type': 'application/fraud+json') }
}
}
Groovy DSL
@confiturapl @mgrzejszczak / @4financeit
What is a contract?
io.codearte.accurest.dsl.GroovyDsl.make {
request {
method "PUT"
url "/fraudcheck"
body(''' { “clientPesel":"12345678901", "loanAmount":123.123 } ''' )
headers { header("Content-Type", "application/fraud+json") }
}
response {
status 200
body( """{ "fraudCheckStatus": "OK"}""")
headers { header('Content-Type': 'application/fraud+json') }
}
}
FOR A GIVEN
REQUEST
@confiturapl @mgrzejszczak / @4financeit
What is a contract?
io.codearte.accurest.dsl.GroovyDsl.make {
request {
method "PUT"
url "/fraudcheck"
body(''' { “clientPesel":"12345678901", "loanAmount":123.123 } ''' )
headers { header("Content-Type", "application/fraud+json") }
}
response {
status 200
body( """{ "fraudCheckStatus": "OK"}""")
headers { header('Content-Type': 'application/fraud+json') }
}
}
WE’LL HAVE SUCH A
RESPONSE
@confiturapl @mgrzejszczak / @4financeit
So how am I supposed to work?
@confiturapl @mgrzejszczak / @4financeit
Workflow - Consumer side
CLONE SERVER REPO
AND WORK OFFLINE
@confiturapl @mgrzejszczak / @4financeit
Workflow - Consumer side
1) ALTER THE CONTRACT LOCALLY
2) GENERATE AND COPY STUBS
3) USE STUBS IN CONSUMER TESTS
@confiturapl @mgrzejszczak / @4financeit
What is a stub?
● JSON representation of a Groovy DSL contract
● Understood by Wiremock Http Server Stub
@confiturapl @mgrzejszczak / @4financeit
Workflow - Consumer side
FILE A PULL REQUEST WITH
THE PROPOSED CONTRACT
@confiturapl @mgrzejszczak / @4financeit
Server tests - what happens there?
● server has DSLs with contracts
● tests are generated from the contracts
● stubs that consumers can use are
generated from the contracts
@confiturapl @mgrzejszczak / @4financeit
Workflow - Server side
● oh, I have a PR with the proposed contract
● I don’t have the implementation ready so
my generated tests are failing
● I’ll add the implementation, fix the tests
and merge the PR!
@confiturapl @mgrzejszczak / @4financeit
Workflow - Server side
IMPLEMENTATION IS READY
I’LL PUBLISH MY STUB!
@confiturapl @mgrzejszczak / @4financeit
Consumer Technology
Wiremock
http://wiremock.org
testCompile 'com.github.tomakehurst:wiremock:1.56'
{
"request": {
"method": "GET",
"url": "/hello"
},
"response": {
"status": 200,
"body": "Hello world!",
"headers": { "Content-Type": "text/plain" }
}
}
Configuration
Sample definition
@confiturapl @mgrzejszczak / @4financeit
Server Technology
Accurate REST
https://github.com/Codearte/accurest
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'io.codearte.accurest:accurest-gradle-plugin:0.7.0'
}
}
apply plugin: 'accurest'
@confiturapl @mgrzejszczak / @4financeit
Example
@confiturapl @mgrzejszczak / @4financeit
New feature
@confiturapl @mgrzejszczak / @4financeit
Let consumer drive the contract!
@confiturapl @mgrzejszczak / @4financeit
Live coding - consumer side
@confiturapl @mgrzejszczak / @4financeit
Consumer prepared the contract
io.codearte.accurest.dsl.GroovyDsl.make {
request {
method "PUT"
url "/fraudcheck"
body(''' { “clientPesel":"1234567890", "loanAmount":99999 } ''' )
headers { header("Content-Type", "application/vnd.fraud.v1+json") }
}
response {
status 200
body( """{ "fraudCheckStatus": "REJECTED", "rejectionReason": "Amount too high" }""")
headers { header('Content-Type': 'application/vnd.fraud.v1+json') }
}
}
@confiturapl @mgrzejszczak / @4financeit
Time for server side implementation!
@confiturapl @mgrzejszczak / @4financeit
Live coding - server side
@confiturapl @mgrzejszczak / @4financeit
CDC benefits
@confiturapl @mgrzejszczak / @4financeit
CDC benefits
● Rapid API prototyping
● Non-blocking development
● Behaviour Driven Development
@confiturapl @mgrzejszczak / @4financeit
CDC benefits
● Client tells what he needs
● Quality - continuously checking if contract
is valid
@confiturapl @mgrzejszczak / @4financeit
CDC benefits
● if server breaks API compatibility
consumer tests fail
● if server adds new API I can reuse it
immediately in my tests
@confiturapl @mgrzejszczak / @4financeit
CDC benefits
● The server tests are generated for you
● Any typos / misunderstandings will be found
out immediately
@confiturapl @mgrzejszczak / @4financeit
Not so fast...
● Maintaining datasets
● What exactly to verify for server side?
● Breaking changes
● Accurest under development
○ I also have to sleep sometimes
@confiturapl @mgrzejszczak / @4financeit
Q&A
https://github.com/marcingrzejszczak/2015_confitura_cdc
Accurest: https://github.com/Codearte/accurest
Micro-Infra-Spring: https://github.com/4finance/micro-infra-spring
CDC: http://martinfowler.com/articles/consumerDrivenContracts.html

Stick to the rules - Consumer Driven Contracts. 2015.07 Confitura

  • 1.
    Stick to therules! Consumer Driven Contracts 04.07.2015 - Confitura PL Marcin Grzejszczak @mgrzejszczak
  • 2.
    @confiturapl @mgrzejszczak /@4financeit Swim for a dream http://swimforadream.com/ Adam will swim 18.5 km from Hel to Gdynia Money for 3 charity organizations
  • 3.
    @confiturapl @mgrzejszczak /@4financeit Marcin Grzejszczak ● Software Architect at 4financeIT ● Author of "Mockito Instant", "Mockito Cookbook" ● Co-author of "micro-infra-spring", “spring-cloud-zookeeper”, “spring-cloud-sleuth” Twitter: @MGrzejszczak Blog: http://toomuchcoding.blogspot.com Homepage: http://marcin.grzejszczak.pl
  • 4.
    @confiturapl @mgrzejszczak /@4financeit Agenda ● Short introduction ● Real life scenario with a hilarious joke ● How does it work? ● Live (hopefully) coding ● Summary
  • 5.
    @confiturapl @mgrzejszczak /@4financeit Consumer Driven Contracts ● TDD on architectural level ○ mistakes occur both in implementation and design ● Try to use API before implementing it
  • 6.
    @confiturapl @mgrzejszczak /@4financeit Real life scenario...
  • 7.
    @confiturapl @mgrzejszczak /@4financeit Real life scenario... Hi! I’m team X and we have spent weeks to tweak our code to use your API!
  • 8.
    @confiturapl @mgrzejszczak /@4financeit Real life scenario... That’s so sweet… But we’ve just changed our API because well, it’s ours.
  • 9.
    @confiturapl @mgrzejszczak /@4financeit Real life scenario... You’ve got to be shitting me! (however it sounds)
  • 10.
    @confiturapl @mgrzejszczak /@4financeit Real life scenario...
  • 11.
    @confiturapl @mgrzejszczak /@4financeit CDC building blocks ● Server ● Consumer ● Contract
  • 12.
    @confiturapl @mgrzejszczak /@4financeit CDC building blocks
  • 13.
    @confiturapl @mgrzejszczak /@4financeit How to make life easier? Use common contract
  • 14.
    @confiturapl @mgrzejszczak /@4financeit Contract definition
  • 15.
    @confiturapl @mgrzejszczak /@4financeit What is a contract? io.codearte.accurest.dsl.GroovyDsl.make { request { method "PUT" url "/fraudcheck" body(''' { “clientPesel":"12345678901", "loanAmount":123.123 } ''' ) headers { header("Content-Type", "application/fraud+json") } } response { status 200 body( """{ "fraudCheckStatus": "OK"}""") headers { header('Content-Type': 'application/fraud+json') } } }
  • 16.
    @confiturapl @mgrzejszczak /@4financeit What is a contract? io.codearte.accurest.dsl.GroovyDsl.make { request { method "PUT" url "/fraudcheck" body(''' { “clientPesel":"12345678901", "loanAmount":123.123 } ''' ) headers { header("Content-Type", "application/fraud+json") } } response { status 200 body( """{ "fraudCheckStatus": "OK"}""") headers { header('Content-Type': 'application/fraud+json') } } } Groovy DSL
  • 17.
    @confiturapl @mgrzejszczak /@4financeit What is a contract? io.codearte.accurest.dsl.GroovyDsl.make { request { method "PUT" url "/fraudcheck" body(''' { “clientPesel":"12345678901", "loanAmount":123.123 } ''' ) headers { header("Content-Type", "application/fraud+json") } } response { status 200 body( """{ "fraudCheckStatus": "OK"}""") headers { header('Content-Type': 'application/fraud+json') } } } FOR A GIVEN REQUEST
  • 18.
    @confiturapl @mgrzejszczak /@4financeit What is a contract? io.codearte.accurest.dsl.GroovyDsl.make { request { method "PUT" url "/fraudcheck" body(''' { “clientPesel":"12345678901", "loanAmount":123.123 } ''' ) headers { header("Content-Type", "application/fraud+json") } } response { status 200 body( """{ "fraudCheckStatus": "OK"}""") headers { header('Content-Type': 'application/fraud+json') } } } WE’LL HAVE SUCH A RESPONSE
  • 19.
    @confiturapl @mgrzejszczak /@4financeit So how am I supposed to work?
  • 20.
    @confiturapl @mgrzejszczak /@4financeit Workflow - Consumer side CLONE SERVER REPO AND WORK OFFLINE
  • 21.
    @confiturapl @mgrzejszczak /@4financeit Workflow - Consumer side 1) ALTER THE CONTRACT LOCALLY 2) GENERATE AND COPY STUBS 3) USE STUBS IN CONSUMER TESTS
  • 22.
    @confiturapl @mgrzejszczak /@4financeit What is a stub? ● JSON representation of a Groovy DSL contract ● Understood by Wiremock Http Server Stub
  • 23.
    @confiturapl @mgrzejszczak /@4financeit Workflow - Consumer side FILE A PULL REQUEST WITH THE PROPOSED CONTRACT
  • 24.
    @confiturapl @mgrzejszczak /@4financeit Server tests - what happens there? ● server has DSLs with contracts ● tests are generated from the contracts ● stubs that consumers can use are generated from the contracts
  • 25.
    @confiturapl @mgrzejszczak /@4financeit Workflow - Server side ● oh, I have a PR with the proposed contract ● I don’t have the implementation ready so my generated tests are failing ● I’ll add the implementation, fix the tests and merge the PR!
  • 26.
    @confiturapl @mgrzejszczak /@4financeit Workflow - Server side IMPLEMENTATION IS READY I’LL PUBLISH MY STUB!
  • 27.
    @confiturapl @mgrzejszczak /@4financeit Consumer Technology Wiremock http://wiremock.org testCompile 'com.github.tomakehurst:wiremock:1.56' { "request": { "method": "GET", "url": "/hello" }, "response": { "status": 200, "body": "Hello world!", "headers": { "Content-Type": "text/plain" } } } Configuration Sample definition
  • 28.
    @confiturapl @mgrzejszczak /@4financeit Server Technology Accurate REST https://github.com/Codearte/accurest buildscript { repositories { mavenCentral() } dependencies { classpath 'io.codearte.accurest:accurest-gradle-plugin:0.7.0' } } apply plugin: 'accurest'
  • 29.
    @confiturapl @mgrzejszczak /@4financeit Example
  • 30.
    @confiturapl @mgrzejszczak /@4financeit New feature
  • 31.
    @confiturapl @mgrzejszczak /@4financeit Let consumer drive the contract!
  • 32.
    @confiturapl @mgrzejszczak /@4financeit Live coding - consumer side
  • 33.
    @confiturapl @mgrzejszczak /@4financeit Consumer prepared the contract io.codearte.accurest.dsl.GroovyDsl.make { request { method "PUT" url "/fraudcheck" body(''' { “clientPesel":"1234567890", "loanAmount":99999 } ''' ) headers { header("Content-Type", "application/vnd.fraud.v1+json") } } response { status 200 body( """{ "fraudCheckStatus": "REJECTED", "rejectionReason": "Amount too high" }""") headers { header('Content-Type': 'application/vnd.fraud.v1+json') } } }
  • 34.
    @confiturapl @mgrzejszczak /@4financeit Time for server side implementation!
  • 35.
    @confiturapl @mgrzejszczak /@4financeit Live coding - server side
  • 36.
    @confiturapl @mgrzejszczak /@4financeit CDC benefits
  • 37.
    @confiturapl @mgrzejszczak /@4financeit CDC benefits ● Rapid API prototyping ● Non-blocking development ● Behaviour Driven Development
  • 38.
    @confiturapl @mgrzejszczak /@4financeit CDC benefits ● Client tells what he needs ● Quality - continuously checking if contract is valid
  • 39.
    @confiturapl @mgrzejszczak /@4financeit CDC benefits ● if server breaks API compatibility consumer tests fail ● if server adds new API I can reuse it immediately in my tests
  • 40.
    @confiturapl @mgrzejszczak /@4financeit CDC benefits ● The server tests are generated for you ● Any typos / misunderstandings will be found out immediately
  • 41.
    @confiturapl @mgrzejszczak /@4financeit Not so fast... ● Maintaining datasets ● What exactly to verify for server side? ● Breaking changes ● Accurest under development ○ I also have to sleep sometimes
  • 42.
    @confiturapl @mgrzejszczak /@4financeit Q&A https://github.com/marcingrzejszczak/2015_confitura_cdc Accurest: https://github.com/Codearte/accurest Micro-Infra-Spring: https://github.com/4finance/micro-infra-spring CDC: http://martinfowler.com/articles/consumerDrivenContracts.html