3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 1/48
@chrisbiscardi
PARALLELIZINGPRODUCT DEVELOPMENT
WITH GRAPHQL
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 2/48
�CHRISBISCARDI
honeycomb.iocoffee@chrisbiscardibiscarch
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 3/48
APPLICATIONARCHITECTURE
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 4/48
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 5/48
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 6/48
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 7/48
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 8/48
SCHEMA DEFINITION LANGUAGE
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 9/48
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 10/48
Queries
drafts
title
{
{
}
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 11/48
Results
{
"data" {
"drafts": [{
"title": "Solving World Hunger"
}]
}
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 12/48
blog schematype Post
String
String
DateTime
Int
Blog
type Blog
String
String
String
Post
{
id: !
title: !
publishedAt: !
likes: ! @default(value: 0)
blog: @relation(name: "Posts")
}
{
id: !
name: !
description: ,
posts: [ !]! @relation(name: "Posts")
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 13/48
Arrays
Post
type Post { Stringid: ! Stringtitle: ! DateTimepublishedAt: ! Int likes: ! @default(value: 0) Blog blog: @relation(name: "Posts")}type Blog { Stringid: ! Stringname: ! Stringdescription: ,
}posts: [ !]! @relation(name: "Posts")
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 14/48
DIRECTIVESEVERYTHING ELSE
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 15/48
RESOLVERS
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 16/48
Trivial ResolversHuman
obj args context
obj name
: {
name( , , ) {
return .
}
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 17/48
Async Resolversobj args context
context db args id
userData userData
human( , , ) {
return . .loadHumanByID( . ).then(
=> new Human( )
)
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 18/48
directive on FIELD_DEFINITION
type Query
String
Directive Resolvers@upper
{
hello: @upper
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 19/48
next src args context
str
str
str
str
Directive Resolversupper( , , , ) {
return next().then(( ) => {
if (typeof( ) === 'string') {
return .toUpperCase();
}
return ;
});
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 20/48
SCENARIO 1
A New Product
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 21/48
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 22/48
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 23/48
mysql query
accounts
posts id authorId
id ${obj id}
isPublished
${args skip}
Resolving with SQLreturn . (`SELECT
"user"."id" AS "id",
"posts"."id" AS "postId",
"posts"."title" AS "postTitle",
"posts"."body" AS "postText",
"posts"."tags" AS "postTags",
"posts"."created" AS "postCreated",
FROM AS "user"
LEFT JOIN ON "user". = "posts".
WHERE "user". = .
AND = 1
LIMIT . , 1000`)
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 24/48
obj args ctx info
ctx prisma query
where
author id obj id
isPublished
skip args skip
info
SQL with PrismapublicPosts( , , , ) {
return . . .posts(
: {
: { : . },
: true,
},
: . ,
// enables schema stitching
)
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 25/48
prisma init➜ prisma init full-03
? How to set up a new Prisma service?
Minimal setup: database-only
❯ GraphQL server/fullstack boilerplate (recommended)
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 26/48
prisma init➜ prisma init full-03
? How to set up a new Prisma service?
Running $ graphql create ...
? Choose GraphQL boilerplate project:
❯ node-basic Basic GraphQL server (incl.
database)
node-advanced GraphQL server (incl. database &
authentication)
typescript-basic Basic GraphQL server (incl.
database)
typescript-advanced GraphQL server (incl. database &
authentication)
react-fullstack-basic React app + GraphQL server (incl.
database )
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 27/48
prisma deploy[graphql create] Running boilerplate install script...
Running $ prisma deploy...
? Please choose the cluster you want to deploy "full-03@dev"
to
prisma-eu1 Public development cluster
prisma-us1 Public development cluster
❯ local Local cluster (requires Docker)
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 28/48
prisma deployChanges:
Post (Type)
+ Created type `Post`
+ Created field `id` of type `GraphQLID!`
+ Created field `isPublished` of type `Boolean!`
+ Created field `title` of type `String!`
+ Created field `text` of type `String!`
+ Created field `updatedAt` of type `DateTime!`
+ Created field `createdAt` of type `DateTime!`
Applying changes 1.1s
Hooks:
Importing seed dataset from `seed.graphql` 498ms
Writing database schema to `src/generated/prisma.graphql`
0ms
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 29/48
tree . �I node_modules➜ tree . -I node_modules
.
├── README.md ├── database │ ├── datamodel.graphql │ ├── prisma.yml │ └── seed.graphql ├── package.json ├── src │ ├── generated │ │ └── prisma.graphql │ ├── index.js │ └── schema.graphql └── yarn.lock
3 directories, 9 files
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 30/48
Schematype Post
ID
Boolean
String
String
{
id: ! @unique
isPublished: ! @default(value: false)
title: !
text: !
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 31/48
Seeds
createPost
id
createPost
id
createPost
id
mutation {
first: (data: {
title: "Hello World"
text: "This is my first blog post ever!"
isPublished: true
}) {
}
second: (data: {
title: "My Second Post"
text: "My first post was good, but this one is better!"
isPublished: true
}) {
}
third: (data: {
title: "Solving World Hunger"
text: "This is a draft..."
isPublished: false
}) {
}
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 32/48
playground➜ yarn playground
yarn run v1.3.2
$ graphql playground
Serving playground at http://localhost:3000/playground
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 33/48
playgroundbrew cask install graphql-playground
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 34/48
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 35/48
Updatingtype Post
ID
Boolean
String
String
String
{
id: ! @unique
isPublished: ! @default(value: false)
title: ! @deprecated
title2:
text: !
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 36/48
Updating➜ yarn prisma deploy
Changes:
Post (Type)
+ Created field `title2` of type `String`
Applying changes 1.1s
Your GraphQL database endpoint is live:
HTTP: http://localhost:4466/full-03/dev
WS: ws://localhost:4466/full-03/dev
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 37/48
SCENARIO 2
Frontend
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 38/48
graphql-faker
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 39/48
type Person
String firstName
String
Faker Directives{
name: @fake(type: )
gender: @examples(values: ["male", "female"])
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 40/48
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 41/48
Apollo Boostapollo-clientapollo-cache-inmemoryapollo-link-httpapollo-link-errorapollo-link-stategraphql-tag
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 42/48
link-state withClientState
cache
stateLink
cache
resolvers
Mutation
updateNetworkStatus _ isConnected cache
data
networkStatus
__typename
isConnected
cache data
import { } from 'apollo-link-state';
// This is the same cache you pass into new ApolloClient
const = new InMemoryCache(...);
const = withClientState({
,
: {
: {
: ( , { }, { }) =>
{
const = {
: {
: 'NetworkStatus',
},
};
.writeData({ });
return null
},
},
}
});
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 43/48
SCENARIO 3
Go is Awesome!
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 44/48
src/schema.graphql
type Query
Post
Post
post ID Post
type Mutation
createDraft String String Post
deletePost ID Post
publish ID Post
# import Post from "./generated/prisma.graphql"
{
feed: [ !]!
drafts: [ !]!
(id: !):
}
{
(title: !, text: ):
(id: !):
(id: !):
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 45/48
Query
PostsID
PostID
PostsConnectionID
NodeID
PostWhereInput
AND PostWhereInput
OR PostWhereInput
ID
Id_not
Id_in
Id_not_in
Id_lt
gqlgen -out generated.go -package maintype struct {
int
int
int
int
}
type struct {
[]
[]
*string
*string
[]string
[]string
*string
}
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 46/48
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 47/48
[presentation]: Spectacle[diagrams]: whimsical.co
CREDITS
3/6/2018 Spectacle Presentation
http://localhost:3000/#/6?export 48/48
Q & A