SlideShare ist ein Scribd-Unternehmen logo
1 von 101
Downloaden Sie, um offline zu lesen
GraphQL in the
PHP ecosystem
What is GraphQL?
GraphQL ?
• GraphQL is a protocol
GraphQL ?
• GraphQL is a protocol
• It is not:
• A fancy new database
• A database query language like SQL
GraphQL ?
• GraphQL is a protocol
• GraphQL is a challenger to those other
protocols:
• REST
• Web-services (SOAP/WSDL based)
A bit of history
Web-services
(~1999)
• Strongly typed
• Self-describing (WSDL)
• XML-based
A bit of history
Web-services
(~1999)
• Strongly typed
• Self-describing (WSDL)
• XML-based
A bit of history
Web-services
(~1999)
REST
(~2005)
• Strongly typed
• Self-describing (WSDL)
• XML-based
• Weakly typed
• Non self-describing
(still OpenAPI for doc)
• Mostly JSON based
A bit of history
Web-services
(~1999)
REST
(~2005)
• Strongly typed
• Self-describing (WSDL)
• XML-based
• Weakly typed
• Non self-describing
(still OpenAPI for doc)
• Mostly JSON based
A bit of history
Web-services
(~1999)
REST
(~2005)
GraphQL
(2015)
• Strongly typed
• Self-describing (WSDL)
• XML-based
• Weakly typed
• Non self-describing
(still OpenAPI for doc)
• Mostly JSON based
• Strongly typed
• Self-describing
• JSON based
• + Client driven queries
GraphQL ?
It is developed by Facebook and was first used in
the Facebook API.
Facebook also provides:
• A JS client (to query a GraphQL server)
• A NodeJS server library
Tons of server implementations exist.
Why GraphQL?
What problem does GraphQL solves?
• Your API often changes
• You develop a new feature but your API
does not exactly respond to your needs.
What problem does GraphQL solves?
• For instance: you are developing a
marketplace. You need a page to display a
product, along some company information.
/api/product/42 /api/company/35
REST
What problem does GraphQL solves?
• Alternative, still REST
• But what if some pages don’t need the
company details?
/api/product/42
REST
What problem does GraphQL solves?
• Yet another alternative, still REST
/api/product/42?with_company=true
REST
Flags hell 😨! Probably one
flag per consumer of the API
What problem does GraphQL solves?
• GraphQL to the rescue!
• GraphQL is a paradigm shift.
• The client asks for the list of fields it wants.
GET /graphql?query= Single endpoint
The name of the query is « products »
List of fields requested
What problem does GraphQL solves?
• GraphQL to the rescue!
• Another request of the same query with a
different set of fields
No need to change the code on the
server-side! All this data in one API call!
GET /graphql?query=
GraphQL types
Types
GraphQL is strongly typed.
It comes with a « schema
language » but this is rarely
used while developing.
It is however useful to
understand what is going on.
≠
Schema language
product(id: 42) {
name
company {
name
logo
country {
name
}
}
}
Query language
Types
Note:
• [Product] ➔ an array of
Products
• String ➔ a string (or null)
• String! ➔ a non-nullable string
Hence:
• [Product!]! ➔ An array (non-
nullable) of products that are also
non-nullable.
Types
Some « scalar » types:
• ID: a unique identifier (~=String)
• String
• Int
• Float
• Boolean
No support for « Date » in the
standard (but custom types are
supported by some implementations)
Types
Support for “arguments”:
• product(id: ID!)
➔ the product query
requires an “id” field of
type “ID” to be passed.
Types
Bonus:
• Support for interfaces
• Support for Union types
• Support for “InputType” (to pass complex
objects in queries)
Mutations
So far, we mostly talked about queries (because
this is what is fun in GraphQL).
GraphQL can also do mutations (to change the
state of the DB)
Out of
GraphQL
scope
Transport is out of scope
• You usually do GraphQL over HTTP/HTTPS
• But nothing prevents you from using GraphQL
over UDP, or mail, …
Transport is out of scope
• You usually do GraphQL over HTTP/HTTPS
• But nothing prevents you from using GraphQL
over UDP, or mail, or homing pigeon whatever!
Authentication is out of scope
• GraphQL does not deal with authentication.
• You are free to deal with it in any way you want:
• Session-based
• or using Oauth2
• or using a token…
• Authentication can happen using a REST API,
or even using a GraphQL mutation!
Pagination is out of scope
• GraphQL does not deal with pagination in the
standard.
• You are free to add limit/offset parameters to
your queries
• “Relay” is providing some conventions to deal
with pagination (more on that later)
The GraphQL
ecosystem
Ecosystem (a small part of…)
Browser
GraphQL
Client
Server
GraphQL
Middleware DB
RelayJS
Apollo
ReactJS
Express-
graphql
NodeJS
Webonyx/
GraphQL-
PHP
PHP
GraphiQL
(for dev!)
Zoom on GraphQL in PHP
Core library Wrapper library
• Low level
• Parsing
• Service requests
• Powerful
• Feature complete
• Hard to use (poor DX)
• High level
• Opiniated
• Easy to use
Zoom on GraphQL in PHP
Core library Wrapper library
• webonyx/graphql-php
• De-facto standard in PHP
• Youshido/GraphQL
•  Abandonned 
Zoom on GraphQL in PHP
Core library Wrapper library
• API Platform (Symfony)
• Overblog GraphQL Bundle (Symfony)
• Lighthouse (Laravel)
• … and now GraphQLite
Zoom of Webonyx/GraphQL-PHP
Define a type
Zoom of Webonyx/GraphQL-PHP
Define a query
Zoom of Webonyx/GraphQL-PHP
Actually resolving a query
Costs VS benefits
Costs Gains
Strict types
Self-described
Client
driven
Work
You need a wrapper library
Costs Gains
Strict types
Self-described
Client
driven
Work
GraphQL
library
Strategies
Schema-first Code-first
• Design the GraphQL schema first
• Find a way to link it to your code
• Design your domain code
• Generate the schema from the code
Strategies
Schema-first Code-first
• Overblog GraphQL Bundle
• Lighthouse
• API Platform
• GraphQLite
Strategies
Schema-first Code-first
• Overblog GraphQL Bundle
• Lighthouse
• API Platform
• GraphQLite
Lighthouse
Strategies
Schema-first Code-first
• Overblog GraphQL Bundle
• Lighthouse
• API Platform
• GraphQLite
API Platform
GraphQLite
The idea
Let’s imagine we want to do a simple “echo”
query in PHP.
The idea
Let’s imagine we want to do a simple “echo”
query in PHP.
The idea
Using webonyx/GraphQL-PHP
type Query {
echo(message: String!): String
}
The idea
The same “echo” method in pure PHP
function echoMsg(string $message): string
{
return $message;
}
function echoMsg(string $message): string
{
return $message;
}
The idea
The same “echo” method in pure PHP
Query name
Arguments
Return type
Resolver
The idea
The same “echo” method in pure PHP
/**
* @Query
*/
function echoMsg(string $message): string
{
return $message;
}
The idea
• PHP is already typed.
• We should be able to get types from PHP and
convert them to a GraphQL schema
PHP
objects
GraphQL
objects
GraphQLite
Works well with Doctrine
Bonus:
• It plays nice with Doctrine ORM too
• (we also have native bindings with TDBM, our
in-house ORM)
DB
model
PHP
objects
GraphQL
objects
Doctrine GraphQLite
GraphQLite
GraphQLite is:
• Framework agnostic
• Symfony bundle and Laravel package
available
• PHP 7.2+
• Based on Webonyx/GraphQL-PHP
Demo time!
Our playground
First query
namespace AppController;
use AppEntityPost;
use AppRepositoryPostRepository;
use TheCodingMachineGraphQLiteAnnotationsQuery;
class PostController
{
/**
* @var PostRepository
*/
private $postRepository;
public function __construct(PostRepository $postRepository)
{
$this->postRepository = $postRepository;
}
/**
* @Query()
*/
public function getPosts(?string $search): array
{
return $this->postRepository->findAllFilterBySearch($search);
}
}
First query
First query
namespace AppController;
use AppEntityPost;
use AppRepositoryPostRepository;
use TheCodingMachineGraphQLiteAnnotationsQuery;
class PostController
{
/**
* @var PostRepository
*/
private $postRepository;
public function __construct(PostRepository $postRepository)
{
$this->postRepository = $postRepository;
}
/**
* @Query()
* @return Post[]
*/
public function getPosts(?string $search): array
{
return $this->postRepository->findAllFilterBySearch($search);
}
}
First query
<?php
namespace AppEntity;
use TheCodingMachineGraphQLiteAnnotationsField;
use TheCodingMachineGraphQLiteAnnotationsType;
/**
* @Type()
*/
class Post
{
//…
/**
* @Field(outputType="ID")
*/
public function getId(): int
{
return $this->id;
}
/**
* @Field()
*/
public function getMessage(): string
{
return $this->message;
}
/**
* @Field()
*/
public function getCreated(): DateTimeImmutable
{
return $this->created;
}
}
First query
First query
<?php
namespace AppEntity;
use TheCodingMachineGraphQLiteAnnotationsField;
use TheCodingMachineGraphQLiteAnnotationsType;
/**
* @Type()
*/
class Post
{
// …
/**
* @Field()
*/
public function getAuthor(): User
{
return $this->author;
}
}
First query
First query
<?php
namespace AppEntity;
use TheCodingMachineGraphQLiteAnnotationsField;
use TheCodingMachineGraphQLiteAnnotationsType;
/**
* @Type()
*/
class User implements UserInterface
{
// …
/**
* @Field(outputType="ID!")
*/
public function getId(): int
{
return $this->id;
}
/**
* @Field()
*/
public function getLogin(): string
{
return $this->login;
}
// …
First query
Improving our
sample
Improving our sample
What if I want to get the list of comments from my
“post” type?
(Assuming I have no “getComments” method in
the Post class)
Improving our sample
Say hello to “type extension”!
You can add fields in an existing type, using the
“@ExtendType” annotation.
Improving our sample
namespace AppTypes;
use AppEntityComment;
use AppRepositoryCommentRepository;
use TheCodingMachineGraphQLiteAnnotationsExtendType;
use AppEntityPost;
use TheCodingMachineGraphQLiteAnnotationsField;
/**
* @ExtendType(class=Post::class)
*/
class PostType
{
/**
* @var CommentRepository
*/
private $commentRepository;
public function __construct(CommentRepository $commentRepository)
{
$this->commentRepository = $commentRepository;
}
/**
* @Field()
* @return Comment[]
*/
public function getComments(Post $post): array
{
return $this->commentRepository->findByPost($post);
}
}
Improving our sample
namespace AppTypes;
use AppEntityComment;
use AppRepositoryCommentRepository;
use TheCodingMachineGraphQLiteAnnotationsExtendType;
use AppEntityPost;
use TheCodingMachineGraphQLiteAnnotationsField;
/**
* @ExtendType(class=Post::class)
*/
class PostType
{
/**
* @var CommentRepository
*/
private $commentRepository;
public function __construct(CommentRepository $commentRepository)
{
$this->commentRepository = $commentRepository;
}
/**
* @Field()
* @return Comment[]
*/
public function getComments(Post $post): array
{
return $this->commentRepository->findByPost($post);
}
}
It is a service!
Improving our samplenamespace AppTypes;
use AppEntityComment;
use AppRepositoryCommentRepository;
use TheCodingMachineGraphQLiteAnnotationsExtendType;
use AppEntityPost;
use TheCodingMachineGraphQLiteAnnotationsField;
/**
* @ExtendType(class=Post::class)
*/
class PostType
{
/**
* @var CommentRepository
*/
private $commentRepository;
public function __construct(CommentRepository $commentRepository)
{
$this->commentRepository = $commentRepository;
}
/**
* @Field()
* @return Comment[]
*/
public function getComments(Post $post): array
{
return $this->commentRepository->findByPost($post);
}
}
Current object
is passed as first
parameter
Improving our sample
Improving our sample
Even better: fields can have their own arguments.
For instance, you may want to fetch a paginated
list of comments.
Improving our sample
namespace AppTypes;
use AppEntityComment;
use AppRepositoryCommentRepository;
use TheCodingMachineGraphQLiteAnnotationsExtendType;
use AppEntityPost;
use TheCodingMachineGraphQLiteAnnotationsField;
/**
* @ExtendType(class=Post::class)
*/
class PostType
{
// …
/**
* @Field()
* @return Comment[]
*/
public function getComments(Post $post, int $limit = 20, int $offset = 0): array
{
return $this->commentRepository->findByPost($post)
->setMaxResults($limit)
->setFirstResult($offset)
->getResult();
}
}
From the 2nd parameter,
arguments are added to the field
Improving our sample
Native pagination?
Yes please!
Native pagination
Actually, you don’t even have to bother adding
pagination as GraphQLite integrates natively with
Porpaginas.
(Porpaginas integrates with Doctrine and TDBM)
Native pagination
use PorpaginasDoctrineORMORMQueryResult;
/**
* @ExtendType(class=Post::class)
*/
class PostType
{
// …
/**
* @Field()
* @return Comment[]
*/
public function getComments(Post $post): ORMQueryResult
{
return new ORMQueryResult($this->commentRepository->findByPost($post));
}
}
Needed for Doctrine ORM.
Not even necessary for TDBM 5 ResultIterator’s that can be returned directly.
Authentication and
authorization
Authentication and authorization
@Logged and @Right annotations can be used
with @Field too!
More features?
More features!
TDBM integration
Inheritance / interfaces
More features!
Everything is clearly documented at:
Thanks @JUN for the help
https://graphqlite.thecodingmachine.io
What’s next?
• Release of GraphQLite 4 in June
• Deferred type support
• Injection of services in method
parameters
• Improved performances
• Custom scalar types
• Enum’s support
• …
So… GraphQL
everywhere?
GraphQL everywhere?
• GraphQLite makes it trivial to write a GraphQL
API. It is now easier to start a GraphQL API
than a REST API! o/
• GraphQL makes a lot of sense for most of our
projects because it eases the separation
between front-end and back-end
• And the tooling in JS/TS is awesome
GraphQL everywhere?
• Performance warning! GraphQL itself is fast
but…
• N+1 problem
• It is easy to write slow queries ➔ Warning with
front facing websites.
GraphQL everywhere?
• Two strategies available to avoid the “N+1”
problem:
• Analyzing the GraphQL query and “joining”
accordingly
• Or the “data-loader” pattern
• + a need to set limits on the queries
complexity to avoid “rogue” queries
Questions?
@david_negrier
@moufmouf
graphqlite.thecodingmachine.io
We are hiring!
More cool stuff:
• https://www.thecodingmachine.com/open-source/
• https://thecodingmachine.io
David Négrier
From the client
side
…
Apollo to the
rescue!
Zoom on Apollo
• Apollo is a GraphQL client (it is a JS lib).
• It has bindings with:
• Angular
• React
• VueJS
• You bundle a React/Angular/Vue component
in a Apollo component and Apollo takes in
charge the query to the server
Dependencies in package.json
{
"devDependencies": {
"@symfony/webpack-encore": "^0.22.0",
"axios": "^0.18.0",
"vue": "^2.5.17",
"vue-loader": "^15.4.2",
"vue-router": "^3.0.2",
"vue-template-compiler": "^2.5.17",
"vuex": "^3.0.1",
"webpack-notifier": "^1.6.0",
"apollo-cache-inmemory": "^1.3.12",
"apollo-client": "^2.4.8",
"apollo-link": "^1.2.6",
"apollo-link-http": "^1.5.9",
"graphql": "^14.0.2",
"graphql-tag": "^2.10.0",
"vue-apollo": "^3.0.0-beta.27"
},
"license": "UNLICENSED",
"private": true,
"scripts": {
"dev-server": "encore dev-server",
"dev": "encore dev",
"watch": "encore dev --watch",
"build": "encore production --progress"
}
}
Declarative usage
<template>
<div>
<div class="row col">
<h1>Posts</h1>
</div>
<form>
<div class="form-row">
<div class="col-8">
<input v-model="search" type="text" class="form-control" placeholder="Search">
</div>
</div>
</form>
<ApolloQuery
:query="require('../graphql/posts.gql')"
:variables="{ search }"
>
<template slot-scope="{ result: { loading, error, data } }">
// ……… Do something with {{data}}
</template>
</ApolloQuery>
</div>
</template>
<script>
export default {
name: 'posts',
data () {
return {
search: ''
};
},
}
</script>
graphql/posts.gql
query searchPosts ($search: String) {
posts(search: $search) {
id
message
author {
login
}
comments {
items {
id
message
author {
login
}
}
}
}
}
Declarative usage
<template>
<div>
<div class="row col">
<h1>Posts</h1>
</div>
<form>
<div class="form-row">
<div class="col-8">
<input v-model="search" type="text" class="form-control" placeholder="Search">
</div>
</div>
</form>
<ApolloQuery
:query="require('../graphql/posts.gql')"
:variables="{ search }"
>
<template slot-scope="{ result: { loading, error, data } }">
// ……… Do something with {{data}}
</template>
</ApolloQuery>
</div>
</template>
<script>
export default {
name: 'posts',
data () {
return {
search: ''
};
},
}
</script>
Declarative usage
<ApolloQuery
:query="require('../graphql/posts.gql')"
:variables="{ search }"
>
<template slot-scope="{ result: { loading, error, data } }">
<!-- Loading -->
<div v-if="loading" class="loading apollo row col">Loading...</div>
<!-- Error -->
<div v-else-if="error" class="error apollo row col">An error occurred</div>
<!-- Result -->
<div v-else-if="data" class="result apollo ">
<div v-for="post in data.posts" class="border">
<div class="row">
<div class="col">
<h3>Article</h3>
{{ post.message }}
</div>
</div>
<div class="row col"><em>Authored by: {{ post.author.login }}</em></div>
<div class="row">
<div class="col">
<h3>Comments</h3>
<div v-for="comment in post.comments.items" class="border">
<div class="row border">
<div class="col">
<p>Comment:</p>
{{ comment.message }}
<p>By: {{ comment.author.login }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- No result -->
<div v-else class="no-result apollo">No result :(</div>
</template>
</ApolloQuery>
But where is Redux?
• Apollo comes internally with its own store.
• Redux is really less useful with Apollo and you
can simply scrap ~90% of your reducers.
• Still useful for niche places (like managing the
current logged user)
Questions?
@david_negrier
@moufmouf
graphqlite.thecodingmachine.io
We are hiring!
More cool stuff:
• https://www.thecodingmachine.com/open-source/
• https://thecodingmachine.io
David Négrier

Weitere ähnliche Inhalte

Was ist angesagt?

Was ist angesagt? (20)

Rest API
Rest APIRest API
Rest API
 
Patterns in Eclipse
Patterns in EclipsePatterns in Eclipse
Patterns in Eclipse
 
C++ Restrictions for Game Programming.
C++ Restrictions for Game Programming.C++ Restrictions for Game Programming.
C++ Restrictions for Game Programming.
 
Test Automation - Principles and Practices
Test Automation - Principles and PracticesTest Automation - Principles and Practices
Test Automation - Principles and Practices
 
Engenharia de software
Engenharia de softwareEngenharia de software
Engenharia de software
 
REST API
REST APIREST API
REST API
 
Writing REST APIs with OpenAPI and Swagger Ada
Writing REST APIs with OpenAPI and Swagger AdaWriting REST APIs with OpenAPI and Swagger Ada
Writing REST APIs with OpenAPI and Swagger Ada
 
Soap vs rest
Soap vs restSoap vs rest
Soap vs rest
 
.Net Core
.Net Core.Net Core
.Net Core
 
What is an API
What is an APIWhat is an API
What is an API
 
Hibernate ORM: Tips, Tricks, and Performance Techniques
Hibernate ORM: Tips, Tricks, and Performance TechniquesHibernate ORM: Tips, Tricks, and Performance Techniques
Hibernate ORM: Tips, Tricks, and Performance Techniques
 
REST API and CRUD
REST API and CRUDREST API and CRUD
REST API and CRUD
 
OpenAPI at Scale
OpenAPI at ScaleOpenAPI at Scale
OpenAPI at Scale
 
Test Design and Automation for REST API
Test Design and Automation for REST APITest Design and Automation for REST API
Test Design and Automation for REST API
 
API Presentation
API PresentationAPI Presentation
API Presentation
 
Introduction to Apache Synapse
Introduction to Apache SynapseIntroduction to Apache Synapse
Introduction to Apache Synapse
 
API Basics
API BasicsAPI Basics
API Basics
 
Communication Patterns Using Data-Centric Publish/Subscribe
Communication Patterns Using Data-Centric Publish/SubscribeCommunication Patterns Using Data-Centric Publish/Subscribe
Communication Patterns Using Data-Centric Publish/Subscribe
 
API Docs with OpenAPI 3.0
API Docs with OpenAPI 3.0API Docs with OpenAPI 3.0
API Docs with OpenAPI 3.0
 
BCA IPU VB.NET UNIT-I
BCA IPU VB.NET UNIT-IBCA IPU VB.NET UNIT-I
BCA IPU VB.NET UNIT-I
 

Ähnlich wie PHP, the GraphQL ecosystem and GraphQLite

Rapid API Development ArangoDB Foxx
Rapid API Development ArangoDB FoxxRapid API Development ArangoDB Foxx
Rapid API Development ArangoDB Foxx
Michael Hackstein
 

Ähnlich wie PHP, the GraphQL ecosystem and GraphQLite (20)

Tutorial: Building a GraphQL API in PHP
Tutorial: Building a GraphQL API in PHPTutorial: Building a GraphQL API in PHP
Tutorial: Building a GraphQL API in PHP
 
GraphQL in Ruby on Rails - basics
GraphQL in Ruby on Rails - basicsGraphQL in Ruby on Rails - basics
GraphQL in Ruby on Rails - basics
 
Graphql usage
Graphql usageGraphql usage
Graphql usage
 
apidays LIVE Australia 2020 - Have your cake and eat it too: GraphQL? REST? W...
apidays LIVE Australia 2020 - Have your cake and eat it too: GraphQL? REST? W...apidays LIVE Australia 2020 - Have your cake and eat it too: GraphQL? REST? W...
apidays LIVE Australia 2020 - Have your cake and eat it too: GraphQL? REST? W...
 
Graphql presentation
Graphql presentationGraphql presentation
Graphql presentation
 
GraphQL - The new "Lingua Franca" for API-Development
GraphQL - The new "Lingua Franca" for API-DevelopmentGraphQL - The new "Lingua Franca" for API-Development
GraphQL - The new "Lingua Franca" for API-Development
 
Rapid API Development ArangoDB Foxx
Rapid API Development ArangoDB FoxxRapid API Development ArangoDB Foxx
Rapid API Development ArangoDB Foxx
 
Polyglot Grails
Polyglot GrailsPolyglot Grails
Polyglot Grails
 
CONDG April 23 2020 - Baskar Rao - GraphQL
CONDG April 23 2020 - Baskar Rao - GraphQLCONDG April 23 2020 - Baskar Rao - GraphQL
CONDG April 23 2020 - Baskar Rao - GraphQL
 
Elixir absinthe-basics
Elixir absinthe-basicsElixir absinthe-basics
Elixir absinthe-basics
 
GraphQL Introduction
GraphQL IntroductionGraphQL Introduction
GraphQL Introduction
 
Building a GraphQL API in PHP
Building a GraphQL API in PHPBuilding a GraphQL API in PHP
Building a GraphQL API in PHP
 
GraphQL Europe Recap
GraphQL Europe RecapGraphQL Europe Recap
GraphQL Europe Recap
 
Hands On - GraphQL
Hands On - GraphQLHands On - GraphQL
Hands On - GraphQL
 
Cascalog at Strange Loop
Cascalog at Strange LoopCascalog at Strange Loop
Cascalog at Strange Loop
 
About Clack
About ClackAbout Clack
About Clack
 
GraphQL - A query language to empower your API consumers (NDC Sydney 2017)
GraphQL - A query language to empower your API consumers (NDC Sydney 2017)GraphQL - A query language to empower your API consumers (NDC Sydney 2017)
GraphQL - A query language to empower your API consumers (NDC Sydney 2017)
 
Implementing OpenAPI and GraphQL services with gRPC
Implementing OpenAPI and GraphQL services with gRPCImplementing OpenAPI and GraphQL services with gRPC
Implementing OpenAPI and GraphQL services with gRPC
 
GraphQL + relay
GraphQL + relayGraphQL + relay
GraphQL + relay
 
Getting Started with Spring for GraphQL
Getting Started with Spring for GraphQLGetting Started with Spring for GraphQL
Getting Started with Spring for GraphQL
 

Mehr von JEAN-GUILLAUME DUJARDIN

Mehr von JEAN-GUILLAUME DUJARDIN (16)

Do you speak technique ?
Do you speak technique ?Do you speak technique ?
Do you speak technique ?
 
Methode Agile
Methode Agile Methode Agile
Methode Agile
 
Livre blanc docker
Livre blanc docker Livre blanc docker
Livre blanc docker
 
Conception d'un Extranet
Conception d'un ExtranetConception d'un Extranet
Conception d'un Extranet
 
Etude des Frameworks PHP
Etude des Frameworks PHPEtude des Frameworks PHP
Etude des Frameworks PHP
 
Framework JavaScript Web - Brief techno
Framework JavaScript Web - Brief technoFramework JavaScript Web - Brief techno
Framework JavaScript Web - Brief techno
 
Modèle cahier des charges site web
Modèle cahier des charges site webModèle cahier des charges site web
Modèle cahier des charges site web
 
Gérer un pic d'audience
Gérer un pic d'audienceGérer un pic d'audience
Gérer un pic d'audience
 
3 piliers d'un bon référencement web
3 piliers d'un bon référencement web3 piliers d'un bon référencement web
3 piliers d'un bon référencement web
 
Brief Nouveaux outils collaboratifs
Brief Nouveaux outils collaboratifsBrief Nouveaux outils collaboratifs
Brief Nouveaux outils collaboratifs
 
Livre Blanc Web temps réel - Node JS
Livre Blanc Web temps réel - Node JSLivre Blanc Web temps réel - Node JS
Livre Blanc Web temps réel - Node JS
 
Livre Blanc Sauvetage de projets
Livre Blanc Sauvetage de projetsLivre Blanc Sauvetage de projets
Livre Blanc Sauvetage de projets
 
Intranet 2.0
Intranet 2.0Intranet 2.0
Intranet 2.0
 
Hec Web Marketing
Hec Web MarketingHec Web Marketing
Hec Web Marketing
 
Livre blanc améliorez les performances de vos projets web - v1.1
Livre blanc   améliorez les performances de vos projets web - v1.1Livre blanc   améliorez les performances de vos projets web - v1.1
Livre blanc améliorez les performances de vos projets web - v1.1
 
TCM - Livre blanc sur les plateformes communautaires Open Source
TCM - Livre blanc sur les plateformes communautaires Open SourceTCM - Livre blanc sur les plateformes communautaires Open Source
TCM - Livre blanc sur les plateformes communautaires Open Source
 

Kürzlich hochgeladen

TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 

Kürzlich hochgeladen (20)

TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 

PHP, the GraphQL ecosystem and GraphQLite

  • 1. GraphQL in the PHP ecosystem
  • 3. GraphQL ? • GraphQL is a protocol
  • 4. GraphQL ? • GraphQL is a protocol • It is not: • A fancy new database • A database query language like SQL
  • 5. GraphQL ? • GraphQL is a protocol • GraphQL is a challenger to those other protocols: • REST • Web-services (SOAP/WSDL based)
  • 6. A bit of history Web-services (~1999) • Strongly typed • Self-describing (WSDL) • XML-based
  • 7. A bit of history Web-services (~1999) • Strongly typed • Self-describing (WSDL) • XML-based
  • 8. A bit of history Web-services (~1999) REST (~2005) • Strongly typed • Self-describing (WSDL) • XML-based • Weakly typed • Non self-describing (still OpenAPI for doc) • Mostly JSON based
  • 9. A bit of history Web-services (~1999) REST (~2005) • Strongly typed • Self-describing (WSDL) • XML-based • Weakly typed • Non self-describing (still OpenAPI for doc) • Mostly JSON based
  • 10. A bit of history Web-services (~1999) REST (~2005) GraphQL (2015) • Strongly typed • Self-describing (WSDL) • XML-based • Weakly typed • Non self-describing (still OpenAPI for doc) • Mostly JSON based • Strongly typed • Self-describing • JSON based • + Client driven queries
  • 11. GraphQL ? It is developed by Facebook and was first used in the Facebook API. Facebook also provides: • A JS client (to query a GraphQL server) • A NodeJS server library Tons of server implementations exist.
  • 13. What problem does GraphQL solves? • Your API often changes • You develop a new feature but your API does not exactly respond to your needs.
  • 14. What problem does GraphQL solves? • For instance: you are developing a marketplace. You need a page to display a product, along some company information. /api/product/42 /api/company/35 REST
  • 15. What problem does GraphQL solves? • Alternative, still REST • But what if some pages don’t need the company details? /api/product/42 REST
  • 16. What problem does GraphQL solves? • Yet another alternative, still REST /api/product/42?with_company=true REST Flags hell 😨! Probably one flag per consumer of the API
  • 17. What problem does GraphQL solves? • GraphQL to the rescue! • GraphQL is a paradigm shift. • The client asks for the list of fields it wants. GET /graphql?query= Single endpoint The name of the query is « products » List of fields requested
  • 18. What problem does GraphQL solves? • GraphQL to the rescue! • Another request of the same query with a different set of fields No need to change the code on the server-side! All this data in one API call! GET /graphql?query=
  • 20. Types GraphQL is strongly typed. It comes with a « schema language » but this is rarely used while developing. It is however useful to understand what is going on.
  • 21. ≠ Schema language product(id: 42) { name company { name logo country { name } } } Query language
  • 22. Types Note: • [Product] ➔ an array of Products • String ➔ a string (or null) • String! ➔ a non-nullable string Hence: • [Product!]! ➔ An array (non- nullable) of products that are also non-nullable.
  • 23. Types Some « scalar » types: • ID: a unique identifier (~=String) • String • Int • Float • Boolean No support for « Date » in the standard (but custom types are supported by some implementations)
  • 24. Types Support for “arguments”: • product(id: ID!) ➔ the product query requires an “id” field of type “ID” to be passed.
  • 25. Types Bonus: • Support for interfaces • Support for Union types • Support for “InputType” (to pass complex objects in queries)
  • 26. Mutations So far, we mostly talked about queries (because this is what is fun in GraphQL). GraphQL can also do mutations (to change the state of the DB)
  • 28. Transport is out of scope • You usually do GraphQL over HTTP/HTTPS • But nothing prevents you from using GraphQL over UDP, or mail, …
  • 29. Transport is out of scope • You usually do GraphQL over HTTP/HTTPS • But nothing prevents you from using GraphQL over UDP, or mail, or homing pigeon whatever!
  • 30. Authentication is out of scope • GraphQL does not deal with authentication. • You are free to deal with it in any way you want: • Session-based • or using Oauth2 • or using a token… • Authentication can happen using a REST API, or even using a GraphQL mutation!
  • 31. Pagination is out of scope • GraphQL does not deal with pagination in the standard. • You are free to add limit/offset parameters to your queries • “Relay” is providing some conventions to deal with pagination (more on that later)
  • 33. Ecosystem (a small part of…) Browser GraphQL Client Server GraphQL Middleware DB RelayJS Apollo ReactJS Express- graphql NodeJS Webonyx/ GraphQL- PHP PHP GraphiQL (for dev!)
  • 34. Zoom on GraphQL in PHP Core library Wrapper library • Low level • Parsing • Service requests • Powerful • Feature complete • Hard to use (poor DX) • High level • Opiniated • Easy to use
  • 35. Zoom on GraphQL in PHP Core library Wrapper library • webonyx/graphql-php • De-facto standard in PHP • Youshido/GraphQL •  Abandonned 
  • 36. Zoom on GraphQL in PHP Core library Wrapper library • API Platform (Symfony) • Overblog GraphQL Bundle (Symfony) • Lighthouse (Laravel) • … and now GraphQLite
  • 40. Costs VS benefits Costs Gains Strict types Self-described Client driven Work
  • 41. You need a wrapper library Costs Gains Strict types Self-described Client driven Work GraphQL library
  • 42. Strategies Schema-first Code-first • Design the GraphQL schema first • Find a way to link it to your code • Design your domain code • Generate the schema from the code
  • 43. Strategies Schema-first Code-first • Overblog GraphQL Bundle • Lighthouse • API Platform • GraphQLite
  • 44. Strategies Schema-first Code-first • Overblog GraphQL Bundle • Lighthouse • API Platform • GraphQLite Lighthouse
  • 45. Strategies Schema-first Code-first • Overblog GraphQL Bundle • Lighthouse • API Platform • GraphQLite API Platform
  • 47. The idea Let’s imagine we want to do a simple “echo” query in PHP.
  • 48. The idea Let’s imagine we want to do a simple “echo” query in PHP.
  • 49. The idea Using webonyx/GraphQL-PHP type Query { echo(message: String!): String }
  • 50. The idea The same “echo” method in pure PHP function echoMsg(string $message): string { return $message; }
  • 51. function echoMsg(string $message): string { return $message; } The idea The same “echo” method in pure PHP Query name Arguments Return type Resolver
  • 52. The idea The same “echo” method in pure PHP /** * @Query */ function echoMsg(string $message): string { return $message; }
  • 53. The idea • PHP is already typed. • We should be able to get types from PHP and convert them to a GraphQL schema PHP objects GraphQL objects GraphQLite
  • 54. Works well with Doctrine Bonus: • It plays nice with Doctrine ORM too • (we also have native bindings with TDBM, our in-house ORM) DB model PHP objects GraphQL objects Doctrine GraphQLite
  • 55. GraphQLite GraphQLite is: • Framework agnostic • Symfony bundle and Laravel package available • PHP 7.2+ • Based on Webonyx/GraphQL-PHP
  • 58. First query namespace AppController; use AppEntityPost; use AppRepositoryPostRepository; use TheCodingMachineGraphQLiteAnnotationsQuery; class PostController { /** * @var PostRepository */ private $postRepository; public function __construct(PostRepository $postRepository) { $this->postRepository = $postRepository; } /** * @Query() */ public function getPosts(?string $search): array { return $this->postRepository->findAllFilterBySearch($search); } }
  • 60. First query namespace AppController; use AppEntityPost; use AppRepositoryPostRepository; use TheCodingMachineGraphQLiteAnnotationsQuery; class PostController { /** * @var PostRepository */ private $postRepository; public function __construct(PostRepository $postRepository) { $this->postRepository = $postRepository; } /** * @Query() * @return Post[] */ public function getPosts(?string $search): array { return $this->postRepository->findAllFilterBySearch($search); } }
  • 62. <?php namespace AppEntity; use TheCodingMachineGraphQLiteAnnotationsField; use TheCodingMachineGraphQLiteAnnotationsType; /** * @Type() */ class Post { //… /** * @Field(outputType="ID") */ public function getId(): int { return $this->id; } /** * @Field() */ public function getMessage(): string { return $this->message; } /** * @Field() */ public function getCreated(): DateTimeImmutable { return $this->created; } }
  • 64. First query <?php namespace AppEntity; use TheCodingMachineGraphQLiteAnnotationsField; use TheCodingMachineGraphQLiteAnnotationsType; /** * @Type() */ class Post { // … /** * @Field() */ public function getAuthor(): User { return $this->author; } }
  • 66. First query <?php namespace AppEntity; use TheCodingMachineGraphQLiteAnnotationsField; use TheCodingMachineGraphQLiteAnnotationsType; /** * @Type() */ class User implements UserInterface { // … /** * @Field(outputType="ID!") */ public function getId(): int { return $this->id; } /** * @Field() */ public function getLogin(): string { return $this->login; } // …
  • 69. Improving our sample What if I want to get the list of comments from my “post” type? (Assuming I have no “getComments” method in the Post class)
  • 70. Improving our sample Say hello to “type extension”! You can add fields in an existing type, using the “@ExtendType” annotation.
  • 71. Improving our sample namespace AppTypes; use AppEntityComment; use AppRepositoryCommentRepository; use TheCodingMachineGraphQLiteAnnotationsExtendType; use AppEntityPost; use TheCodingMachineGraphQLiteAnnotationsField; /** * @ExtendType(class=Post::class) */ class PostType { /** * @var CommentRepository */ private $commentRepository; public function __construct(CommentRepository $commentRepository) { $this->commentRepository = $commentRepository; } /** * @Field() * @return Comment[] */ public function getComments(Post $post): array { return $this->commentRepository->findByPost($post); } }
  • 72. Improving our sample namespace AppTypes; use AppEntityComment; use AppRepositoryCommentRepository; use TheCodingMachineGraphQLiteAnnotationsExtendType; use AppEntityPost; use TheCodingMachineGraphQLiteAnnotationsField; /** * @ExtendType(class=Post::class) */ class PostType { /** * @var CommentRepository */ private $commentRepository; public function __construct(CommentRepository $commentRepository) { $this->commentRepository = $commentRepository; } /** * @Field() * @return Comment[] */ public function getComments(Post $post): array { return $this->commentRepository->findByPost($post); } } It is a service!
  • 73. Improving our samplenamespace AppTypes; use AppEntityComment; use AppRepositoryCommentRepository; use TheCodingMachineGraphQLiteAnnotationsExtendType; use AppEntityPost; use TheCodingMachineGraphQLiteAnnotationsField; /** * @ExtendType(class=Post::class) */ class PostType { /** * @var CommentRepository */ private $commentRepository; public function __construct(CommentRepository $commentRepository) { $this->commentRepository = $commentRepository; } /** * @Field() * @return Comment[] */ public function getComments(Post $post): array { return $this->commentRepository->findByPost($post); } } Current object is passed as first parameter
  • 75. Improving our sample Even better: fields can have their own arguments. For instance, you may want to fetch a paginated list of comments.
  • 76. Improving our sample namespace AppTypes; use AppEntityComment; use AppRepositoryCommentRepository; use TheCodingMachineGraphQLiteAnnotationsExtendType; use AppEntityPost; use TheCodingMachineGraphQLiteAnnotationsField; /** * @ExtendType(class=Post::class) */ class PostType { // … /** * @Field() * @return Comment[] */ public function getComments(Post $post, int $limit = 20, int $offset = 0): array { return $this->commentRepository->findByPost($post) ->setMaxResults($limit) ->setFirstResult($offset) ->getResult(); } } From the 2nd parameter, arguments are added to the field
  • 79. Native pagination Actually, you don’t even have to bother adding pagination as GraphQLite integrates natively with Porpaginas. (Porpaginas integrates with Doctrine and TDBM)
  • 80. Native pagination use PorpaginasDoctrineORMORMQueryResult; /** * @ExtendType(class=Post::class) */ class PostType { // … /** * @Field() * @return Comment[] */ public function getComments(Post $post): ORMQueryResult { return new ORMQueryResult($this->commentRepository->findByPost($post)); } } Needed for Doctrine ORM. Not even necessary for TDBM 5 ResultIterator’s that can be returned directly.
  • 81.
  • 83. Authentication and authorization @Logged and @Right annotations can be used with @Field too!
  • 86. More features! Everything is clearly documented at: Thanks @JUN for the help https://graphqlite.thecodingmachine.io
  • 87. What’s next? • Release of GraphQLite 4 in June • Deferred type support • Injection of services in method parameters • Improved performances • Custom scalar types • Enum’s support • …
  • 89. GraphQL everywhere? • GraphQLite makes it trivial to write a GraphQL API. It is now easier to start a GraphQL API than a REST API! o/ • GraphQL makes a lot of sense for most of our projects because it eases the separation between front-end and back-end • And the tooling in JS/TS is awesome
  • 90. GraphQL everywhere? • Performance warning! GraphQL itself is fast but… • N+1 problem • It is easy to write slow queries ➔ Warning with front facing websites.
  • 91. GraphQL everywhere? • Two strategies available to avoid the “N+1” problem: • Analyzing the GraphQL query and “joining” accordingly • Or the “data-loader” pattern • + a need to set limits on the queries complexity to avoid “rogue” queries
  • 92. Questions? @david_negrier @moufmouf graphqlite.thecodingmachine.io We are hiring! More cool stuff: • https://www.thecodingmachine.com/open-source/ • https://thecodingmachine.io David Négrier
  • 94. Zoom on Apollo • Apollo is a GraphQL client (it is a JS lib). • It has bindings with: • Angular • React • VueJS • You bundle a React/Angular/Vue component in a Apollo component and Apollo takes in charge the query to the server
  • 95. Dependencies in package.json { "devDependencies": { "@symfony/webpack-encore": "^0.22.0", "axios": "^0.18.0", "vue": "^2.5.17", "vue-loader": "^15.4.2", "vue-router": "^3.0.2", "vue-template-compiler": "^2.5.17", "vuex": "^3.0.1", "webpack-notifier": "^1.6.0", "apollo-cache-inmemory": "^1.3.12", "apollo-client": "^2.4.8", "apollo-link": "^1.2.6", "apollo-link-http": "^1.5.9", "graphql": "^14.0.2", "graphql-tag": "^2.10.0", "vue-apollo": "^3.0.0-beta.27" }, "license": "UNLICENSED", "private": true, "scripts": { "dev-server": "encore dev-server", "dev": "encore dev", "watch": "encore dev --watch", "build": "encore production --progress" } }
  • 96. Declarative usage <template> <div> <div class="row col"> <h1>Posts</h1> </div> <form> <div class="form-row"> <div class="col-8"> <input v-model="search" type="text" class="form-control" placeholder="Search"> </div> </div> </form> <ApolloQuery :query="require('../graphql/posts.gql')" :variables="{ search }" > <template slot-scope="{ result: { loading, error, data } }"> // ……… Do something with {{data}} </template> </ApolloQuery> </div> </template> <script> export default { name: 'posts', data () { return { search: '' }; }, } </script>
  • 97. graphql/posts.gql query searchPosts ($search: String) { posts(search: $search) { id message author { login } comments { items { id message author { login } } } } }
  • 98. Declarative usage <template> <div> <div class="row col"> <h1>Posts</h1> </div> <form> <div class="form-row"> <div class="col-8"> <input v-model="search" type="text" class="form-control" placeholder="Search"> </div> </div> </form> <ApolloQuery :query="require('../graphql/posts.gql')" :variables="{ search }" > <template slot-scope="{ result: { loading, error, data } }"> // ……… Do something with {{data}} </template> </ApolloQuery> </div> </template> <script> export default { name: 'posts', data () { return { search: '' }; }, } </script>
  • 99. Declarative usage <ApolloQuery :query="require('../graphql/posts.gql')" :variables="{ search }" > <template slot-scope="{ result: { loading, error, data } }"> <!-- Loading --> <div v-if="loading" class="loading apollo row col">Loading...</div> <!-- Error --> <div v-else-if="error" class="error apollo row col">An error occurred</div> <!-- Result --> <div v-else-if="data" class="result apollo "> <div v-for="post in data.posts" class="border"> <div class="row"> <div class="col"> <h3>Article</h3> {{ post.message }} </div> </div> <div class="row col"><em>Authored by: {{ post.author.login }}</em></div> <div class="row"> <div class="col"> <h3>Comments</h3> <div v-for="comment in post.comments.items" class="border"> <div class="row border"> <div class="col"> <p>Comment:</p> {{ comment.message }} <p>By: {{ comment.author.login }}</p> </div> </div> </div> </div> </div> </div> </div> <!-- No result --> <div v-else class="no-result apollo">No result :(</div> </template> </ApolloQuery>
  • 100. But where is Redux? • Apollo comes internally with its own store. • Redux is really less useful with Apollo and you can simply scrap ~90% of your reducers. • Still useful for niche places (like managing the current logged user)
  • 101. Questions? @david_negrier @moufmouf graphqlite.thecodingmachine.io We are hiring! More cool stuff: • https://www.thecodingmachine.com/open-source/ • https://thecodingmachine.io David Négrier