{"id":2899,"date":"2022-01-06T02:40:21","date_gmt":"2022-01-06T02:40:21","guid":{"rendered":"http:\/\/10.0.0.14:5556\/?p=2899"},"modified":"2022-01-06T02:40:21","modified_gmt":"2022-01-06T02:40:21","slug":"todo-app-with-gatsby-django-docker-part-2-configure-apollo","status":"publish","type":"post","link":"https:\/\/tutorials.leesonresearch.com\/tutorials\/2022\/01\/06\/todo-app-with-gatsby-django-docker-part-2-configure-apollo\/","title":{"rendered":"Todo App with Gatsby, Django &#038; Docker Part 2 &#8212; Configure Apollo"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\">Configure the Apollo Client<\/h1>\n\n\n\n<p>Last chapter we dockerized Gatsby giving us both our development and our production environments. Next step is to setup Gatsby so that it can run queries against our Django Graphene server using the Apollo Client.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">What is Apollo?<\/h4>\n\n\n\n<p><a href=\"https:\/\/www.apollographql.com\/docs\/react\/\" target=\"_blank\" rel=\"noreferrer noopener\">Quoting from the Apollo docs:<\/a><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p><strong>Apollo Client<\/strong> is a comprehensive state management library for JavaScript that enables you to manage both local and remote data with GraphQL. Use it to fetch, cache, and modify application data, all while automatically updating your UI.<\/p><cite><a href=\"https:\/\/www.apollographql.com\/docs\/react\/\" target=\"_blank\" rel=\"noreferrer noopener\">Apollo Docs<\/a><\/cite><\/blockquote>\n\n\n\n<p>It is with Apollo that Gatsby will be able to query, edit and post to our Django Graphene server.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Configuring Apollo<\/h4>\n\n\n\n<p>We will be needing to install two node packages:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>@apollo\/client, to manage both local and remote data with GraphQL. Use it to fetch, cache, and modify application data, all while automatically updating your UI<\/li><li>cross-fetch, a Universal Fetch API for Node, Browsers and React Native.<\/li><\/ul>\n\n\n\n<h5 class=\"wp-block-heading\">Install NPM Packages<\/h5>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# Very important, cd to frontend\ncd frontend\n\nnpm install --save @apollo\/client\nnpm install --save cross-fetch\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Configure Apollo in Gatsby<\/h4>\n\n\n\n<p>Next we need to create a directory for Apollo and four config files:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# cd to the root of our project\nmkdir frontend\/src\/apollo\ntouch frontend\/src\/apollo\/client.js\ntouch frontend\/src\/apollo\/wrap-root-element.js\ntouch frontend\/gatsby-browser.js\ntouch frontend\/gatsby-ssr.js\n<\/pre><\/div>\n\n\n<h5 class=\"wp-block-heading\">Configure client.js<\/h5>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# frontend\/src\/apollo\/client.js\n\nimport fetch from 'cross-fetch';\nimport { ApolloClient, InMemoryCache, HttpLink } from '@apollo\/client';\n\nexport const client = new ApolloClient({\n  link: new HttpLink({\n    uri: 'http:\/\/localhost:5555\/graphql\/',\n    fetch,\n  }),\n  cache: new InMemoryCache()\n});\n<\/pre><\/div>\n\n\n<p>Note the trailing slash in <strong>http:\/\/localhost:5555\/graphql\/<\/strong> . <br>Django needs the trailing slash or you will get and error. I&#8217;ve been bit by this gotcha more than once. \ud83d\ude42<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Configure wrap-root-element.js<\/h5>\n\n\n\n<p>Gatsby will generate separate static pages for all the components in the pages directory. Above all these pages is a root component which will allow us to wrap this root component with Apollo.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# frontend\/src\/apollo\/wrap-root-element.js\n\nimport React from 'react';\nimport { ApolloProvider } from '@apollo\/client';\nimport { client } from '.\/client';\n\nexport const wrapRootElement = ({ element }) =&gt; (\n  &amp;lt;ApolloProvider client={client}&gt;{element}&amp;lt;\/ApolloProvider&gt;\n);\n<\/pre><\/div>\n\n\n<h5 class=\"wp-block-heading\">Configure gatsby-browser.js<\/h5>\n\n\n\n<p>The gatsby-browser.js file allows us to respond to actions within the browser and wrap our site with wrapRootElement.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# frontend\/gatsby-browser.js\n\nexport { wrapRootElement } from '.\/src\/apollo\/wrap-root-element';\n<\/pre><\/div>\n\n\n<h5 class=\"wp-block-heading\">Configure gatsby-ssr.js<\/h5>\n\n\n\n<p>The gatsby-ssr.js file allows us to alter content of static HTML files as they are being rendered with Server-Side Rendering by Gatsby and Node.js.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# frontend\/gatsby-ssr.js\n\nexport { wrapRootElement } from '.\/src\/apollo\/wrap-root-element';\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Configure Allowed Hosts and Cors in Django<\/h4>\n\n\n\n<p>In order for Django to allow a connection with our Gatsby frontend we need to update the Django settings file&#8217;s <strong>ALLOWED_HOSTS<\/strong> ip address and add the Django Cors Headers app which adds Cross-Origin Resource Sharing (CORS) headers to responses. This allows in-browser requests to our Django app from other origins, in this case the other origin being our Gatsby app running on localhost port 8000.<\/p>\n\n\n\n<p>If you cut and pasted the Django requirements.txt file from way back in Part 1, Chapter 1 of this tutorial, then you already have django-cors-headers installed. If not, you will need to add the Cors app to the Django requirements.txt file:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# server\/requirements.txt\n\n# code ...\n\ndjango-cors-headers&gt;=3.5.0\n\n# code ...\n<\/pre><\/div>\n\n\n<h5 class=\"wp-block-heading\">Add Gatsby IP to Django Allowed Hosts<\/h5>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# server\/todo_proj\/settings.py\n\n# code ...\n\nALLOWED_HOSTS = &#x5B;'localhost']\n<\/pre><\/div>\n\n\n<h5 class=\"wp-block-heading\">Add Django Cors Headers App to Django Settings<\/h5>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; highlight: [6,7,8,9,23,27]; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n# server\/todo_proj\/settings.py\n\n# code ...\n\nALLOWED_HOSTS = &#x5B;'localhost']\nCORS_ORIGIN_ALLOW_ALL = False\nCORS_ORIGIN_WHITELIST = &#x5B;\n    &quot;http:\/\/localhost:8000&quot;,\n]\n\n# Application definition\n\nINSTALLED_APPS = &#x5B;\n    'django.contrib.admin',\n    'django.contrib.auth',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.messages',\n    'django.contrib.staticfiles',\n    'todo_app',\n    'mptt',\n    'graphene_django', \n    'corsheaders',\n]\n\nMIDDLEWARE = &#x5B;\n    'corsheaders.middleware.CorsMiddleware',\n    'django.middleware.security.SecurityMiddleware',\n    'django.contrib.sessions.middleware.SessionMiddleware',\n    'django.middleware.common.CommonMiddleware',\n    'django.middleware.csrf.CsrfViewMiddleware',\n    'django.contrib.auth.middleware.AuthenticationMiddleware',\n    'django.contrib.messages.middleware.MessageMiddleware',\n    'django.middleware.clickjacking.XFrameOptionsMiddleware',\n    'django.contrib.auth.middleware.AuthenticationMiddleware',\n]\n\n# code ...\n<\/pre><\/div>\n\n\n<p>Now we need to power down our app and rebuild:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\ndocker-compose down\n<\/pre><\/div>\n\n\n<p>&#8230; and rebuild:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\ndocker-compose build\n<\/pre><\/div>\n\n\n<p>If you run into errors you can always rebuild the Docker containers with the no cache flag:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\ndocker-compose build --no-cache\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\">Querying the Django Server from Gatsby <\/h4>\n\n\n\n<p>Now the moment of truth where we make our first query from our new Gatsby frontend to the Django backend.<\/p>\n\n\n\n<p>From the Django Admin UI: http:\/\/localhost:5555\/admin add a todo and note the todo&#8217;s id number.<\/p>\n\n\n\n<p>As a test we will try something simple from the Gatsby index page:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n\/\/ frontend\/src\/pages\/index.js\n\nimport React from &quot;react&quot;;\n\n\/\/ 1)\nimport { useQuery } from '@apollo\/client';\n\n\/\/ 2)\nimport gql from 'graphql-tag';\n\n\/\/ 3)\nconst APOLLO_QUERY = gql`\n  query {\n    todo(id: 1) { \n      id\n      title\n      task\n    }\n  }\n`;\n\nexport default function Home() {\n\n  \/\/ 4)\n  const { loading, error, data } = useQuery(APOLLO_QUERY)\n  if (loading) return &amp;lt;p&gt;Loading...&amp;lt;\/p&gt;;\n  if (error) return &amp;lt;p&gt;Error!&amp;lt;\/p&gt;;\n\n  return(\n    &amp;lt;div&gt;\n      &amp;lt;div&gt;Hello World!&amp;lt;\/div&gt;\n      &amp;lt;div&gt;\n        Title: {data.todo.title}\n      &amp;lt;\/div&gt;\n    &amp;lt;\/div&gt;\n  )\n}\n<\/pre><\/div>\n\n\n<p>Hitting http:\/\/localhost:8000 you should see something like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"772\" height=\"387\" src=\"http:\/\/10.0.0.14\/wp-content\/uploads\/2020\/11\/gatsby_first_query.png\" alt=\"\" class=\"wp-image-1346\" srcset=\"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/gatsby_first_query.png 772w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/gatsby_first_query-300x150.png 300w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/gatsby_first_query-768x385.png 768w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/gatsby_first_query-600x301.png 600w\" sizes=\"auto, (max-width: 772px) 100vw, 772px\" \/><figcaption>http:\/\/localhost:8000<\/figcaption><\/figure>\n\n\n\n<h5 class=\"wp-block-heading\">What is happening in our Apollo query?<\/h5>\n\n\n\n<p>Lets walk through the script we just wrote.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n1)\nimport { useQuery } from '@apollo\/client';\n<\/pre><\/div>\n\n\n<p>The Apollo useQuery React Hook will fetch our data automatically.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n2)\nimport gql from 'graphql-tag';\n<\/pre><\/div>\n\n\n<p>Remember Django&#8217;s GraphiQL playground, (http:\/\/localhost:5555\/graphql) which allows us to test our queries? Lets say we want to query all the todos we currently have in our Django backend database:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"550\" src=\"http:\/\/10.0.0.14\/wp-content\/uploads\/2020\/11\/django_query_todos-1024x550.png\" alt=\"\" class=\"wp-image-1354\" srcset=\"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/django_query_todos-1024x550.png 1024w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/django_query_todos-300x161.png 300w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/django_query_todos-768x412.png 768w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/django_query_todos-600x322.png 600w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/django_query_todos-945x508.png 945w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/django_query_todos.png 1052w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>http:\/\/localhost:5555\/graphql<\/figcaption><\/figure>\n\n\n\n<p>Voila! We get all our todos, in my case only one with the id of 1. Note, check your Django backend http:\/\/localhost:5555\/admin to confirm that you have a todo in your db with an id of 1 otherwise you will get an error. You can use any todo id that is available in your db.<\/p>\n\n\n\n<p>Lets query for a specific todo using my todo&#8217;s id as the query argument:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"550\" src=\"http:\/\/10.0.0.14\/wp-content\/uploads\/2020\/11\/django_query_todo-1024x550.png\" alt=\"\" class=\"wp-image-1355\" srcset=\"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/django_query_todo-1024x550.png 1024w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/django_query_todo-300x161.png 300w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/django_query_todo-768x412.png 768w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/django_query_todo-600x322.png 600w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/django_query_todo-945x508.png 945w, https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-content\/uploads\/2020\/11\/django_query_todo.png 1052w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>http:\/\/localhost:5555\/graphql<\/figcaption><\/figure>\n\n\n\n<p>Now how do we run this query from our Gatsby index.js page? That&#8217;s what Gatsby&#8217;s graphql-tag is all about because in step 3):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n\/\/ frontend\/src\/pages\/index.js\n\n\/\/ code ...\n\nimport gql from 'graphql-tag';\n\n\/\/ 3)\n\/\/ your id number may be different\nconst APOLLO_QUERY = gql`\n  query {\n    todo(id: 1) { \n      id\n      title\n      task\n    }\n  }\n`;\n<\/pre><\/div>\n\n\n<p>The Gatsby graphql-tag, in this case gql&#8220; wraps the same query we used in our Django GraphiQL query above. This allows us to cut and paste from the GraphiQL query directly into our graphql-tag above.<\/p>\n\n\n\n<p>Now for loading the result from our query:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n\/\/ frontend\/src\/pages\/index.js\n\n 4)\n const { loading, error, data } = useQuery(APOLLO_QUERY)\n if (loading) return &amp;lt;p&gt;Loading...&amp;lt;\/p&gt;;\n if (error) return &amp;lt;p&gt;Error!&amp;lt;\/p&gt;;\n<\/pre><\/div>\n\n\n<p>Here we use useQuery to fetch the data and de-structure the result into the loading status, (boolean true false), error if there is any and data which if the query is successful will contain the result. <\/p>\n\n\n\n<p>Step 5 we print to the screen our result:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: Double click to copy; notranslate\" title=\"Double click to copy\">\n\/\/ frontend\/src\/pages\/index.js\n\n   &amp;lt;div&gt;\n      &amp;lt;div&gt;Hello World!&amp;lt;\/div&gt;\n      &amp;lt;div&gt;\n        5)\n        Todo Title: {data.todo.title}\n      &amp;lt;\/div&gt;\n    &amp;lt;\/div&gt;\n<\/pre><\/div>\n\n\n<p>&#8230; unless we have an error we then print to the screen.<\/p>\n\n\n\n<p>Congratulations! We can now query our Django backend from Gatsby.<\/p>\n\n\n\n<p>Next chapter we setup TDD for Gatsby.<\/p>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link\" href=\"tdd-with-gatsby-docker-part-1-setup-dev-env\">&lt; Previous:  Chapter 8<\/a><\/div>\n\n\n\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link\" href=\"tdd-with-gatsby-django-docker-part-2-chapter-10-setup-gatsby-for-tdd\">Next: Chapter 10 &gt;<\/a><\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>How to use the Apollo client to let Gatsby talk to Django Graphene.<\/p>\n","protected":false},"author":1,"featured_media":277,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20,12],"tags":[38,10],"class_list":["post-2899","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-featured-tutorial","category-gatsby","tag-apollo","tag-gatsby"],"_links":{"self":[{"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/posts\/2899","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/comments?post=2899"}],"version-history":[{"count":1,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/posts\/2899\/revisions"}],"predecessor-version":[{"id":2900,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/posts\/2899\/revisions\/2900"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/media\/277"}],"wp:attachment":[{"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/media?parent=2899"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/categories?post=2899"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tutorials.leesonresearch.com\/tutorials\/wp-json\/wp\/v2\/tags?post=2899"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}