Slide 1

Slide 1 text

Improving API communication Using GraphQL

Slide 2

Slide 2 text

Who am I to say anything about it? Currently working at TicketSwap Worked with SOAP, REST and GraphQL in producBon

Slide 3

Slide 3 text

Why should we care about improving APIs? A liCle history…

Slide 4

Slide 4 text

First, there was SOAP

Slide 5

Slide 5 text

Remember SOAP? Microsoft

Slide 6

Slide 6 text

Remember SOAP? Prose in the spec does not specify that attributes are allowed on the Body element

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

SOAP had advantages • Language neutral: can be implemented in any language • Pla.orm independent: can be executed on any plaHorm • Rela5vely simple: uses XML, which is easy to read and write • Scalable: uses HTTP protocol, which allows underlying plaHorms to easily scale

Slide 9

Slide 9 text

And some disadvantages • Slooooooooow: uses XML, which is was slow to parse, and debug • Depends on WSDL: needs a meta service to describe it’s uses, but is tedious to write • XML is hard to read: manually reading a soap envelop and response is not for the faint of hart

Slide 10

Slide 10 text

Then came REST(fullness) Roy Fielding here

Slide 11

Slide 11 text

REST was easier • Much simpler: by reusing HTTP verbs and using JSON • Easy resource discovery: every resource has a unique URL

Slide 12

Slide 12 text

But left some parts out • Resource discovery was s5ll hard: a client had to know the url • Redundant and unneeded informa5on: a resource exposes everything it knows, always • No batching support: 1 request for each resource • Limited by HTTP verbs: not all mutaBons can be mapped

Slide 13

Slide 13 text

To compensate, HATEOS was added

Slide 14

Slide 14 text

HATEOS fixed things • Discoverability: by reusing HTTP verbs and using JSON • Availability based on state: every resource has a unique URL

Slide 15

Slide 15 text

But was hard • Hard to work with: it’s not easy to read all those _link fields • LiIle tooling support: discovery must be done manually • Focus on long-term design: which most people are not very good at • Lots of requests: as each link sBll requires a new request

Slide 16

Slide 16 text

Enter GraphQL Describe your data Ask for what you want Get predictable results type Project { name: String tagline: String contributors: [User] } { project(name: "GraphQL") { tagline } } { "project": { "tagline": "A query language for APIs" } }

Slide 17

Slide 17 text

Enter GraphQL Describe your data Ask for what you want Get predictable results type Project { name: String tagline: String contributors: [User] } { project(name: "GraphQL") { tagline } } { "project": { "tagline": "A query language for APIs" } }

Slide 18

Slide 18 text

Enter GraphQL Describe your data Ask for what you want Get predictable results type Project { name: String tagline: String contributors: [User] } { project(name: "GraphQL") { tagline } } { "project": { "tagline": "A query language for APIs" } }

Slide 19

Slide 19 text

Enter GraphQL Describe your data Ask for what you want Get predictable results type Project { name: String tagline: String contributors: [User] } { project(name: "GraphQL") { tagline } } { "project": { "tagline": "A query language for APIs" } }

Slide 20

Slide 20 text

In use by Facebook since 2012 An open standard since 2015 hIp:/ /graphql.org

Slide 21

Slide 21 text

Also adopted by

Slide 22

Slide 22 text

Powerful type system • Int • Float • String • Boolean • ID • Custom scalar • Enum • Union • List • Non-null • Interface • (Input) Object

Slide 23

Slide 23 text

Get what you need

Slide 24

Slide 24 text

Get many resources

Slide 25

Slide 25 text

Developer tools

Slide 26

Slide 26 text

Developer tools

Slide 27

Slide 27 text

Developer tools

Slide 28

Slide 28 text

Development libraries • Javascript • Ruby • PHP • Python • Java • C/C++ • Go • Scala • .Net • SwiZ • Elixir • Haskell • Lua • Elm • Clojure • ClojureScript • OCaml • Rust • R • SQL

Slide 29

Slide 29 text

Demo time

Slide 30

Slide 30 text

In PHP

Slide 31

Slide 31 text

$queryType = new \GraphQL\Type\Definition\ObjectType([ 'name' => 'Query', 'fields' => [ 'echo' => [ 'type' => \GraphQL\Type\Definition\Type::string(), 'args' => [ 'message' => ['type' => \GraphQL\Type\Definition\Type::string()], ], 'resolve' => function ($root, $args) { return $root['prefix'].$args['message']; } ], ], ]);

Slide 32

Slide 32 text

$queryType = new \GraphQL\Type\Definition\ObjectType([ 'name' => 'Query', 'fields' => [ 'echo' => [ 'type' => \GraphQL\Type\Definition\Type::string(), 'args' => [ 'message' => ['type' => \GraphQL\Type\Definition\Type::string()], ], 'resolve' => function ($root, $args) { return $root['prefix'].$args['message']; } ], ], ]);

Slide 33

Slide 33 text

$queryType = new \GraphQL\Type\Definition\ObjectType([ 'name' => 'Query', 'fields' => [ 'echo' => [ 'type' => \GraphQL\Type\Definition\Type::string(), 'args' => [ 'message' => ['type' => \GraphQL\Type\Definition\Type::string()], ], 'resolve' => function ($root, $args) { return $root['prefix'].$args['message']; } ], ], ]);

Slide 34

Slide 34 text

$queryType = new \GraphQL\Type\Definition\ObjectType([ 'name' => 'Query', 'fields' => [ 'echo' => [ 'type' => \GraphQL\Type\Definition\Type::string(), 'args' => [ 'message' => ['type' => \GraphQL\Type\Definition\Type::string()], ], 'resolve' => function ($root, $args) { return $root['prefix'].$args['message']; } ], ], ]);

Slide 35

Slide 35 text

$queryType = new \GraphQL\Type\Definition\ObjectType([ 'name' => 'Query', 'fields' => [ 'echo' => [ 'type' => \GraphQL\Type\Definition\Type::string(), 'args' => [ 'message' => ['type' => \GraphQL\Type\Definition\Type::string()], ], 'resolve' => function ($root, $args) { return $root['prefix'].$args['message']; } ], ], ]);

Slide 36

Slide 36 text

$schema = new Schema([ 'query' => $queryType, ]); $rawInput = file_get_contents('php://input'); $input = json_decode($rawInput, true); $query = $input['query']; $variableValues = isset($input['variables']) ? $input['variables'] : null; $rootValue = ['prefix' => 'You said: ']; $result = GraphQL::execute($schema, $query, $rootValue, null, $variableValues); header('Content-Type: application/json; charset=UTF-8'); echo json_encode($result);

Slide 37

Slide 37 text

$schema = new Schema([ 'query' => $queryType, ]); $rawInput = file_get_contents('php://input'); $input = json_decode($rawInput, true); $query = $input['query']; $variableValues = isset($input['variables']) ? $input['variables'] : null; $rootValue = ['prefix' => 'You said: ']; $result = GraphQL::execute($schema, $query, $rootValue, null, $variableValues); header('Content-Type: application/json; charset=UTF-8'); echo json_encode($result);

Slide 38

Slide 38 text

$schema = new Schema([ 'query' => $queryType, ]); $rawInput = file_get_contents('php://input'); $input = json_decode($rawInput, true); $query = $input['query']; $variableValues = isset($input['variables']) ? $input['variables'] : null; $rootValue = ['prefix' => 'You said: ']; $result = GraphQL::execute($schema, $query, $rootValue, null, $variableValues); header('Content-Type: application/json; charset=UTF-8'); echo json_encode($result);

Slide 39

Slide 39 text

$schema = new Schema([ 'query' => $queryType, ]); $rawInput = file_get_contents('php://input'); $input = json_decode($rawInput, true); $query = $input['query']; $variableValues = isset($input['variables']) ? $input['variables'] : null; $rootValue = ['prefix' => 'You said: ']; $result = GraphQL::execute($schema, $query, $rootValue, null, $variableValues); header('Content-Type: application/json; charset=UTF-8'); echo json_encode($result);

Slide 40

Slide 40 text

$schema = new Schema([ 'query' => $queryType, ]); $rawInput = file_get_contents('php://input'); $input = json_decode($rawInput, true); $query = $input['query']; $variableValues = isset($input['variables']) ? $input['variables'] : null; $rootValue = ['prefix' => 'You said: ']; $result = GraphQL::execute($schema, $query, $rootValue, null, $variableValues); header('Content-Type: application/json; charset=UTF-8'); echo json_encode($result);

Slide 41

Slide 41 text

PHP demo time

Slide 42

Slide 42 text

Our first implementation…

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

Relay

Slide 46

Slide 46 text

• Node • Viewer Required fields

Slide 47

Slide 47 text

$queryType = new \GraphQL\Type\Definition\ObjectType([ 'name' => 'Query', 'fields' => [ 'node' => [ 'type' => \GraphQL\Type\Definition\Type::listOf($nodeInterface), 'args' => [ 'id' => ['type' => \GraphQL\Type\Definition\Type::id()], ], 'resolve' => function ($root, $args) { // Resolve the node by ID } ], ], ]);

Slide 48

Slide 48 text

{ node(id: "Q2l0eTox") { ... on City { name } ... on Location { name } } }

Slide 49

Slide 49 text

{ viewer { firstname lastname recentlyVisitedEvents { name } } }

Slide 50

Slide 50 text

Connections • Connec5on: relaBons between models are called connecBons • Node: a specific data item • Edge: the relaBonship between two nodes

Slide 51

Slide 51 text

{ viewer { firstname lastname wantedListings(first:5) { pageInfo { hasNextPage } edges { cursor node { # Node details } } } } }

Slide 52

Slide 52 text

{ viewer { firstname lastname wantedListings(first:5) { pageInfo { hasNextPage } edges { cursor node { # Node details } } } } }

Slide 53

Slide 53 text

{ viewer { firstname lastname wantedListings(first:5) { pageInfo { hasNextPage } edges { cursor node { # Node details } } } } }

Slide 54

Slide 54 text

{ viewer { firstname lastname wantedListings(first:5) { pageInfo { hasNextPage } edges { cursor node { # Node details } } } } }

Slide 55

Slide 55 text

Complexity overload

Slide 56

Slide 56 text

Query Complexity Analysis use GraphQL\GraphQL; /** @var \GraphQL\Validator\Rules\QueryComplexity $queryComplexity */ $queryComplexity = DocumentValidator::getRule('QueryComplexity'); $queryComplexity->setMaxQueryComplexity($maxQueryComplexity = 110); GraphQL::execute(/*...*/);

Slide 57

Slide 57 text

Limiting Query Depth use GraphQL\GraphQL; /** @var \GraphQL\Validator\Rules\QueryDepth $queryDepth */ $queryDepth = DocumentValidator::getRule('QueryDepth'); $queryDepth->setMaxQueryDepth($maxQueryDepth = 10); GraphQL::execute(/*...*/);

Slide 58

Slide 58 text

N+1 problem

Slide 59

Slide 59 text

Uses batching and caching to efficiently load resources Data loader

Slide 60

Slide 60 text

'resolve' => function ($root, $args) { return $this->dataLoader($args[‘id']); }

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

public function load(array $ids) : Promise { $nodes = // Find all nodes by id $nodeValues = // Map them to returnable values return $this->promiseAdapter->createFulfilled($eventValues); }

Slide 63

Slide 63 text

Look at: • hIps:/ /github.com/facebook/dataloader • hIps:/ /github.com/overblog/dataloader-php Data loader

Slide 64

Slide 64 text

One more thing

Slide 65

Slide 65 text

Mutations

Slide 66

Slide 66 text

$mutationType = new \GraphQL\Type\Definition\ObjectType( [ 'name' => 'Calc', 'fields' => [ 'sum' => [ 'type' => \GraphQl\Type\Definition\Type::int(), 'args' => [ 'x' => ['type' => \GraphQl\Type\Definition\Type::int()], 'y' => ['type' => \GraphQl\Type\Definition\Type::int()], ], 'resolve' => function ($root, $args) { return $args['x'] + $args['y']; }, ], ], ] );

Slide 67

Slide 67 text

$mutationType = new \GraphQL\Type\Definition\ObjectType( [ 'name' => 'Calc', 'fields' => [ 'sum' => [ 'type' => \GraphQl\Type\Definition\Type::int(), 'args' => [ 'x' => ['type' => \GraphQl\Type\Definition\Type::int()], 'y' => ['type' => \GraphQl\Type\Definition\Type::int()], ], 'resolve' => function ($root, $args) { return $args['x'] + $args['y']; }, ], ], ] );

Slide 68

Slide 68 text

$mutationType = new \GraphQL\Type\Definition\ObjectType( [ 'name' => ‘Mutation', 'fields' => [ 'sum' => [ 'type' => \GraphQl\Type\Definition\Type::int(), 'args' => [ 'x' => ['type' => \GraphQl\Type\Definition\Type::int()], 'y' => ['type' => \GraphQl\Type\Definition\Type::int()], ], 'resolve' => function ($root, $args) { return $args['x'] + $args['y']; }, ], ], ] );

Slide 69

Slide 69 text

$mutationType = new \GraphQL\Type\Definition\ObjectType( [ 'name' => ‘Mutation', 'fields' => [ 'sum' => [ 'type' => \GraphQl\Type\Definition\Type::int(), 'args' => [ 'x' => ['type' => \GraphQl\Type\Definition\Type::int()], 'y' => ['type' => \GraphQl\Type\Definition\Type::int()], ], 'resolve' => function ($root, $args) { return $args['x'] + $args['y']; }, ], ], ] );

Slide 70

Slide 70 text

$mutationType = new \GraphQL\Type\Definition\ObjectType( [ 'name' => ‘Mutation', 'fields' => [ 'sum' => [ 'type' => \GraphQl\Type\Definition\Type::int(), 'args' => [ 'x' => ['type' => \GraphQl\Type\Definition\Type::int()], 'y' => ['type' => \GraphQl\Type\Definition\Type::int()], ], 'resolve' => function ($root, $args) { return $args['x'] + $args['y']; }, ], ], ] );

Slide 71

Slide 71 text

Conclusion • Hard to master: new developers might not be familiar with it • S5ll rough around the edges: libraries and frameworks are sBll at their infancy • Deep complexity problems: can be hard to find and solve

Slide 72

Slide 72 text

Conclusion • Easy discovery: fun and easy to work with • Powerful tools: from developer tools to libraries and frameworks • Lightweight communica5on: using only what you need reduces overhead • Inline documenta5on: no more separate documentaBon to ship

Slide 73

Slide 73 text

Resources • hCp:/ /graphql.org • hCps:/ /github.com/chentsulin/awesome-graphql • hCps:/ /www.learnrelay.org