Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building tools for GraphQL

Building tools for GraphQL

Adopting GraphQL can be fairly demanding and it takes some time to find the right tooling. What can we do to improve DX and supercharge our GraphQL development? Let's deep-dive into GraphQL tooling that help us building GraphQL at scale.

Glenn Reyes

October 19, 2018
Tweet

More Decks by Glenn Reyes

Other Decks in Programming

Transcript

  1. Setup the server 1. Install GraphQL server 2. Configure server

    3. Setup an IDE 4. Install build & type system 5. Configure build & type system 6. ...
  2. const { GraphQLServer } = require('graphql-yoga'); const typeDefs = `

    type Query { hello(name: String): String! } `; const resolvers = { Query: { hello: (_, { name }) => `Hello ${name || 'World'}`, }, }; const server = new GraphQLServer({ typeDefs, resolvers }); server.start(() => console.log('Server is running on localhost:4000'));
  3. const { GraphQLServer } = require('graphql-yoga'); const typeDefs = `

    type Query { hello(name: String): String! } `; const resolvers = { Query: { hello: (_, { name }) => `Hello ${name || 'World'}`, }, }; const server = new GraphQLServer({ typeDefs, resolvers }); server.start(() => console.log('Server is running on localhost:4000')); const { GraphQLServer } = require('graphql-yoga');
  4. const { GraphQLServer } = require('graphql-yoga'); const typeDefs = `

    type Query { hello(name: String): String! } `; const resolvers = { Query: { hello: (_, { name }) => `Hello ${name || 'World'}`, }, }; const server = new GraphQLServer({ typeDefs, resolvers }); server.start(() => console.log('Server is running on localhost:4000')); 
 
 const typeDefs = ` type Query { hello(name: String): String! } `;
  5. const { GraphQLServer } = require('graphql-yoga'); const typeDefs = `

    type Query { hello(name: String): String! } `; const resolvers = { Query: { hello: (_, { name }) => `Hello ${name || 'World'}`, }, }; const server = new GraphQLServer({ typeDefs, resolvers }); server.start(() => console.log('Server is running on localhost:4000')); 
 
 
 
 
 
 
 const resolvers = { Query: { hello: (_, { name }) => `Hello ${name || 'World'}`, }, };
  6. const { GraphQLServer } = require('graphql-yoga'); const typeDefs = `

    type Query { hello(name: String): String! } `; const resolvers = { Query: { hello: (_, { name }) => `Hello ${name || 'World'}`, }, }; const server = new GraphQLServer({ typeDefs, resolvers }); server.start(() => console.log('Server is running on localhost:4000')); 
 
 
 
 
 
 
 
 
 
 
 
 
 const server = new GraphQLServer({ typeDefs, resolvers }); server.start(() => console.log('Server is running on localhost:4000'));
  7. graphql-yoga ✅ GraphQL Server ✅ IDE (Playground) ❌ GraphQL imports

    ❌ Live reloading ❌ Babel (Latest ES features)
  8. const { ApolloServer, gql } = require('apollo-server'); const typeDefs =

    gql` type Query { "A simple type for getting started!" hello: String } `; const resolvers = { Query: { hello: () => 'world', }, }; const server = new ApolloServer({ typeDefs, resolvers, }); server.listen().then(({ url }) => { console.log(` Server ready at ${url}`); });
  9. const { ApolloServer, gql } = require('apollo-server'); const typeDefs =

    gql` type Query { "A simple type for getting started!" hello: String } `; const resolvers = { Query: { hello: () => 'world', }, }; const server = new ApolloServer({ typeDefs, resolvers, }); server.listen().then(({ url }) => { console.log(` Server ready at ${url}`); }); const { ApolloServer, gql } = require('apollo-server');
  10. const { ApolloServer, gql } = require('apollo-server'); const typeDefs =

    gql` type Query { "A simple type for getting started!" hello: String } `; const resolvers = { Query: { hello: () => 'world', }, }; const server = new ApolloServer({ typeDefs, resolvers, }); server.listen().then(({ url }) => { console.log(` Server ready at ${url}`); }); 
 
 const typeDefs = gql` type Query { "A simple type for getting started!" hello: String } `;
  11. const { ApolloServer, gql } = require('apollo-server'); const typeDefs =

    gql` type Query { "A simple type for getting started!" hello: String } `; const resolvers = { Query: { hello: () => 'world', }, }; const server = new ApolloServer({ typeDefs, resolvers, }); server.listen().then(({ url }) => { console.log(` Server ready at ${url}`); }); 
 
 
 
 
 
 
 
 const resolvers = { Query: { hello: () => 'world', }, };
  12. const { ApolloServer, gql } = require('apollo-server'); const typeDefs =

    gql` type Query { "A simple type for getting started!" hello: String } `; const resolvers = { Query: { hello: () => 'world', }, }; const server = new ApolloServer({ typeDefs, resolvers, }); server.listen().then(({ url }) => { console.log(` Server ready at ${url}`); }); 
 
 
 
 
 
 
 
 
 
 
 
 
 
 const server = new ApolloServer({ typeDefs, resolvers, }); server.listen().then(({ url }) => { console.log(` Server ready at ${url}`); });
  13. apollo-server ✅ GraphQL Server ✅ IDE (Playground) ❌ GraphQL imports

    ❌ Live reloading ❌ Babel (Latest ES features)
  14. apollo-server backpack ✅ GraphQL Server ✅ IDE (GraphiQL, Playground) ❌

    GraphQL imports ✅ Live reloading ✅ Babel (Latest ES features) ✅ Live reloading ✅ Babel (Latest ES features)
  15. apollo-server
 backpack graphql-tag/loader ✅ GraphQL Server ✅ IDE (GraphiQL, Playground)

    ✅ GraphQL imports ✅ Live reloading ✅ Babel (Latest ES features)
  16. Look up what we need & install Write down all

    the boilerplate code Set up and configure build system Check if everything works as expected
  17. Setup the server 1. Install GraphQL server 2. Configure server

    3. Setup an IDE 4. Install build & type system 5. Configure build & type system 6. ...
  18. Setup the server 1. Install GraphQL server 2. Configure server

    3. Setup an IDE 4. Install build & type system 5. Configure build & type system 6. ...
  19. #!/usr/bin/env node const nodemon = require('nodemon'); const webpack = require('webpack');

    const config = require('../webpack.config'); const compiler = webpack(config); const serverPaths = Object.keys(compiler.options.entry).map(entry => path.join(compiler.options.output.path, `${entry}.js`), ); compiler.watch( config.watchOptions, once((error, stats) => { if (error || stats.hasErrors()) { throw Error(error || stats.toJson().errors); } nodemon({ script: serverPaths[0], watch: serverPaths }).on( 'quit', process.exit, ); }), );
  20. #!/usr/bin/env node const nodemon = require('nodemon'); const webpack = require('webpack');

    const config = require('../webpack.config'); const compiler = webpack(config); const serverPaths = Object.keys(compiler.options.entry).map(entry => path.join(compiler.options.output.path, `${entry}.js`), ); compiler.watch( config.watchOptions, once((error, stats) => { if (error || stats.hasErrors()) { throw Error(error || stats.toJson().errors); } nodemon({ script: serverPaths[0], watch: serverPaths }).on( 'quit', process.exit, ); }), ); 
 
 
 
 const compiler = webpack(config); 
 
 
 compiler.watch( 
 
 
 
 nodemon( 
 ); }), ); webpack
  21. Entry file: server.js import { ApolloServer } from 'apollo-server'; import

    { resolvers, typeDefs } from './srcFiles'; const server = new ApolloServer({ typeDefs, resolvers }); server .listen({ port: 4000 }) .then(({ url }) => console.log(` Server ready at ${url}`)); export default server;
  22. Entry file: server.js import { ApolloServer } from 'apollo-server'; import

    { resolvers, typeDefs } from './srcFiles'; const server = new ApolloServer({ typeDefs, resolvers }); server .listen({ port: 4000 }) .then(({ url }) => console.log(` Server ready at ${url}`)); export default server; import { resolvers, typeDefs } from './srcFiles';
  23. Importing typeDefs & resolvers const importFirst = req => req.keys().map(mod

    => req(mod).default || req(mod))[0]; export const resolvers = importFirst( require.context( process.env.GRAPHPACK_SRC_DIR, true, /^\.\/(resolvers|resolvers\/index)\.(js|ts)$/, ), );
 export const typeDefs = importFirst( require.context( process.env.GRAPHPACK_SRC_DIR, true, /^\.\/(schema|schema\/index)\.(graphql|js|ts)$/, ), );
  24. Importing typeDefs & resolvers const importFirst = req => req.keys().map(mod

    => req(mod).default || req(mod))[0]; export const resolvers = importFirst( require.context( process.env.GRAPHPACK_SRC_DIR, true, /^\.\/(resolvers|resolvers\/index)\.(js|ts)$/, ), );
 export const typeDefs = importFirst( require.context( process.env.GRAPHPACK_SRC_DIR, true, /^\.\/(schema|schema\/index)\.(graphql|js|ts)$/, ), ); 
 
 
 
 require.context(
 
 
 
 )
 
 
 
 require.context(
 
 
 
 )
  25. Wrap up ⭐ Start with zero configuration ⭐ Run the

    server by a single command ⭐ Hide all the boilerplate code ⭐ Focus on writing GraphQL
  26. import gql from 'graphql-tag'; import { Query } from 'react-apollo';

    const getTalks = gql` query getTalks { talks { title speaker { name } } } `; const Talks = () => ( <Query query={getTalks}> {({ loading, error, data }) => { if (loading) return 'Loading...'; if (error) return `Error! ${error.message}`; return data.talks.map(talk => ( <article> <h4>{talk.title}</h4> <p>By {talk.speaker.name}</p> </article> )); }} </Query> );
  27. import gql from 'graphql-tag'; import { Query } from 'react-apollo';

    const getTalks = gql` query getTalks { talks { title speaker { name } } } `; const Talks = () => ( <Query query={getTalks}> {({ loading, error, data }) => { if (loading) return 'Loading...'; if (error) return `Error! ${error.message}`; return data.talks.map(talk => ( <article> <h4>{talk.title}</h4> <p>By {talk.speaker.name}</p> </article> )); }} </Query> ); import gql from 'graphql-tag'; import { Query } from 'react-apollo';
  28. import gql from 'graphql-tag'; import { Query } from 'react-apollo';

    const getTalks = gql` query getTalks { talks { title speaker { name } } } `; const Talks = () => ( <Query query={getTalks}> {({ loading, error, data }) => { if (loading) return 'Loading...'; if (error) return `Error! ${error.message}`; return data.talks.map(talk => ( <article> <h4>{talk.title}</h4> <p>By {talk.speaker.name}</p> </article> )); }} </Query> ); 
 
 const getTalks = gql` query getTalks { talks { title speaker { name } } } `;
  29. import gql from 'graphql-tag'; import { Query } from 'react-apollo';

    const getTalks = gql` query getTalks { talks { title speaker { name } } } `; const Talks = () => ( <Query query={getTalks}> {({ loading, error, data }) => { if (loading) return 'Loading...'; if (error) return `Error! ${error.message}`; return data.talks.map(talk => ( <article> <h4>{talk.title}</h4> <p>By {talk.speaker.name}</p> </article> )); }} </Query> ); 
 
 
 
 
 
 
 
 
 
 
 
 
 const Talks = () => ( <Query query={getTalks}> {({ loading, error, data }) => { if (loading) return 'Loading...'; if (error) return `Error! ${error.message}`; return data.talks.map(talk => ( <article> <h4>{talk.title}</h4> <p>By {talk.speaker.name}</p> </article> )); }} </Query> );
  30. const Talks = () => ( <Query query={getTalks}> {({ loading,

    error, data }) => { if (loading) return 'Loading...'; if (error) return `Error! ${error.message}`; return data.talks.map(talk => ( <article> <h4>{talk.title}</h4> <p>By {talk.speaker.name}</p> </article> )); }} </Query> ); 
 query={getTalks}
  31. import gql from 'graphql-tag';
 
 const TalksQuery = gql` query

    getTalks { talks { title speaker { name } } } `;
  32. Takeaways ⚡ Automate repetitive tasks ⚡ Build tools to reduce

    boilerplate code ⚡ Make them open source ⚡ Focus on writing GraphQL code ⚡ Less code === less bugs