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.

Getting Started with GraphQL && PHP

131 views

Published on

Talk given at Longhorn PHP 2019

Published in: Software
  • Be the first to comment

  • Be the first to like this

Getting Started with GraphQL && PHP

  1. 1. @AndrewRota | Longhorn PHP 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 APIs Today ‣ ‣ ‣
  7. 7. @AndrewRota Associate Director, Software Engineering
  8. 8. “GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data.”
  9. 9. { conferences { name dates } } "conferences": [ { "name": "LonghornPHP", "dates": "May 2 - 4, 2019" } ]
  10. 10. { conferences { name speakers { name twitter } } } { "conferences": [ { "name": "LonghornPHP", "speakers": [ { "name": "Andrew Rota", "twitter": "https://twitter.com/andrewrota" } ] } ] }
  11. 11. Topics ‣ ‣ ‣ ‣ ‣ ‣
  12. 12. GraphQL ‣ ‣ ‣
  13. 13. GraphQL Implementations ‣ technology agnostic ‣ ‣
  14. 14. GraphQL Advantages ‣ ‣ ‣ ‣
  15. 15. GraphQL in a web stack QueryClient (e.g., browser, mobile app) /graphql on PHP Server response Database
  16. 16. GraphQL in a web stack QueryClient (e.g., browser, mobile app) /graphql on PHP Server response Cache Service Database
  17. 17. GraphQL in a web stack QueryClient (e.g., browser, mobile app) /graphql server response Cache REST Service Database PHP
  18. 18. Queries + Fields ‣ fields ‣ same shape query { conferences { name dates } } query field
  19. 19. Fields ‣ ‣ sub-selection ‣ avoid multiple requests query { conferences { name speakers { name } } } sub-selection
  20. 20. Arguments ‣ arguments each field { conference(name: "LonghornPHP") { speakers { name } } } argument
  21. 21. Variables ‣ query SearchConfs($name: String){ conferences(nameFilter:$name) { name } } {"name": "LonghornPHP"}
  22. 22. Types + Schemas ‣ set of types
  23. 23. Types + Schemas ‣ type Conference { name: String! url: String! description: String location: String dates: String! # List of speakers at this conference speakers: [Speaker] }
  24. 24. Types + Schemas ‣ ‣ 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
  25. 25. Query + Mutation Types ‣ Query Mutation ‣ Root fields entry points type Query { # Returns conferences conferences: [Conference] # Returns speakers speakers: [Speaker] } root fields root type
  26. 26. Queries ‣ ‣ ‣ query ConferenceNamesAndDates{ conferences { name dates } } operation nameoperation type fields
  27. 27. Mutations ‣ ‣ mutation mutation { addSpeaker( name: "Andrew Rota", twitter: "https://twitter.com/andrewrota") { id } }
  28. 28. Queries from JavaScript ‣ ‣ query ConferenceNamesAndDates{ conferences { name dates } }
  29. 29. Lokka a simple graphql client library ‣ const t = new HttpTransport('/graphql'); t.send(`query ConferenceNamesAndDates{ conferences { name dates } }`).then(response => { console.log(response); });
  30. 30. Apollo complete data management solution ‣ ‣ ‣ ‣ ‣ <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>
  31. 31. graphql-php ‣ ‣ ‣ ‣ implementation of the GraphQL spec in PHP
  32. 32. Handle queries ‣ ‣ Schema ‣ GraphQL::executeQuery $schema = new Schema([ 'query' => Types::query() ]); $result = GraphQL::executeQuery( $schema, $requestData['query'], null, $appContext, (array)$requestData['variables'] ); $output = $result->toArray();
  33. 33. Query.
  34. 34. Root fields ‣ fields ‣ type resolve use GraphQLTypeDefinitionObjectType; use GraphQLTypeDefinitionType; $queryType = new ObjectType([ 'name' => 'Query', 'fields' => [ 'message' => [ 'type' => Type::string(), 'resolve' => function () { return 'hello world'; } ], ] ]);
  35. 35. Fields can return objects ‣ ‣ $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'; } ], ] ]);
  36. 36. Resolvers ‣ ‣ ‣ ‣ $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'; } ], ] ]);
  37. 37. 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
  38. 38. Custom object type ‣ $config = [ 'name' => 'Conference', 'fields' => [ 'name' => Type::nonNull(Types::string()), 'url' => Type::nonNull(Types::string()), 'location' => Types::string(), ] ];
  39. 39. Custom object type ‣ ‣ $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); } ] ] ];
  40. 40. n+1 problem ‣ { conferences { name speakers{ name } } }
  41. 41. Solution: deferred resolvers ‣ ‣ ‣ 'resolve' => function($root) { SpeakerCollection::add($root->id); return new Deferred(function() use ($root) { return SpeakerCollection::get($root->id); }); }
  42. 42. Limiting Query Complexity and Depth ‣ ‣
  43. 43. Persisted Queries queryClient Server query { conferences { name dates } } idClient Server{ id: 001 } ‣ ‣ ‣ ‣ With persisted queries:
  44. 44. Introspection ‣ ‣ ‣ { "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 } ] } ] } } }
  45. 45. GraphiQL - in browser IDE for exploring GraphQL
  46. 46. Graphql Playground - like GraphiQL, but more features
  47. 47. Voyager - Any GraphQL API as an interactive graph
  48. 48. PHPStorm JS GraphQL Plugin - IDE Integration
  49. 49. Types can be used in client-side code ‣ Apollo Codegen ‣
  50. 50. @AndrewRota Resources ‣ ‣ ‣ ‣

×