Coherent REST API design

25
- documentation and testing using Swagger and Pact Coherent REST API design

Transcript of Coherent REST API design

Page 1: Coherent REST API design

- documentation and testing using Swagger and Pact

Coherent REST API design

Page 2: Coherent REST API design

2.

Contact Information

Frederik Mogensen

Software Developer, Cloud Team

Stibo Systems

E: [email protected]

L: linkedin.com/in/fmogensen

Page 3: Coherent REST API design

3.

Agenda

Contract driven API design Provider contracts - with Swagger Consumer Driven contracts - with Pact

Page 4: Coherent REST API design

1

Contract driven API design

Page 5: Coherent REST API design

5.

APIs in a Microservice architecture Unstable / changing APIs No type safety between services No developer confidence

Page 6: Coherent REST API design

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

Page 7: Coherent REST API design

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: []

Page 8: Coherent REST API design

8.

Why define service endpoints?

API that are JSON first Documentation and clarity Server / Client code generation

Page 9: Coherent REST API design

9.

Iterative API first development

Update Swagger Definition

Generate Endpoints

Implement functionality

Test and validate API

New demands for API

Page 10: Coherent REST API design

10.

Demo using Swagger and Postman

Page 11: Coherent REST API design

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

Page 12: Coherent REST API design

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

Page 13: Coherent REST API design

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

Page 14: Coherent REST API design

14.

Pacts – The basics

Consumer ProviderRequest

Response

http://www.slideshare.net/bethesque/pact-44565612

Page 15: Coherent REST API design

15.

Pacts – The basics

Consumer ProviderRequest

Response

Request

Response

PactConsumerProvider

http://www.slideshare.net/bethesque/pact-44565612

Page 16: Coherent REST API design

16.

Pact Example

Frontend

Mapping

Product

Datastandard

Login

User

iPhone

Pact BrokerMapping

PactFrontendMapping

ProductPactMappingProduct

LoginPactFrontend

Login

Datastandard Pact

MappingDatastandard

UserPactLoginUser

PactiPhone

Login

Page 17: Coherent REST API design

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

Page 18: Coherent REST API design

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

Page 19: Coherent REST API design

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

Page 20: Coherent REST API design

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

Page 21: Coherent REST API design

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

Page 22: Coherent REST API design

22.

Problems that can be detected with Pact

Change of the endpoint URL Change in the expected parameters Change in the response payload

Page 23: Coherent REST API design

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.

Page 24: Coherent REST API design

Questions and Comments

Page 25: Coherent REST API design

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