{"componentChunkName":"component---src-components-post-tsx","path":"/minimum-viable-graphql-quickstart","result":{"pageContext":{"searchData":[{"id":"cjjg9ui0t303s010375m42b9w","title":"Turn a Browser Window into a Notepad with This One-Liner","slug":"/turn-a-browser-window-into-a-notepad-with-this-one-liner","avatar":"https://s3.amazonaws.com/contentkit/static/cjjg9ui0t303s010375m42b9w/OYIaJ1KK_400x400(1).png","date":"July 1, 2020"},{"id":"cjiy7xl9o17w701039gvl18a5","title":"Creating a Collaborative Editor with Draftjs for Fun","slug":"/draft-js-collaborative-editor","avatar":"https://s3.amazonaws.com/contentkit/static/cjiy7xl9o17w701039gvl18a5/draft-js.png","date":"June 28, 2020"},{"id":"cjeqgfsdsnmx90167n7j290kt","title":"How To Include SASS In Your React Project","slug":"/sass-react-webpack","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfsdsnmx90167n7j290kt/parcel-bundler.png","date":"May 1, 2020"},{"id":"cjiy4tseq0tnw0103bc5s7sxj","title":"How to Add a Loading Indicator to Material Ui's Component","slug":"/creating-a-material-ui-button-with-spinner-that-reflects-loading-state","avatar":"https://s3.amazonaws.com/contentkit/static/cjiy4tseq0tnw0103bc5s7sxj/material-ui.png","date":"January 28, 2020"},{"id":"cjkq4u7470ihr0157ad175b12","title":"Connecting to AWS Lambda via WebSockets","slug":"/connecting-to-aws-lambda-via-websockets","avatar":"https://s3.amazonaws.com/contentkit/static/cjkq4u7470ihr0157ad175b12/MQTT.js.png","date":"January 12, 2020"},{"id":"cjeqgfnhknnpe0199zbfwwkd8","title":"6 Really Cool APIs to Have Fun With","slug":"/cool-apis-to-have-fun-with","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfnhknnpe0199zbfwwkd8/scale-api.png","date":"January 1, 2020"},{"id":"cjeqgftvknnr30199dvw266qh","title":"Installing Node Canvas in AWS Lambda","slug":"/node-canvas-aws-lambda","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgftvknnr30199dvw266qh/aws-lambda.jpg","date":"December 31, 2019"},{"id":"cjn5fv8kl0pfj0124wwebufms","title":"GoLang Cheatsheet","slug":"/golang-cheatsheet","avatar":"https://s3.amazonaws.com/contentkit/static/cjn5fv8kl0pfj0124wwebufms/golang.png","date":"October 13, 2019"},{"id":"cjn15y8740liw0175u3s707eh","title":"Scheduled Jobs & Work Queues With Postgresql","slug":"/scheduled-jobs-work-queues-with-postgresql","avatar":"https://s3.amazonaws.com/contentkit/static/cjn15y8740liw0175u3s707eh/kxHkAenZ_400x400.jpg","date":"October 8, 2019"},{"id":"cjmym86fh0jy1013398nfzuqu","title":"Creating a Bot to Refill Parking Meters Using AWS Lambda","slug":"/creating-a-bot-to-refill-parking-meters-using-aws-lambda","avatar":"https://s3.amazonaws.com/contentkit/static/cjmym86fh0jy1013398nfzuqu/prwHMlRn_400x400.jpg","date":"October 7, 2019"},{"id":"cjmsaqt6l09le01046qeukpp9","title":"The USPS Tracking API: How To Track Packages","slug":"/usps-tracking-api","avatar":"https://s3.amazonaws.com/contentkit/static/cjmsaqt6l09le01046qeukpp9/usps.png","date":"October 3, 2019"},{"id":"cjeqgfuyenmy20167rycnmiql","title":"Stormpath vs Firebase - A Side-By-Side Comparison","slug":"/stormpath-vs-firebase-a-side-by-side-comparison","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfuyenmy20167rycnmiql/m3cEA33V_400x400.jpg","date":"September 2, 2019"},{"id":"cjeqgfv88nnrt01997wxd4rnl","title":"Sending emails with Firebase Cloud Functions","slug":"/firebase-functions-sending-emails","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfv88nnrt01997wxd4rnl/firebase.jpg","date":"September 2, 2019"},{"id":"cjeqgfqjknnq20199oe3zwi37","title":"Deploying To DigitalOcean From Travis","slug":"/deploying-to-digitalocean-travis","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfqjknnq20199oe3zwi37/digitalocean.jpeg","date":"August 25, 2019"},{"id":"cjkvpbr6p06z50181fg7xvsc3","title":"Circumventing AWS Lambda's Bundle Size Limit","slug":"/circumventing-aws-lambdas-bundle-size-limit","avatar":"https://s3.amazonaws.com/contentkit/static/cjkvpbr6p06z50181fg7xvsc3/b2lWK7c0_400x400.png","date":"August 15, 2019"},{"id":"cjiy45h7m0iba0111f5imt5em","title":"A Quick Way to List All Unicode Characters (Javascript)","slug":"/unicode-characters-javascript","avatar":"https://s3.amazonaws.com/contentkit/static/cjiy45h7m0iba0111f5imt5em/unicode.png","date":"July 29, 2019"},{"id":"ci1rxc41tm8yi7nd156pz9dom","title":"Kibana Rest API","slug":"/kibana-rest-api","avatar":"https://s3.amazonaws.com/contentkit/static/ci1rxc41tm8yi7nd156pz9dom/elastic.png","date":"July 24, 2019"},{"id":"cjeqgfjgennmw0199wha3j6u0","title":"Airtable As A Database For Middleman [Tutorial]","slug":"/airtable-middleman-database","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfjgennmw0199wha3j6u0/airtable-books.png","date":"June 1, 2019"},{"id":"cjeqgfj5qnnmr0199vzd85xuo","title":"Building A Multiplayer Game With Three.Js + WebSockets","slug":"/multiplayer-game-threejs","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfj5qnnmr0199vzd85xuo/three.jpg","date":"June 1, 2019"},{"id":"cjeqgfi8hnnml0199f1jyo1p5","title":"The Best Sketch Plugins","slug":"/the-best-sketch-plugins","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfi8hnnml0199f1jyo1p5/sketch.png","date":"June 1, 2019"},{"id":"d9920hsu8y7365frf2c6fxrx2","title":"Configuring Vault by Hashicorp in AWS EC2","slug":"/configuring-vault-by-hashicorp-in-aws-ec2","avatar":"https://s3.amazonaws.com/contentkit/static/d9920hsu8y7365frf2c6fxrx2/vault.png","date":"April 15, 2019"},{"id":"cjeqgfvsfnns00199mlbff48i","title":"Best Zapier Alternatives","slug":"/best-zapier-alternatives","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfvsfnns00199mlbff48i/zapier-alternative-workato.png","date":"January 31, 2019"},{"id":"cjn3l18390lyt0158i8qxs5dc","title":"Running A Simple Node Web Server On AWS EC2","slug":"/running-a-simple-node-web-server-on-aws-ec2","avatar":"https://s3.amazonaws.com/contentkit/static/cjn3l18390lyt0158i8qxs5dc/aws.png","date":"October 11, 2018"},{"id":"cjeqgfr4snmwz01673m8l4i51","title":"Graph.Cool vs Firebase","slug":"/graphcool-vs-firebase","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfr4snmwz01673m8l4i51/graphcool.png","date":"October 7, 2018"},{"id":"cjklurup00k0201739mflg9sz","title":"Accessing Redis on an Aws EC2 Instance from the Outside\t","slug":"/accessing-redis-on-an-aws-ec2-instance-from-the-outside","avatar":"https://s3.amazonaws.com/contentkit/static/cjklurup00k0201739mflg9sz/logo.jpeg","date":"August 9, 2018"},{"id":"cjkfzvvxt08up0191l38aadq4","title":"Using PDFtk in AWS Lamba","slug":"/using-pdftk-in-aws-lamba","avatar":"https://s3.amazonaws.com/contentkit/static/cjkfzvvxt08up0191l38aadq4/pdftk.png","date":"August 4, 2018"},{"id":"cjeqgfqsgnnq70199l4vc6vim","title":"Configuring WebSockets on Elastic Beanstalk/EC2","slug":"/websockets-aws-elasticbeanstalk-ec2","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfqsgnnq70199l4vc6vim/aws.png","date":"July 15, 2018"},{"id":"cjit96q2yk0is0111qpbmw66s","title":"Getting Started With Gmail API","slug":"/gmail-api-quickstart","avatar":"https://s3.amazonaws.com/contentkit/static/cjit96q2yk0is0111qpbmw66s/gmail.png","date":"June 28, 2018"},{"id":"cjeqgfo23nmwd0167ynqe7xi8","title":"5 Tips For Using NextJs","slug":"/5-tips-for-using-nextjs","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfo23nmwd0167ynqe7xi8/bHjpwZem_400x400.png","date":"June 1, 2018"},{"id":"cjhxixcyhw4ze01035butoukz","title":"React unstable_deferredUpdates","slug":"/react-unstable_deferredupdates","avatar":"https://s3.amazonaws.com/contentkit/static/cjhxixcyhw4ze01035butoukz/OYIaJ1KK_400x400(1).png","date":"June 1, 2018"},{"id":"cjeqgflpnnnoy01993y7aez8a","title":"Simple Web Scraping With Javascript","slug":"/simple-web-scraping","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgflpnnnoy01993y7aez8a/developer-tools-scraping.png","date":"May 1, 2018"},{"id":"cjeqgfk9lnnn101994ll4ursr","title":"Easy: Add Firebase Facebook Login To Your React App","slug":"/firebase-facebook-login-react","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfk9lnnn101994ll4ursr/firebase.png","date":"May 1, 2018"},{"id":"cjeqgfiqrnmtj0167dmz5g5dg","title":"The 5 Best Static Site Web Hosts","slug":"/the-5-best-static-site-web-hosts","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfiqrnmtj0167dmz5g5dg/digital-ocean.png","date":"May 1, 2018"},{"id":"cjeqgfmi2nmvs01670pgebekn","title":"Tips and Tricks For Using NightmareJs","slug":"/nightmare-js","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfmi2nmvs01670pgebekn/nightmare.png","date":"May 1, 2018"},{"id":"cjeqgfkqennn60199707yp1fb","title":"Why You Should Create Your Next React Web App With Firebase","slug":"/firebase-react-tutorial","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfkqennn60199707yp1fb/firebase.jpg","date":"May 1, 2018"},{"id":"cjeqgfpr6nnpx019978qzmaok","title":"How to Flush Data From Heroku Redis","slug":"/heroku-redis-flushall","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfpr6nnpx019978qzmaok/3wgIDj3j_400x400.png","date":"April 1, 2018"},{"id":"cjeqgfm8xnnp30199vxndhkgh","title":"5 Ways To Style React Components","slug":"/5-ways-to-style-react-components","avatar":null,"date":"April 1, 2018"},{"id":"cjeqgflz7nmvm0167yo7wsjg3","title":"Delete Spreadsheet Rows For Google Sheets","slug":"/delete-rows-google-sheets","avatar":null,"date":"April 1, 2018"},{"id":"cjeqgfp84nnps0199dvru09ll","title":"Make An Uptime Monitoring Microservice In Under 50 Lines of Code","slug":"/twilio-uptime-monitoring-node-tutorial","avatar":null,"date":"April 1, 2018"},{"id":"cjeqgfri4nnqd0199zsv6a9fl","title":"Hexo - The Best Static Site Generator? ","slug":"/deploy-a-hexo-blog","avatar":null,"date":"April 1, 2018"},{"id":"cjeqgfoygnnpn0199f31dgk9m","title":"Airtable As A Minimum Viable Database For Your ReactJs Project","slug":"/airtable-reactjs","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfoygnnpn0199f31dgk9m/airtable-screenshot.png","date":"March 2, 2018"},{"id":"cjeqgfn6pnmw0016793f81hpx","title":"The Advanced Guide To ReactJs Checkboxes","slug":"/reactjs-checkboxes","avatar":null,"date":"January 20, 2018"},{"id":"cjeqgfe8znnly01991jo5xkxx","title":"Minimum Viable GraphQL QuickStart","slug":"/minimum-viable-graphql-quickstart","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfe8znnly01991jo5xkxx/graphcool-schema.png","date":"January 1, 2018"},{"id":"cjeqgfgegnnmb0199jp3hv2xx","title":"How To Add A Contact Form To Your Ghost Blog","slug":"/ghost-blog-contact-form","avatar":null,"date":"November 1, 2017"},{"id":"cjeqgfmvxnnp90199bdti4r8n","title":"PHP Scraping Tutorial - Scrape Reddit With Goutte","slug":"/php-scraping-tutorial-scrape-reddit-with-goutte","avatar":null,"date":"October 7, 2017"},{"id":"cjeqgfpz1nmwp0167c5j46eij","title":"Cannot read property 'loose' of undefined","slug":"/cannot-read-property-loose-of-undefined","avatar":null,"date":"August 25, 2017"},{"id":"cjeqgftlanmxg0167zipvfzp1","title":"Airtable API Example & Tutorial - Generating Charts","slug":"/airtable-api-example-tutorial","avatar":null,"date":"January 31, 2017"},{"id":"cjeqgfphbnmwk0167ldz2mv2q","title":"React onClick Example and Tutorial","slug":"/react-onclick-example-and-tutorial","avatar":null,"date":"January 2, 2017"},{"id":"cjeqgfq8ynmwu0167z6c51ynp","title":"React Tables - How To Render Tables In ReactJS","slug":"/reactjs-tables","avatar":null,"date":"January 2, 2017"},{"id":"cjeqgfuoznmxu0167ayt2zkc3","title":"How To Add A Class in ReactJS","slug":"/reactjs-add-class","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgfu6gnnrb0199nyrddra0","title":"Fetching Github Blame with the GraphQL API V4","slug":"/github-blame-graphql-api-v4","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgfsmsnnqo0199o2x7dl4x","title":"How To Add Meta Descriptions to Middleman Pages","slug":"/middleman-meta-descriptions","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgfs2wnnqi0199rco2vvz2","title":"Zapier Webhook Post Example & Tutorial","slug":"/zapier-webhook-post-example-tutorial","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgfvhunmy90167t6ouqfmb","title":"Setting Up A Job Queue For A Node App [Tutorial]","slug":"/job-queue-node","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgftbcnnqy0199nc1f92te","title":"NextJs vs Create-React-App - A Side-By-Side Comparison","slug":"/nextjs-vs-create-react-app","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgft2pnnqt01990ty8fmeu","title":"How To Create A Modal In ReactJS [Tutorial]","slug":"/reactjs-modal","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgfugpnnrj0199x7anb33t","title":"How To Use Twilio With ReactJS","slug":"/reactjs-twilio-example-tutorial","avatar":null,"date":"March 14, 2018"}],"post":{"id":"cjeqgfe8znnly01991jo5xkxx","title":"Minimum Viable GraphQL QuickStart","slug":"minimum-viable-graphql-quickstart","published_at":"2018-01-01T21:34:50.595","created_at":"2018-03-14T02:16:23","excerpt":"Minimum Viable GraphQL QuickStart","image":{"id":"cjfxlqioz5gy50179rrqht749","url":"static/cjeqgfe8znnly01991jo5xkxx/graphcool-schema.png"},"posts_tags":[],"date":"January 1, 2018","html":"
We'll use React, GraphQL and Apollo to make a simple counter. We'll also use Graph.Cool as our hosted GraphQL backend. GraphCool is a GraphQL backend as a service, analogous to Firebase.
\nGraphQL. GraphQL enables you to fetch exactly the data that you need from your database, no more or less. GraphQL let's you bundle nested requests into a single request. Instead of requesting users/{userId} and then posts/{postId} you request { users: { posts } } at once.
\nApollo. Apollo is the easiest way to get started with GraphQL. The alternative to Apollo is Relay. In this example, we'll be using apollo-react to build a simple React component that fetches and pushes data to our GraphQL database.
\nGraphCool. GraphCool is analogous to Firebase. If you want to host your own GraphQL server that's fine - but GraphCool is great for prototyping. Unlike Firebase, there's no vendor lock-in with GraphCool. You can swap in an in-house solution later.
\nIf you're familiar with Redux and its syntax connect(mapStateToProps, mapDispatchToProps)(App), client-side graphQL won't be difficult for you to learn.
\nApollo has its own internal redux store. Apollo makes requests to your GraphQL server and intelligently updates it's internal store. Wrapping your React components with Apollo gives you access to Apollo's internal store.
\nThis graphql-react-apollo is a minimum viable example of how you'd use Apollo and GraphQL, client-side. In this example we make a counter that keeps track of button clicks.
\nClone this sample project and and install dependencies:
\ngit clone https://github.com/focuswish/graphql-react-apollo.git \ncd graphql-react-apollo\nnpm install
\n\nCreate a GraphCool account (if you don't already have one). And be sure to install the GraphCool commandline interface.
\nnpm install -g graphcool\ngraphcool auth # login
\nA new GraphCool project comes with User and File schema by default. We're going to initialize a new GraphCool project that adds a Counter schema:
\nFrom graphql-react-apollo issue the following;
\ngraphcool init\nhttps://raw.githubusercontent.com/focuswish/graphql-react-apollo/master/example.graphql
\nThe URI after 'graphcool init' points to schema for a new type, Counter:
\ntype Counter {\n count: Int!\n}
\nIf initializing the new GraphCool project is successful, you should see a Simple and Relay API URI printed in the console that looks something like:
\nSimple API: https://api.graph.cool/simple/v1/cj5d82p4jmjg90127sqeiu4kg\nRelay API: https://api.graph.cool/relay/v1/cj5d82p4jmjg90127sqeiu4kg
\nYou can also access your simple and relay API URIs from the GraphCool Console.
\nCopy + paste the Simple API URI into src/index.js as follows:
\nconst networkInterface = createNetworkInterface({\n uri: 'https://api.graph.cool/simple/v1/cj5d82p4jmjg90127sqeiu4kg',\n});
\nStart the server:
\nnpm run dev
\nLet's start with a new project from scratch.
\nFirst we'll setup Apollo client.
\nmkdir my-app && cd my-app\nnpm i react-apollo react react-dom --save
\n// App.js\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport {createNetworkInterface, ApolloClient, ApolloProvider} from 'react-apollo';\nconst networkInterface = createNetworkInterface({\n uri: 'https://api.graph.cool/simple/v1/cj5d82p4jmjg90127sqeiu4kg',\n});\nconst client = new ApolloClient({networkInterface})\n// Wrap our root component (<App />) in <ApolloProvider></ApolloProvider>\nReactDOM.render(\n <ApolloProvider client={client}>\n <App />\n </ApolloProvider>,\n document.getElementById('root')\n)
\nLet's create a simple root component. We initialized the GraphCool project with sample schema for a counter. This sample schema only had one field, \"count\":
\ntype Counter {\n count: Int!\n}
\nInt is one of the primitative types. The exclaimation mark means that this field is non-nullable.
\nWhen you initialized this new GraphCool project, you provided a URL to the above schema. GraphCool automatically added some fields (ID, createdAt, and UpdatedAt).
\ntype Counter implements Node {\n count: Int!\n createdAt: DateTime!\n id: ID! @isUnique\n updatedAt: DateTime!\n}
\nSince we haven't populated our container with data yet, we'll make a button that creates a new counter.
\nconst App = ({createCounter}) => (\n <div>\n <button onClick={() => ( createCounter({count: 0}) )}>Create counter</button>\n </div>\n)
\nJust like with redux, we'll pass a createCounter() prop to our
The syntax looks like this:
\nimport {graphql} from 'react-apollo';\nconst createCounter = gql`\n mutation createCounter(\n $count: Int!\n ) {\n createCounter(\n count: $count\n ) {\n count\n id\n }\n }\n`\nconst AppWithData = graphql(createCounter, {\n props: ({ mutate }) => ({\n createCounter: ({count}) => mutate({variables: { count } }),\n }),\n})(App)
\nNote that we've named our mutation 'createCounter.' This can be a useful heuristic, but naming mutations and queries isn't necessary. The state of affairs is analogous to javascript where you can write anonymous or named functions, e.g., () => {...} or function namedFunction() {...}.
\nA mutation is anything that mutates a node, like creating, updating, or deleting nodes. We use queries to read data.
\nMutation syntax looks like:
\n# name our mutation\nmutation createCounter(\n # The count should be an integer (int)\n # The exclaimation-mark (!) means that $count is a required field\n $count: Int!\n ) {\n createCounter(\n # Pass $count as a variable\n count: $count\n ) {\n # The values we want this mutation to return\n # We could also return createdAt, updatedAt\n count\n id\n }\n}
\nWe could also add a default value to the count field with:
\nmutation createCounter($count: Int = 0) {...}
\nThis syntax is similar to ES6 parameter defaults, e.g., createCounter(count = 0)
\nOnce again, we're using react-apollo to interface with GraphQL on the client-side.
\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport {createNetworkInterface, ApolloClient, ApolloProvider, graphql} from 'react-apollo';\nconst App = ({createCounter}) => (\n <div>\n <button onClick={() => ( createCounter({count: 0}) )}>Create counter</button>\n </div>\n)\nconst createCounter = gql`\n mutation createCounter(\n $count: Int!\n ) {\n createCounter(\n count: $count\n ) {\n count\n id\n }\n }\n`\nconst AppWithData = graphql(createCounter, {\n props: ({ mutate }) => ({\n createCounter: ({count}) => mutate({variables: { count }})\n })\n})(App)\nconst networkInterface = createNetworkInterface({\n uri: 'https://api.graph.cool/simple/v1/cj5d82p4jmjg90127sqeiu4kg',\n});\nconst client = new ApolloClient({networkInterface})\nReactDOM.render(\n <ApolloProvider client={client}>\n <AppWithData />\n </ApolloProvider>,\n document.getElementById('root')\n)
\nGraphQL really shines with queries. That's because GraphQL empowers us to ask for only the data that we need. Nested queries are a breeze so we don't need to make multiple roundtrips to the server to gain access to a deeply nested edge.
\n\n\nWith GraphCool, you can query all nodes of a certain type with all{Nodes}. For example, if you want to query all of the records of type User, we invoke allUsers.
\nTo query a specific node, you pass an ID as a variable.
\nSome GraphQl nomenclature:
\n