├── .bookignore ├── .gitignore ├── .nvmrc ├── .prettierrc ├── README.md ├── book-assets └── book.json ├── docsearch.json ├── gatsby-config.js ├── gatsby-ssr.js ├── img ├── 404-root.png ├── INTERNAL_SERVER_ERROR.png ├── InputError.png ├── SectionByNumber.png ├── SectionContent.png ├── adding-review.gif ├── afterlimit-after-orderby.png ├── afterlimit-after.png ├── afterlimit-initial.png ├── android-chapters-type-mismatch.png ├── android-chapters.png ├── android-sections-header.png ├── android-sections.png ├── android-starter-chapters.png ├── android-starter-sections.png ├── android-studio.png ├── apollo-devtools-docs-scrollY.png ├── array-request-payload.png ├── atlas-cluster.png ├── atlas-regions.png ├── auth-directive-admin.png ├── auth-directive-user.png ├── auth-directive-without-roles.png ├── authorization-header-playground.png ├── browserlist.png ├── cache-with-orderBy.png ├── chapterByTitle-schema.png ├── cloudinary-upload-widget.jpg ├── connections-after.png ├── connections-initial.png ├── costInCents-with-header.png ├── costInCents.png ├── coverage-above-threshold.png ├── coverage-bash.png ├── coverage-below-threshold.png ├── coverage-index.png ├── coverage-user-16.png ├── coverage-user-18.png ├── coverage-user-19.png ├── coverage-user-fields.png ├── coverage-user-red.png ├── coverage-web.png ├── cra.png ├── createReview-downtown-job.png ├── createReview-internal-server-error.png ├── createReview-mutation.png ├── createReview-success.png ├── createReview-with-author.png ├── createUser.png ├── data-sources-full-coverage.png ├── date-literal-error.png ├── date-variable-value-error.png ├── delayed-favoriting.gif ├── devtools-ViewedMutation.png ├── devtools-cache.png ├── devtools-graphiql.png ├── devtools-query.png ├── edit-review.gif ├── empty-reviews.png ├── eslint-vscode-tooltip.png ├── eslint-vscode.png ├── expo-android.png ├── expo-home-screen.png ├── expo-iOS.png ├── expo-library-compatibility.png ├── expo-section-list.png ├── expo-splash.png ├── expo-terminal.png ├── expo-web.png ├── favorite-mutation.png ├── fetchMore-reviews-cache.png ├── fullReview-with-author.png ├── github-graphql-explorer.png ├── github-stargazers-totalCount.png ├── github-stargazers.png ├── githubStars-subscription.png ├── google-trends.png ├── graph-manager-clients.png ├── graph-manager-error-instances.png ├── graph-manager-errors.png ├── graph-manager-metrics.png ├── graph-manager-trace.png ├── graph-manager-unnamed-operation.png ├── graphiql.jpg ├── groups-mongo.jpg ├── guide-app.png ├── hasura-add-created-at.png ├── hasura-add-foreign-key.png ├── hasura-add-insert-permission.png ├── hasura-add-relationship.png ├── hasura-admin-insert-review.png ├── hasura-admin-secret.png ├── hasura-after-import.png ├── hasura-console.png ├── hasura-create-action.png ├── hasura-data-console.png ├── hasura-hello-query.png ├── hasura-heroku-create.png ├── hasura-insert-review.png ├── hasura-review-author.png ├── hasura-review-table.png ├── hasura-reviews-with-created-at.png ├── hasura-reviews.png ├── hasura-search-users.png ├── health-check.png ├── hello-get-query.png ├── hello-schema.png ├── hello-world.png ├── hidden-review-icons.png ├── infinite-loop.gif ├── internal-server-error.png ├── invalid-id.png ├── invalid-jwt-test-failure.png ├── invalid-objectid-error.png ├── isoString-with-variable.png ├── launch-next-query.png ├── loading-skeleton.png ├── loading-temperature.png ├── localhost-internal-server-error.png ├── location-button.png ├── login.gif ├── me-query-with-auth-header.png ├── me-query-with-null-results.png ├── me-query.png ├── me-with-all-fields.png ├── me-with-name.png ├── mocking-casual.png ├── mocking-default.png ├── mocking-external.png ├── mongo-network-error.png ├── mongo-users.jpg ├── multiple-invalid-createReview-args.png ├── must-be-logged-in.png ├── mutation-log.png ├── non-nullable-id-error.png ├── npm-graphql-downloads.png ├── npm-test-App-fail.png ├── null-group.jpg ├── null-reviews-with-email.png ├── old │ └── 404.png ├── onegraph-codesandbox-data.png ├── onegraph-codesandbox-oauth.png ├── onegraph-create-persisted-query.png ├── onegraph-dashboard.png ├── onegraph-google-analytics.png ├── onegraph-persisted-query.png ├── optimistic-favoriting.gif ├── play-chapters.png ├── play-githubStars.png ├── play-section-suggestions.png ├── play-suggestions.png ├── playground-app-hello.png ├── playground-app-url.png ├── ppp-in-browser.png ├── private-reviews.png ├── query-plan.png ├── redis-cached-user.png ├── remove-review-network-error.png ├── remove-review-response.gif ├── remove-review.gif ├── request-payload.png ├── revews-with-updatedAt.png ├── review-count.png ├── review-created.gif ├── review-text-too-short.png ├── review-updatedAt-error.png ├── reviews-createdAt.png ├── reviews-playground-two-results.png ├── reviews-playground.png ├── reviews-query.png ├── reviews-schema.png ├── reviews-table.png ├── reviews-through-gateway.png ├── reviews-with-author.png ├── root-mutation-console.png ├── root-mutation.png ├── satellite-image.png ├── schema-chapters.png ├── schema-local-mutation.png ├── schema-removeReview.png ├── schema-reviews.png ├── scrollY-in-cache.png ├── searchUsers.png ├── section-content.png ├── section-query-playground.png ├── section-query-schema.png ├── section-views.png ├── security-and-privacy-settings.png ├── security-dialog.png ├── sentry-formatError.png ├── sentry-uncaught-error.png ├── setMyPhoto.png ├── skiplimit-all-args.png ├── skiplimit-default-args.png ├── skiplimit-invalid-args.png ├── sql-coverage-report.png ├── sql-date-error.png ├── sql-reviews.png ├── sql-time-working.png ├── ssr-502-error.png ├── ssr-hello-world.png ├── ssr-react.png ├── ssr-spinner.png ├── ssr-user-agent.png ├── stars-between-0-and-5.png ├── stars.png ├── status-code-500.png ├── subscription-downtown-job.png ├── subscription-start.png ├── subscription-websocket-event.png ├── subscription-websocket-start.png ├── table-of-contents-test-error.png ├── table-of-contents.png ├── tableplus-reviews.png ├── temperature.png ├── the-cache.png ├── topology-was-destroyed.png ├── tshirt-directive.png ├── unexpected-error.png ├── updating-favorite-count.gif ├── upper-directive.png ├── user-null-email.png ├── user-null-forbidden.png ├── user-profile.png ├── user-query-3-fields.png ├── user-query.png ├── user-reviews-through-gateway.png ├── user-service.png ├── user-through-gateway.png ├── users-and-groups.jpg ├── users-groupid-mongo.jpg ├── users-groups-and-group.jpg ├── users-with-groups.jpg ├── viewed-section-request.png ├── viewedSection-schema.png ├── vue-chapters.png ├── vue-sections.png ├── vue-starter.png ├── websocket-data.png └── write-fragment.gif ├── package-lock.json ├── package.json ├── scripts └── build.sh ├── src ├── assets │ ├── logo-text.svg │ ├── logo.svg │ ├── star.svg │ └── stripe-climate.svg ├── components │ ├── CurrentTemperature.css │ ├── CurrentTemperature.js │ ├── CurrentUser.css │ ├── CurrentUser.js │ ├── Odometer.js │ ├── Profile.css │ ├── Profile.js │ ├── Review.js │ ├── ReviewCreatedNotification.js │ ├── ReviewForm.js │ ├── ReviewList.js │ ├── Reviews.css │ ├── Reviews.js │ ├── Reviews.test.js │ ├── Section.js │ ├── Section.test.js │ ├── StarCount.css │ ├── StarCount.js │ ├── TableOfContents.js │ ├── TableOfContents.test.js │ ├── Unsubscribe.css │ ├── Unsubscribe.js │ └── landing │ │ ├── AboveFold.css │ │ ├── AboveFold.js │ │ ├── Author.js │ │ ├── Authors.css │ │ ├── Authors.js │ │ ├── BelowFold.js │ │ ├── ElonLanding.css │ │ ├── ElonLanding.js │ │ ├── EmailIcon.js │ │ ├── Emoji.css │ │ ├── Emoji.js │ │ ├── Footer.css │ │ ├── Footer.js │ │ ├── Landing.css │ │ ├── Landing.js │ │ ├── LandingToC.css │ │ ├── LandingToC.js │ │ ├── LinkNewTab.js │ │ ├── Links.css │ │ ├── Links.js │ │ ├── LogoName.css │ │ ├── LogoName.js │ │ ├── MediumLogo.js │ │ ├── Package.css │ │ ├── Package.js │ │ ├── Payment.css │ │ ├── Payment.js │ │ ├── Paypal.css │ │ ├── Paypal.js │ │ ├── Pricing.css │ │ ├── Pricing.js │ │ ├── ScrollToTopOnMount.js │ │ ├── Stats.css │ │ ├── Stats.js │ │ ├── Sup.js │ │ ├── Team.js │ │ ├── Testimonials.css │ │ ├── Testimonials.js │ │ ├── Topics.css │ │ ├── Topics.js │ │ ├── Tshirt.css │ │ ├── Tshirt.js │ │ ├── TshirtOrderForm.css │ │ ├── TshirtOrderForm.js │ │ ├── TwitterLogo.js │ │ ├── Welcome.css │ │ └── Welcome.js ├── gatsby-theme-apollo │ └── client.js ├── gatsby-theme-guide-core │ ├── components │ │ └── logo.js │ ├── pages │ │ └── 404.js │ └── utils │ │ └── colors.js ├── gatsby-theme-guide │ ├── components │ │ ├── above-nav.js │ │ ├── footer.js │ │ ├── further-asides.js │ │ ├── header-button.js │ │ ├── mobile-logo.js │ │ └── paywall.js │ ├── guide.css │ └── startup.js ├── gatsby-theme-material-ui-top-layout │ └── theme.js ├── graphql │ └── Review.js ├── lib │ ├── apollo.js │ ├── auth.js │ ├── chapters.js │ ├── common.css │ ├── confetti.js │ ├── errorLink.js │ ├── helpers.js │ ├── images.js │ ├── link.js │ ├── packages.js │ ├── payment.js │ ├── sections.js │ ├── track.js │ ├── useUser.js │ └── validators.js ├── pages │ ├── index.js │ ├── me.js │ ├── paypal │ │ └── [package].js │ ├── reviews.js │ ├── team │ │ └── [token].js │ ├── tshirt.js │ ├── unsubscribe │ │ └── [token].js │ ├── videos.js │ └── welcome.js ├── setupTests.js └── startup │ ├── google-analytics.js │ ├── index.js │ └── logrocket.js ├── static ├── .well-known │ └── apple-developer-merchantid-domain-association ├── external.svg ├── favicon.ico ├── robots.txt ├── service-worker.js └── startupranking1138863810361710.html └── text ├── .nvmrc ├── README.md ├── SUMMARY.md ├── android ├── caching.md ├── first-query.md ├── flow.md ├── index.md ├── querying-with-variables.md ├── setting-up-apollo-android.md └── viewmodel.md ├── background ├── authentication.md ├── browser-performance.md ├── cdn.md ├── continuous-integration.md ├── databases.md ├── git.md ├── http.md ├── index.md ├── javascript.md ├── json.md ├── latency.md ├── mobile-apps.md ├── node-npm-and-nvm.md ├── react.md ├── server.md ├── spa.md ├── ssr.md ├── testing.md ├── vue.md └── webhooks.md ├── client ├── anywhere-http.md ├── client-libraries.md └── index.md ├── federation ├── deploying-federation.md ├── extending-entities.md ├── federated-gateway.md ├── federated-service.md ├── index.md └── managed-federation.md ├── img ├── ios └── index.md ├── preface.md ├── preventing-dos-attacks └── index.md ├── privacy.md ├── query-language ├── arguments.md ├── directives.md ├── document.md ├── field-aliases.md ├── fields.md ├── fragments.md ├── index.md ├── mutations.md ├── operations.md ├── selection-sets.md ├── subscriptions.md ├── summary.md └── variables.md ├── react-native ├── adding-a-screen.md ├── adding-apollo.md ├── app-structure.md ├── deploying.md ├── index.md └── persisting.md ├── react ├── advanced │ ├── batching.md │ ├── client-side-ordering-and-filtering.md │ ├── index.md │ ├── local-state.md │ ├── multiple-endpoints.md │ ├── paginating.md │ ├── persisting.md │ ├── prefetching.md │ ├── rest.md │ └── review-subscriptions.md ├── authentication.md ├── extended-topics │ ├── index.md │ ├── linting.md │ ├── server-side-rendering.md │ ├── testing.md │ └── uploading-files.md ├── index.md ├── mutating.md ├── querying.md └── setting-up.md ├── server-analytics └── index.md ├── server ├── building │ ├── authentication.md │ ├── authorization.md │ ├── creating-users.md │ ├── custom-scalars.md │ ├── data-sources.md │ ├── errors.md │ ├── index.md │ ├── project-setup.md │ ├── subscriptions.md │ └── types-and-resolvers.md ├── extended-topics │ ├── apollo-federation.md │ ├── custom-schema-directives.md │ ├── file-uploads.md │ ├── hasura.md │ ├── index.md │ ├── mocking.md │ ├── pagination.md │ ├── performance.md │ ├── schema-design.md │ ├── schema-validation.md │ ├── security.md │ └── subscriptions-in-depth.md ├── future.md ├── img ├── index.md ├── introduction.md ├── more-data-sources │ ├── custom-data-source.md │ ├── graphql.md │ ├── index.md │ ├── rest.md │ └── sql.md ├── production │ ├── analytics.md │ ├── database-hosting.md │ ├── deployment.md │ ├── error-reporting.md │ ├── index.md │ └── querying-in-production.md └── testing │ ├── code-coverage.md │ ├── end-to-end-tests.md │ ├── index.md │ ├── review-integration-tests.md │ ├── static-testing.md │ ├── unit-tests.md │ └── user-integration-tests.md ├── service-integrations ├── creating-persisted-queries.md ├── index.md ├── making-a-query.md └── writing-server-side-code.md ├── ssr ├── adding-apollo.md ├── adding-react.md ├── index.md └── setting-up-the-server.md ├── summary-extra.md ├── terms.md ├── type-system ├── descriptions.md ├── directives.md ├── enums.md ├── extending.md ├── field-arguments.md ├── index.md ├── interfaces.md ├── introspection.md ├── lists.md ├── non-null.md ├── objects.md ├── scalars.md ├── schema.md ├── summary.md ├── types.md └── unions.md ├── understanding-graphql ├── a-simple-graphql-server.md ├── a-simple-rest-api-server.md ├── async-data-loading.md ├── filtering-the-data.md ├── graphql-as-an-alternative-to-a-rest-api.md ├── index.md ├── introduction.md ├── multiple-types-of-data.md ├── querying-a-set-of-data.md ├── security-and-error-handling.md └── tying-this-all-together.md ├── validation-and-execution ├── execution.md ├── index.md └── validation.md └── vue ├── further-topics.md ├── index.md ├── querying-with-variables.md ├── querying.md └── setting-up-apollo.md /.bookignore: -------------------------------------------------------------------------------- 1 | build -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | .cache/ 4 | .connect-deps-cache/ 5 | public/ 6 | .env* 7 | out/ 8 | book-assets/ 9 | emoji-words/ 10 | scripts/ 11 | 12 | .vercel 13 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | singleQuote: true 2 | semi: false 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **Table of Contents** 4 | 5 | - [Supporting](#supporting) 6 | - [Contributors](#contributors) 7 | - [Contributing](#contributing) 8 | - [Text](#text) 9 | - [Formatting](#formatting) 10 | - [Setup](#setup) 11 | - [Site](#site) 12 | - [With local theme](#with-local-theme) 13 | 14 | 15 | 16 | ## Supporting 17 | 18 | If you'd like to read the Guide, and if you can afford to purchase it or if your company reimburses you for educational materials (most do 👍), we would value your support: [https://graphql.guide](https://graphql.guide). 19 | 20 | ## Contributors 21 | 22 | [/GraphQLGuide/book/graphs/contributors](https://github.com/GraphQLGuide/book/graphs/contributors) 23 | 24 | Thank you to everyone who has contributed 😃 🙌 25 | 26 | ## Contributing 27 | 28 | We welcome issues and PRs! For large changes, we recommend opening an issue first to get feedback before putting in the work of a PR. Minor things like typo fixes or suggested re-wordings can go directly to PRs and will usually get a quick response 😊 29 | 30 | ### Text 31 | 32 | #### Formatting 33 | 34 | - Use curly quotes (“ ‘ ’ ”) unless inside code blocks, in which case use straight quotes (' ") 35 | 36 | #### Setup 37 | 38 | If you're working on gitbook-related issues or want to see how your PR will be formatted, follow these steps to get set up after cloning: 39 | 40 | ```sh 41 | npm i -g gitbook-cli 42 | gitbook install 43 | mkdir out/ 44 | cd scripts 45 | ./build.sh 46 | ``` 47 | 48 | ### Site 49 | 50 | #### With local theme 51 | 52 | ``` 53 | git clone https://github.com/GraphQLGuide/gatsby-theme-apollo.git 54 | git clone https://github.com/GraphQLGuide/book.git 55 | cd book/ 56 | connect-deps link ../gatsby-theme-apollo/packages/gatsby-theme-apollo-docs ../gatsby-theme-apollo/packages/gatsby-theme-apollo-core --connect --watch 57 | ``` 58 | 59 | --- 60 | 61 | [Changelog](https://github.com/GraphQLGuide/book/releases) 62 | -------------------------------------------------------------------------------- /book-assets/book.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "📖 The GraphQL Guide", 3 | "description": "The best way to learn GraphQL—the new REST ✨", 4 | "author": "John Resig and Loren Sands-Ramshaw", 5 | "pdf": { 6 | "fontSize": 16 7 | }, 8 | "plugins": ["prism", "-highlight", "advanced-emoji"], 9 | "pluginsConfig": { 10 | "prism": { 11 | "lang": { 12 | "gql": "graphql", 13 | "js": "jsx", 14 | "sh": "intentionally-nonexistant", 15 | "kt": "kotlin", 16 | "swift": "swift", 17 | "vue": "vue", 18 | "yaml": "yaml" 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /docsearch.json: -------------------------------------------------------------------------------- 1 | { 2 | "index_name": "guide", 3 | "start_urls": ["https://graphql.guide/"], 4 | "stop_urls": ["https://graphql.guide/preface$"], 5 | "selectors": { 6 | "default": { 7 | "lvl0": ".content-wrapper h1", 8 | "lvl1": ".content-wrapper h2", 9 | "lvl2": ".content-wrapper h3", 10 | "lvl3": ".content-wrapper h4", 11 | "lvl4": ".content-wrapper h5", 12 | "text": ".content-wrapper p, .content-wrapper li" 13 | } 14 | }, 15 | "only_content_level": true 16 | } 17 | -------------------------------------------------------------------------------- /gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { URL } from 'url' 3 | 4 | function getLinkProps({ crossOrigin, pathname }) { 5 | switch (typeof crossOrigin) { 6 | case `string`: 7 | return { crossOrigin } 8 | case `function`: 9 | return getLinkProps({ crossOrigin: crossOrigin(pathname), pathname }) 10 | default: 11 | return { crossOrigin: `anonymous` } 12 | } 13 | } 14 | 15 | export const onRenderBody = ( 16 | { setHeadComponents, pathname = `/` }, 17 | { crossOrigin = `anonymous` } = {} 18 | ) => { 19 | const props = getLinkProps({ crossOrigin, pathname }) 20 | 21 | const assets = [ 22 | 'https://fonts.gstatic.com/s/sourcecodepro/v11/HI_SiYsKILxRpg3hIP6sJ7fM7PqlPevT.ttf', 23 | 'https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7g.ttf', 24 | 'https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwlxdr.ttf', 25 | ] 26 | 27 | setHeadComponents( 28 | assets.map((href) => { 29 | let assetProps 30 | 31 | // External urls should get the props from the plugin configuration. 32 | // Local urls will be forced with `crossOrigin: "anonymous"` 33 | try { 34 | // check if URL is external, if not this constructor throws. 35 | new URL(href) 36 | assetProps = props 37 | } catch (e) { 38 | assetProps = { crossOrigin: `anonymous` } 39 | } 40 | 41 | return ( 42 | 43 | ) 44 | }) 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /img/404-root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/404-root.png -------------------------------------------------------------------------------- /img/INTERNAL_SERVER_ERROR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/INTERNAL_SERVER_ERROR.png -------------------------------------------------------------------------------- /img/InputError.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/InputError.png -------------------------------------------------------------------------------- /img/SectionByNumber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/SectionByNumber.png -------------------------------------------------------------------------------- /img/SectionContent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/SectionContent.png -------------------------------------------------------------------------------- /img/adding-review.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/adding-review.gif -------------------------------------------------------------------------------- /img/afterlimit-after-orderby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/afterlimit-after-orderby.png -------------------------------------------------------------------------------- /img/afterlimit-after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/afterlimit-after.png -------------------------------------------------------------------------------- /img/afterlimit-initial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/afterlimit-initial.png -------------------------------------------------------------------------------- /img/android-chapters-type-mismatch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/android-chapters-type-mismatch.png -------------------------------------------------------------------------------- /img/android-chapters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/android-chapters.png -------------------------------------------------------------------------------- /img/android-sections-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/android-sections-header.png -------------------------------------------------------------------------------- /img/android-sections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/android-sections.png -------------------------------------------------------------------------------- /img/android-starter-chapters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/android-starter-chapters.png -------------------------------------------------------------------------------- /img/android-starter-sections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/android-starter-sections.png -------------------------------------------------------------------------------- /img/android-studio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/android-studio.png -------------------------------------------------------------------------------- /img/apollo-devtools-docs-scrollY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/apollo-devtools-docs-scrollY.png -------------------------------------------------------------------------------- /img/array-request-payload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/array-request-payload.png -------------------------------------------------------------------------------- /img/atlas-cluster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/atlas-cluster.png -------------------------------------------------------------------------------- /img/atlas-regions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/atlas-regions.png -------------------------------------------------------------------------------- /img/auth-directive-admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/auth-directive-admin.png -------------------------------------------------------------------------------- /img/auth-directive-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/auth-directive-user.png -------------------------------------------------------------------------------- /img/auth-directive-without-roles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/auth-directive-without-roles.png -------------------------------------------------------------------------------- /img/authorization-header-playground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/authorization-header-playground.png -------------------------------------------------------------------------------- /img/browserlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/browserlist.png -------------------------------------------------------------------------------- /img/cache-with-orderBy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/cache-with-orderBy.png -------------------------------------------------------------------------------- /img/chapterByTitle-schema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/chapterByTitle-schema.png -------------------------------------------------------------------------------- /img/cloudinary-upload-widget.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/cloudinary-upload-widget.jpg -------------------------------------------------------------------------------- /img/connections-after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/connections-after.png -------------------------------------------------------------------------------- /img/connections-initial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/connections-initial.png -------------------------------------------------------------------------------- /img/costInCents-with-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/costInCents-with-header.png -------------------------------------------------------------------------------- /img/costInCents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/costInCents.png -------------------------------------------------------------------------------- /img/coverage-above-threshold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/coverage-above-threshold.png -------------------------------------------------------------------------------- /img/coverage-bash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/coverage-bash.png -------------------------------------------------------------------------------- /img/coverage-below-threshold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/coverage-below-threshold.png -------------------------------------------------------------------------------- /img/coverage-index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/coverage-index.png -------------------------------------------------------------------------------- /img/coverage-user-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/coverage-user-16.png -------------------------------------------------------------------------------- /img/coverage-user-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/coverage-user-18.png -------------------------------------------------------------------------------- /img/coverage-user-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/coverage-user-19.png -------------------------------------------------------------------------------- /img/coverage-user-fields.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/coverage-user-fields.png -------------------------------------------------------------------------------- /img/coverage-user-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/coverage-user-red.png -------------------------------------------------------------------------------- /img/coverage-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/coverage-web.png -------------------------------------------------------------------------------- /img/cra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/cra.png -------------------------------------------------------------------------------- /img/createReview-downtown-job.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/createReview-downtown-job.png -------------------------------------------------------------------------------- /img/createReview-internal-server-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/createReview-internal-server-error.png -------------------------------------------------------------------------------- /img/createReview-mutation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/createReview-mutation.png -------------------------------------------------------------------------------- /img/createReview-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/createReview-success.png -------------------------------------------------------------------------------- /img/createReview-with-author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/createReview-with-author.png -------------------------------------------------------------------------------- /img/createUser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/createUser.png -------------------------------------------------------------------------------- /img/data-sources-full-coverage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/data-sources-full-coverage.png -------------------------------------------------------------------------------- /img/date-literal-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/date-literal-error.png -------------------------------------------------------------------------------- /img/date-variable-value-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/date-variable-value-error.png -------------------------------------------------------------------------------- /img/delayed-favoriting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/delayed-favoriting.gif -------------------------------------------------------------------------------- /img/devtools-ViewedMutation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/devtools-ViewedMutation.png -------------------------------------------------------------------------------- /img/devtools-cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/devtools-cache.png -------------------------------------------------------------------------------- /img/devtools-graphiql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/devtools-graphiql.png -------------------------------------------------------------------------------- /img/devtools-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/devtools-query.png -------------------------------------------------------------------------------- /img/edit-review.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/edit-review.gif -------------------------------------------------------------------------------- /img/empty-reviews.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/empty-reviews.png -------------------------------------------------------------------------------- /img/eslint-vscode-tooltip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/eslint-vscode-tooltip.png -------------------------------------------------------------------------------- /img/eslint-vscode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/eslint-vscode.png -------------------------------------------------------------------------------- /img/expo-android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/expo-android.png -------------------------------------------------------------------------------- /img/expo-home-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/expo-home-screen.png -------------------------------------------------------------------------------- /img/expo-iOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/expo-iOS.png -------------------------------------------------------------------------------- /img/expo-library-compatibility.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/expo-library-compatibility.png -------------------------------------------------------------------------------- /img/expo-section-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/expo-section-list.png -------------------------------------------------------------------------------- /img/expo-splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/expo-splash.png -------------------------------------------------------------------------------- /img/expo-terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/expo-terminal.png -------------------------------------------------------------------------------- /img/expo-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/expo-web.png -------------------------------------------------------------------------------- /img/favorite-mutation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/favorite-mutation.png -------------------------------------------------------------------------------- /img/fetchMore-reviews-cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/fetchMore-reviews-cache.png -------------------------------------------------------------------------------- /img/fullReview-with-author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/fullReview-with-author.png -------------------------------------------------------------------------------- /img/github-graphql-explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/github-graphql-explorer.png -------------------------------------------------------------------------------- /img/github-stargazers-totalCount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/github-stargazers-totalCount.png -------------------------------------------------------------------------------- /img/github-stargazers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/github-stargazers.png -------------------------------------------------------------------------------- /img/githubStars-subscription.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/githubStars-subscription.png -------------------------------------------------------------------------------- /img/google-trends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/google-trends.png -------------------------------------------------------------------------------- /img/graph-manager-clients.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/graph-manager-clients.png -------------------------------------------------------------------------------- /img/graph-manager-error-instances.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/graph-manager-error-instances.png -------------------------------------------------------------------------------- /img/graph-manager-errors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/graph-manager-errors.png -------------------------------------------------------------------------------- /img/graph-manager-metrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/graph-manager-metrics.png -------------------------------------------------------------------------------- /img/graph-manager-trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/graph-manager-trace.png -------------------------------------------------------------------------------- /img/graph-manager-unnamed-operation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/graph-manager-unnamed-operation.png -------------------------------------------------------------------------------- /img/graphiql.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/graphiql.jpg -------------------------------------------------------------------------------- /img/groups-mongo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/groups-mongo.jpg -------------------------------------------------------------------------------- /img/guide-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/guide-app.png -------------------------------------------------------------------------------- /img/hasura-add-created-at.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-add-created-at.png -------------------------------------------------------------------------------- /img/hasura-add-foreign-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-add-foreign-key.png -------------------------------------------------------------------------------- /img/hasura-add-insert-permission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-add-insert-permission.png -------------------------------------------------------------------------------- /img/hasura-add-relationship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-add-relationship.png -------------------------------------------------------------------------------- /img/hasura-admin-insert-review.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-admin-insert-review.png -------------------------------------------------------------------------------- /img/hasura-admin-secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-admin-secret.png -------------------------------------------------------------------------------- /img/hasura-after-import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-after-import.png -------------------------------------------------------------------------------- /img/hasura-console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-console.png -------------------------------------------------------------------------------- /img/hasura-create-action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-create-action.png -------------------------------------------------------------------------------- /img/hasura-data-console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-data-console.png -------------------------------------------------------------------------------- /img/hasura-hello-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-hello-query.png -------------------------------------------------------------------------------- /img/hasura-heroku-create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-heroku-create.png -------------------------------------------------------------------------------- /img/hasura-insert-review.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-insert-review.png -------------------------------------------------------------------------------- /img/hasura-review-author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-review-author.png -------------------------------------------------------------------------------- /img/hasura-review-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-review-table.png -------------------------------------------------------------------------------- /img/hasura-reviews-with-created-at.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-reviews-with-created-at.png -------------------------------------------------------------------------------- /img/hasura-reviews.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-reviews.png -------------------------------------------------------------------------------- /img/hasura-search-users.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hasura-search-users.png -------------------------------------------------------------------------------- /img/health-check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/health-check.png -------------------------------------------------------------------------------- /img/hello-get-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hello-get-query.png -------------------------------------------------------------------------------- /img/hello-schema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hello-schema.png -------------------------------------------------------------------------------- /img/hello-world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hello-world.png -------------------------------------------------------------------------------- /img/hidden-review-icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/hidden-review-icons.png -------------------------------------------------------------------------------- /img/infinite-loop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/infinite-loop.gif -------------------------------------------------------------------------------- /img/internal-server-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/internal-server-error.png -------------------------------------------------------------------------------- /img/invalid-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/invalid-id.png -------------------------------------------------------------------------------- /img/invalid-jwt-test-failure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/invalid-jwt-test-failure.png -------------------------------------------------------------------------------- /img/invalid-objectid-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/invalid-objectid-error.png -------------------------------------------------------------------------------- /img/isoString-with-variable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/isoString-with-variable.png -------------------------------------------------------------------------------- /img/launch-next-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/launch-next-query.png -------------------------------------------------------------------------------- /img/loading-skeleton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/loading-skeleton.png -------------------------------------------------------------------------------- /img/loading-temperature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/loading-temperature.png -------------------------------------------------------------------------------- /img/localhost-internal-server-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/localhost-internal-server-error.png -------------------------------------------------------------------------------- /img/location-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/location-button.png -------------------------------------------------------------------------------- /img/login.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/login.gif -------------------------------------------------------------------------------- /img/me-query-with-auth-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/me-query-with-auth-header.png -------------------------------------------------------------------------------- /img/me-query-with-null-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/me-query-with-null-results.png -------------------------------------------------------------------------------- /img/me-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/me-query.png -------------------------------------------------------------------------------- /img/me-with-all-fields.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/me-with-all-fields.png -------------------------------------------------------------------------------- /img/me-with-name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/me-with-name.png -------------------------------------------------------------------------------- /img/mocking-casual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/mocking-casual.png -------------------------------------------------------------------------------- /img/mocking-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/mocking-default.png -------------------------------------------------------------------------------- /img/mocking-external.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/mocking-external.png -------------------------------------------------------------------------------- /img/mongo-network-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/mongo-network-error.png -------------------------------------------------------------------------------- /img/mongo-users.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/mongo-users.jpg -------------------------------------------------------------------------------- /img/multiple-invalid-createReview-args.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/multiple-invalid-createReview-args.png -------------------------------------------------------------------------------- /img/must-be-logged-in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/must-be-logged-in.png -------------------------------------------------------------------------------- /img/mutation-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/mutation-log.png -------------------------------------------------------------------------------- /img/non-nullable-id-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/non-nullable-id-error.png -------------------------------------------------------------------------------- /img/npm-graphql-downloads.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/npm-graphql-downloads.png -------------------------------------------------------------------------------- /img/npm-test-App-fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/npm-test-App-fail.png -------------------------------------------------------------------------------- /img/null-group.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/null-group.jpg -------------------------------------------------------------------------------- /img/null-reviews-with-email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/null-reviews-with-email.png -------------------------------------------------------------------------------- /img/old/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/old/404.png -------------------------------------------------------------------------------- /img/onegraph-codesandbox-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/onegraph-codesandbox-data.png -------------------------------------------------------------------------------- /img/onegraph-codesandbox-oauth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/onegraph-codesandbox-oauth.png -------------------------------------------------------------------------------- /img/onegraph-create-persisted-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/onegraph-create-persisted-query.png -------------------------------------------------------------------------------- /img/onegraph-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/onegraph-dashboard.png -------------------------------------------------------------------------------- /img/onegraph-google-analytics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/onegraph-google-analytics.png -------------------------------------------------------------------------------- /img/onegraph-persisted-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/onegraph-persisted-query.png -------------------------------------------------------------------------------- /img/optimistic-favoriting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/optimistic-favoriting.gif -------------------------------------------------------------------------------- /img/play-chapters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/play-chapters.png -------------------------------------------------------------------------------- /img/play-githubStars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/play-githubStars.png -------------------------------------------------------------------------------- /img/play-section-suggestions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/play-section-suggestions.png -------------------------------------------------------------------------------- /img/play-suggestions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/play-suggestions.png -------------------------------------------------------------------------------- /img/playground-app-hello.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/playground-app-hello.png -------------------------------------------------------------------------------- /img/playground-app-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/playground-app-url.png -------------------------------------------------------------------------------- /img/ppp-in-browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/ppp-in-browser.png -------------------------------------------------------------------------------- /img/private-reviews.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/private-reviews.png -------------------------------------------------------------------------------- /img/query-plan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/query-plan.png -------------------------------------------------------------------------------- /img/redis-cached-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/redis-cached-user.png -------------------------------------------------------------------------------- /img/remove-review-network-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/remove-review-network-error.png -------------------------------------------------------------------------------- /img/remove-review-response.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/remove-review-response.gif -------------------------------------------------------------------------------- /img/remove-review.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/remove-review.gif -------------------------------------------------------------------------------- /img/request-payload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/request-payload.png -------------------------------------------------------------------------------- /img/revews-with-updatedAt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/revews-with-updatedAt.png -------------------------------------------------------------------------------- /img/review-count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/review-count.png -------------------------------------------------------------------------------- /img/review-created.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/review-created.gif -------------------------------------------------------------------------------- /img/review-text-too-short.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/review-text-too-short.png -------------------------------------------------------------------------------- /img/review-updatedAt-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/review-updatedAt-error.png -------------------------------------------------------------------------------- /img/reviews-createdAt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/reviews-createdAt.png -------------------------------------------------------------------------------- /img/reviews-playground-two-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/reviews-playground-two-results.png -------------------------------------------------------------------------------- /img/reviews-playground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/reviews-playground.png -------------------------------------------------------------------------------- /img/reviews-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/reviews-query.png -------------------------------------------------------------------------------- /img/reviews-schema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/reviews-schema.png -------------------------------------------------------------------------------- /img/reviews-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/reviews-table.png -------------------------------------------------------------------------------- /img/reviews-through-gateway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/reviews-through-gateway.png -------------------------------------------------------------------------------- /img/reviews-with-author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/reviews-with-author.png -------------------------------------------------------------------------------- /img/root-mutation-console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/root-mutation-console.png -------------------------------------------------------------------------------- /img/root-mutation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/root-mutation.png -------------------------------------------------------------------------------- /img/satellite-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/satellite-image.png -------------------------------------------------------------------------------- /img/schema-chapters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/schema-chapters.png -------------------------------------------------------------------------------- /img/schema-local-mutation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/schema-local-mutation.png -------------------------------------------------------------------------------- /img/schema-removeReview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/schema-removeReview.png -------------------------------------------------------------------------------- /img/schema-reviews.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/schema-reviews.png -------------------------------------------------------------------------------- /img/scrollY-in-cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/scrollY-in-cache.png -------------------------------------------------------------------------------- /img/searchUsers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/searchUsers.png -------------------------------------------------------------------------------- /img/section-content.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/section-content.png -------------------------------------------------------------------------------- /img/section-query-playground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/section-query-playground.png -------------------------------------------------------------------------------- /img/section-query-schema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/section-query-schema.png -------------------------------------------------------------------------------- /img/section-views.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/section-views.png -------------------------------------------------------------------------------- /img/security-and-privacy-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/security-and-privacy-settings.png -------------------------------------------------------------------------------- /img/security-dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/security-dialog.png -------------------------------------------------------------------------------- /img/sentry-formatError.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/sentry-formatError.png -------------------------------------------------------------------------------- /img/sentry-uncaught-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/sentry-uncaught-error.png -------------------------------------------------------------------------------- /img/setMyPhoto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/setMyPhoto.png -------------------------------------------------------------------------------- /img/skiplimit-all-args.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/skiplimit-all-args.png -------------------------------------------------------------------------------- /img/skiplimit-default-args.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/skiplimit-default-args.png -------------------------------------------------------------------------------- /img/skiplimit-invalid-args.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/skiplimit-invalid-args.png -------------------------------------------------------------------------------- /img/sql-coverage-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/sql-coverage-report.png -------------------------------------------------------------------------------- /img/sql-date-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/sql-date-error.png -------------------------------------------------------------------------------- /img/sql-reviews.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/sql-reviews.png -------------------------------------------------------------------------------- /img/sql-time-working.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/sql-time-working.png -------------------------------------------------------------------------------- /img/ssr-502-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/ssr-502-error.png -------------------------------------------------------------------------------- /img/ssr-hello-world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/ssr-hello-world.png -------------------------------------------------------------------------------- /img/ssr-react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/ssr-react.png -------------------------------------------------------------------------------- /img/ssr-spinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/ssr-spinner.png -------------------------------------------------------------------------------- /img/ssr-user-agent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/ssr-user-agent.png -------------------------------------------------------------------------------- /img/stars-between-0-and-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/stars-between-0-and-5.png -------------------------------------------------------------------------------- /img/stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/stars.png -------------------------------------------------------------------------------- /img/status-code-500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/status-code-500.png -------------------------------------------------------------------------------- /img/subscription-downtown-job.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/subscription-downtown-job.png -------------------------------------------------------------------------------- /img/subscription-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/subscription-start.png -------------------------------------------------------------------------------- /img/subscription-websocket-event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/subscription-websocket-event.png -------------------------------------------------------------------------------- /img/subscription-websocket-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/subscription-websocket-start.png -------------------------------------------------------------------------------- /img/table-of-contents-test-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/table-of-contents-test-error.png -------------------------------------------------------------------------------- /img/table-of-contents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/table-of-contents.png -------------------------------------------------------------------------------- /img/tableplus-reviews.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/tableplus-reviews.png -------------------------------------------------------------------------------- /img/temperature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/temperature.png -------------------------------------------------------------------------------- /img/the-cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/the-cache.png -------------------------------------------------------------------------------- /img/topology-was-destroyed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/topology-was-destroyed.png -------------------------------------------------------------------------------- /img/tshirt-directive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/tshirt-directive.png -------------------------------------------------------------------------------- /img/unexpected-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/unexpected-error.png -------------------------------------------------------------------------------- /img/updating-favorite-count.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/updating-favorite-count.gif -------------------------------------------------------------------------------- /img/upper-directive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/upper-directive.png -------------------------------------------------------------------------------- /img/user-null-email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/user-null-email.png -------------------------------------------------------------------------------- /img/user-null-forbidden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/user-null-forbidden.png -------------------------------------------------------------------------------- /img/user-profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/user-profile.png -------------------------------------------------------------------------------- /img/user-query-3-fields.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/user-query-3-fields.png -------------------------------------------------------------------------------- /img/user-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/user-query.png -------------------------------------------------------------------------------- /img/user-reviews-through-gateway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/user-reviews-through-gateway.png -------------------------------------------------------------------------------- /img/user-service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/user-service.png -------------------------------------------------------------------------------- /img/user-through-gateway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/user-through-gateway.png -------------------------------------------------------------------------------- /img/users-and-groups.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/users-and-groups.jpg -------------------------------------------------------------------------------- /img/users-groupid-mongo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/users-groupid-mongo.jpg -------------------------------------------------------------------------------- /img/users-groups-and-group.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/users-groups-and-group.jpg -------------------------------------------------------------------------------- /img/users-with-groups.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/users-with-groups.jpg -------------------------------------------------------------------------------- /img/viewed-section-request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/viewed-section-request.png -------------------------------------------------------------------------------- /img/viewedSection-schema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/viewedSection-schema.png -------------------------------------------------------------------------------- /img/vue-chapters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/vue-chapters.png -------------------------------------------------------------------------------- /img/vue-sections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/vue-sections.png -------------------------------------------------------------------------------- /img/vue-starter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/vue-starter.png -------------------------------------------------------------------------------- /img/websocket-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/websocket-data.png -------------------------------------------------------------------------------- /img/write-fragment.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/img/write-fragment.gif -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd .. 3 | cp book-assets/book.json text/ 4 | cd text/ 5 | gitbook pdf ./ ../out/the-graphql-guide.pdf 6 | gitbook epub ./ ../out/the-graphql-guide.epub 7 | gitbook mobi ./ ../out/the-graphql-guide.mobi -------------------------------------------------------------------------------- /src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/star.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/stripe-climate.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/CurrentTemperature.css: -------------------------------------------------------------------------------- 1 | .CurrentTemperature { 2 | display: flex; 3 | align-items: center; 4 | margin-right: 40px; 5 | color: var(--link); 6 | } 7 | 8 | .CurrentTemperature > button { 9 | font-size: 1em; 10 | } 11 | 12 | .CurrentTemperature > button:active, 13 | .CurrentTemperature > button:hover, 14 | .CurrentTemperature > button:focus { 15 | color: var(--link-active); 16 | } 17 | -------------------------------------------------------------------------------- /src/components/CurrentUser.css: -------------------------------------------------------------------------------- 1 | .CurrentUser:not(.inline) { 2 | position: absolute; 3 | right: 0; 4 | top: 0; 5 | padding-right: 15px; /* room for scrollbar */ 6 | transition: transform 200ms; 7 | } 8 | 9 | .CurrentUser.inline { 10 | /* color: var(--pink); */ 11 | display: flex; 12 | align-items: center; 13 | } 14 | 15 | .CurrentUser:not(.inline) > button { 16 | padding: 36px; /* line up vertically with StarCount */ 17 | } 18 | 19 | .CurrentUser > .Spinner { 20 | margin-top: 16px; 21 | margin-right: 50px; 22 | font-size: 8px; 23 | } 24 | /* 25 | .CurrentUser > button:hover, 26 | .CurrentUser > button:active { 27 | text-decoration: underline; 28 | } */ 29 | 30 | .CurrentUser :is(a, button) { 31 | display: flex; 32 | align-items: center; 33 | color: var(--link); 34 | } 35 | 36 | .CurrentUser :active:is(button, a), 37 | .CurrentUser :focus:is(button, a), 38 | .CurrentUser :hover:is(button, a) { 39 | color: var(--link-active) !important; 40 | text-decoration: none; 41 | } 42 | 43 | .User > img { 44 | width: 50px; 45 | height: 50px; 46 | margin-right: 10px; 47 | border-radius: 25px; 48 | padding: 2px; 49 | border: 2px solid var(--pink); 50 | } 51 | -------------------------------------------------------------------------------- /src/components/CurrentUser.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'gatsby' 3 | import classNames from 'classnames' 4 | 5 | import './CurrentUser.css' 6 | import { useUser } from '../lib/useUser' 7 | import { login } from '../lib/auth' 8 | 9 | export default ({ inline, buttonText, onClick }) => { 10 | const { user, loggingIn } = useUser() 11 | 12 | let content 13 | 14 | if (loggingIn) { 15 | content =
16 | } else if (!user) { 17 | content = 18 | } else { 19 | content = ( 20 | 21 | {user.firstName} 22 | {user.firstName} 23 | 24 | ) 25 | } 26 | 27 | return
{content}
28 | } 29 | -------------------------------------------------------------------------------- /src/components/Odometer.js: -------------------------------------------------------------------------------- 1 | import Odometer from 'react-odometerjs' 2 | export default Odometer 3 | -------------------------------------------------------------------------------- /src/components/Profile.css: -------------------------------------------------------------------------------- 1 | .Profile a { 2 | color: var(--pink); 3 | } 4 | 5 | .Profile-header { 6 | margin-bottom: 60px; 7 | } 8 | 9 | .Profile-login, 10 | .Profile-logout { 11 | color: var(--pink); 12 | } 13 | 14 | .Profile-login:hover, 15 | .Profile-login:active, 16 | .Profile-logout:hover, 17 | .Profile-logout:active { 18 | text-decoration: underline; 19 | } 20 | 21 | .Profile-logout { 22 | display: block; 23 | padding: 20px 0; 24 | width: 100%; 25 | } 26 | 27 | .Profile-login { 28 | margin-top: var(--vert-spacer); 29 | } 30 | 31 | .Profile dt { 32 | float: left; 33 | clear: left; 34 | width: 250px; /* half .Profile-contents width */ 35 | margin-right: 1em; 36 | text-align: right; 37 | } 38 | 39 | .Profile dt::after { 40 | content: ':'; 41 | } 42 | 43 | .Profile dd { 44 | padding: 0 0 1em 0; 45 | text-align: left; 46 | } 47 | 48 | .Profile-footer { 49 | width: 1200px; 50 | max-width: 100%; 51 | margin: 40px auto 0; 52 | } 53 | 54 | .Profile-membership-link { 55 | margin-left: 24px; 56 | } 57 | -------------------------------------------------------------------------------- /src/components/ReviewCreatedNotification.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { useSubscription } from '@apollo/client' 3 | import { Snackbar } from '@material-ui/core' 4 | import get from 'lodash/get' 5 | 6 | import { ON_REVIEW_CREATED_SUBSCRIPTION } from '../graphql/Review' 7 | 8 | export default () => { 9 | const [isOpen, setIsOpen] = useState(false) 10 | 11 | const { data } = useSubscription(ON_REVIEW_CREATED_SUBSCRIPTION, { 12 | onSubscriptionData: () => { 13 | setIsOpen(true) 14 | setTimeout(() => setIsOpen(false), 5000) 15 | }, 16 | }) 17 | 18 | const review = get(data, 'reviewCreated') 19 | return review ? ( 20 | setIsOpen(false)} 24 | message={`New review from ${review.author.name}: ${review.text}`} 25 | /> 26 | ) : null 27 | } 28 | -------------------------------------------------------------------------------- /src/components/Reviews.css: -------------------------------------------------------------------------------- 1 | .Reviews { 2 | -webkit-overflow-scrolling: touch; 3 | } 4 | 5 | .Reviews-header { 6 | text-align: center; 7 | } 8 | 9 | .Reviews-header h1 { 10 | font-size: 2.5em; 11 | font-weight: normal; 12 | } 13 | 14 | .Reviews-favorite-count { 15 | position: absolute; 16 | left: 50%; 17 | display: flex; 18 | align-items: center; 19 | margin: 9px 0 0 160px; 20 | font-size: 20px; 21 | color: rgba(0, 0, 0, 0.54); 22 | } 23 | 24 | .Reviews-favorite-count > svg { 25 | margin-right: 6px; 26 | } 27 | -------------------------------------------------------------------------------- /src/components/Reviews.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import get from 'lodash/get' 3 | import { Favorite, Add } from '@material-ui/icons' 4 | import { Fab, Modal, MenuItem, FormControl, Select } from '@material-ui/core' 5 | 6 | import './Reviews.css' 7 | import { useUser } from '../lib/useUser' 8 | import ReviewForm from './ReviewForm' 9 | import ReviewList from './ReviewList' 10 | import ReviewCreatedNotification from './ReviewCreatedNotification' 11 | 12 | export default () => { 13 | const [addingReview, setAddingReview] = useState(false) 14 | const [orderBy, setOrderBy] = useState('createdAt_DESC') 15 | 16 | const { user } = useUser() 17 | const favoriteCount = get(user, 'favoriteReviews.length') 18 | 19 | return ( 20 |
21 |
22 |
23 | {favoriteCount ? ( 24 |
25 | 26 | {favoriteCount} 27 |
28 | ) : null} 29 |

Reviews

30 | 31 | 32 | 40 | 41 |
42 |
43 | 44 | 45 | 46 | 47 | 48 | {user && ( 49 |
50 | setAddingReview(true)} 52 | color="primary" 53 | className="Reviews-add" 54 | > 55 | 56 | 57 | 58 | setAddingReview(false)}> 59 | setAddingReview(false)} /> 60 | 61 |
62 | )} 63 |
64 | ) 65 | } 66 | -------------------------------------------------------------------------------- /src/components/Reviews.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { screen, fireEvent } from '@testing-library/react' 3 | 4 | import Reviews from './Reviews' 5 | 6 | describe('Reviews', () => { 7 | it('alerts when deleting', async () => { 8 | jest.spyOn(window, 'alert').mockImplementation(() => {}) 9 | 10 | mockedRender(, { 11 | Mutation: () => ({ 12 | removeReview: () => { 13 | throw new Error('unauthorized') 14 | }, 15 | }), 16 | }) 17 | 18 | await wait() 19 | fireEvent.click(screen.getAllByRole('button', { name: 'Open menu' })[0]) 20 | await wait() 21 | fireEvent.click(screen.getAllByRole('menuitem', { name: 'Delete' })[0]) 22 | await wait() 23 | fireEvent.click(screen.getAllByRole('button', { name: 'Sudo delete' })[0]) 24 | await wait() 25 | expect(window.alert).toHaveBeenCalled() 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /src/components/Section.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { screen } from '@testing-library/react' 3 | 4 | import Section from './Section' 5 | 6 | describe('Section', () => { 7 | it('should render loading status', async () => { 8 | render( 9 | 10 |
11 | 12 | ) 13 | 14 | screen.getByRole('status') 15 | await wait() 16 | screen.getByRole('status') 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /src/components/StarCount.css: -------------------------------------------------------------------------------- 1 | .StarCount { 2 | position: relative; 3 | left: -3px; 4 | display: flex; 5 | align-items: center; 6 | text-decoration: none; 7 | transition: transform 200ms; 8 | color: var(--link); 9 | font-size: 16px; 10 | font-weight: bold; 11 | } 12 | 13 | .StarCount:hover, 14 | .StarCount:focus { 15 | color: var(--link-active); 16 | } 17 | 18 | .StarCount::after { 19 | content: 'stars'; 20 | padding-left: 5px; 21 | padding-bottom: 1px; 22 | } 23 | 24 | .StarCount.loading { 25 | opacity: 0; 26 | } 27 | 28 | .StarCount > svg { 29 | width: 27px; 30 | height: 27px; 31 | margin: -4px 2px 0 0; 32 | } 33 | 34 | .StarCount > svg * { 35 | stroke: var(--link); 36 | fill: var(--link); 37 | } 38 | 39 | .StarCount:hover > svg *, 40 | .StarCount:active > svg *, 41 | .StarCount:focus > svg * { 42 | stroke: var(--link-active); 43 | fill: var(--link-active); 44 | } 45 | -------------------------------------------------------------------------------- /src/components/StarCount.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react' 2 | import { gql, useQuery } from '@apollo/client' 3 | import classNames from 'classnames' 4 | import loadable from '@loadable/component' 5 | 6 | import { ReactComponent as StarIcon } from '../assets/star.svg' 7 | import './StarCount.css' 8 | 9 | const Odometer = loadable(() => import('./Odometer')) 10 | 11 | const STARS_QUERY = gql` 12 | query StarsQuery { 13 | githubStars 14 | } 15 | ` 16 | 17 | const STARS_SUBSCRIPTION = gql` 18 | subscription StarsSubscription { 19 | githubStars 20 | } 21 | ` 22 | 23 | export default () => { 24 | const { data, loading, subscribeToMore } = useQuery(STARS_QUERY) 25 | 26 | useEffect( 27 | () => 28 | subscribeToMore({ 29 | document: STARS_SUBSCRIPTION, 30 | updateQuery: ( 31 | _, 32 | { 33 | subscriptionData: { 34 | data: { githubStars }, 35 | }, 36 | } 37 | ) => ({ githubStars }), 38 | }), 39 | [subscribeToMore] 40 | ) 41 | 42 | return ( 43 | 49 | 50 | {data && } 51 | 52 | ) 53 | } 54 | -------------------------------------------------------------------------------- /src/components/TableOfContents.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { screen } from '@testing-library/react' 3 | import { MockedProvider } from '@apollo/client/testing' 4 | 5 | import TableOfContents, { CHAPTER_QUERY } from './TableOfContents' 6 | 7 | const mocks = [ 8 | { 9 | request: { query: CHAPTER_QUERY }, 10 | result: { 11 | data: { 12 | chapters: [ 13 | { 14 | id: 1, 15 | number: 1, 16 | title: 'mocks-title', 17 | sections: [ 18 | { 19 | id: '1', 20 | number: 1, 21 | title: 'Hello World', 22 | }, 23 | { 24 | id: '2', 25 | number: 2, 26 | title: 'Hello World', 27 | }, 28 | ], 29 | }, 30 | { 31 | id: 2, 32 | number: 2, 33 | title: 'mocks-title', 34 | sections: [ 35 | { 36 | id: '3', 37 | number: 3, 38 | title: 'Hello World', 39 | }, 40 | { 41 | id: '4', 42 | number: 4, 43 | title: 'Hello World', 44 | }, 45 | ], 46 | }, 47 | ], 48 | }, 49 | }, 50 | }, 51 | ] 52 | 53 | describe('TableOfContents', () => { 54 | it('renders loading status and chapters', async () => { 55 | mockedRender(, { 56 | Chapter: () => ({ 57 | title: () => 'Chapter-title', 58 | }), 59 | }) 60 | 61 | screen.getByRole('status') 62 | await wait() 63 | screen.getAllByText('Chapter-title') 64 | }) 65 | 66 | it('works with MockedProvider', async () => { 67 | render( 68 | 69 | 70 | 71 | ) 72 | 73 | await wait() 74 | screen.getAllByText('mocks-title') 75 | }) 76 | }) 77 | -------------------------------------------------------------------------------- /src/components/Unsubscribe.css: -------------------------------------------------------------------------------- 1 | .Unsubscribe { 2 | margin-top: 60px; 3 | text-align: center; 4 | } 5 | -------------------------------------------------------------------------------- /src/components/Unsubscribe.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react' 2 | import { gql, useMutation } from '@apollo/client' 3 | 4 | import './Unsubscribe.css' 5 | 6 | const UNSUBSCRIBE = gql` 7 | mutation Unsubscribe($token: String!) { 8 | unsubscribe(token: $token) 9 | } 10 | ` 11 | 12 | const Unsubscribe = ({ token }) => { 13 | const [unsubscribe, { data }] = useMutation(UNSUBSCRIBE) 14 | useEffect(() => { 15 | unsubscribe({ variables: { token } }) 16 | }, [unsubscribe, token]) 17 | 18 | let message = 'Unsubscribing...' 19 | if (data) { 20 | if (data.unsubscribe) { 21 | message = 'Unsubscribed ✅' 22 | } else { 23 | message = 24 | "Sorry, unsubscribe token not recognized. Please reply to your email with 'unsubscribe' in the body, and we'll process it manually." 25 | } 26 | } 27 | 28 | return
{message}
29 | } 30 | 31 | export default Unsubscribe 32 | -------------------------------------------------------------------------------- /src/components/landing/Author.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Avatar, Paper, Typography } from '@material-ui/core' 3 | 4 | import TwitterLogo from './TwitterLogo' 5 | import LinkNewTab from './LinkNewTab' 6 | 7 | const Author = ({ name, twitter, avatar, children }) => ( 8 | 9 | 13 | 14 | {twitter} 15 | 16 | 17 | 18 | {name} 19 | 20 |
{children}
21 |
22 | ) 23 | 24 | export default Author 25 | -------------------------------------------------------------------------------- /src/components/landing/Authors.css: -------------------------------------------------------------------------------- 1 | .Authors { 2 | padding: var(--vert-spacer) 0; 3 | background-image: linear-gradient(345deg, var(--pink-light), var(--pink)); 4 | } 5 | 6 | .Authors-header { 7 | margin-bottom: var(--vert-spacer) !important; 8 | text-align: center; 9 | color: white !important; 10 | } 11 | 12 | .Authors-list { 13 | display: flex; 14 | flex-wrap: wrap; 15 | justify-content: center; 16 | } 17 | 18 | .Author { 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | min-width: 370px; 23 | width: 30vw; 24 | max-width: 500px; 25 | padding: 32px; 26 | margin: 0 5vw; 27 | } 28 | 29 | .Author-avatar { 30 | order: -1; 31 | width: 100px !important; 32 | height: 100px !important; 33 | } 34 | 35 | .Author-name { 36 | order: -1; 37 | margin-top: 16px !important; 38 | text-align: center; 39 | } 40 | 41 | .Author-twitter { 42 | display: flex; 43 | align-items: center; 44 | padding: 8px 40px 20px; 45 | margin-right: 7px; /* make feel more balanced w/ avatar */ 46 | font-family: var(--code); 47 | } 48 | 49 | .Author-twitter > .TwitterLogo { 50 | margin-right: 2px; 51 | width: 30px; 52 | height: 30px; 53 | } 54 | 55 | .Author-twitter > .TwitterLogo * { 56 | fill: #1da1f2; 57 | } 58 | 59 | .Author-twitter:hover + .Author-avatar { 60 | animation: spin 3s linear infinite; 61 | } 62 | 63 | @keyframes spin { 64 | 100% { 65 | transform: rotate3d(0, 1, 0, 360deg); 66 | } 67 | } 68 | 69 | .Author-description { 70 | margin-top: 5px; 71 | } 72 | 73 | @media only screen and (max-width: 450px) { 74 | .Authors-header { 75 | margin-bottom: var(--vert-spacer) !important; 76 | } 77 | 78 | .Authors-header img:first-child { 79 | display: none; 80 | } 81 | 82 | .Author { 83 | min-width: 80vw; 84 | } 85 | } 86 | 87 | @media only screen and (max-width: 945px) { 88 | .Author:first-child { 89 | margin-bottom: var(--vert-spacer); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/components/landing/Authors.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Typography } from '@material-ui/core' 3 | 4 | import './Authors.css' 5 | import Author from './Author' 6 | 7 | const Authors = () => ( 8 |
9 | 10 | The Authors 11 | 12 |
13 | 18 | John is a JavaScript expert. He created jQuery and is Chief Software 19 | Architect at Khan Academy. Nine years ago, he stepped back from jQuery 20 | and wrote his last book. He’s been exploring the power of GraphQL and is 21 | convinced that it’s the future of API development. 22 | 23 | 24 | 29 | Loren is a consultant who loves teaching and writing. He has worked on 30 | Apollo and the Meteor Guide, built full-stack web and mobile apps for 31 | over a decade, founded startups, and TA’ed many Computer Science courses 32 | at Dartmouth. 33 | 34 |
35 |
36 | ) 37 | 38 | export default Authors 39 | -------------------------------------------------------------------------------- /src/components/landing/BelowFold.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Authors from './Authors' 4 | import Topics from './Topics' 5 | import Testimonials from './Testimonials' 6 | import Stats from './Stats' 7 | import Pricing from './Pricing' 8 | import Links from './Links' 9 | 10 | const BelowFold = () => ( 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | ) 20 | 21 | export default BelowFold 22 | -------------------------------------------------------------------------------- /src/components/landing/ElonLanding.css: -------------------------------------------------------------------------------- 1 | .ElonLanding { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | margin: 50px 0 80px; 6 | text-align: center; 7 | } 8 | 9 | .ElonLanding-avatar { 10 | width: 200px; 11 | margin-top: 10px; 12 | } 13 | 14 | .ElonLanding-quote { 15 | font-size: 1.8rem !important; 16 | } 17 | -------------------------------------------------------------------------------- /src/components/landing/ElonLanding.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Image } from 'cloudinary-react' 3 | import { Typography } from '@material-ui/core' 4 | 5 | import './ElonLanding.css' 6 | 7 | const ElonLanding = () => ( 8 |
9 | {/* 10 | As recommended by Elon Musk! 11 | */} 12 | 13 | 18 | 19 | “The future is all robo-colonoscopies and GraphQL.” 20 | 21 | 22 | 29 | 30 |
31 | ) 32 | export default ElonLanding 33 | -------------------------------------------------------------------------------- /src/components/landing/EmailIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default props => ( 4 | 5 | 6 | 7 | ) 8 | -------------------------------------------------------------------------------- /src/components/landing/Emoji.css: -------------------------------------------------------------------------------- 1 | .Emoji { 2 | width: 1.5em; 3 | height: 1.5em; 4 | vertical-align: -0.35em; 5 | margin: 0 0.25em; 6 | } 7 | -------------------------------------------------------------------------------- /src/components/landing/Footer.css: -------------------------------------------------------------------------------- 1 | .Footer { 2 | padding-bottom: 30px; 3 | color: var(--gray500); 4 | } 5 | 6 | .Footer a:hover, 7 | .Footer a:active { 8 | color: var(--pink); 9 | } 10 | 11 | .Footer > hr { 12 | margin-bottom: 64px; 13 | } 14 | 15 | .Footer-row { 16 | display: flex; 17 | justify-content: center; 18 | flex-wrap: wrap; 19 | } 20 | 21 | .Footer-row > * { 22 | margin: 0 15px; 23 | } 24 | 25 | .Footer-divider { 26 | margin: 15px 0; 27 | text-align: center; 28 | letter-spacing: 15px; 29 | line-height: 20px; 30 | } 31 | -------------------------------------------------------------------------------- /src/components/landing/Footer.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react' 2 | import { Link, navigate } from 'gatsby' 3 | 4 | import './Footer.css' 5 | import LinkNewTab from './LinkNewTab' 6 | import { login } from '../../lib/auth' 7 | 8 | const Footer = ({ legal }) => ( 9 |
10 | {legal || ( 11 | 12 |
13 |
14 | Reviews 15 | 16 | Twitter 17 | 18 | Blog 19 | 20 | hi@graphql.guide 21 | 22 |
23 |
···
24 |
25 | )} 26 |
27 |
The GraphQL Guide © {new Date().getFullYear()}
28 | Terms 29 | Privacy 30 | {legal ? ( 31 | 34 | ) : ( 35 |
36 | 37 | Gatsby theme 38 | {' '} 39 | by Apollo 40 |
41 | )} 42 |
43 |
44 | ) 45 | 46 | export default Footer 47 | -------------------------------------------------------------------------------- /src/components/landing/Landing.css: -------------------------------------------------------------------------------- 1 | .Landing { 2 | position: relative; 3 | max-width: 100vw; 4 | overflow-x: hidden; 5 | } 6 | 7 | .Landing p { 8 | line-height: 1.4; 9 | font-size: 1rem; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/landing/LandingToC.css: -------------------------------------------------------------------------------- 1 | .LandingToC { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | width: 100vw; 6 | padding: var(--vert-spacer) 0; 7 | color: white; 8 | background-image: linear-gradient( 9 | 345deg, 10 | var(--pink-light), 11 | var(--pink-dark) 12 | ); 13 | } 14 | 15 | .LandingToC-header { 16 | color: white !important; 17 | margin-bottom: calc(var(--vert-spacer) + 30px) !important; 18 | } 19 | 20 | .LandingToC-header > img { 21 | margin: 0 20px; 22 | } 23 | 24 | .LandingToC-content { 25 | /* display: flex; 26 | justify-content: center; */ 27 | column-count: 2; 28 | width: 70vw; 29 | margin-left: calc(40vw - 240px); /* right column text is shorter than left */ 30 | } 31 | 32 | .LandingToC-chapters { 33 | margin: 0; 34 | padding: 0; 35 | list-style-type: none; 36 | font-size: var(--font-larger); 37 | } 38 | 39 | .LandingToC-chapters > li { 40 | margin-bottom: 1em; 41 | } 42 | 43 | .LandingToC-chapters > li.-non-numbered { 44 | display: block; 45 | } 46 | 47 | .LandingToC-sections { 48 | margin-top: 0.75em; 49 | list-style-type: lower-roman; 50 | font-size: var(--font-medium); 51 | } 52 | 53 | .LandingToC > footer { 54 | padding: 0 10vw; 55 | text-align: center; 56 | margin-top: 60px; 57 | font-style: italic; 58 | } 59 | 60 | @media only screen and (max-width: 575px) { 61 | .LandingToC-header { 62 | text-align: center; 63 | } 64 | .LandingToC-header img:last-child { 65 | display: none; 66 | } 67 | } 68 | 69 | @media only screen and (max-width: 1500px) { 70 | .LandingToC-content { 71 | width: 100vw; 72 | margin-left: calc(50vw - 200px); 73 | } 74 | } 75 | 76 | @media only screen and (max-width: 700px) { 77 | .LandingToC-content { 78 | column-count: 1; 79 | margin-left: 10vw; 80 | width: 80vw; 81 | } 82 | 83 | .LandingToC-header { 84 | margin-bottom: var(--vert-spacer) !important; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/components/landing/LandingToC.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Typography from 'material-ui/Typography' 3 | 4 | import './LandingToC.css' 5 | import Emoji from './Emoji' 6 | 7 | import chapters from '../../lib/chapters' 8 | import sections from '../../lib/sections' 9 | 10 | const LandingToC = () => ( 11 |
12 | 13 | 14 | Table of Contents 15 | 16 | 17 |
18 |
    19 | {chapters.map(({ id, title, sectionless, nonNumbered }) => ( 20 |
  1. 21 | {nonNumbered || `${id}. `} 22 | {title} 23 | {sectionless || ( 24 |
      25 | {sections.map( 26 | ({ id: sectionId, chapterId, title }) => 27 | id === chapterId &&
    1. {title}
    2. 28 | )} 29 |
    30 | )} 31 |
  2. 32 | ))} 33 |
34 |
35 |
36 | Contents subject to change during the beta. Currently published chapters 37 | are 1, 5, 6, and Background. 38 |
39 |
40 | ) 41 | 42 | export default LandingToC 43 | -------------------------------------------------------------------------------- /src/components/landing/LinkNewTab.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default ({ children, ...props }) => ( 4 | 5 | {children} 6 | 7 | ) 8 | -------------------------------------------------------------------------------- /src/components/landing/Links.css: -------------------------------------------------------------------------------- 1 | .Links { 2 | background-image: linear-gradient(345deg, var(--pink-light), var(--pink)); 3 | color: white; 4 | } 5 | 6 | .Links .Footer { 7 | color: white; 8 | } 9 | 10 | /* match bg color */ 11 | .MediumLogo-m { 12 | fill: var(--pink-light); 13 | } 14 | 15 | .Links-text { 16 | color: white !important; 17 | } 18 | 19 | .Links a, 20 | .Links a:active, 21 | .Links a:visited { 22 | color: white; 23 | } 24 | 25 | .Links-body { 26 | padding-top: 50px; 27 | display: flex; 28 | justify-content: center; 29 | flex-wrap: wrap; 30 | } 31 | 32 | .Links-body > a { 33 | margin: 0 2vw; 34 | margin-bottom: 50px; 35 | } 36 | 37 | .Links-paper { 38 | width: 140px; 39 | padding: 0 10px 10px; 40 | display: flex; 41 | flex-direction: column; 42 | align-items: center; 43 | justify-content: flex-start; 44 | color: var(--pink); 45 | /* background-color: rgba(255, 255, 255, 0.1) !important; */ 46 | } 47 | 48 | .Links-paper > .TwitterLogo * { 49 | fill: var(--pink); 50 | /* fill: var(--white); */ 51 | } 52 | 53 | .Links-paper > .TwitterLogo, 54 | .EmailIcon, 55 | .MediumLogo { 56 | margin: 10% 0; 57 | width: 50% !important; 58 | } 59 | 60 | .EmailIcon > *, 61 | .MediumLogo-square { 62 | fill: var(--pink); 63 | } 64 | 65 | .MediumLogo-m { 66 | fill: white; 67 | } 68 | 69 | @media only screen and (max-width: 800px) { 70 | .Links-paper > .TwitterLogo, 71 | .EmailIcon, 72 | .MediumLogo { 73 | margin: 3vw 0; 74 | } 75 | 76 | .Links-body { 77 | padding: var(--vert-spacer) 0 0; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/components/landing/Links.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Footer from './Footer' 3 | import { Paper } from '@material-ui/core' 4 | 5 | import './Links.css' 6 | import TwitterLogo from './TwitterLogo' 7 | import MediumLogo from './MediumLogo' 8 | import EmailIcon from './EmailIcon' 9 | import LinkNewTab from './LinkNewTab' 10 | 11 | const Links = () => ( 12 |
13 |
14 | 15 | 16 | 17 | hi@graphql.guide 18 | 19 | 20 | 21 | 22 | 23 | @graphqlguide 24 | 25 | 26 | 27 | 28 | 29 | Blog 30 | 31 | 32 |
33 | 34 |
35 |
36 | ) 37 | 38 | export default Links 39 | -------------------------------------------------------------------------------- /src/components/landing/LogoName.css: -------------------------------------------------------------------------------- 1 | .LogoName { 2 | width: 130px; 3 | height: calc(130px * (1021.775 / 2369.692)); 4 | } 5 | 6 | .LogoName-text * { 7 | fill: var(--gray800); 8 | } 9 | -------------------------------------------------------------------------------- /src/components/landing/MediumLogo.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default props => ( 4 | 5 | 6 | 7 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /src/components/landing/Paypal.css: -------------------------------------------------------------------------------- 1 | .Paypal { 2 | position: relative; 3 | z-index: 2; /* todo not needed after remove header */ 4 | min-height: 100vh; 5 | padding-top: 20vh; 6 | display: flex; 7 | justify-content: center; 8 | background-color: var(--gray300); 9 | } 10 | 11 | .Paypal-content { 12 | width: 400px; 13 | } 14 | 15 | .Paypal-content a { 16 | color: var(--pink); 17 | } 18 | 19 | .Paypal-step2 { 20 | position: relative; 21 | } 22 | 23 | .Paypal-login { 24 | display: flex; 25 | justify-content: center; 26 | margin: 10px 0 24px; 27 | } 28 | 29 | .Paypal-login > .CurrentUser > .Spinner { 30 | margin: 0 0 24px; 31 | color: var(--gray500); 32 | } 33 | -------------------------------------------------------------------------------- /src/components/landing/Paypal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useQueryParam, NumberParam } from 'use-query-params' 3 | 4 | import './Paypal.css' 5 | import { getPackage } from '../../lib/packages' 6 | import CurrentUser from '../CurrentUser' 7 | import Emoji from './Emoji' 8 | import LinkNewTab from './LinkNewTab' 9 | import { useUser } from '../../lib/useUser' 10 | 11 | const Paypal = ({ pkg }) => { 12 | const { loggedIn } = useUser() 13 | const packageInfo = getPackage(pkg || 'full') 14 | let { name } = packageInfo 15 | 16 | const [licenses] = useQueryParam('licenses', NumberParam) 17 | const price = packageInfo.fullPrice(licenses) 18 | 19 | return ( 20 |
21 |
22 |

23 | Package: {name} 24 |

25 |

26 | Step 1: 27 | Send ${price} via PayPal, with your Github username in the payment 28 | note. 29 |

30 |

31 | 32 | paypal.me/graphqlguide/ 33 | {price} 34 | 35 |

36 |
37 |

38 | Step 2: 39 | Create an account: 40 |

41 | {loggedIn && } 42 |
43 | 44 |
45 |
46 |

47 | Step 3: 48 | We’ll manually add the package you bought to your user record in the 49 | database and email you the ebook 😄 50 |

51 |
52 |
53 | ) 54 | } 55 | 56 | export default Paypal 57 | -------------------------------------------------------------------------------- /src/components/landing/Pricing.css: -------------------------------------------------------------------------------- 1 | .Pricing { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | padding: var(--vert-spacer) 0; 6 | background-image: linear-gradient(345deg, white, var(--gray100)); 7 | } 8 | 9 | .Pricing-individual, 10 | .Pricing-group { 11 | width: 100vw; 12 | display: flex; 13 | flex-direction: row; 14 | flex-wrap: wrap; 15 | justify-content: space-evenly; 16 | align-items: stretch; 17 | } 18 | 19 | .Pricing-note { 20 | margin-right: 20px; 21 | margin-top: 16px; 22 | } 23 | 24 | .Pricing-notes { 25 | margin: 80px 16px 0; 26 | max-width: 630px; /* don't let last line wrap */ 27 | padding-bottom: 16px; 28 | text-align: center; 29 | } 30 | 31 | .Sup { 32 | cursor: pointer; 33 | color: var(--link); 34 | padding: 2px; 35 | } 36 | 37 | .Sup:hover, 38 | .Sup:active, 39 | .Sup:focus { 40 | color: var(--pink); 41 | } 42 | 43 | @media only screen and (max-width: 420px) { 44 | .Pricing-notes { 45 | margin-top: 60px; 46 | padding-bottom: 0; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/components/landing/ScrollToTopOnMount.js: -------------------------------------------------------------------------------- 1 | import { Component } from 'react' 2 | 3 | class ScrollToTopOnMount extends Component { 4 | componentDidMount() { 5 | window.scrollTo(0, 0) 6 | } 7 | 8 | render() { 9 | return null 10 | } 11 | } 12 | 13 | export default ScrollToTopOnMount 14 | -------------------------------------------------------------------------------- /src/components/landing/Stats.css: -------------------------------------------------------------------------------- 1 | .Stats { 2 | display: flex; 3 | justify-content: center; 4 | padding: 70px 0; 5 | color: white; 6 | background-image: linear-gradient( 7 | 345deg, 8 | var(--blue-light), 9 | var(--blue-dark) 10 | ); 11 | /* background-image: linear-gradient(345deg, var(--gray300), var(--gray600)); */ 12 | } 13 | .Stats-list { 14 | display: flex; 15 | justify-content: center; 16 | flex-wrap: wrap; 17 | width: 80vw; 18 | max-width: 1200px; 19 | } 20 | .Stat { 21 | display: flex; 22 | flex-direction: column; 23 | align-items: center; 24 | width: 25%; 25 | } 26 | .Stat > svg { 27 | height: 48px; 28 | width: auto !important; 29 | } 30 | .Stat-number { 31 | position: relative; 32 | font-size: 28px; 33 | font-weight: 400; 34 | margin: 24px 0 12px; 35 | color: white; 36 | } 37 | .Stat-number.-with-plus:after { 38 | content: '+'; 39 | font-weight: 300; 40 | position: absolute; 41 | right: -17px; 42 | } 43 | .Stat-caption { 44 | font-weight: 600; 45 | } 46 | @media only screen and (max-width: 700px) { 47 | .Stats { 48 | padding-bottom: 0; 49 | } 50 | .Stat { 51 | width: 50%; 52 | padding-bottom: 70px; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/components/landing/Stats.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import FontAwesomeIcon from '@fortawesome/react-fontawesome' 3 | import faFileAlt from '@fortawesome/fontawesome-free-solid/faFileAlt' 4 | import faCode from '@fortawesome/fontawesome-free-solid/faCode' 5 | import faBookOpen from '@fortawesome/fontawesome-free-solid/faBookOpen' 6 | import faVideo from '@fortawesome/fontawesome-free-solid/faVideo' 7 | 8 | import './Stats.css' 9 | 10 | const Stats = () => ( 11 |
12 |
13 |
14 | 15 |

886

16 |
Total pages
17 |
18 |
19 | 20 |

12

21 |
Chapters
22 |
23 |
24 | 25 |

5,000

26 |
Lines of code
27 |
28 |
29 | 30 |

2

31 |
Videos
32 |
33 |
34 |
35 | ) 36 | 37 | export default Stats 38 | -------------------------------------------------------------------------------- /src/components/landing/Sup.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const scrollDown = () => 4 | document.getElementById('pricing-notes').scrollIntoView(false) 5 | 6 | export default ({ children }) => ( 7 | 10 | ) 11 | -------------------------------------------------------------------------------- /src/components/landing/Testimonials.css: -------------------------------------------------------------------------------- 1 | .Testimonials { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: center; 5 | align-items: center; 6 | padding: 70px 0; 7 | color: white; 8 | background-image: linear-gradient(345deg, var(--pink-light), var(--pink)); 9 | } 10 | 11 | .Testimonials-list { 12 | display: flex; 13 | width: 100%; 14 | /* max-width: 1100px; */ 15 | align-content: center; 16 | justify-content: space-around; 17 | flex-wrap: wrap; 18 | } 19 | 20 | @media only screen and (min-width: 848px) { 21 | .Testimonials-list > div:first-child { 22 | order: 3; 23 | } 24 | .Testimonials-list > div:nth-child(3) { 25 | order: -1; 26 | } 27 | } 28 | 29 | .Testimonials-list > div { 30 | align-self: center; 31 | margin: 0 10px 60px; 32 | } 33 | 34 | .Testimonials-list .Review { 35 | margin: 0; 36 | } 37 | 38 | .Testimonials-more { 39 | margin-top: 20px; 40 | color: white; 41 | font-weight: bold; 42 | } 43 | 44 | .Testimonials-more:hover, 45 | .Testimonials-more:active, 46 | .Testimonials-more:focus { 47 | color: var(--link); 48 | } 49 | -------------------------------------------------------------------------------- /src/components/landing/Topics.css: -------------------------------------------------------------------------------- 1 | .Topics { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | padding: var(--vert-spacer) 0 calc(var(--vert-spacer) - 36px); /* compensate for bottom padding */ 6 | background-image: linear-gradient(345deg, white, var(--gray100)); 7 | } 8 | 9 | .Topics-header { 10 | margin-bottom: 45px !important; 11 | color: var(--cover-black) !important; 12 | text-align: center; 13 | } 14 | 15 | .Topics-list { 16 | display: flex; 17 | flex-wrap: wrap; 18 | justify-content: center; 19 | width: 90vw; 20 | max-width: 1200px; 21 | } 22 | 23 | .Topic { 24 | display: flex; 25 | align-items: center; 26 | flex-direction: column; 27 | width: 25%; 28 | padding: 0 15px 36px; 29 | text-align: center; 30 | } 31 | 32 | .Topic > svg { 33 | height: 85px; 34 | width: auto !important; 35 | margin-bottom: 30px; 36 | color: var(--pink); 37 | } 38 | 39 | .Topic-title { 40 | color: var(--gray700) !important; 41 | } 42 | 43 | .Topic-caption { 44 | color: var(--gray600); 45 | font-weight: 300; 46 | } 47 | 48 | .Topic > hr { 49 | background: var(--pink); 50 | border: none; 51 | height: 1px; 52 | width: 20%; 53 | margin-top: 24px; 54 | margin-bottom: 24px; 55 | } 56 | 57 | .Topics a { 58 | color: var(--pink); 59 | } 60 | 61 | .Topics a:hover, 62 | .Topics a:active, 63 | .Topics a:focus { 64 | color: var(--pink-light); 65 | text-decoration: underline; 66 | } 67 | 68 | .Topics-toc { 69 | margin-bottom: 55px; 70 | } 71 | 72 | @media only screen and (max-width: 800px) { 73 | .Topic { 74 | width: 100%; 75 | } 76 | 77 | .Topics-header { 78 | margin-bottom: var(--vert-spacer) !important; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/components/landing/Tshirt.css: -------------------------------------------------------------------------------- 1 | .Tshirt { 2 | color: white; 3 | background-image: linear-gradient( 4 | 345deg, 5 | var(--pink-light), 6 | var(--pink-dark) 7 | ); 8 | } 9 | 10 | .Tshirt-title { 11 | padding: 80px 0; 12 | color: white !important; 13 | text-align: center; 14 | } 15 | 16 | .Tshirt-modeling { 17 | display: flex; 18 | justify-content: center; 19 | flex-wrap: wrap; 20 | } 21 | 22 | .Tshirt-image { 23 | margin: 0 2vw; 24 | height: 600px; 25 | /* todo fix. this distorts image on mobile (makes it thinner) 26 | max-width: 100vw; */ 27 | } 28 | 29 | .Tshirt-options { 30 | display: flex; 31 | justify-content: center; 32 | flex-wrap: wrap; 33 | } 34 | 35 | .Tshirt-option-title { 36 | padding: 10px 0; 37 | color: white !important; 38 | } 39 | 40 | .Tshirt-option { 41 | margin: 0 2vw; 42 | } 43 | 44 | .Tshirt-option .Tshirt-image { 45 | margin: 0; 46 | } 47 | 48 | .Tshirt-details { 49 | padding-bottom: 40px; 50 | display: flex; 51 | flex-direction: column; 52 | align-items: center; 53 | } 54 | 55 | .Tshirt-common-features { 56 | margin: 40px 0; 57 | } 58 | 59 | .Tshirt-action { 60 | margin-bottom: 40px; 61 | padding: 40px; 62 | display: flex; 63 | flex-direction: column; 64 | align-items: center; 65 | color: var(--text); 66 | } 67 | 68 | .Tshirt-buy { 69 | margin-top: 40px !important; 70 | } 71 | 72 | .Tshirt-login { 73 | display: flex; 74 | margin-top: 20px; 75 | color: var(--display-gray); 76 | } 77 | 78 | .Tshirt-login > button { 79 | margin-left: 10px; 80 | text-decoration: underline; 81 | } 82 | -------------------------------------------------------------------------------- /src/components/landing/TshirtOrderForm.css: -------------------------------------------------------------------------------- 1 | .TshirtOrderForm { 2 | width: 320px; 3 | display: flex; 4 | flex-direction: column; 5 | } 6 | 7 | .TshirtOrderForm > * { 8 | margin-top: 20px !important; 9 | } 10 | 11 | .TshirtOrderForm-sizes { 12 | display: flex; 13 | justify-content: space-around; 14 | } 15 | 16 | .TshirtOrderForm-address { 17 | padding: 15px 0; 18 | text-align: center; 19 | } 20 | 21 | .TshirtOrderForm-email-order { 22 | padding-top: 20px; 23 | text-align: center; 24 | } 25 | -------------------------------------------------------------------------------- /src/components/landing/TwitterLogo.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default props => ( 4 | 10 | 11 | 12 | ) 13 | -------------------------------------------------------------------------------- /src/components/landing/Welcome.css: -------------------------------------------------------------------------------- 1 | .Welcome-wrapper { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | } 6 | 7 | .Welcome { 8 | display: flex; 9 | flex-direction: column; 10 | align-items: center; 11 | text-align: center; 12 | max-width: 650px; 13 | } 14 | 15 | .Welcome h2 { 16 | padding: 80px 0; 17 | font-size: 3rem; 18 | } 19 | 20 | .Welcome > .CurrentUser > button { 21 | color: var(--pink); 22 | } 23 | 24 | .Welcome .Spinner { 25 | color: var(--pink); 26 | } 27 | 28 | .Welcome-user { 29 | margin-top: 24px; 30 | } 31 | 32 | .Welcome-user .Spinner { 33 | margin: -20px 0 50px calc(50% - 12.5px); 34 | } 35 | 36 | .Welcome-tshirt > a { 37 | padding: 0 15px; 38 | } 39 | 40 | .Welcome-tshirt > button { 41 | color: #9e9e9e; 42 | } 43 | 44 | .Welcome-tshirt > button:active, 45 | .Welcome-tshirt > button:focus, 46 | .Welcome-tshirt > button:hover { 47 | color: var(--pink); 48 | } 49 | -------------------------------------------------------------------------------- /src/gatsby-theme-apollo/client.js: -------------------------------------------------------------------------------- 1 | // https://github.com/apollographql/gatsby-theme-apollo/tree/master/packages/gatsby-theme-apollo#gatsby-theme-apollo 2 | 3 | import { apollo } from '../lib/apollo' 4 | 5 | export default apollo 6 | -------------------------------------------------------------------------------- /src/gatsby-theme-guide-core/components/logo.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from '@emotion/styled' 3 | import { ReactComponent as Icon } from '../../assets/logo.svg' 4 | import { ReactComponent as Text } from '../../assets/logo-text.svg' 5 | import { colors } from '../utils/colors' 6 | 7 | const Wrapper = styled.div({ 8 | display: 'flex', 9 | fontSize: 24, 10 | }) 11 | 12 | const StyledIcon = styled(Icon)({ 13 | height: '1.5em', 14 | marginRight: '0.5em', 15 | }) 16 | 17 | const StyledText = styled(Text)({ 18 | height: '1em', 19 | marginTop: '0.33em', 20 | fill: colors.text1, 21 | }) 22 | 23 | export default function Logo() { 24 | return ( 25 | 26 | 27 | 28 | 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /src/gatsby-theme-guide-core/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from '@emotion/styled' 3 | 4 | const Wrapper = styled.div({ 5 | margin: '40px 56px', 6 | maxWidth: 500, 7 | }) 8 | 9 | export default () => ( 10 | 11 |

Page not found

12 |

13 | If there should be a page here, or if there’s a broken link on our site, 14 | please let us know of the issue: 15 |

16 |

17 | 18 | feedback@graphql.guide 19 | 20 |

21 |
22 | ) 23 | -------------------------------------------------------------------------------- /src/gatsby-theme-guide-core/utils/colors.js: -------------------------------------------------------------------------------- 1 | const { colors } = require('@apollo/space-kit/colors') 2 | 3 | exports.colors = { 4 | primary: '#df1797', 5 | // primary: colors.indigo.dark, 6 | primaryLight: colors.indigo.lighter, 7 | secondary: colors.pink.base, 8 | tertiary: colors.teal.dark, 9 | tertiaryLight: colors.teal.base, 10 | divider: colors.silver.dark, 11 | background: colors.silver.light, 12 | background2: colors.silver.base, 13 | text1: colors.black.lighter, 14 | text2: colors.grey.dark, 15 | text3: colors.grey.light, 16 | text4: colors.silver.darker, 17 | warning: colors.yellow.base, 18 | shadow: colors.black.darker, 19 | highlight: colors.blue.base, 20 | highlight2: colors.blue.lighter, 21 | highlight3: colors.blue.lightest, 22 | hoverOpacity: 0.8, 23 | } 24 | -------------------------------------------------------------------------------- /src/gatsby-theme-guide/components/above-nav.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from '@emotion/styled' 3 | import { breakpoints } from 'gatsby-theme-guide-core' 4 | 5 | import CurrentUser from '../../components/CurrentUser' 6 | 7 | const Container = styled.div({ 8 | display: 'none', 9 | [breakpoints.sm]: { 10 | display: 'flex', 11 | justifyContent: 'center', 12 | marginBottom: 24, 13 | }, 14 | }) 15 | 16 | export const AboveNav = ({ onClick }) => ( 17 | 18 | 19 | 20 | ) 21 | -------------------------------------------------------------------------------- /src/gatsby-theme-guide/components/footer.js: -------------------------------------------------------------------------------- 1 | import Footer from '../../components/landing/Footer' 2 | 3 | export default Footer 4 | -------------------------------------------------------------------------------- /src/gatsby-theme-guide/components/further-asides.js: -------------------------------------------------------------------------------- 1 | import StarCount from '../../components/StarCount' 2 | 3 | export const FurtherAsides = StarCount 4 | -------------------------------------------------------------------------------- /src/gatsby-theme-guide/components/header-button.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from '@emotion/styled' 3 | import { breakpoints } from 'gatsby-theme-guide-core' 4 | 5 | import CurrentUser from '../../components/CurrentUser' 6 | import CurrentTemperature from '../../components/CurrentTemperature' 7 | 8 | const Container = styled.div({ 9 | display: 'flex', 10 | flexShrink: 0, 11 | width: 240, 12 | [breakpoints.lg]: { 13 | width: 'auto', 14 | marginRight: 0, 15 | }, 16 | [breakpoints.md]: { 17 | marginLeft: 40, 18 | }, 19 | [breakpoints.sm]: { 20 | display: 'none', 21 | }, 22 | }) 23 | 24 | export default function HeaderButton() { 25 | return ( 26 | 27 | 28 | 29 | 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /src/gatsby-theme-guide/components/mobile-logo.js: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | import { ReactComponent as Icon } from '../../assets/logo.svg' 3 | 4 | export const MobileLogo = styled(Icon)({ 5 | marginLeft: 20, 6 | }) 7 | -------------------------------------------------------------------------------- /src/gatsby-theme-guide/startup.js: -------------------------------------------------------------------------------- 1 | import '../startup/' 2 | -------------------------------------------------------------------------------- /src/gatsby-theme-material-ui-top-layout/theme.js: -------------------------------------------------------------------------------- 1 | import { createMuiTheme } from '@material-ui/core' 2 | 3 | const PINK = '#df1797' 4 | // const PINK = '#e10098' 5 | 6 | const theme = createMuiTheme({ 7 | palette: { primary: { main: PINK } }, 8 | }) 9 | 10 | export default theme 11 | -------------------------------------------------------------------------------- /src/graphql/Review.js: -------------------------------------------------------------------------------- 1 | import gql from 'graphql-tag' 2 | 3 | export const REVIEW_ENTRY = gql` 4 | fragment ReviewEntry on Review { 5 | id 6 | text 7 | stars 8 | createdAt 9 | favorited 10 | author { 11 | id 12 | name 13 | photo 14 | username 15 | } 16 | } 17 | ` 18 | 19 | export const REVIEWS_QUERY = gql` 20 | query ReviewsQuery($after: ObjID, $limit: Int, $orderBy: ReviewOrderBy) { 21 | reviews(after: $after, limit: $limit, orderBy: $orderBy) { 22 | ...ReviewEntry 23 | } 24 | } 25 | ${REVIEW_ENTRY} 26 | ` 27 | 28 | export const ON_REVIEW_CREATED_SUBSCRIPTION = gql` 29 | subscription onReviewCreated { 30 | reviewCreated { 31 | ...ReviewEntry 32 | } 33 | } 34 | ${REVIEW_ENTRY} 35 | ` 36 | 37 | export const ON_REVIEW_UPDATED_SUBSCRIPTION = gql` 38 | subscription onReviewUpdated { 39 | reviewUpdated { 40 | ...ReviewEntry 41 | } 42 | } 43 | ${REVIEW_ENTRY} 44 | ` 45 | 46 | export const ON_REVIEW_DELETED_SUBSCRIPTION = gql` 47 | subscription onReviewDeleted { 48 | reviewDeleted 49 | } 50 | ` 51 | -------------------------------------------------------------------------------- /src/lib/apollo.js: -------------------------------------------------------------------------------- 1 | import { ApolloClient, InMemoryCache, gql } from '@apollo/client' 2 | import find from 'lodash/find' 3 | 4 | import link, { spaceXLink } from './link' 5 | 6 | export const cache = new InMemoryCache({ 7 | typePolicies: { 8 | Query: { 9 | fields: { 10 | reviews: { 11 | merge(existing = [], incoming, { readField }) { 12 | const notAlreadyInCache = (review) => 13 | !find( 14 | existing, 15 | (existingReview) => 16 | readField('id', existingReview) === readField('id', review) 17 | ) 18 | 19 | const newReviews = incoming.filter(notAlreadyInCache) 20 | 21 | return [...existing, ...newReviews] 22 | }, 23 | keyArgs: ['orderBy'], 24 | }, 25 | section: (_, { args: { id }, toReference }) => 26 | toReference({ 27 | __typename: 'Section', 28 | id, 29 | }), 30 | }, 31 | }, 32 | Section: { 33 | fields: { 34 | scrollY: (scrollY) => scrollY || 0, 35 | }, 36 | }, 37 | }, 38 | }) 39 | 40 | /* eslint-disable graphql/template-strings */ 41 | const typeDefs = gql` 42 | extend type Section { 43 | scrollY: Int 44 | } 45 | ` 46 | /* eslint-enable graphql/template-strings */ 47 | 48 | export const apollo = new ApolloClient({ link, cache, typeDefs }) 49 | 50 | export const apolloSpace = new ApolloClient({ 51 | link: spaceXLink, 52 | cache: new InMemoryCache(), 53 | }) 54 | -------------------------------------------------------------------------------- /src/lib/auth.js: -------------------------------------------------------------------------------- 1 | import auth0 from 'auth0-js' 2 | import { 3 | initAuthHelpers, 4 | login as auth0Login, 5 | logout as auth0Logout, 6 | } from 'auth0-helpers' 7 | import { makeVar } from '@apollo/client' 8 | 9 | import { apollo } from './apollo' 10 | 11 | const client = new auth0.WebAuth({ 12 | domain: 'graphql.auth0.com', 13 | clientID: '8fErnZoF3hbzQ2AbMYu5xcS0aVNzQ0PC', 14 | responseType: 'token', 15 | audience: 'https://api.graphql.guide', 16 | scope: 'openid profile guide', 17 | }) 18 | 19 | initAuthHelpers({ 20 | client, 21 | usePopup: true, 22 | authOptions: { 23 | connection: 'github', 24 | owp: true, 25 | popupOptions: { height: 623 }, // make tall enough for content 26 | }, 27 | checkSessionOptions: { 28 | redirect_uri: 'https://graphql.guide', 29 | }, 30 | returnToAfterLogout: 'https://graphql.guide', 31 | onError: (e) => console.error(e), 32 | }) 33 | 34 | export const loginInProgressVar = makeVar(false) 35 | 36 | export const login = (cb) => { 37 | loginInProgressVar(true) 38 | 39 | auth0Login({ 40 | onCompleted: (e) => { 41 | loginInProgressVar(false) 42 | if (e) { 43 | console.error(e) 44 | return 45 | } 46 | 47 | apollo.reFetchObservableQueries().then(() => { 48 | if (typeof cb === 'function') { 49 | cb() 50 | } 51 | }) 52 | }, 53 | }) 54 | } 55 | 56 | export const logout = () => { 57 | auth0Logout() 58 | apollo.resetStore() 59 | } 60 | -------------------------------------------------------------------------------- /src/lib/chapters.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | // { 3 | // id: -3, 4 | // title: 'Foreword' 5 | // }, 6 | { 7 | id: -2, 8 | title: 'Preface', 9 | sectionless: true, 10 | nonNumbered: true 11 | }, 12 | { 13 | id: -1, 14 | title: 'Introduction', 15 | sectionless: true, 16 | nonNumbered: true 17 | }, 18 | { 19 | id: 1, 20 | title: 'Understanding GraphQL through REST' 21 | }, 22 | { 23 | id: 2, 24 | title: 'Query Language' 25 | }, 26 | { 27 | id: 3, 28 | title: 'Type System' 29 | }, 30 | { 31 | id: 4, 32 | title: 'Validation & Execution' 33 | }, 34 | { 35 | id: 5, 36 | title: 'Client Dev' 37 | }, 38 | { 39 | id: 6, 40 | title: 'React' 41 | }, 42 | { 43 | id: 7, 44 | title: 'Vue', 45 | sectionless: true 46 | }, 47 | { 48 | id: 8, 49 | title: 'React Native', 50 | sectionless: true 51 | }, 52 | { 53 | id: 9, 54 | title: 'iOS', 55 | sectionless: true 56 | }, 57 | { 58 | id: 10, 59 | title: 'Android', 60 | sectionless: true 61 | }, 62 | { 63 | id: 11, 64 | title: 'Server Dev' 65 | }, 66 | { 67 | id: 12, 68 | title: 'Background', 69 | nonNumbered: true 70 | } 71 | ] 72 | -------------------------------------------------------------------------------- /src/lib/common.css: -------------------------------------------------------------------------------- 1 | .-nowrap { 2 | white-space: nowrap; 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/confetti.js: -------------------------------------------------------------------------------- 1 | import confetti from 'canvas-confetti' 2 | 3 | import { inBrowser } from './helpers' 4 | 5 | export const fireworks = () => { 6 | const DURATION_IN_MS = 3 * 1000 7 | const endTime = Date.now() + DURATION_IN_MS 8 | 9 | const firework = () => { 10 | confetti({ 11 | startVelocity: 20, 12 | spread: 700, 13 | ticks: 200, 14 | origin: { 15 | x: Math.random(), 16 | y: Math.random() - 0.2, 17 | }, 18 | }) 19 | 20 | const done = Date.now() > endTime 21 | if (done) { 22 | return 23 | } 24 | 25 | setTimeout(firework, Math.random() * 700) 26 | } 27 | 28 | firework() 29 | } 30 | 31 | if (inBrowser) { 32 | window.fireworks = fireworks 33 | } 34 | -------------------------------------------------------------------------------- /src/lib/errorLink.js: -------------------------------------------------------------------------------- 1 | import { onError } from '@apollo/client/link/error' 2 | 3 | const KNOWN_ERRORS = [ 4 | 'unauthorized', 5 | 'already-associated', 6 | 'order-failed', 7 | 'checkout-session-not-completed', 8 | 'unknown-token', 9 | 'signup-token-has-already-been-used', 10 | ] 11 | 12 | export const errorLink = onError(({ graphQLErrors, networkError }) => { 13 | if (networkError) { 14 | console.log(`[Network error]: ${networkError}`) 15 | return 16 | } 17 | 18 | if (graphQLErrors) { 19 | const unknownErrors = graphQLErrors.filter( 20 | (error) => !KNOWN_ERRORS.includes(error.message) 21 | ) 22 | 23 | if (unknownErrors.length) { 24 | alert('😳 An unexpected error occurred on the server') 25 | unknownErrors.map(({ message, locations, path }) => 26 | console.log(`[GraphQL error]: Message: ${message}, Path: ${path}`) 27 | ) 28 | } 29 | } 30 | }) 31 | -------------------------------------------------------------------------------- /src/lib/helpers.js: -------------------------------------------------------------------------------- 1 | export const inBrowser = typeof window === 'object' 2 | export const inDevelopment = process.env.NODE_ENV === 'development' 3 | -------------------------------------------------------------------------------- /src/lib/images.js: -------------------------------------------------------------------------------- 1 | import Core from 'cloudinary-core' 2 | 3 | export default new Core.Cloudinary({ cloud_name: 'graphql' }) 4 | -------------------------------------------------------------------------------- /src/lib/track.js: -------------------------------------------------------------------------------- 1 | import ReactGA from 'react-ga' 2 | import find from 'lodash/find' 3 | import defer from 'lodash/defer' 4 | 5 | const EVENTS = [ 6 | { 7 | name: 'purchase', 8 | category: 'User', 9 | }, 10 | { 11 | name: 'checkout', 12 | category: 'User', 13 | }, 14 | ] 15 | 16 | const track = (name, data) => { 17 | defer(() => { 18 | const event = find(EVENTS, { name }) 19 | if (!event) { 20 | throw new Error('unknown event type—add it to track.js') 21 | } 22 | 23 | ReactGA.event({ 24 | category: event.category, 25 | action: name, 26 | ...(data.package && { label: data.package }), 27 | }) 28 | window.heap.track(name, data) 29 | }) 30 | } 31 | 32 | export default track 33 | -------------------------------------------------------------------------------- /src/lib/useUser.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { gql, useQuery, useReactiveVar } from '@apollo/client' 3 | import LogRocket from 'logrocket' 4 | import ReactGA from 'react-ga' 5 | 6 | import { loginInProgressVar } from './auth' 7 | import { associateSession } from './payment' 8 | import { inBrowser, inDevelopment } from './helpers' 9 | 10 | export const USER_QUERY = gql` 11 | query UserQuery { 12 | currentUser { 13 | id 14 | firstName 15 | name 16 | username 17 | email 18 | photo 19 | hasPurchased 20 | hasTshirt 21 | ebookUrl 22 | favoriteReviews { 23 | id 24 | } 25 | } 26 | } 27 | ` 28 | 29 | function track(user) { 30 | if (inDevelopment) return 31 | 32 | const { id, name, email, hasPurchased } = user 33 | const userData = { 34 | name, 35 | email, 36 | hasPurchased, 37 | } 38 | 39 | window.heap.identify(id, 'ID') 40 | window.heap.addUserProperties(userData) 41 | ReactGA.set({ 42 | id, 43 | ...userData, 44 | }) 45 | LogRocket.identify(id, userData) 46 | } 47 | 48 | export function useUser() { 49 | const { data, loading } = useQuery(USER_QUERY) 50 | const loginInProgress = useReactiveVar(loginInProgressVar) 51 | const user = data && data.currentUser 52 | 53 | useEffect(() => { 54 | if (user && inBrowser) { 55 | associateSession() 56 | track(user) 57 | } 58 | }, [user]) 59 | 60 | return { 61 | user, 62 | loggedIn: !!user, 63 | loggingIn: loading || loginInProgress, 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/lib/validators.js: -------------------------------------------------------------------------------- 1 | import { 2 | createValidator, 3 | composeValidators, 4 | combineValidators, 5 | isRequired, 6 | hasLengthLessThan, 7 | } from 'revalidate' 8 | 9 | const isString = createValidator( 10 | (message) => (value) => { 11 | if (!(typeof value === 'string')) { 12 | return message 13 | } 14 | }, 15 | (field) => `${field} must be a String` 16 | ) 17 | 18 | export const validateReview = combineValidators({ 19 | text: composeValidators( 20 | isRequired, 21 | isString, 22 | hasLengthLessThan(500) 23 | )('Review text'), 24 | stars: createValidator( 25 | (message) => (value) => { 26 | if (![null, 1, 2, 3, 4, 5].includes(value)) { 27 | return message 28 | } 29 | }, 30 | (field) => `${field} must be a number 1–5` 31 | )('Stars'), 32 | }) 33 | 34 | // validateReview({ 35 | // text: 1, 36 | // stars: 5 37 | // }) 38 | // 39 | // => {text: "Review text must be a String"} 40 | 41 | // validateReview({ 42 | // text: 'my review', 43 | // stars: 'a string' 44 | // }) 45 | // 46 | // => {stars: Stars must be a number 1–5`} 47 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import Landing from '../components/landing/Landing' 2 | 3 | export default Landing 4 | -------------------------------------------------------------------------------- /src/pages/me.js: -------------------------------------------------------------------------------- 1 | import Profile from '../components/Profile' 2 | 3 | export default Profile 4 | -------------------------------------------------------------------------------- /src/pages/paypal/[package].js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Paypal from '../../components/landing/Paypal' 3 | 4 | export default ({ params }) => 5 | -------------------------------------------------------------------------------- /src/pages/reviews.js: -------------------------------------------------------------------------------- 1 | import Reviews from '../components/Reviews' 2 | 3 | export default Reviews 4 | -------------------------------------------------------------------------------- /src/pages/team/[token].js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Team from '../../components/landing/Team' 3 | 4 | export default ({ params }) => { 5 | if (!params.token) { 6 | return 'Missing token parameter' 7 | } 8 | 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /src/pages/tshirt.js: -------------------------------------------------------------------------------- 1 | import Tshirt from '../components/landing/Tshirt' 2 | 3 | export default Tshirt 4 | -------------------------------------------------------------------------------- /src/pages/unsubscribe/[token].js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Unsubscribe from '../../components/Unsubscribe' 3 | 4 | export default ({ params }) => 5 | -------------------------------------------------------------------------------- /src/pages/videos.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import YouTube from 'react-youtube' 3 | import { Link } from 'gatsby' 4 | 5 | import { useUser } from '../lib/useUser' 6 | import { login } from '../lib/auth' 7 | import { getPackage } from '../lib/packages' 8 | 9 | export default () => { 10 | const { user, loggingIn } = useUser() 11 | const pkg = getPackage(user?.hasPurchased) 12 | 13 | if (loggingIn) { 14 | return ( 15 |
16 |
17 |
18 | ) 19 | } else if (!user) { 20 | return ( 21 |
22 | 25 |
26 | ) 27 | } else if (pkg?.individualPackage() === 'full') { 28 | return ( 29 |
30 | 31 | 32 |
33 | ) 34 | } else if (pkg?.individualPackage() === 'pro') { 35 | return
Videos coming soon
36 | } else { 37 | return ( 38 |
39 | 40 | Purchase the Pro or Full package 41 | 42 |
43 | ) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/pages/welcome.js: -------------------------------------------------------------------------------- 1 | import Welcome from '../components/landing/Welcome' 2 | 3 | export default Welcome 4 | -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | createApolloErrorProvider, 4 | createApolloMockedProvider, 5 | createApolloLoadingProvider, 6 | } from 'apollo-mocked-provider' 7 | import { ApolloLink } from '@apollo/client' 8 | import { printSchema, buildClientSchema } from 'graphql' 9 | import fs from 'fs' 10 | import { render, waitFor } from '@testing-library/react' 11 | import { createMemoryHistory } from 'history' 12 | import { Router } from 'react-router-dom' 13 | 14 | import '@testing-library/jest-dom/extend-expect' 15 | 16 | const responseLogger = new ApolloLink((operation, forward) => { 17 | return forward(operation).map((result) => { 18 | console.log(JSON.stringify(result, null, ' ')) 19 | return result 20 | }) 21 | }) 22 | 23 | const schema = JSON.parse(fs.readFileSync('schema.json')) 24 | const typeDefs = printSchema(buildClientSchema(schema.data)) 25 | const ApolloMockedProvider = createApolloMockedProvider(typeDefs, { 26 | links: () => [responseLogger], 27 | }) 28 | 29 | global.ApolloMockedProvider = ApolloMockedProvider 30 | global.ApolloErrorProvider = createApolloErrorProvider() 31 | global.ApolloLoadingProvider = createApolloLoadingProvider() 32 | 33 | const RouterWrapper = ({ children }) => { 34 | const history = createMemoryHistory() 35 | 36 | return {children} 37 | } 38 | 39 | global.render = (ui, options) => 40 | render(ui, { wrapper: RouterWrapper, ...options }) 41 | 42 | global.mockedRender = (ui, customResolvers, options) => { 43 | let id = 1 44 | 45 | const MockedWrapper = ({ children }) => ( 46 | 47 | ({ 50 | id: id++, 51 | number: id++, 52 | }), 53 | ObjID: () => id++, 54 | ...customResolvers, 55 | }} 56 | > 57 | {children} 58 | 59 | 60 | ) 61 | 62 | return render(ui, { wrapper: MockedWrapper, ...options }) 63 | } 64 | 65 | global.wait = () => waitFor(() => {}) 66 | -------------------------------------------------------------------------------- /src/startup/google-analytics.js: -------------------------------------------------------------------------------- 1 | import ReactGA from 'react-ga' 2 | 3 | ReactGA.initialize('UA-96115966-1') 4 | -------------------------------------------------------------------------------- /src/startup/index.js: -------------------------------------------------------------------------------- 1 | // only run in browser 2 | 3 | import './google-analytics' 4 | import './logrocket' 5 | -------------------------------------------------------------------------------- /src/startup/logrocket.js: -------------------------------------------------------------------------------- 1 | import LogRocket from 'logrocket' 2 | 3 | LogRocket.init('0pof5j/guide') 4 | -------------------------------------------------------------------------------- /static/external.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GraphQLGuide/book/a378cdaf542a026be8d2dcaec26c5d073d2c9f34/static/favicon.ico -------------------------------------------------------------------------------- /static/robots.txt: -------------------------------------------------------------------------------- 1 | Sitemap: https://graphql.guide/sitemap.xml -------------------------------------------------------------------------------- /static/service-worker.js: -------------------------------------------------------------------------------- 1 | self.addEventListener('install', function () { 2 | self.skipWaiting() 3 | }) 4 | 5 | self.addEventListener('activate', function () { 6 | self.clients.matchAll({ type: 'window' }).then(function (windowClients) { 7 | windowClients.forEach((windowClient) => { 8 | windowClient.navigate(windowClient.url) 9 | }) 10 | }) 11 | 12 | if ('serviceWorker' in navigator) { 13 | navigator.serviceWorker.ready.then(function (registration) { 14 | registration.unregister().then(() => window.location.reload(true)) 15 | }) 16 | } 17 | }) 18 | -------------------------------------------------------------------------------- /static/startupranking1138863810361710.html: -------------------------------------------------------------------------------- 1 | startupranking-site-verification: startupranking1138863810361710.html -------------------------------------------------------------------------------- /text/.nvmrc: -------------------------------------------------------------------------------- 1 | 8 2 | -------------------------------------------------------------------------------- /text/android/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Overview 3 | description: Table of contents for the Android chapter 4 | --- 5 | 6 | # Chapter 10: Android 7 | 8 | Chapter contents: 9 | 10 | * [Setting up Apollo Android](setting-up-apollo-android.md) 11 | * [First query](first-query.md) 12 | * [Querying with variables](querying-with-variables.md) 13 | * [Caching](caching.md) 14 | * [ViewModel](viewmodel.md) 15 | * [Flow](flow.md) 16 | 17 | --- 18 | 19 | Background: [mobile apps](../background/mobile-apps.md), [Android and Kotlin](../background/mobile-apps.md#android) 20 | 21 | In this chapter, we’ll build a small Android app using the [Apollo Android](https://www.apollographql.com/docs/android/) library to make a couple GraphQL queries and get the data for our UI. 22 | 23 | Apollo Android doesn’t use Apollo Client, the JavaScript library behind the [React](../react/index.md), [Vue](../vue/index.md), and [React Native](../react-native/index.md) chapters. It’s a separate codebase with its own feature set: 24 | 25 | - Generates Java and Kotlin typed models from our operations and [fragments](https://www.apollographql.com/docs/android/essentials/fragments/) 26 | - Three types of [caching](caching.md) 27 | - [RxJava](https://www.apollographql.com/docs/android/advanced/rxjava3/) and [coroutine](https://www.apollographql.com/docs/android/advanced/coroutines/) APIs 28 | - [File uploads](https://www.apollographql.com/docs/android/essentials/mutations/#uploading-files) 29 | - [Persisted queries](https://www.apollographql.com/docs/android/advanced/persisted-queries/) 30 | - [Custom scalar types](https://www.apollographql.com/docs/android/essentials/custom-scalar-types/) 31 | 32 | The app we’ll build is the table of contents for the Guide. It has two pages: the first, a list of chapters, and the second, a list of sections in a chapter. 33 | 34 | ![The first page with a list of chapters](../img/android-chapters.png) 35 | ![The second page with a list of sections](../img/android-sections.png) 36 | -------------------------------------------------------------------------------- /text/background/continuous-integration.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Continuous integration 3 | --- 4 | 5 | # Continuous integration 6 | 7 | While continuous integration (CI) technically means merging to `master` frequently, in modern web development it usually means the process of tests being run automatically on each commit. It’s often done with a service like [CircleCI](https://circleci.com/) that monitors our commits on GitHub, runs the tests, and provides a webpage for each commit where we can view the test output. We can also set it up to do something after the test, such as: 8 | 9 | - Mark a pull request as passing or failing the tests. 10 | - Mark that commit as passing or failing by adding a red X or green checkmark next to the commit in the repository’s history. 11 | - If successful, deploy the code to a server—for example the staging or production server. 12 | 13 | When the last step is included, the process may also be called continuous delivery or continuous deployment. 14 | 15 | -------------------------------------------------------------------------------- /text/background/git.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Git 3 | --- 4 | 5 | # Git 6 | 7 | [Git](https://en.wikipedia.org/wiki/Git) is a version control system for saving your code and keeping a history of the changes. Unfamiliar? Try this [interactive tutorial](https://try.github.io/). 8 | -------------------------------------------------------------------------------- /text/background/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contents 3 | description: This chapter provides concise introductions to various background topics. 4 | --- 5 | 6 | # Chapter: Background 7 | 8 | Chapter contents: 9 | 10 | * [JavaScript](javascript.md) 11 | * [JavaScript](javascript.md#classes) 12 | * [JSON](json.md) 13 | * [Git](git.md) 14 | * [Node, npm, and nvm](node-npm-and-nvm.md) 15 | * [HTTP](http.md) 16 | * [Server](server.md) 17 | * [Databases](databases.md) 18 | * [MongoDB](databases.md#mongodb) 19 | * [Redis](databases.md#redis) 20 | * [SQL](databases.md#sql) 21 | * [SPA](spa.md) 22 | * [SSR](ssr.md) 23 | * [React](react.md) 24 | * [Vue](vue.md) 25 | * [Mobile apps](mobile-apps.md) 26 | * [Android](mobile-apps.md#android) 27 | * [iOS](mobile-apps.md#ios) 28 | * [React Native](mobile-apps.md#react-native) 29 | * [Latency](latency.md) 30 | * [CDN](cdn.md) 31 | * [Webhooks](webhooks.md) 32 | * [Testing](testing.md) 33 | * [Mocking](testing.md#mocking) 34 | * [Types of tests](testing.md#types-of-tests) 35 | * [Continuous integration](continuous-integration.md) 36 | * [Authentication](authentication.md) 37 | * [Tokens vs. sessions](authentication.md#tokens-vs-sessions) 38 | * [localStorage vs. cookies](authentication.md#localstorage-vs-cookies) 39 | * [Browser performance](browser-performance.md) 40 | 41 | --- 42 | 43 | This chapter provides concise introductions to various background topics. You’re welcome to either read them all up front or individually as you go along—at the beginning of a section, you’ll find a list of topics it assumes knowledge of, like the [Anywhere: HTTP](../client/anywhere-http.md) section, which has two listed: 44 | 45 | > Background: [HTTP](http.md), [JSON](json.md) 46 | 47 | Some topics, like [Git](git.md) and [Node](node-npm-and-nvm.md), are necessary for following along with the coding. Others, like [Tokens vs. sessions](authentication.md#tokens-vs-sessions), are nice to know, but not essential. -------------------------------------------------------------------------------- /text/background/json.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JSON 3 | --- 4 | 5 | # JSON 6 | 7 | JSON is a file format for data objects. The objects are structured in attribute–value pairs, where the attribute is a string and the value can be one of the following types: 8 | 9 | - Number: `1.14` 10 | - String: `"foo"` 11 | - Boolean: `true` 12 | - null: `null` 😄 13 | - Array of other types: `["foo", true, 1.14]` 14 | - Object: `{ "name": "john" }` 15 | 16 | In JSON documents, whitespace doesn’t matter, and commas go between attribute–value pairs and between items in arrays. Here’s an example, formatted with nice whitespace: 17 | 18 | ```json 19 | { 20 | "authors": [ 21 | { 22 | "name": "john", 23 | "wearsGlasses": true 24 | }, 25 | { 26 | "name": "loren", 27 | "wearsGlasses": true 28 | } 29 | ] 30 | } 31 | ``` 32 | 33 | > It’s also valid JSON to have an array at the top level of the document, e.g.: 34 | > 35 | > `[{ "name": "john" }, { "name": "loren" }]` 36 | 37 | In JavaScript, if we have this document in a string, we can parse it to create a JavaScript object with the same data: 38 | 39 | ```js 40 | const jsObject = JSON.parse(jsonString) 41 | ``` 42 | 43 | When working with raw [HTTP](http.md) responses that contain a JSON body, we have to use `JSON.parse()` to get the data into an object. But we’ll mostly be working with libraries that take care of this step for us. 44 | 45 | 46 | -------------------------------------------------------------------------------- /text/background/server.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Server 3 | --- 4 | 5 | # Server 6 | 7 | The term *server* may refer to: 8 | 9 | 1. A computer connected to a network (usually the internet). 10 | 2. A process running on that computer that listens to one or more ports. 11 | 3. The group of computers/processes that share the responsibility of handling requests. 12 | 13 | In web development, servers are usually either static file servers (which serve files like our HTML, images, and JS bundle), application (app) servers (the ones that power our API and that the client talks to), or database servers. *Server-side* either means app servers or everything that’s not the client-side (including file, app, and database servers, as well as any other servers they talk to). 14 | 15 | -------------------------------------------------------------------------------- /text/background/spa.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SPA 3 | --- 4 | 5 | # SPA 6 | 7 | An [SPA](https://en.wikipedia.org/wiki/Single-page_application) (single-page application) is a website that keeps the same page loaded for the duration of the user’s session. Instead of a traditional website, in which every link or button that is clicked causes an [HTTP request](http.md) to be sent to the server and a new HTML page to be loaded, there is a single HTML page, and JavaScript changes the page to show different views. React, Angular, and Vue are all JS libraries for making SPAs (often called *view libraries*). 8 | -------------------------------------------------------------------------------- /text/background/ssr.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SSR 3 | --- 4 | 5 | # SSR 6 | 7 | SSR (server-side rendering) is when, instead of sending a small HTML file and a JS bundle that we ask the client to parse and render into HTML, our server sends fully rendered HTML (that it created by running the JS view code on the server). When that rendered HTML is cached, the client browser will display the page faster than a normal SPA (a normal SPA displays a blank or skeleton HTML page, and then JavaScript constructs the view and puts it on the page). We also have code from our view library that, once the browser loads the static HTML, attaches our app’s event handlers (like `onClick`, `onSubmit`, etc.) to the page (through a process called *hydration*). 8 | 9 | SSR was traditionally necessary for allowing search engines to index page content. However, Google and Bing now use JavaScript to render web pages, so SPAs are usually indexed fine. (You can check by searching `site:mydomain.com` or using Google’s [URL Inspection Tool](https://support.google.com/webmasters/answer/9012289?hl=en).) 10 | -------------------------------------------------------------------------------- /text/background/vue.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Vue 3 | --- 4 | 5 | # Vue 6 | 7 | [Vue.js](https://v3.vuejs.org/guide/introduction.html) was created in 2014 by Evan You after working with Angular.js at Google. Evan wanted a lightweight view library that had the good parts of Angular. It has since evolved a lot, is now in its third major version, and has a number of accompanying tooling and libraries, including a devtools browser extension, a CLI, a webpack loader, and a router library. 8 | 9 | Similarly to React, Vue has components, declarative templating, and a virtual DOM. Instead of JSX, Vue uses an HTML-based syntax with double curly brace interpolation and special attributes called *directives*. Javascript expressions can be used inside both. Like React, Vue has reactivity, but in a different fashion. React components have functions that re-run whenever a prop or piece of state changes. In Vue, the `setup()` function is run once. The template includes reactive objects, and when any of its reactive objects are changed, it gets re-rendered. 10 | 11 | Vue also has [two-way data binding](https://v3.vuejs.org/guide/forms.html#basic-usage) on form inputs: when a data object is bound to a form input, the object is updated when the user makes a change (for example, typing in an `