Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Performant APIs with GraphQL and PHP
@AndrewRota | Dutch PHP Conference 2019
APIs are important
Native Mobile Apps
Web browsers
(http requests from JavaScript)
External API
API
Native Mobile Apps
Web browsers
External API
API
article
comment
comment
author
author
author
Native Mobile Apps
Web browsers
External API
API
article
comment
comment author
Native Mobile Apps
Web browsers
External API
APIgetBlog
Challenges with Traditional APIs
‣ Over-fetching data
‣ Under-fetching data, requiring multiple round-trips
‣ Time spent i...
GraphQL offers an alternative
architecture for developing efficient,
easy to understand APIs.
Andrew Rota
@AndrewRota
Associate Director, Software Engineering
What is GraphQL?
“GraphQL is a query
language for APIs and a
runtime for fulfilling those
queries with your existing
data.”
{
conferences {
name
dates
}
}
"conferences": [
{
"name": "Dutch PHP 2019",
"dates": "June 6-8, 2019"
}
]
{
conferences {
name
speakers {
name
twitter
}
}
}
{
"conferences": [
{
"name": "Dutch PHP 2019",
"speakers": [
{
"name": ...
Topics
‣ Introduction
‣ GraphQL Concepts
‣ Client-Side GraphQL
‣ Server-side GraphQL with PHP
‣ Beyond the Basics
‣ GraphQ...
GraphQL
‣ Developed internally at Facebook in 2012
‣ Open sourced in 2015
‣ Spec: facebook.github.io/graphql/draft
GraphQL Implementations
‣ GraphQL is technology agnostic on both client and server
‣ Client implementations:
‣ Server impl...
GraphQL Advantages
‣ Client requests exactly the shape of the data it needs
‣ Multiple resources can be queried in a singl...
GraphQL in a web stack
QueryClient
(e.g., browser, mobile
app)
/graphql on
PHP Server
response
Database
GraphQL in a web stack
QueryClient
(e.g., browser, mobile
app)
/graphql on
PHP Server
response
Cache
Service
Database
GraphQL in a web stack
QueryClient
(e.g., browser, mobile
app)
/graphql
server
response
Cache
REST Service
Database
PHP
GraphQL Concepts
Queries + Fields
‣ In GraphQL you make queries
for fields on objects
‣ The response will have the
same shape as the query
...
Fields
‣ Fields might be scalar values,
or they might be other Objects.
‣ Fields can refer to Objects, and
you can make a ...
Arguments
‣ You can pass named
arguments to each field
and nested object.
{
conference(name: "LonghornPHP") {
speakers {
n...
Variables
‣ Dynamic values can be
passed into queries via
variables
query SearchConfs($name: String){
conferences(nameFilt...
Types + Schemas
‣ Every GraphQL service
defines the a set of types
that describe what data can
be requested
Types + Schemas
‣ GraphQL servers can be
written in any language, so
we describe types with a
language-agnostic “GraphQL
s...
Types + Schemas
‣ GraphQL servers can be
written in any language, so
we describe types with a
language-agnostic “GraphQL
s...
Query + Mutation Types
‣ There are two special types
in every GraphQL schema:
Query and Mutation
‣ Root fields you define ...
Queries
‣ Queries ask for for data;
analogous to GET requests.
‣ GraphQL clients (e.g.,
browsers, mobile apps),
make queri...
Mutations
‣ Mutations are for modifying
data; analogous to
POST/PUT/DELETE requests.
‣ They start with the mutation
root t...
GraphQL on the Client
Client-side GraphQL is about writing queries to request data from
a GraphQL server with a defined schema.
Queries from JavaScript
‣ Queries are made via HTTP
requests to a single endpoint
‣ There are several libraries
available ...
Lokka
a simple graphql client library
‣ Lokka is a simple JavaScript
library for sending GraphQL
queries in JavaScript, ju...
Apollo
complete data management solution
‣ Declarative API for queries and
mutations
‣ Normalized client-side caching
‣ Co...
GraphQL on the Server
Client-side GraphQL is about writing queries to request data from
a GraphQL server with a defined schema.
Server-side Grap...
Let’s build a GraphQL server in PHP!
webonyx/graphql-php
Provides:
‣ Type primitives for your Type system
‣ Query parsing, validation, and
execution against a ...
Create a /graphql endpoint to handle requests, and execute queries
Handle queries
‣ Queries are made via HTTP
requests to a single endpoint
‣ GraphQL::executeQuery
parses, validates, and
ex...
Then start with the special root type, Query.
Root fields
‣ This root type (Query) has a
list of root fields, which are
the entry points to the API
‣ Each field has a t...
Fields can return objects
‣ A field can also return a
custom ObjectType, which is
a type with its own collection
of fields...
Resolvers
‣ Resolve functions tell the server
how to get the data for the field
‣ Resolve function can be
implemented howe...
...let’s take a closer look at a resolve function
function($root, $args, $context, ResolveInfo $info) {
return DataSource:...
Creating a custom ObjectType
1. Define your object type
2. Add it to a new field
3. Write the field resolver function
Custom object type
‣ Just like the root query type,
a custom type is a collection
of fields, each with their own
types
$co...
Custom object type
‣ Just like the root query type,
a custom type is a collection
of fields, each with their own
types
‣ F...
And now we have a GraphQL server!
GraphQL Tooling
Introspection
‣ A key feature of GraphQL is
its introspection system
‣ You can ask any GraphQL
schema about what queries
i...
GraphiQL - in browser IDE for exploring GraphQL
Graphql Playground - like GraphiQL, but more features
Voyager - Any GraphQL API as an interactive graph
PHPStorm JS GraphQL Plugin - IDE Integration
Types can be used in client-side code
‣ If you’re using a client-side language that supports types, you can
generate types...
Beyond the Basics
n+1 problem
‣ Data-fetching problem that
occurs when you need to
fetch related items in a
one-to-many relationship
{
confe...
Solution: deferred resolvers
‣ graphql-php provides Deferred
objects to delay field resolution
until we can make a single ...
Limiting Query Complexity and Depth
‣ graphql-php provides a method to calculate and limit the complexity
of any query, ba...
Persisted Queries
queryClient Server
query {
conferences {
name
dates
}
}
idClient Server{ id: 001 }
‣ In production, quer...
Subscriptions
Client Server
Subscribe to an event
‣ GraphQL subscriptions push
data to the client when
events happen, usua...
Challenges
GraphQL is a new paradigm that offers a lot of new opportunities
for developing performant APIs, but with that comes new
ch...
Challenges when using GraphQL
‣ It’s more complex than RESTful APIs
‣ ORMs are not ready to work performantly with GraphQL...
GraphQL might not always be the best choice for your API:
consider your use case and the problems you’re trying to solve,
...
GraphQL makes it easier to make
more efficient queries between your
client and your server.
GraphQL provides new ways to think
about your APIs and the structure of
your application’s data.
Give it a try!
Thanks!
Andrew Rota
@AndrewRota
Resources
‣ graphql.org
‣ github.com/webonyx/graphql-php
‣ github.com/chentsulin/awesome-graphql
‣...
Upcoming SlideShare
Loading in …5
×

Performant APIs with GraphQL and PHP (Dutch PHP 2019)

145 views

Published on

Conference talk given on June 7, 2019, at Dutch PHP Conference.

Published in: Software
  • Be the first to comment

  • Be the first to like this

Performant APIs with GraphQL and PHP (Dutch PHP 2019)

  1. 1. Performant APIs with GraphQL and PHP @AndrewRota | Dutch PHP Conference 2019
  2. 2. APIs are important Native Mobile Apps Web browsers (http requests from JavaScript) External API API
  3. 3. Native Mobile Apps Web browsers External API API article comment comment author author author
  4. 4. Native Mobile Apps Web browsers External API API article comment comment author
  5. 5. Native Mobile Apps Web browsers External API APIgetBlog
  6. 6. Challenges with Traditional APIs ‣ Over-fetching data ‣ Under-fetching data, requiring multiple round-trips ‣ Time spent iterating on endpoints and expected data shape
  7. 7. GraphQL offers an alternative architecture for developing efficient, easy to understand APIs.
  8. 8. Andrew Rota @AndrewRota Associate Director, Software Engineering
  9. 9. What is GraphQL? “GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data.”
  10. 10. { conferences { name dates } } "conferences": [ { "name": "Dutch PHP 2019", "dates": "June 6-8, 2019" } ]
  11. 11. { conferences { name speakers { name twitter } } } { "conferences": [ { "name": "Dutch PHP 2019", "speakers": [ { "name": "Andrew Rota", "twitter": "https://twitter.com/andrewrota" } ] } ] }
  12. 12. Topics ‣ Introduction ‣ GraphQL Concepts ‣ Client-Side GraphQL ‣ Server-side GraphQL with PHP ‣ Beyond the Basics ‣ GraphQL Tooling
  13. 13. GraphQL ‣ Developed internally at Facebook in 2012 ‣ Open sourced in 2015 ‣ Spec: facebook.github.io/graphql/draft
  14. 14. GraphQL Implementations ‣ GraphQL is technology agnostic on both client and server ‣ Client implementations: ‣ Server implementations:
  15. 15. GraphQL Advantages ‣ Client requests exactly the shape of the data it needs ‣ Multiple resources can be queried in a single request ‣ API is defined with a strongly-typed schema ‣ Enables strong tooling for developers
  16. 16. GraphQL in a web stack QueryClient (e.g., browser, mobile app) /graphql on PHP Server response Database
  17. 17. GraphQL in a web stack QueryClient (e.g., browser, mobile app) /graphql on PHP Server response Cache Service Database
  18. 18. GraphQL in a web stack QueryClient (e.g., browser, mobile app) /graphql server response Cache REST Service Database PHP
  19. 19. GraphQL Concepts
  20. 20. Queries + Fields ‣ In GraphQL you make queries for fields on objects ‣ The response will have the same shape as the query query { conferences { name dates } } query field
  21. 21. Fields ‣ Fields might be scalar values, or they might be other Objects. ‣ Fields can refer to Objects, and you can make a sub-selection for fields of these Objects. ‣ This lets you avoid making multiple requests for related resources query { conferences { name speakers { name } } } sub-selection
  22. 22. Arguments ‣ You can pass named arguments to each field and nested object. { conference(name: "LonghornPHP") { speakers { name } } } argument
  23. 23. Variables ‣ Dynamic values can be passed into queries via variables query SearchConfs($name: String){ conferences(nameFilter:$name) { name } } {"name": "LonghornPHP"}
  24. 24. Types + Schemas ‣ Every GraphQL service defines the a set of types that describe what data can be requested
  25. 25. Types + Schemas ‣ GraphQL servers can be written in any language, so we describe types with a language-agnostic “GraphQL schema language” type Conference { name: String! url: String! description: String location: String dates: String! # List of speakers at this conference speakers: [Speaker] }
  26. 26. Types + Schemas ‣ GraphQL servers can be written in any language, so we describe types with a language-agnostic “GraphQL schema language” ‣ Types include: object, scalar, list, enumeration, union, interface, and non-nullable. type Conference { name: String! url: String! description: String location: String dates: String! # List of speakers at this conference speakers: [Speaker] } non-nullable scalar type list of object types
  27. 27. Query + Mutation Types ‣ There are two special types in every GraphQL schema: Query and Mutation ‣ Root fields you define on Query and Mutation are the entry points of requests type Query { # Returns conferences conferences: [Conference] # Returns speakers speakers: [Speaker] } root fields root type
  28. 28. Queries ‣ Queries ask for for data; analogous to GET requests. ‣ GraphQL clients (e.g., browsers, mobile apps), make queries against a single GraphQL endpoint ‣ Operation name and type can be optional query ConferenceNamesAndDates{ conferences { name dates } } operation nameoperation type fields
  29. 29. Mutations ‣ Mutations are for modifying data; analogous to POST/PUT/DELETE requests. ‣ They start with the mutation root type, and will often leverage arguments, but are otherwise the same as queries mutation { addSpeaker( name: "Andrew Rota", twitter: "https://twitter.com/andrewrota") { id } }
  30. 30. GraphQL on the Client
  31. 31. Client-side GraphQL is about writing queries to request data from a GraphQL server with a defined schema.
  32. 32. Queries from JavaScript ‣ Queries are made via HTTP requests to a single endpoint ‣ There are several libraries available to manage GraphQL on the client query ConferenceNamesAndDates{ conferences { name dates } }
  33. 33. Lokka a simple graphql client library ‣ Lokka is a simple JavaScript library for sending GraphQL queries in JavaScript, just like standard fetch or ajax requests const t = new HttpTransport('/graphql'); t.send(`query ConferenceNamesAndDates{ conferences { name dates } }`).then(response => { console.log(response); });
  34. 34. Apollo complete data management solution ‣ Declarative API for queries and mutations ‣ Normalized client-side caching ‣ Combine local and remote data ‣ Pagination, error handling, refetching, and optimistic UI ‣ Client libraries for popular frontend frameworks (React.js, Angular, Vue), as well as native Android and iOS applications <Query client={client} query={CONFERENCES_QUERY}> {({ loading, error, data }) => { if (loading) return 'Loading...'; if (error) return `Error!`; return ( <ul> {data.conferences.map(conference => ( <li>{conference.name}</li> ))} </ul> ); }} </Query>
  35. 35. GraphQL on the Server
  36. 36. Client-side GraphQL is about writing queries to request data from a GraphQL server with a defined schema. Server-side GraphQL is about implementing that schema to return data.
  37. 37. Let’s build a GraphQL server in PHP!
  38. 38. webonyx/graphql-php Provides: ‣ Type primitives for your Type system ‣ Query parsing, validation, and execution against a Type system ‣ Type introspection ‣ Tools for deferred field resolution Feature-complete implementation of the GraphQL spec in PHP, inspired by Facebook’s original node-js reference library.
  39. 39. Create a /graphql endpoint to handle requests, and execute queries
  40. 40. Handle queries ‣ Queries are made via HTTP requests to a single endpoint ‣ GraphQL::executeQuery parses, validates, and executes the query $schema = new Schema([ 'query' => Types::query() ]); $result = GraphQL::executeQuery( $schema, $requestData['query'], null, $appContext, (array)$requestData['variables'] ); $output = $result->toArray();
  41. 41. Then start with the special root type, Query.
  42. 42. Root fields ‣ This root type (Query) has a list of root fields, which are the entry points to the API ‣ Each field has a type, and a resolve method for getting the data use GraphQLTypeDefinitionObjectType; use GraphQLTypeDefinitionType; $queryType = new ObjectType([ 'name' => 'Query', 'fields' => [ 'message' => [ 'type' => Type::string(), 'resolve' => function () { return 'hello world'; } ], ] ]);
  43. 43. Fields can return objects ‣ A field can also return a custom ObjectType, which is a type with its own collection of fields. ‣ It can also return lists of other types $queryType = new ObjectType([ 'name' => 'Query', 'fields' => [ 'conferences' => [ 'type' => Types::listOf(Types::conference()), 'description' => 'Returns conferences', 'resolve' => function() { return DataSource::getConferences(); } ], 'message' => [ 'type' => Type::string(), 'resolve' => function () { return 'hello world'; } ], ] ]);
  44. 44. Resolvers ‣ Resolve functions tell the server how to get the data for the field ‣ Resolve function can be implemented however you’d like to get the data: SQL queries, cache, or another API ‣ For scalars, the return value will be the value of the field ‣ For object types, the return value will be passed on to nested fields $queryType = new ObjectType([ 'name' => 'Query', 'fields' => [ 'conferences' => [ 'type' => Types::listOf(Types::conference()), 'description' => 'Returns conferences', 'resolve' => function() { return DataSource::getConferences(); } ], 'message' => [ 'type' => Type::string(), 'resolve' => function () { return 'hello world'; } ], ] ]);
  45. 45. ...let’s take a closer look at a resolve function function($root, $args, $context, ResolveInfo $info) { return DataSource::getData($root->id); } root / parent result arguments app context query AST and other meta info
  46. 46. Creating a custom ObjectType
  47. 47. 1. Define your object type 2. Add it to a new field 3. Write the field resolver function
  48. 48. Custom object type ‣ Just like the root query type, a custom type is a collection of fields, each with their own types $config = [ 'name' => 'Conference', 'fields' => [ 'name' => Type::nonNull(Types::string()), 'url' => Type::nonNull(Types::string()), 'location' => Types::string(), ] ];
  49. 49. Custom object type ‣ Just like the root query type, a custom type is a collection of fields, each with their own types ‣ Fields on a type can also have custom ObjectTypes $config = [ 'name' => 'Conference', 'fields' => [ 'name' => Type::nonNull(Types::string()), 'url' => Type::nonNull(Types::string()), 'location' => Types::string(), 'speakers' => [ 'type' => Types::listOf(Types::speaker()), 'resolve' => function($root) { return DataSource::getSpeakersAtConf($root->id); } ] ] ];
  50. 50. And now we have a GraphQL server!
  51. 51. GraphQL Tooling
  52. 52. Introspection ‣ A key feature of GraphQL is its introspection system ‣ You can ask any GraphQL schema about what queries it supports ‣ This unlocks opportunities for powerful tooling { "data": { "__schema": { "queryType": { "name": "Query" }, "types": [ { "kind": "OBJECT", "name": "Query", "description": null, "fields": [ { "name": "conferences", "description": "Returns a list of PHP conferences", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Conference", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ] } ] } } }
  53. 53. GraphiQL - in browser IDE for exploring GraphQL
  54. 54. Graphql Playground - like GraphiQL, but more features
  55. 55. Voyager - Any GraphQL API as an interactive graph
  56. 56. PHPStorm JS GraphQL Plugin - IDE Integration
  57. 57. Types can be used in client-side code ‣ If you’re using a client-side language that supports types, you can generate types for graphql queries automatically from the GraphQL schema using tools such as Apollo Codegen ‣ Examples: TypeScript, FlowType, or Swift (iOS)
  58. 58. Beyond the Basics
  59. 59. n+1 problem ‣ Data-fetching problem that occurs when you need to fetch related items in a one-to-many relationship { conferences { name speakers{ name } } }
  60. 60. Solution: deferred resolvers ‣ graphql-php provides Deferred objects to delay field resolution until we can make a single batch request for the data ‣ Once all non-deferred fields are resolved, graphql-php will call the wrapped closures ‣ If you have an environment that supports async operations (e.g., HHVM, ReactPHP, PHP threads), some fields can also resolve async. 'resolve' => function($root) { SpeakerCollection::add($root->id); return new Deferred(function() use ($root) { return SpeakerCollection::get($root->id); }); }
  61. 61. Limiting Query Complexity and Depth ‣ graphql-php provides a method to calculate and limit the complexity of any query, based on the sum of complexity scores set per field ‣ You can also limit the nested fields requested in queries
  62. 62. Persisted Queries queryClient Server query { conferences { name dates } } idClient Server{ id: 001 } ‣ In production, queries can be extracted at build-time as “persisted queries” ‣ Clients send the server the reference to the query ‣ Reduce data sent to server ‣ Restrict queries that can be run to a pre-built whitelist With persisted queries:
  63. 63. Subscriptions Client Server Subscribe to an event ‣ GraphQL subscriptions push data to the client when events happen, usually over a long-lived WebSocket connection. ‣ graphql-php does not implement support for subscriptions subscription SubscribeToVotes { newVote { time, voter, value } }
  64. 64. Challenges
  65. 65. GraphQL is a new paradigm that offers a lot of new opportunities for developing performant APIs, but with that comes new challenges as well.
  66. 66. Challenges when using GraphQL ‣ It’s more complex than RESTful APIs ‣ ORMs are not ready to work performantly with GraphQL (yet) ‣ Caching is a lot more challenging ‣ Application metrics are more complicated Robert Zhu’s “The Case Against GraphQL” (bit.ly/against-graphql)
  67. 67. GraphQL might not always be the best choice for your API: consider your use case and the problems you’re trying to solve, weigh the tradeoffs, and make an informed decision.
  68. 68. GraphQL makes it easier to make more efficient queries between your client and your server.
  69. 69. GraphQL provides new ways to think about your APIs and the structure of your application’s data.
  70. 70. Give it a try!
  71. 71. Thanks!
  72. 72. Andrew Rota @AndrewRota Resources ‣ graphql.org ‣ github.com/webonyx/graphql-php ‣ github.com/chentsulin/awesome-graphql ‣ Howtographql.com Tutorial: slideshare.net/andrewrota/tutorial-building-a-graphql-api-in-php/

×