SlideShare una empresa de Scribd logo
1 de 33
Descargar para leer sin conexión
GraphQL in production
Stefano Masini
@stefanomasini
16 May 2017
https://creativecommons.org/licenses/by-nc-sa/4.0/
GraphQL
• Alternative to REST
• Space efficient in the network
• Nice way to describe the UI data requirements
• Nice way to organize code on the server
GraphQL
query {
loggedUser {
name
avatarUrl
}
}
Request
{
loggedUser: {
name: "Stefano Masini",
avatarUrl: "http://..."
}
}
Response
GraphQL
Query
Read
Mutation
Write
Subscription
Server-side events
Relay
GraphQL
• Component data requirements
• Communication
• Caching
Transport layer
Application state management
Modern
Balsamiq Cloud
• 26k LOC + actual editor: 130k LOC
• ~ 30 external dependencies (non-trivial ones)

→ 115 deps in package.json 

→ 860 mods in node_modules
• ~200 React Components (spread in 55 files)
• 32 GraphQL mutations
• 25 events
• 120 integration tests → ~80% coverage (server-side)
graphql Other HTTP
operations
mutationsschema
Other HTTP
Redis
Database
notifications
mail
payment
processor
Architecture
AWS / Convox
Hexagonal architecture
adapter
adapter adapter
adapter
adapter
adapter
19 adapters in Cloud
• authentication
• cache
• database
• logging
• mailing
• pub-sub
• routing
• ...
→ Dependency injection
→ GraphQL context
“You wanted a banana
but what you got

was a gorilla
holding the banana
and the entire jungle.”
Joe Armstrong
Dependencies
const ProjectType = new GraphQLObjectType({
name: 'Project',
interfaces: [nodeInterface],
fields: () => ({
id: globalIdField('Project', project => `${project.id}-${project.siteId}`),
properties: {
type: ProjectPropertiesType,
description: 'The project properties that live on the BAS',
resolve: resolveWithLogger('properties', (project, args, { basAdapter, logger }) =>
basAdapter.getProjectProperties(project.id, project.siteId, logger)),
},
lastModified: { type: GraphQLInt, },
mockupCount: { type: GraphQLInt, },
publicView: { type: GraphQLBoolean },
users: {
type: UsersInProjectConnection,
description: 'The users (with roles) belonging to this project.',
resolve: resolveWithLogger('users', (project, args, {db}) =>
connectionFromPromisedArray(
db.queryUsersInProjectByProjectId(project.id), args)),
},
}),
});
A type definition
export default function({SiteType}) {
return buildMutationDefinition({
operationName: 'changeSiteName',
inputFields: {
siteId: { type: new GraphQLNonNull(GraphQLInt) },
name: { type: new GraphQLNonNull(GraphQLString) },
},
outputFields: {
site: {
type: SiteType,
resolve: ({siteId}, _, {db, loggedUser}) => db.querySiteById(siteId),
},
},
});
}
A mutation definition
naming convention
js_src
! mutations
! changeSiteName.js
...
! operations
! changeSiteName.js
...
Type definition
Implementation

(resolver)
An operation
export default function ({db, siteId, name, logger, notificationCentral,
subscriptionsManager, loggedUser, cache, whenFinished}) {
logger.info('performing operation: changeSiteName');
return db.withTransaction(async function () {
let userInSite = await db.queryUserInSiteById(siteId, loggedUser);
if (!userInSite) {
throw new ErrorWithInfo('User does not belong to site', {
detail: `User ${loggedUser.id} not in site ${siteId}`,
code: 'RENAME_SITE_USER_NOT_IN_SITE'
});
}
if (!userInSite.isSiteOwner()) {
throw new ErrorWithInfo('User is not site owner', {
detail: `User ${loggedUser.id} is not owner of site ${siteId}`,
code: 'RENAME_SITE_USER_NOT_SITE_OWNER'
});
}
let site = await db.changeSiteName(siteId, name);
...
await cache.storeSite(site);
await db.addHistoryLine(changeSiteName(siteId, name, loggedUser));
whenFinished(() => {
notificationCentral.notifySiteNameChanged(siteId, name, logger);
});
return {siteId};
});
}
Error management
1. A simple text for the user
• Indicate the next step
2. A detailed text for the server logs
• To help debug the issue
3. A unique error code
• To pinpoint the snippet of code
throw new ErrorWithInfo('User does not belong to site', {
detail: `User ${loggedUser.id} not in site ${siteId}`,
code: 'RENAME_SITE_USER_NOT_IN_SITE'
});
Reactivity
1. Overfetching
mutation
changeUserAvatar
Client Server
event on
channel: Application
forceFetch ALL
2. Specific events
mutation
changeUserAvatar
Client Server
event: userAvatarChanged
channel: Application
forceFetch
UserAvatarComponent
3. Narrow channels
mutation
changeUserAvatar
Client Server
channel: User
event: userAvatarChanged
forceFetch
UserAvatarComponent
A hairy mess
channel user-me
channel user-23
channel user-42
channel site-4
changeUserAvatar
→channel user-x
changeUserName
→channel user-x
changeUserName
→channel user-x
→channel site-y
Frontend
Backend
Reactivity
• Relay Classic: no solution out of the box
• Pub-Sub + forceFetch: a solution but inefficient
• Relay Modern and Apollo: GraphQL Subscriptions
• Live queries: promising, but still open discussion
inherent complexity, deal with it
• dataloader
• https://github.com/facebook/dataloader
• makes GraphQL go O(n) → O(log n)
• ad-hoc caching
• Redis
• Tied to database access
• Ripples through all mutations
• Transactionality
Efficient data access
Testing
DB
Redis Mailing
Notifications
GraphQL
request
Test start
check results
check mocked 

environment
Test runner Server
Regenerate DB
setup A
setup B
setup C
GraphQL request
serve request
cleanup C
cleanup B
cleanup A
Test end
120 tests in < 30 seconds
200 ms per test
Your cool new app
Naming conventions
Default behaviours
ORM
Boilerplate
Automagic caching
Explicit configuration
plain SQL
ad-hoc caching
Cool
Advanced
Productive
Repetitive
Uninteresting
Unsurprising
Predictable
SAFEMAGIC
Be cool, but play safe
Stefano Masini
@stefanomasini
16 May 2017
Y U NO

FEEDBACK

Más contenido relacionado

La actualidad más candente

Live Streaming & Server Sent Events
Live Streaming & Server Sent EventsLive Streaming & Server Sent Events
Live Streaming & Server Sent Events
tkramar
 
Scalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JSScalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JS
Cosmin Mereuta
 

La actualidad más candente (20)

[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
 
How to connect AngularJS to servers
How to connect AngularJS to serversHow to connect AngularJS to servers
How to connect AngularJS to servers
 
API Days Paris - Automatic Testing of (RESTful) API Documentation
API Days Paris - Automatic Testing of (RESTful) API DocumentationAPI Days Paris - Automatic Testing of (RESTful) API Documentation
API Days Paris - Automatic Testing of (RESTful) API Documentation
 
Using Sakai with Multiple Locales
Using Sakai with Multiple LocalesUsing Sakai with Multiple Locales
Using Sakai with Multiple Locales
 
Flask and Angular: An approach to build robust platforms
Flask and Angular:  An approach to build robust platformsFlask and Angular:  An approach to build robust platforms
Flask and Angular: An approach to build robust platforms
 
REST Easy with AngularJS - ng-grid CRUD EXAMPLE
REST Easy with AngularJS - ng-grid CRUD EXAMPLEREST Easy with AngularJS - ng-grid CRUD EXAMPLE
REST Easy with AngularJS - ng-grid CRUD EXAMPLE
 
Retrofit
RetrofitRetrofit
Retrofit
 
運用 Exposed 管理及操作資料庫
運用 Exposed 管理及操作資料庫運用 Exposed 管理及操作資料庫
運用 Exposed 管理及操作資料庫
 
Live Streaming & Server Sent Events
Live Streaming & Server Sent EventsLive Streaming & Server Sent Events
Live Streaming & Server Sent Events
 
Scalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JSScalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JS
 
React native-firebase startup-mtup
React native-firebase startup-mtupReact native-firebase startup-mtup
React native-firebase startup-mtup
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's
 
React for Beginners
React for BeginnersReact for Beginners
React for Beginners
 
ASP.NET WEB API
ASP.NET WEB APIASP.NET WEB API
ASP.NET WEB API
 
Benchx: An XQuery benchmarking web application
Benchx: An XQuery benchmarking web application Benchx: An XQuery benchmarking web application
Benchx: An XQuery benchmarking web application
 
Promises, Promises
Promises, PromisesPromises, Promises
Promises, Promises
 
Javascript Everywhere From Nose To Tail
Javascript Everywhere From Nose To TailJavascript Everywhere From Nose To Tail
Javascript Everywhere From Nose To Tail
 
React redux
React reduxReact redux
React redux
 
Building a Serverless company with Node.js, React and the Serverless Framewor...
Building a Serverless company with Node.js, React and the Serverless Framewor...Building a Serverless company with Node.js, React and the Serverless Framewor...
Building a Serverless company with Node.js, React and the Serverless Framewor...
 
ajax - the basics
ajax - the basicsajax - the basics
ajax - the basics
 

Similar a A real-world Relay application in production - Stefano Masini - Codemotion Amsterdam 2017

Jasigsakai12 columbia-customizes-cas
Jasigsakai12 columbia-customizes-casJasigsakai12 columbia-customizes-cas
Jasigsakai12 columbia-customizes-cas
ellentuck
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 
Google apps script database abstraction exposed version
Google apps script database abstraction   exposed versionGoogle apps script database abstraction   exposed version
Google apps script database abstraction exposed version
Bruce McPherson
 
Web Technologies - forms and actions
Web Technologies -  forms and actionsWeb Technologies -  forms and actions
Web Technologies - forms and actions
Aren Zomorodian
 

Similar a A real-world Relay application in production - Stefano Masini - Codemotion Amsterdam 2017 (20)

GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0
 
Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019
 
Exploring Relay land
Exploring Relay landExploring Relay land
Exploring Relay land
 
FwDays 2021: Metarhia Technology Stack for Node.js
FwDays 2021: Metarhia Technology Stack for Node.jsFwDays 2021: Metarhia Technology Stack for Node.js
FwDays 2021: Metarhia Technology Stack for Node.js
 
GWT Enterprise Edition
GWT Enterprise EditionGWT Enterprise Edition
GWT Enterprise Edition
 
Jasigsakai12 columbia-customizes-cas
Jasigsakai12 columbia-customizes-casJasigsakai12 columbia-customizes-cas
Jasigsakai12 columbia-customizes-cas
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Integrating React.js Into a PHP Application
Integrating React.js Into a PHP ApplicationIntegrating React.js Into a PHP Application
Integrating React.js Into a PHP Application
 
Data models in Angular 1 & 2
Data models in Angular 1 & 2Data models in Angular 1 & 2
Data models in Angular 1 & 2
 
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeGDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
 
Implement Service Broker with Spring Boot #cf_tokyo
Implement Service Broker with Spring Boot #cf_tokyoImplement Service Broker with Spring Boot #cf_tokyo
Implement Service Broker with Spring Boot #cf_tokyo
 
Google apps script database abstraction exposed version
Google apps script database abstraction   exposed versionGoogle apps script database abstraction   exposed version
Google apps script database abstraction exposed version
 
Introduction to CloudStack API
Introduction to CloudStack APIIntroduction to CloudStack API
Introduction to CloudStack API
 
iOS Reactive Cocoa Pipeline
iOS Reactive Cocoa PipelineiOS Reactive Cocoa Pipeline
iOS Reactive Cocoa Pipeline
 
Workshop 27: Isomorphic web apps with ReactJS
Workshop 27: Isomorphic web apps with ReactJSWorkshop 27: Isomorphic web apps with ReactJS
Workshop 27: Isomorphic web apps with ReactJS
 
Use Windows Azure Service Bus, BizTalk Services, Mobile Services, and BizTalk...
Use Windows Azure Service Bus, BizTalk Services, Mobile Services, and BizTalk...Use Windows Azure Service Bus, BizTalk Services, Mobile Services, and BizTalk...
Use Windows Azure Service Bus, BizTalk Services, Mobile Services, and BizTalk...
 
Spring Web Services: SOAP vs. REST
Spring Web Services: SOAP vs. RESTSpring Web Services: SOAP vs. REST
Spring Web Services: SOAP vs. REST
 
Web Technologies - forms and actions
Web Technologies -  forms and actionsWeb Technologies -  forms and actions
Web Technologies - forms and actions
 
Data Modeling and Relational to NoSQL
Data Modeling and Relational to NoSQLData Modeling and Relational to NoSQL
Data Modeling and Relational to NoSQL
 
Scalable Angular 2 Application Architecture
Scalable Angular 2 Application ArchitectureScalable Angular 2 Application Architecture
Scalable Angular 2 Application Architecture
 

Más de Codemotion

Más de Codemotion (20)

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending story
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storia
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard Altwasser
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
 

Último

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 

Último (20)

TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 

A real-world Relay application in production - Stefano Masini - Codemotion Amsterdam 2017

  • 1. GraphQL in production Stefano Masini @stefanomasini 16 May 2017 https://creativecommons.org/licenses/by-nc-sa/4.0/
  • 2. GraphQL • Alternative to REST • Space efficient in the network • Nice way to describe the UI data requirements • Nice way to organize code on the server
  • 3. GraphQL query { loggedUser { name avatarUrl } } Request { loggedUser: { name: "Stefano Masini", avatarUrl: "http://..." } } Response
  • 5. Relay GraphQL • Component data requirements • Communication • Caching Transport layer Application state management Modern
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11. Balsamiq Cloud • 26k LOC + actual editor: 130k LOC • ~ 30 external dependencies (non-trivial ones)
 → 115 deps in package.json 
 → 860 mods in node_modules • ~200 React Components (spread in 55 files) • 32 GraphQL mutations • 25 events • 120 integration tests → ~80% coverage (server-side)
  • 12. graphql Other HTTP operations mutationsschema Other HTTP Redis Database notifications mail payment processor Architecture AWS / Convox
  • 13. Hexagonal architecture adapter adapter adapter adapter adapter adapter 19 adapters in Cloud • authentication • cache • database • logging • mailing • pub-sub • routing • ... → Dependency injection → GraphQL context
  • 14. “You wanted a banana but what you got
 was a gorilla holding the banana and the entire jungle.” Joe Armstrong Dependencies
  • 15. const ProjectType = new GraphQLObjectType({ name: 'Project', interfaces: [nodeInterface], fields: () => ({ id: globalIdField('Project', project => `${project.id}-${project.siteId}`), properties: { type: ProjectPropertiesType, description: 'The project properties that live on the BAS', resolve: resolveWithLogger('properties', (project, args, { basAdapter, logger }) => basAdapter.getProjectProperties(project.id, project.siteId, logger)), }, lastModified: { type: GraphQLInt, }, mockupCount: { type: GraphQLInt, }, publicView: { type: GraphQLBoolean }, users: { type: UsersInProjectConnection, description: 'The users (with roles) belonging to this project.', resolve: resolveWithLogger('users', (project, args, {db}) => connectionFromPromisedArray( db.queryUsersInProjectByProjectId(project.id), args)), }, }), }); A type definition
  • 16. export default function({SiteType}) { return buildMutationDefinition({ operationName: 'changeSiteName', inputFields: { siteId: { type: new GraphQLNonNull(GraphQLInt) }, name: { type: new GraphQLNonNull(GraphQLString) }, }, outputFields: { site: { type: SiteType, resolve: ({siteId}, _, {db, loggedUser}) => db.querySiteById(siteId), }, }, }); } A mutation definition naming convention js_src ! mutations ! changeSiteName.js ... ! operations ! changeSiteName.js ... Type definition Implementation
 (resolver)
  • 17. An operation export default function ({db, siteId, name, logger, notificationCentral, subscriptionsManager, loggedUser, cache, whenFinished}) { logger.info('performing operation: changeSiteName'); return db.withTransaction(async function () { let userInSite = await db.queryUserInSiteById(siteId, loggedUser); if (!userInSite) { throw new ErrorWithInfo('User does not belong to site', { detail: `User ${loggedUser.id} not in site ${siteId}`, code: 'RENAME_SITE_USER_NOT_IN_SITE' }); } if (!userInSite.isSiteOwner()) { throw new ErrorWithInfo('User is not site owner', { detail: `User ${loggedUser.id} is not owner of site ${siteId}`, code: 'RENAME_SITE_USER_NOT_SITE_OWNER' }); } let site = await db.changeSiteName(siteId, name); ... await cache.storeSite(site); await db.addHistoryLine(changeSiteName(siteId, name, loggedUser)); whenFinished(() => { notificationCentral.notifySiteNameChanged(siteId, name, logger); }); return {siteId}; }); }
  • 18. Error management 1. A simple text for the user • Indicate the next step 2. A detailed text for the server logs • To help debug the issue 3. A unique error code • To pinpoint the snippet of code throw new ErrorWithInfo('User does not belong to site', { detail: `User ${loggedUser.id} not in site ${siteId}`, code: 'RENAME_SITE_USER_NOT_IN_SITE' });
  • 20.
  • 21.
  • 22. 1. Overfetching mutation changeUserAvatar Client Server event on channel: Application forceFetch ALL
  • 23. 2. Specific events mutation changeUserAvatar Client Server event: userAvatarChanged channel: Application forceFetch UserAvatarComponent
  • 24. 3. Narrow channels mutation changeUserAvatar Client Server channel: User event: userAvatarChanged forceFetch UserAvatarComponent
  • 26.
  • 27. channel user-me channel user-23 channel user-42 channel site-4 changeUserAvatar →channel user-x changeUserName →channel user-x changeUserName →channel user-x →channel site-y Frontend Backend
  • 28. Reactivity • Relay Classic: no solution out of the box • Pub-Sub + forceFetch: a solution but inefficient • Relay Modern and Apollo: GraphQL Subscriptions • Live queries: promising, but still open discussion inherent complexity, deal with it
  • 29. • dataloader • https://github.com/facebook/dataloader • makes GraphQL go O(n) → O(log n) • ad-hoc caching • Redis • Tied to database access • Ripples through all mutations • Transactionality Efficient data access
  • 30. Testing DB Redis Mailing Notifications GraphQL request Test start check results check mocked 
 environment Test runner Server Regenerate DB setup A setup B setup C GraphQL request serve request cleanup C cleanup B cleanup A Test end 120 tests in < 30 seconds 200 ms per test
  • 32. Naming conventions Default behaviours ORM Boilerplate Automagic caching Explicit configuration plain SQL ad-hoc caching Cool Advanced Productive Repetitive Uninteresting Unsurprising Predictable SAFEMAGIC
  • 33. Be cool, but play safe Stefano Masini @stefanomasini 16 May 2017 Y U NO
 FEEDBACK