Coherent REST API design
-
Upload
frederik-mogensen -
Category
Technology
-
view
408 -
download
1
Transcript of Coherent REST API design
- documentation and testing using Swagger and Pact
Coherent REST API design
2.
Contact Information
Frederik Mogensen
Software Developer, Cloud Team
Stibo Systems
L: linkedin.com/in/fmogensen
3.
Agenda
Contract driven API design Provider contracts - with Swagger Consumer Driven contracts - with Pact
1
Contract driven API design
5.
APIs in a Microservice architecture Unstable / changing APIs No type safety between services No developer confidence
2
Provider contracts- with Swagger
“ A Provider Contract is a
description of a service offered by a
provider” - Steven Smith https://dzone.com/articles/application-pattern-consumer
7.
Swagger Example The Petstore
paths: '/pet/’: post: tags: - pet description : Add a new pet to the store consumes: - application/json produces: - application/json parameters: - in: body name: body description: Pet object that needs to be added to the store required: true schema: $ref: '#/definitions/Pet‘ responses: '405': description: Invalid input '200': description: successful operation
'/pet/{petId}': get: tags: - pet summary: Find pet by ID produces: - application/json parameters: - name: petId in: path description: ID of pet to return required: true type: integer responses: '200': description: successful operation schema: $ref: '#/definitions/Pet' '404': description: Pet not found security: - api_key: []
8.
Why define service endpoints?
API that are JSON first Documentation and clarity Server / Client code generation
9.
Iterative API first development
Update Swagger Definition
Generate Endpoints
Implement functionality
Test and validate API
New demands for API
10.
Demo using Swagger and Postman
3
Consumer-Driven contracts- with Pact
“ A Consumer Driven Contract is a
description of how a provider satisfies an
aggregate of Consumer Contracts ” - Steven Smith https://dzone.com/articles/application-pattern-consumer
12.
Integration test in a Microservice architecture
Characteristic Slow
Easy to break
Hard to fix
Scales BADLY
Lots of infrastructure
Lots of set up
False negatives
Infrastructure Startup all services
Populate Databases
Mock away external
services
http://www.slideshare.net/bethesque/pact-44565612
13.
Pact tests
Characteristic Fast
Stable
Easy to debug
Reliable
No extra infrastructure
Low setup
Scales linearly
Contracts for only the needed stuffConsumer-driven contracts describes the complete set of functionality demanded by the current set of consumers.
http://www.slideshare.net/bethesque/pact-44565612
14.
Pacts – The basics
Consumer ProviderRequest
Response
http://www.slideshare.net/bethesque/pact-44565612
15.
Pacts – The basics
Consumer ProviderRequest
Response
Request
Response
PactConsumerProvider
http://www.slideshare.net/bethesque/pact-44565612
16.
Pact Example
Frontend
Mapping
Product
Datastandard
Login
User
iPhone
Pact BrokerMapping
PactFrontendMapping
ProductPactMappingProduct
LoginPactFrontend
Login
Datastandard Pact
MappingDatastandard
UserPactLoginUser
PactiPhone
Login
17.
Pact BrokerMapping
PactFrontendMapping
ProductPactMappingProduct
LoginPactFrontend
Login
Datastandard Pact
MappingDatastandard
UserPactLoginUser
PactiPhone
Login
Pact Example
Frontend
Login
Consumer publishes pact on
build
Provider gets all pacts from broker -
on test
18.
Defining a Pact
@Pact(provider = "Datastandard", consumer = "Mapping")public PactFragment createFragment(PactDslWithProvider builder) {
return builder .given("datastandard-default") .uponReceiving("A request for category with id=1 in specific datastandard") .path("/dataStandards/dataId/categories/1") .method("GET") .willRespondWith() .status(200) .body( "{" + "\"id\": \"1\"," + "\"name\": \"Toys\"" + "}" ) .toFragment();}
PactConsumerProvider
http://www.slideshare.net/bethesque/pact-44565612
19.
Pact example{ "consumer": { "name": "Mapping" }, "provider": { "name": "Datastandard" }, "interactions": [ { "producer_state": "datastandard-default", "description": "A request for category with id=1 in specific datastandard", "request": { "method": "get", "path": "/dataStandards/dataId/categories/1" }, "response": { "status": 200, "headers": { "Content-Type": "application/json" }, "body": { "id": "1", "name": "Toys" } } } ], "metadata": { "pactSpecificationVersion": "1.0.0" }}
PactConsumerProvider
20.
Validating Pact on Consumer side
@Rulepublic PactProviderRule rule = new PactProviderRule("Datastandard","localhost",“1234",this);
@Test@PactVerification("Datastandard")public void runTest() { // Path variables String datastandardId = "dataId"; String categoryId = "1";
DatastandardService datastandardService = new DatastandardService("http://localhost:1234");
Category category = datastandardService.getCategory(datastandardId, categoryId); Category expectedCategory = new Category().withId("1").withName("Toys");
Assert.assertEquals(expectedCategory, category);}
ConsumerRequest
Response
PactConsumerProvider
http://www.slideshare.net/bethesque/pact-44565612
21.
Validating Pact on Provider side@RunWith(PactRunner.class)@SpringApplicationConfiguration(classes = LeapDataStandardApplication.class)@ContextConfiguration(classes = TestAppConfig.class)@PactBroker(BrokerProtocol = "http", BrokerHost = "docker-machine",
BrokerPort = "80", ProviderName = "Datastandard")public class DatastandardControllerTest {
@Autowired private DataStandardController apiController; private DataStandardDelegateController delegateController = mock(DataStandardDelegateController.class, Mockito.RETURNS_SMART_NULLS);
@Before public void setUp() throws Exception { ReflectionTestUtils.setField(apiController, "delegate", delegateController); }
@ProviderState(value = "datastandard-default", deferredResponseInMillis = 0) public DataStandardController shouldResponseCorrectForDefaultDataSet() { when(delegateController.getStandardCategory( eq("dataId"), eq("1") )) .thenReturn(new ResponseEntity<>( new Category().withId("1").withName("Toys"), HttpStatus.OK));
return apiController; }}
Provider
Request
Response
PactConsumerProvider
http://www.slideshare.net/bethesque/pact-44565612
22.
Problems that can be detected with Pact
Change of the endpoint URL Change in the expected parameters Change in the response payload
23.
What is it not good for?
Performance and load testing. Functional testing of the provider
Should be done by provider's own tests
Pact is about checking the contents and
format of requests and responses.
Questions and Comments
25.
References, documentation and more…
github.com/realestate-com-au/pact martinfowler.com/articles/consumerDrivenContracts.html slideshare.net/bethesque/pact-44565612 slideshare.net/evanbottcher/from-monoliths-to-microservices-at-
realestatecomau techblog.newsweaver.com/why-should-you-use-consumer-driven-contr
acts-for-microservices-integration-tests/ dzone.com/articles/application-pattern-consumer