Coherent REST API design

Post on 12-Apr-2017

408 views 1 download

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

E: frmo@stibosystems.com

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