{"id":21964185,"url":"https://github.com/shaoruu/not-so-modern-graphql-tutorial","last_synced_at":"2025-04-06T00:09:00.938Z","repository":{"id":39469295,"uuid":"188877424","full_name":"shaoruu/not-so-modern-graphql-tutorial","owner":"shaoruu","description":":book: A simple and easy GraphQL tutorial to get started with GraphQL.","archived":false,"fork":false,"pushed_at":"2024-04-19T01:49:22.000Z","size":14359,"stargazers_count":321,"open_issues_count":5,"forks_count":33,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-29T22:11:16.228Z","etag":null,"topics":["apollo","dvfcfbgv","graphql","graphql-yoga","huang","ian","modern","prisma","react","shaoruu","tutorial"],"latest_commit_sha":null,"homepage":"https://blog.shaoruu.io/modern-graphql-tutorial/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shaoruu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-05-27T16:33:17.000Z","updated_at":"2025-01-08T01:10:33.000Z","dependencies_parsed_at":"2024-11-29T12:02:05.303Z","dependency_job_id":"a9aca37a-f4c7-497e-bad8-a1444041ef3d","html_url":"https://github.com/shaoruu/not-so-modern-graphql-tutorial","commit_stats":null,"previous_names":["shaoruu/not-so-modern-graphql-tutorial"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shaoruu%2Fnot-so-modern-graphql-tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shaoruu%2Fnot-so-modern-graphql-tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shaoruu%2Fnot-so-modern-graphql-tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shaoruu%2Fnot-so-modern-graphql-tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shaoruu","download_url":"https://codeload.github.com/shaoruu/not-so-modern-graphql-tutorial/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247415967,"owners_count":20935387,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apollo","dvfcfbgv","graphql","graphql-yoga","huang","ian","modern","prisma","react","shaoruu","tutorial"],"created_at":"2024-11-29T12:01:12.456Z","updated_at":"2025-04-06T00:09:00.905Z","avatar_url":"https://github.com/shaoruu.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IMPORTANT NOTE: THIS WAS *MORDERN* IN 2019, VERY OUTDATED NOW!!\n\n# Modern GraphQL Tutorial\n\nAfter this tutorial, you will be able to:\n\n- Create your own GraphQL schema\n- Serve a backend API for data fetching\n- Start a simple react GraphQL client\n- Fetch data!\n\n## Table of Contents\n\n- [Modern GraphQL Tutorial](#modern-graphql-tutorial)\n  - [Table of Contents](#table-of-contents)\n  - [Introduction](#introduction)\n  - [Getting Started](#getting-started)\n  - [GraphQL Playground](#graphql-playground)\n  - [Basic Syntax](#basic-syntax)\n  - [Schema](#schema)\n    - [Basic Types:](#basic-types)\n  - [Queries, Mutations and Subscriptions](#queries-mutations-and-subscriptions)\n    - [Queries](#queries)\n    - [Mutations](#mutations)\n    - [Subscriptions](#subscriptions)\n  - [Apollo Client](#apollo-client)\n    - [Setting up Apollo client](#setting-up-apollo-client)\n    - [Querying and Subscribing](#querying-and-subscribing)\n    - [Mutating](#mutating)\n  - [Wrapping Up](#wrapping-up)\n  - [References](#references)\n\n## Introduction\n\nBefore we start, let me give you a brief introduction to GraphQL. GraphQL is a _query language_ for API's. It is a more efficient alternative to traditional RESTful API's since it is:\n\n- **Faster** - with user-defined specification for data fetching, GraphQL prevents clients from underfetching or overfetching, making network requests more efficient.\n- **More Flexible** - user can define their own schemas and data types to share between frontend and backend.\n- **Faster Production** - with schemas acting as a contract for data fetching between the frontend team and backend team, both teams can do their individual work without further communication.\n\nAn example would be: Say you are creating an Instagram-like app. When a user opens up the app, you want to show him the posts on his news feed, so you make a network request to your backend and fetch all the post data. As for the traditional RESTful API, you fetch the post data including the comments and details about the comments on the posts. However, that would be overfetching since the user may not necessarily click into individual posts to check comments. Here, GraphQL comes into play by letting you specify what kind of data you want and how many comments you want for each post. This not only limits the amount of data needed to transfer through the internet, it also speeds up the fetching efficiency and speed.\n\nIn this tutorial, I will teach you how to set up your own GraphQL API, write a simple GraphQL client, and start communication between backend and frontend.\n\nI will be using [graphql-yoga](https://github.com/prisma/graphql-yoga) for the backend service, and [apollo](https://github.com/apollographql/react-apollo) for a simple client side.\n\n## Getting Started\n\nType the following steps into terminal to get started with this tutorial.\n\n```bash\ngit clone https://github.com/ian13456/modern-graphql-tutorial.git\n\ncd modern-graphql-tutorial/backend\n\nyarn\n```\n\nI will walk you through each file later on and teach you what it's for.\n\n## GraphQL Playground\n\nOne awesome tool that comes with [graphql-yoga](https://github.com/prisma/graphql-yoga) is [GraphQL Playground](https://github.com/prisma/graphql-playground). GraphQL Playground allows us to test our schemas without having to set up a client side. Essentially, it serves as a GraphQL client to run [queries](#Queries) and [mutations](#Mutations) on.\n\nAfter cloning the repository, run `yarn start` and navigate to http://localhost:5000. Don't worry. At this point it is normal to have zero clue about what the playground is all about. Pasted below is the process of setting up a simple GraphQLServer and serving it on port 5000. Disregard the imports as they will be discussed later on. All you have to know is that the following section of code sets you up with a working GraphQLServer.\n\n```javascript\n// backend/src/index.js\n\nimport { GraphQLServer, PubSub } from 'graphql-yoga'\nimport db from './db'\nimport Query from './resolvers/Query'\nimport Mutation from './resolvers/Mutation'\nimport Subscription from './resolvers/Subscription'\nimport User from './resolvers/User'\nimport Post from './resolvers/Post'\nimport Comment from './resolvers/Comment'\n\n// This will be covered later.\nconst pubsub = new PubSub()\n\n// Don't worry about anything; just know that this initializes the server.\nconst server = new GraphQLServer({\n  typeDefs: './src/schema.graphql',\n  resolvers: {\n    Query,\n    Mutation,\n    Subscription,\n    User,\n    Post,\n    Comment\n  },\n  context: {\n    db,\n    pubsub\n  }\n})\n\n// Serving server on port 5000\nserver.start({ port: process.env.PORT | 5000 }, () =\u003e {\n  console.log(`The server is up on port ${process.env.PORT | 5000}!`)\n})\n```\n\n## Basic Syntax\n\nAs mentioned before, GraphQL is a query language with _specific_ syntax.\n\nHere an example of a basic query:\n\n```graphql\nquery {\n  users {\n    username\n    password\n    creditCardNumber\n  }\n}\n```\n\nAs I said before, GraphQL gives you the ability to specify what data's are needed for fetching.\n\nLets start from the beginning. The out-most layer `query { }` specifies that the type of this GraphQL request is a query, meaning that it is simply asking for data.\n\nOn the second layer, we have the specific _query_ to run called `users { }`. This tells the server which kind of data the client wants, and lets the server know what to do accordingly.\n\nLastly, within the `users` query we have the specific attributes that we are fetching for **EACH** user, in this case we are trying to fetch the `username`, `password` and `creditCardNumber`.\n\n## Schema\n\nA GraphQL Schema is what defines the basic types. The file is often named `schema.graphql`, sitting in the same directory as index.js. You add it into the server with the **`typedefs`** option in graphql-yoga.\n\n### Basic Types:\n\nThese are the basic scalar types in GraphQL. Scalar types basically mean that these values are scalars and **do not contain any sub-fields below them.**\n\n- String\n- Int\n- Float\n- Boolean\n- ID\n\nTo add on, GraphQL \"[Lists](https://graphqlmastery.com/blog/graphql-list-how-to-use-arrays-in-graphql-schema)\" is a type that defines an array of a certain type with the notation `[]`. For example: `[String]` represents a type that is a list of Strings.\n\nFor other special types such as `queries`, `mutations` and `subscriptions`, I will go deeper on how to define them once I explain what they are later on.\n\n## Queries, Mutations and Subscriptions\n\nQueries, mutations and subscriptions are the three **major** types that you include in `schema.graphql` that define what the GraphQL requests should look like. Essentially they differ between different HTTP request types for each GraphQL request.\n\nBefore I dig into what these three types are, I want to teach you about what GraphQL **resolvers** are for first.\n\n[Resolvers](https://medium.com/paypal-engineering/graphql-resolvers-best-practices-cd36fdbcef55) are methods that you write in any language that defines what each query, mutation, and subscription does. They basically tell the GraphQL endpoint how to handle different types of data fetches. In most cases, resolvers are where you alter the _database_ after receiving data from GraphQL requests. In graphql-yoga, they are the files imported and included in the **`resolvers`** option in the new `GraphQLServer`.\n\nWith the knowledge of `schemas` and `resolvers`, we can now learn the top three request types in GraphQL.\n\n### Queries\n\nThese are the types of network requests that simply ask for data from the server.\n\nRemember the example I showed you in the [Basic Syntax](#Basic-Syntax) section?\n\nHere I defined the exact same query type `users` that I showed you.\n\n```graphql\n# backend/src/schema.graphql\n\ntype Query {\n  users(query: String): [User!]!\n}\n\ntype User {\n  id: ID!\n  name: String!\n  email: String!\n  age: Int\n  posts: [Post!]!\n  comments: [Comment!]!\n}\n```\n\nThere are three important keys that I want to point out in this short GraphQL code:\n\n1. `type Query` v.s. `type User`\n   - Remember \"Query\" is the type of the _outer-most layer_ in a GraphQL request, and \"User\" in this case is just a _user-defined_ type that can be used in the entire schema.\n2. `!` Exclamation marks after type names\n   - `!` in GraphQL means **non-nullable**, meaning that the data sent back cannot be null or undefined. For example, `[String!]!` represents a non-nullable list containing values of Strings that cannot be null.\n3. `(query: String)` after `users`\n   - Just like functions, GraphQL requests can have additional arguments. In this case the query `users` takes in `query` of type `String`. \u003csmall\u003eNotice how there isn't a `!` after `String`. This means that the argument `query` is **optional**.\u003c/small\u003e\n\nHowever, this only tells GraphQLServer what the query _looks like_ though. So, below is where I use **resolvers** to define **HOW** the server should handle any `users` requests.\n\n```javascript\n// backend/src/resolvers/Query.js\n\nusers(parent, args, context, info) {\n  const { db } = context\n\n  // Check if the optional `query` of type String is passed in.\n  if (!args.query) {\n    return db.users\n  }\n\n  // Reaching here means `query` is defined -\u003e filter the data passed back.\n  return db.users.filter((user) =\u003e {\n    return user.name.toLowerCase().includes(args.query.toLowerCase())\n  })\n}\n```\n\nHere's a possible GraphQL request for this `users` query:\n\n```graphql\nquery {\n  users(query: \"a\") {\n    id\n    name\n    age\n  }\n}\n\n# results:\n{\n  \"data\": {\n    \"users\": [\n      {\n        \"id\": \"1\",\n        \"name\": \"Andrew\",\n        \"age\": 27\n      },\n      {\n        \"id\": \"2\",\n        \"name\": \"Sarah\",\n        \"age\": null\n      }\n    ]\n  }\n}\n```\n\n### Mutations\n\nNow that you have a basic understanding of what queries are, Mutations are fairly easy to understand. Mutations are where you _mutate_ the data in the database. \u003csmall\u003enote that I used a temporary file `db.js` as a database since the primary focus of this tutorial is on GraphQL not on databases.\u003c/small\u003e\n\n```graphql\n# backend/src/schema.graphql\n\ntype Mutation {\n  createUser(data: CreateUserInput!): User!\n}\n\ninput CreateUserInput {\n  name: String!\n  email: String!\n  age: Int\n}\n```\n\nThere are only a few things worth noticing in this Mutation type specification:\n\n1. `type Mutation` v.s. previous `type Query`\n   - Later on when making GraphQL requests, use `mutation { }` instead of `query { }`\n2. new keyword `input`\n   - This is used for argument specifications. When arguments become long and nasty, it's best to extract them and define an input type.\n\nOk, with the `createUser` mutation specified above, all we're missing is the _resolver_ corresponding for it \u0026darr;\n\n```javascript\n// backend/src/resolvers/Mutation.js\n\ncreateUser(parent, args, context, info) {\n  const { db } = context\n\n  // Check if email is already taken in fake database\n  const emailTaken = db.users.some((user) =\u003e user.email === args.data.email)\n\n  if (emailTaken) {\n    throw new Error('Email taken')\n  }\n\n  // Create new user object\n  const user = {\n    id: uuidv4(),\n    ...args.data\n  }\n\n  // Save (append) it to fake database\n  db.users.push(user)\n\n  return user\n}\n```\n\nWorth noting that in a regular project, the lines of code where I alter the fake database should be replaced by processes that communicate with an actual database and change/save/delete data.\n\nHere's an example of a GraphQL mutation:\n\n```graphql\nmutation {\n  createUser(data: {\n    name: \"Morgan\"\n    age: 81\n    email: \"morganfreeman@free.com\"\n  }) {\n    id\n    name\n  }\n}\n\n# results:\n{\n  \"data\": {\n    \"createUser\": {\n      \"id\": \"47afd124-0c06-4e2e-992f-0b837d4f0d5e\",\n      \"name\": \"Morgan\"\n    }\n  }\n}\n```\n\n### Subscriptions\n\nSubscriptions are a little bit different from regular Queries and Mutations. This is a very interesting feature provided by GraphQL that handles the **real time** aspect of modern web.\n\nThink of GraphQL Subscriptions as YouTube subscriptions. Once you are subscribed to YouTube channel, you get notified with the latest news from the channel. Not only you, it's everyone who's subscribed gets notified.\n\nWith GraphQL Subscriptions, you can set up quote unquote \"channels\" on your endpoint with specified types of \"content\" that these \"channels\" post. Once data is mutated, you can then \"post\" the data up to the channel, notifying whoever's subscribed. Here's an example in my code of subscriptions on the comment section of a specific post:\n\n```graphql\n# backend/src/schema.graphql\n\ntype Subscription {\n  comment(postId: ID!): CommentSubscriptionPayload!\n}\n\ntype CommentSubscriptionPayload {\n  mutation: MutationType!\n  data: Comment!\n}\n\nenum MutationType {\n  CREATED\n  UPDATED\n  DELETED\n}\n```\n\nThere are only two important key points I want to mention here:\n\n1. `type Subscription`\n   - New type! use `subscription { }` instead of `mutation { }` for outer-most layer.\n2. new keyword `enum`\n   - An enum specifies a set of **`Strings`** that you can use throughout your schema.\n   - When you define an Enum, you are basically defining a set of **fixed** Strings.\n\nThe resolver of GraphQL subscriptions is a bit trickier. Since you are now not only querying or mutating data, but actually setting up a websocket link between the client and the server, you need **pubsub** system on the server-side.\n\nLooking back to index.js, we can now clearly see the initialization of a `PubSub` instance. We then pass it into `context` option in the GraphQLServer.\n\n```javascript\n// backend/src/index.js\n\nimport { GraphQLServer, PubSub } from 'graphql-yoga'\n\n// ...import...lots...of...files...\n\nconst pubsub = new PubSub()\n\nconst server = new GraphQLServer({\n  typeDefs: './src/schema.graphql',\n  resolvers: {\n    Query,\n    Mutation,\n    Subscription,\n    User,\n    Post,\n    Comment\n  },\n  context: {\n    db,\n    pubsub\n  }\n})\n```\n\nNow you may wonder what the `context` option is for. If you look closely to resolver functions of the multiple examples above, you may notice a sequence of \u003ci\u003eweird\u003c/i\u003e function arguments `parent`, `args`, `context` and `info`. This is where the `context` keyword comes in play. By passing both the `pubsub` instance and `db` into `context`, we can use them within our resolvers later on.\n\nHowever, the PubSub system isn't as easily set up as you thought. In order to set up _websocket channels_ for each GraphQL Subscription, you need to set up a required `Subscription` resolver like the one below.\n\n```javascript\n// backend/src/resolvers/Subscription.js\n\nconst Subscription = {\n  comment: {\n    subscribe(parent, { postId }, { db, pubsub }, info) {\n      const post = db.posts.find((post) =\u003e post.id === postId \u0026\u0026 post.published)\n\n      if (!post) {\n        throw new Error('Post not found')\n      }\n\n      return pubsub.asyncIterator(`comment ${postId}`)\n    }\n  }\n}\n\nexport { Subscription as default }\n```\n\nHere I directly destructure `db` and `pubsub` out of `context`, and extract `postId` from the original argument `arguments`. I then check if the post exists or not. If it doesn't, I throw an Error to the console. If it does exit, and here comes the tricky part, I create and return a `pubsub asyncIterator` with a specific tag of `comment ${postId}`. You can think of this with the YouTube subscription example. Creating an `asyncIterator` is like creating a new YouTube channel. Later on you can then post data onto `pubsub` with the specific _channel tag_, and the data will be broadcasted to all instances connected.\n\nWith the `pubsub` system set up, I can now broadcast data throughout all of my resolvers. For example, whenever a comment on a specific post is created, I want to post the comment data onto the comment's individual Subscription Channel. I can do that with the code below:\n\n```javascript\n// backend/src/resolvers/Mutation.js\n\n...\nconst comment = {\n  id: uuidv4(),\n  ...args.data\n}\n\n// THIS IS WHERE I PUBLISH MY DATA TO THE CHANNEL\npubsub.publish(`comment ${args.data.post}`, {\n  comment: {\n    mutation: 'CREATED',\n    data: comment\n  }\n})\n...\n```\n\nTo sum up, here's a quick example of how GraphQL subscriptions work:\n\n```graphql\n# subscription:\nsubscription {\n  comment (postId: 10) {\n    mutation\n    data {\n      text\n      author {\n        name\n      }\n    }\n  }\n}\n\n# mutation that was run after subscription:\nmutation {\n  createComment(data: {\n    text: \"Hello sir! Nice Post!\"\n    author: 1\n    post: 10\n  }) {\n    text\n    author {\n      name\n    }\n  }\n}\n\n# results on subscription side:\n{\n  \"data\": {\n    \"comment\": {\n      \"mutation\": \"CREATED\",\n      \"data\": {\n        \"text\": \"Hello sir! Nice Post!\",\n        \"author\": {\n          \"name\": \"Andrew\"\n        }\n      }\n    }\n  }\n}\n```\n\n## Apollo Client\n\nIn this example, I created an application that contains a form and a list of posts. The form allows you to use `GraphQL mutations` to create posts in the database, and the list of posts is fetched with a `GraphQL query`. This list is actually subscribed to any new posts, which means when the form creates a new post, the post gets saved in the database and sent back to the client spontaneously through a `GraphQL subscription`.\n\n![](https://i.imgur.com/EZOvDS4.png)\n\nBefore I start explaining the magic behind this, I strongly recommend you read the [react-apollo](https://www.apollographql.com/docs/react/essentials/get-started) documentations. It is well documented, and you will definitely learn a lot from it.\n\nIn order to run the live exmaple above, run the commands below:\n\n```bash\ncd frontend\n\nyarn\n\nyarn start\n```\n\n### Setting up Apollo client\n\nIn order to connect to the backend API, you need to set up a _GraphQL client_ like so:\n\n```javascript\n// frontend/src/index.js\n\nimport {\n  ApolloClient,\n  InMemoryCache,\n  ApolloProvider,\n  HttpLink\n} from '@apollo/client'\nimport { split } from 'apollo-link'\nimport { WebSocketLink } from 'apollo-link-ws'\nimport { getMainDefinition } from 'apollo-utilities'\n\n// Create an http link:\nconst httpLink = new HttpLink({\n  uri: 'http://localhost:5000/'\n})\n\n// Create a WebSocket link:\nconst wsLink = new WebSocketLink({\n  uri: `ws://localhost:5000/`,\n  options: { reconnect: true }\n})\n\n// using the ability to split links, you can send data to each link\n// depending on what kind of operation is being sent\nconst link = split(\n  // split based on operation type\n  ({ query }) =\u003e {\n    const definition = getMainDefinition(query)\n    return (\n      definition.kind === 'OperationDefinition' \u0026\u0026\n      definition.operation === 'subscription'\n    )\n  },\n  wsLink,\n  httpLink\n)\n\nconst client = new ApolloClient({\n  link,\n  cache: new InMemoryCache().restore({})\n})\n```\n\nThe HTTP link (`httpLink`) is for queries and mutations, and the WebSocket link (`wsLink`) is for GraphQL subscriptions. With the `split` function, we can tell apart the types of GraphQL requests. We then send the request to different endpoints accordingly.\n\n### Querying and Subscribing\n\nQuerying in [react-apollo](https://www.apollographql.com/docs/react/essentials/get-started) is pretty simple. All you have to do is pass a `gql` tagged string, which is exactly like what you would enter in GraphQL Playground, into a [`Query`](https://www.apollographql.com/docs/react/essentials/queries) component.\n\n```javascript\n// frontend/src/graphql/queries.js\n\nimport { gql } from '@apollo/client'\n\nexport const POSTS_QUERY = gql`\n  query {\n    posts {\n      title\n      body\n      author {\n        name\n      }\n      published\n    }\n  }\n`\n\n// frontend/src/graphql/subscriptions.js\n\nexport const POSTS_SUBSCRIPTION = gql`\n  subscription {\n    post {\n      mutation\n      data {\n        title\n        body\n        author {\n          name\n        }\n        published\n      }\n    }\n  }\n`\n```\n\n```jsx\n// frontend/src/containers/App/App.js\n\n...\n\nconst { loading, error, data, subscribeToMore } = useQuery(POSTS_QUERY)\n\n...\n\nuseEffect(() =\u003e {\n  subscribeToMore({\n    document: POSTS_SUBSCRIPTION,\n    updateQuery: (prev, { subscriptionData }) =\u003e {\n      if (!subscriptionData.data) return prev\n      const newPost = subscriptionData.data.post.data\n\n      return {\n        ...prev,\n        posts: [newPost, ...prev.posts]\n      }\n    }\n  })\n}, [subscribeToMore])\n\n...\n\n\u003cCol xs=\"6\"\u003e\n  {loading ? (\n    \u003cp\u003eLoading...\u003c/p\u003e\n  ) : error ? (\n    \u003cp\u003eError :(((\u003c/p\u003e\n  ) : (\n    data.posts.map((post, id) =\u003e \u003cPost data={post} key={id} /\u003e)\n  )}\n\u003c/Col\u003e\n```\n\nHere, I used the [`useQuery`](https://www.apollographql.com/docs/react/api/react-hooks/#usequery) hook provided by [@apollo/react-hooks](https://www.apollographql.com/docs/react/api/react-hooks/) and passd in my `POSTS_QUERY`. By doing so, GraphQL fires a `GET` request to the backend once the component is mounted, and I can then render whatever is returned with `data`. One thing to notice is the `subscribeToMore` function.\n\nThe [`subscribeToMore`](https://www.apollographql.com/docs/react/advanced/subscriptions#subscribe-to-more) function is what tells the GraphQL client to listen to any updates. Once an update is sent from backend through wsLink to the client, the `updateQuery` function in subscribeToMore gets executed. It basically takes the **cached** posts from the query, `prev`, append the freshly received post onto it, and put the `prev` cache back in place.\n\n### Mutating\n\nMutating in Apollo is also very simple. The [`Mutation`](https://www.apollographql.com/docs/react/essentials/mutations) tag takes in a `gql` tagged mutation, and gives you a function that you can run every time you want to make mutation requests.\n\n```javascript\n// frontend/src/graphql/mutations.js\n\nimport { gql } from '@apollo/client'\n\nexport const CREATE_POST_MUTATION = gql`\n  mutation createPost(\n    $title: String!\n    $body: String!\n    $published: Boolean!\n    $authorId: ID!\n  ) {\n    createPost(\n      data: {\n        title: $title\n        body: $body\n        published: $published\n        author: $authorId\n      }\n    ) {\n      title\n      body\n      author {\n        name\n      }\n      published\n    }\n  }\n`\n```\n\nThe variables with names are just variables that you can pass into later on with the `variables` option. (you will see it later)\n\n```jsx\n// frontend/src/containers/App/App.js\nconst [addPost] = useMutation(CREATE_POST_MUTATION)\n```\n\nI also created a callback, `handleFormSubmit`, which is run everytime the form is submitted. This callback uses `formTitle` and `formBody`, which are just simple react `useState`'s. Basically, [`useMutation`](https://www.apollographql.com/docs/react/api/react-hooks/#usemutation) returns an array, containing a function that you can call to make `POST` requests to the server.\n\n```jsx\n// frontend/src/container/App/App.js\n\n...\n\nconst handleFormSubmit = useCallback(\n  (e) =\u003e {\n    e.preventDefault()\n\n    if (!formTitle || !formBody) return\n\n    addPost({\n      variables: {\n        title: formTitle,\n        body: formBody,\n        published: true,\n        authorId: 2\n      }\n    })\n\n    setFormTitle('')\n    setFormBody('')\n  },\n  [addPost, formTitle, formBody]\n)\n\n...\n\n\u003cForm onSubmit={handleFormSubmit}\u003e\n\n...\n```\n\n## Wrapping Up\n\nThat's it! By now you should be able to:\n\n- Create your own GraphQL API\n- Set up GraphQL client and connect the client to backend\n- Fetch data and listen to data changes\n\nThere are a lot more to learn about GraphQL such as [user authentication](https://www.apollographql.com/docs/react/recipes/authentication). There are even tools that automatically generate the necessary mutations for your GraphQL schema such as [Prisma](https://www.prisma.io/docs/1.33/get-started/01-setting-up-prisma-new-database-TYPESCRIPT-t002/)!\n\nAnyways, hope this tutorial was helpful. Email [me](21ianh1@tas.tw) if you have any further questions!\n\n## References\n\n- [GraphQL Introduction](https://medium.com/devgorilla/what-is-graphql-f0902a959e4)\n- [Modern GraphQL Course](https://www.udemy.com/graphql-bootcamp/)\n- [React Apollo](https://www.apollographql.com/docs/react/essentials/get-started)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshaoruu%2Fnot-so-modern-graphql-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshaoruu%2Fnot-so-modern-graphql-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshaoruu%2Fnot-so-modern-graphql-tutorial/lists"}