SlideShare a Scribd company logo
GraphQL
Consistency through code generation
by Aleksandr Obukhov
Aleksandr Obukhov
Lead Backend Engineer at AMBOSS GmbH
https://github.com/obukhov
@dclg_en
GraphQL
Consistency through code generation
by Aleksandr Obukhov
What is GraphQL?
Rise-your-hands game
Who is well versed with the GraphQL specification?
Who tried to implement GraphQL server with PHP?
Who is supporting GraphQL server in a production environment?
GraphQL
Server implementations are available for multiple languages, including Haskell,
JavaScript, Python, Ruby, Java, C#, Scala, Go, Elixir, Erlang, PHP, and Clojure
- API specification and runtime
- developed by Facebook
- published in 2015
RPC
API Interaction is just a remote
procedure call:
- It has “function name”
- It has arguments
- It has return value (response)
REST
All data is a resource:
- It can be created / read / updated /
deleted
- Resource is identified by URL
- It can be connected to another
resources through relation
Concepts of API
RPC REST
- Versioning of resource schema
- Limited set of operations with
resources
Limitations
- Versioning of endpoints and
response data
- Pre-designed structure of input
and output
Why do we like GraphQL?
Validation of input / output data
Tools: automatic documentation based on schema
Ready-to-be-used specification
Schema defines: data types, abstractions, relations
Operations defined by root Query/Mutation objects
All this can be found in other specifications
Why do we like GraphQL?
Query is disambiguous:
- no wildcard fields – you don’t need resource versions,
- type assertions, interfaces and unions – easy to extend with new types
Nice:
- built-in deprecation mechanism
Instead of implementing complete endpoints, developer defines the way to
resolve relations – easier to reuse code.
Schema definition language is simple and robust
Transport layer
How do we GraphQL?
webonyx/graphql-php
Request
Query
validation
Mapping to
resolvers
Assembling
result
Response
validation &
formatting
Response
Your app API layer
?
Global field resolver to resolve object properties
class DefaultFieldResolver
{
// ...
public function __invoke($source, $args, $context, ResolveInfo $info)
{
$fieldName = $info->fieldName;
$property = null;
if ($source instanceof TypeInterface) {
$method = 'get' . ucfirst($fieldName);
if (!method_exists($source, $method)) {
throw new FieldNotImplemented('Field <' . $fieldName . '> is not implemented for type <' . $info->parentType . '>');
}
$property = call_user_func_array([$source, $method], $args);
}
$fieldValue = $property instanceof Closure ? $property($source, $args, $context, $info) : $property;
return $fieldValue;
}
}
Adapters to represent API objectTypes
class TaxonomyType extends AbstractTaxonomyType
{
/** @var TaxonomyDTO */
private $taxonomy;
// ...
/** @return int */
public function getTreeDepth()
{
return $this->taxonomy->getTreeDepth();
}
/** @return TaxonType[] */
public function getTaxa()
{
return $this->dataLoaderRegistry->get('taxonByParentTaxon')->load($this->taxonomy->getRootTaxonId());
}
}
What are challenges there
Return values is up to your resolver implementation, but still duplicates schema
Resolvers receive validated data, but it is still presented as associative array
All inconsistencies can be spotted in the runtime only
Enum values needs to be duplicated
Input and output types field names needs to be duplicated
You define a set of resolver functions that implement application BL
GraphQL schema: code generation
Tom Landvoigt & Alex Obukhov
What schema defines
Input Object Type
Query Type Mutation Type
EnumInterface Object Type Unions
What schema defines
Input Object Type
input FeedbackInput {
message: String!
type: FeedbackType!
source: FeedbackSource!
}
Query Type
type Query {
user(eid: ID!): User
}
Mutation Type
type Mutation {
submitFeedback(feedback: FeedbackInput!): Boolean
}
Enum
enum Stage {
preclinic
clinic
doctor
}
Interface
interface Entity {
eid: ID!
}
Object Type
type User implements Entity {
eid: ID!
stage: Stage!
firstName: String
lastName: String
}
Code generation: Object Type
type User implements Entity {
eid: ID!
stage: Stage!
firstName: String
lastName: String
}
abstract class AbstractUserType implements EntityInterface
{
/** @return string */
abstract public function getEid();
/** @return string */
abstract public function getStage();
/** @return null|string */
abstract public function getFirstName();
/** @return null|string */
abstract public function getLastName();
}
Abstract class can be extended
by multiple different classes
Code generation: Object Type
class UserType extends AbstractUserType
{
private $user;
/** @return string */
public function getEid()
{
return $this->user->getUuid();
}
...
}
class AdminType extends AbstractUserType
{
private $admin;
/** @return string */
public function getEid()
{
return $this->admin>getExternalId();
}
...
}
Code generation: Interface
interface Entity {
eid: ID!
}
interface EntityInterface
{
/**
* @return string | int
*/
public function getEid();
}
Abstract class implements this
interface automatically
Code generation: Input Object Type
input FeedbackInput {
message: String!
type: FeedbackType!
source: FeedbackSource!
}
class FeedbackInputType
{
/** @var string */
private $message;
/** @var string */
private $type;
/** @var FeedbackSourceType */
private $source;
public function __construct(array $inputValues)
{
$this->message = $inputValues['message'];
$this->type = $inputValues['type'];
$this->source = new FeedbackSourceType(
$inputValues['source']
);
}
Input is wrapped to value object
recursively
Code generation: Enum
enum Stage {
preclinic
clinic
doctor
}
class StageEnum extends Enum
{
const PRECLINIC = 'preclinic';
const CLINIC = 'clinic';
const DOCTOR = 'doctor';
/** @inheritdoc */
public function getValues()
{
return [
self::PRECLINIC,
self::CLINIC,
self::DOCTOR,
];
}
}
Constants can be used to
guarantee the consistency
of schema via static analysis
Code generation: Union
union NodeContent = File | Folder
type Node {
eid: ID!
firstName: String
content: NodeContent
}
class NodeType extends AbstractNodeType
{
/** @return FileType|FolderType */
public function getContents()
{
...
}
}
Union definitions are used to
declare @return in the docblcok
Benefits
- Easier to kick-off new type – just extend and use IDE to create stubs
- Ready-to-be-used value objects for Enum and Input
- Automatic interfaces implementation
- Docblock support for types defined by schema
- Schema inconsistencies can be detected with static code analysis
Thank you! Questions?

More Related Content

PPTX
An Introduction to Functional Programming with Javascript
PPT
Functions in php
PDF
Anonymous Functions in PHP 5.3 - Matthew Weier O’Phinney
PPTX
WHY JAVASCRIPT FUNCTIONAL PROGRAMMING IS SO HARD?
PDF
Object Oriented PHP - PART-2
PDF
Protocol-Oriented Programming in Swift
PPTX
Functional Programming in JavaScript by Luis Atencio
PDF
Protocol in Swift
An Introduction to Functional Programming with Javascript
Functions in php
Anonymous Functions in PHP 5.3 - Matthew Weier O’Phinney
WHY JAVASCRIPT FUNCTIONAL PROGRAMMING IS SO HARD?
Object Oriented PHP - PART-2
Protocol-Oriented Programming in Swift
Functional Programming in JavaScript by Luis Atencio
Protocol in Swift

What's hot (20)

PDF
What You Need to Know about Lambdas
PPT
Php Chapter 2 3 Training
PDF
PHP Unit 3 functions_in_php_2
PDF
Functional Programming in JavaScript
PDF
JavaScript Core
PDF
Client sidescripting javascript
PDF
Functional Javascript
PDF
JavaScript Functions
PDF
Functional Principles for OO Developers
PPTX
Function overloading and overriding
PPT
Class 3 - PHP Functions
ODP
From object oriented to functional domain modeling
PPT
Functions in c++
PDF
Lecture 3 getting_started_with__c_
PDF
JavaScript - Chapter 9 - TypeConversion and Regular Expressions
PPTX
Function overloading
PDF
Contracts in-clojure-pete
PDF
JavaScript For CSharp Developer
PDF
JavaScript - Chapter 6 - Basic Functions
PPTX
Introduction to es6
What You Need to Know about Lambdas
Php Chapter 2 3 Training
PHP Unit 3 functions_in_php_2
Functional Programming in JavaScript
JavaScript Core
Client sidescripting javascript
Functional Javascript
JavaScript Functions
Functional Principles for OO Developers
Function overloading and overriding
Class 3 - PHP Functions
From object oriented to functional domain modeling
Functions in c++
Lecture 3 getting_started_with__c_
JavaScript - Chapter 9 - TypeConversion and Regular Expressions
Function overloading
Contracts in-clojure-pete
JavaScript For CSharp Developer
JavaScript - Chapter 6 - Basic Functions
Introduction to es6
Ad

Similar to PHP: GraphQL consistency through code generation (20)

PPTX
Building a GraphQL API in PHP
PDF
Performant APIs with GraphQL and PHP (Dutch PHP 2019)
PDF
Tutorial: Building a GraphQL API in PHP
PDF
PHP, the GraphQL ecosystem and GraphQLite
PDF
GraphQL-PHP: Dos and don'ts
PDF
PDF
Getting Started with GraphQL && PHP
PDF
apidays LIVE Paris - GraphQL meshes by Jens Neuse
PDF
DEVOXX UK 2018 - GraphQL as an alternative approach to REST
PDF
Graphql, REST and Apollo
PPTX
GraphQL - an elegant weapon... for more civilized age
PDF
Dev sum - Beyond REST with GraphQL in .Net
PDF
GraphQL for Native Apps
PPTX
GraphQL - The new "Lingua Franca" for API-Development
PDF
GraphQL - A love story
PDF
GraphQL Bangkok meetup 5.0
PPTX
gRPC, GraphQL, REST - Which API Tech to use - API Conference Berlin oct 20
PPTX
Introduction to GraphQL
PPTX
Introduction to GraphQL
PPTX
Building a GraphQL API in PHP
Performant APIs with GraphQL and PHP (Dutch PHP 2019)
Tutorial: Building a GraphQL API in PHP
PHP, the GraphQL ecosystem and GraphQLite
GraphQL-PHP: Dos and don'ts
Getting Started with GraphQL && PHP
apidays LIVE Paris - GraphQL meshes by Jens Neuse
DEVOXX UK 2018 - GraphQL as an alternative approach to REST
Graphql, REST and Apollo
GraphQL - an elegant weapon... for more civilized age
Dev sum - Beyond REST with GraphQL in .Net
GraphQL for Native Apps
GraphQL - The new "Lingua Franca" for API-Development
GraphQL - A love story
GraphQL Bangkok meetup 5.0
gRPC, GraphQL, REST - Which API Tech to use - API Conference Berlin oct 20
Introduction to GraphQL
Introduction to GraphQL
Ad

Recently uploaded (20)

PDF
cuic standard and advanced reporting.pdf
PDF
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
PDF
Electronic commerce courselecture one. Pdf
PDF
Transforming Manufacturing operations through Intelligent Integrations
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
solutions_manual_-_materials___processing_in_manufacturing__demargo_.pdf
PPTX
Cloud computing and distributed systems.
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PPTX
Big Data Technologies - Introduction.pptx
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
Telecom Fraud Prevention Guide | Hyperlink InfoSystem
PDF
CIFDAQ's Market Wrap: Ethereum Leads, Bitcoin Lags, Institutions Shift
PPT
Teaching material agriculture food technology
PDF
Chapter 2 Digital Image Fundamentals.pdf
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
AI And Its Effect On The Evolving IT Sector In Australia - Elevate
PDF
HCSP-Presales-Campus Network Planning and Design V1.0 Training Material-Witho...
PDF
Modernizing your data center with Dell and AMD
cuic standard and advanced reporting.pdf
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
Electronic commerce courselecture one. Pdf
Transforming Manufacturing operations through Intelligent Integrations
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
solutions_manual_-_materials___processing_in_manufacturing__demargo_.pdf
Cloud computing and distributed systems.
Understanding_Digital_Forensics_Presentation.pptx
The Rise and Fall of 3GPP – Time for a Sabbatical?
Big Data Technologies - Introduction.pptx
Diabetes mellitus diagnosis method based random forest with bat algorithm
Telecom Fraud Prevention Guide | Hyperlink InfoSystem
CIFDAQ's Market Wrap: Ethereum Leads, Bitcoin Lags, Institutions Shift
Teaching material agriculture food technology
Chapter 2 Digital Image Fundamentals.pdf
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
CIFDAQ's Market Insight: SEC Turns Pro Crypto
AI And Its Effect On The Evolving IT Sector In Australia - Elevate
HCSP-Presales-Campus Network Planning and Design V1.0 Training Material-Witho...
Modernizing your data center with Dell and AMD

PHP: GraphQL consistency through code generation

  • 1. GraphQL Consistency through code generation by Aleksandr Obukhov
  • 2. Aleksandr Obukhov Lead Backend Engineer at AMBOSS GmbH https://github.com/obukhov @dclg_en
  • 3. GraphQL Consistency through code generation by Aleksandr Obukhov
  • 5. Rise-your-hands game Who is well versed with the GraphQL specification? Who tried to implement GraphQL server with PHP? Who is supporting GraphQL server in a production environment?
  • 6. GraphQL Server implementations are available for multiple languages, including Haskell, JavaScript, Python, Ruby, Java, C#, Scala, Go, Elixir, Erlang, PHP, and Clojure - API specification and runtime - developed by Facebook - published in 2015
  • 7. RPC API Interaction is just a remote procedure call: - It has “function name” - It has arguments - It has return value (response) REST All data is a resource: - It can be created / read / updated / deleted - Resource is identified by URL - It can be connected to another resources through relation Concepts of API
  • 8. RPC REST - Versioning of resource schema - Limited set of operations with resources Limitations - Versioning of endpoints and response data - Pre-designed structure of input and output
  • 9. Why do we like GraphQL? Validation of input / output data Tools: automatic documentation based on schema Ready-to-be-used specification Schema defines: data types, abstractions, relations Operations defined by root Query/Mutation objects All this can be found in other specifications
  • 10. Why do we like GraphQL? Query is disambiguous: - no wildcard fields – you don’t need resource versions, - type assertions, interfaces and unions – easy to extend with new types Nice: - built-in deprecation mechanism Instead of implementing complete endpoints, developer defines the way to resolve relations – easier to reuse code. Schema definition language is simple and robust
  • 11. Transport layer How do we GraphQL? webonyx/graphql-php Request Query validation Mapping to resolvers Assembling result Response validation & formatting Response Your app API layer ?
  • 12. Global field resolver to resolve object properties class DefaultFieldResolver { // ... public function __invoke($source, $args, $context, ResolveInfo $info) { $fieldName = $info->fieldName; $property = null; if ($source instanceof TypeInterface) { $method = 'get' . ucfirst($fieldName); if (!method_exists($source, $method)) { throw new FieldNotImplemented('Field <' . $fieldName . '> is not implemented for type <' . $info->parentType . '>'); } $property = call_user_func_array([$source, $method], $args); } $fieldValue = $property instanceof Closure ? $property($source, $args, $context, $info) : $property; return $fieldValue; } }
  • 13. Adapters to represent API objectTypes class TaxonomyType extends AbstractTaxonomyType { /** @var TaxonomyDTO */ private $taxonomy; // ... /** @return int */ public function getTreeDepth() { return $this->taxonomy->getTreeDepth(); } /** @return TaxonType[] */ public function getTaxa() { return $this->dataLoaderRegistry->get('taxonByParentTaxon')->load($this->taxonomy->getRootTaxonId()); } }
  • 14. What are challenges there Return values is up to your resolver implementation, but still duplicates schema Resolvers receive validated data, but it is still presented as associative array All inconsistencies can be spotted in the runtime only Enum values needs to be duplicated Input and output types field names needs to be duplicated You define a set of resolver functions that implement application BL
  • 15. GraphQL schema: code generation Tom Landvoigt & Alex Obukhov
  • 16. What schema defines Input Object Type Query Type Mutation Type EnumInterface Object Type Unions
  • 17. What schema defines Input Object Type input FeedbackInput { message: String! type: FeedbackType! source: FeedbackSource! } Query Type type Query { user(eid: ID!): User } Mutation Type type Mutation { submitFeedback(feedback: FeedbackInput!): Boolean } Enum enum Stage { preclinic clinic doctor } Interface interface Entity { eid: ID! } Object Type type User implements Entity { eid: ID! stage: Stage! firstName: String lastName: String }
  • 18. Code generation: Object Type type User implements Entity { eid: ID! stage: Stage! firstName: String lastName: String } abstract class AbstractUserType implements EntityInterface { /** @return string */ abstract public function getEid(); /** @return string */ abstract public function getStage(); /** @return null|string */ abstract public function getFirstName(); /** @return null|string */ abstract public function getLastName(); } Abstract class can be extended by multiple different classes
  • 19. Code generation: Object Type class UserType extends AbstractUserType { private $user; /** @return string */ public function getEid() { return $this->user->getUuid(); } ... } class AdminType extends AbstractUserType { private $admin; /** @return string */ public function getEid() { return $this->admin>getExternalId(); } ... }
  • 20. Code generation: Interface interface Entity { eid: ID! } interface EntityInterface { /** * @return string | int */ public function getEid(); } Abstract class implements this interface automatically
  • 21. Code generation: Input Object Type input FeedbackInput { message: String! type: FeedbackType! source: FeedbackSource! } class FeedbackInputType { /** @var string */ private $message; /** @var string */ private $type; /** @var FeedbackSourceType */ private $source; public function __construct(array $inputValues) { $this->message = $inputValues['message']; $this->type = $inputValues['type']; $this->source = new FeedbackSourceType( $inputValues['source'] ); } Input is wrapped to value object recursively
  • 22. Code generation: Enum enum Stage { preclinic clinic doctor } class StageEnum extends Enum { const PRECLINIC = 'preclinic'; const CLINIC = 'clinic'; const DOCTOR = 'doctor'; /** @inheritdoc */ public function getValues() { return [ self::PRECLINIC, self::CLINIC, self::DOCTOR, ]; } } Constants can be used to guarantee the consistency of schema via static analysis
  • 23. Code generation: Union union NodeContent = File | Folder type Node { eid: ID! firstName: String content: NodeContent } class NodeType extends AbstractNodeType { /** @return FileType|FolderType */ public function getContents() { ... } } Union definitions are used to declare @return in the docblcok
  • 24. Benefits - Easier to kick-off new type – just extend and use IDE to create stubs - Ready-to-be-used value objects for Enum and Input - Automatic interfaces implementation - Docblock support for types defined by schema - Schema inconsistencies can be detected with static code analysis