One place for hosting & domains

      GraphQL

      How To Handle Images with GraphQL and the Gatsby Image API


      The author selected /dev/color to receive a donation as part of the Write for DOnations program.

      Introduction

      Handling images plays a pivotal role in building websites, but also can be challenging to deal with. Unoptimized images slow down websites, and many images that might look appropriate on a desktop are hard to scale down to a mobile device. Visually manipulating an image can also be tedious and difficult to maintain.

      All of these problems in isolation are not a big issue. The main problem is when you have to keep track of all of these rules and image-scaling techniques. When it comes to Gatsby.js projects, this is where the Gatsby Image API comes in handy. By using GraphQL queries, you can use the Gatsby Image API to take care of image compression, make an image responsive, and even handle basic image styling.

      In this tutorial, you are going to compress, transform, and style images using the Gatsby Image API and GraphQL queries.

      Prerequisites

      Step 1 — Setting Up a New Gatsby Project

      In this first step, you are going to set up a new Gatsby project and familiarize yourself with the key image plugins that you’ll use throughout this tutorial. You will also download and set up an image to optimize throughout the tutorial.

      First, use the CLI tool to start a new project named gatsby-image-project:

      • gatsby new gatsby-image-project https://github.com/gatsbyjs/gatsby-starter-default

      This creates a new website from the starter template in the [gatsby-starter-default](https://github.com/gatsbyjs/gatsby-starter-default) GitHub repository from Gatsby.

      Once the project is created, move into the new project directory:

      Next, open up the index.js file in a text editor of your choice:

      Delete all of the code between the layout wrapper component so that your file is the same as the following:

      gatsby-image-project/src/pages/index.js

      import React from "react"
      import { Link } from "gatsby"
      
      import Layout from "../components/layout"
      import Image from "../components/image"
      import SEO from "../components/seo"
      
      const IndexPage = () => (
        <Layout>
        </Layout>
      )
      
      export default IndexPage
      

      Next, replace the deleted code with the following highlighted JSX, which adds some HTML elements to the website:

      gatsby-image-project/src/pages/index.js

      import React from "react"
      import { Link } from "gatsby"
      
      import Layout from "../components/layout"
      import Image from "../components/image"
      import SEO from "../components/seo"
      
      const IndexPage = () => (
          <Layout>
            <div className="layout">
              <Image className="left-image"/>
              <h2>Hello</h2>
              <p>Welcome to my humble site</p>
              <p>All of our shirts are on sale!</p>
              <button className="shop-button">Shop</button>
            </div>
          </Layout>
      )
      
      export default IndexPage
      

      The Gatsby Image API will provide your new test image to the Image element in a later step. With this, you now have HTML to experiment with.

      Later in the tutorial, you’ll revisit the index.js page. For now, save and exit the file.

      The next file to open is gatsby-config.js. In this file, you will find the plugins responsible for processing images.

      Open up the file with the following:

      Once you have opened the gatsby-config file, locate the gatsby-plugin-sharp, gatsby-transformer-sharp, and gatsby-source-filesystem plugins:

      gatsby-image-project/gatsby-config.js

      module.exports = {
        siteMetadata: {
          title: `Gatsby Default Starter`,
          description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
          author: `@gatsbyjs`,
        },
        plugins: [
          `gatsby-plugin-react-helmet`,
          {
            resolve: `gatsby-source-filesystem`,
            options: {
              name: `images`,
              path: `${__dirname}/src/images`,
            },
          },
          `gatsby-transformer-sharp`,
          `gatsby-plugin-sharp`,
          {
            resolve: `gatsby-plugin-manifest`,
            options: {
              name: `gatsby-starter-default`,
              short_name: `starter`,
              start_url: `/`,
              background_color: `#663399`,
              theme_color: `#663399`,
              display: `minimal-ui`,
              icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
            },
          },
          // this (optional) plugin enables Progressive Web App + Offline functionality
          // To learn more, visit: https://gatsby.dev/offline
          // `gatsby-plugin-offline`,
        ],
      }
      

      These plugins are as follows:

      • gatsby-plugin-sharp: Sharp is an image optimization library that Gatsby uses to process images. The gatsby-plugin-sharp provides a bridge between Sharp and Gatsby.

      • gatsby-transformer-sharp: This plugin performs image transformations, such as resizing, compressing, and changing background color.

      • gatsby-source-filesystem: This plugin allows you to source data from your filesystem into your application. In this case, it enables GraphQL to query images.

      Now that you have an idea of which plugins are used to process images, close the file.

      Next, add an image to your application to optimize, edit, and style later. In this tutorial, you are going to download an image from the Unsplash stock image website. Navigate to this picture of clothes on Unsplash in a browser and download the angela-bailey-jlo7Bf4tUoY-unsplash.jpg image into the /images folder of your Gatsby project. The image must be located in the right directory in order to query the image with GraphQL and transform it using Gatsby’s Image API.

      Alternatively, you can download the image from the command line. First, move to the images directory:

      Next, execute the following command:

      • curl -sL https://images.unsplash.com/photo-1556905055-8f358a7a47b2 -o angela-bailey-jlo7Bf4tUoY-unsplash.jpg

      This will use curl to download the image and output the file as angela-bailey-jlo7Bf4tUoY-unsplash.jpg.

      In this section, you set up your Gatsby project to use Gatsby’s Image API. You explored the Gatsby configuration file to find gatsby-plugin-sharp, gatsby-transform-sharp, and gatsby-source-filesystem, which work together to optimize images. In the next step, you will test out querying and optimizing your image using GraphiQL, the GraphQL integrated development environment (IDE).

      Step 2 — Querying Images with GraphQL

      You are now going to query your new image using GraphQL. GraphQL is a query language for obtaining information from an API. It is also the data layer of Gatsby.

      First, return to the root of your Gatsby project, then start the development server:

      After your site finishes building, you will receive the following output:

      Output

      ... success open and validate gatsby-configs - 0.081s success load plugins - 4.537s success onPreInit - 0.070s success initialize cache - 0.034s success copy gatsby files - 0.320s success onPreBootstrap - 0.177s success createSchemaCustomization - 0.050s success Checking for changed pages - 0.003s success source and transform nodes - 0.264s success building schema - 0.599s info Total nodes: 35, SitePage nodes: 1 (use --verbose for breakdown) success createPages - 0.057s success Checking for changed pages - 0.005s success createPagesStatefully - 0.188s success update schema - 0.046s success write out redirect data - 0.006s success Build manifest and related icons - 0.456s success onPostBootstrap - 0.465s info bootstrap finished - 19.515s success onPreExtractQueries - 0.003s success extract queries from components - 0.932s success write out requires - 0.029s success run page queries - 0.039s - 1/1 25.97/s ⠀ You can now view gatsby-starter-default in the browser. ⠀ http://localhost:8000/ ⠀ View GraphiQL, an in-browser IDE, to explore your site's data and schema ⠀ http://localhost:8000/___graphql ⠀ Note that the development build is not optimized. To create a production build, use gatsby build ⠀ warn ESLintError: /your_filepath/gatsby-image-project/src/pages/index.js 2:10 warning 'Link' is defined but never used no-unused-vars 6:8 warning 'SEO' is defined but never used no-unused-vars ✖ 2 problems (0 errors, 2 warnings) success Building development bundle - 10.814s

      This output contains two links. The first link, https://localhost:8000/, is where you can find your local development site. The second link, http://localhost:8000/___graphql, is the location of GraphiQL. GraphiQL is an integrated development editor (IDE) that allows you to make queries in the browser. This is a useful tool that helps you experiment and make data queries before you add them to your codebase. GraphiQL only works when you are running the development server.

      With the help of GraphiQL, you can try out queries to retrieve your newly downloaded image. Open your browser and enter the GraphiQL URL http://localhost:8000/___graphql into the address bar. The browser will display the GraphiQL interface:

      Screenshot of the GraphQL IDE

      GraphiQL is split into three sections. To the far left is the Explorer, where you can find the fields that you are able to access via GraphQL. In the middle of the IDE is the sandbox where you make queries. Finally, to the far right you can find GraphQL’s documentation.

      Your first goal is to query the angela-bailey-jlo7Bf4tUoY-unsplash.jpg image. Since the image is located in the local filesystem, you choose file in the Explorer box. This will show a dropdown menu of subdirectories. You will search for the image file by relative path, so select on relativePath. relativePath reveals another set of subfolders. You will enter the exact path of the image, so choose the eq for “equals”. Inside the quotes enter the path of the image angela-bailey-jlo7Bf4tUoY-unsplash.jpg.

      GraphQL IDE showing the query to locate the image in the filesystem

      Now you are set to try out your first image manipulation. Your original image is 1920 by 1280 pixels. That is too big for your landing page, and it would help to make the image responsive. Normally, you would have to hard code the width into CSS and add media queries to make the image responsive. Gatsby’s Image API does all of that work for you, without you needing to write extra CSS.

      Select childImageSharp in the Explorer box, which transforms the image under the hood. Make sure to choose this from the top-level menu, not from under file. Choose fluid from the next dropdown. A fluid image stretches to fill its container. In the dropdown options for fluid, check maxWidth and enter the 750.

      The blue values just below the purple querying parameters are the different values you can return. Choose src and srcSet to return the location of the original and transformed image. Then click the play button to view the results:

      childImageSharp parameters

      After selecting the parameters, GraphiQL builds the following query:

      query MyQuery {
        file(relativePath: {eq: "angela-bailey-jlo7Bf4tUoY-unsplash.jpg"}) {
          childImageSharp {
            fluid(maxWidth: 750) {
              src
              srcSet
            }
          }
        }
      }
      

      In the box on the right of the GraphiQL interface, you will find the return values. This will show:

      • src: Location of the image after processing.

      • srcSet: Same image set to a different size. This feature comes in handy if you want your images to be responsive.

      You do not have to choose fluid in your query; you also have the option to choose fix. A fixed image creates responsive images 1x, 1.5x, and 2x pixel densities using the <picture> element. The following is an example of a fixed query:

      query MyQuery {
        file(relativePath: {eq: "angela-bailey-jlo7Bf4tUoY-unsplash.jpg"}) {
          childImageSharp {
            fixed(cropFocus: CENTER) {
              src
              srcSet
            }
          }
        }
      }
      

      This query will return the following:

      {
        "data": {
          "file": {
            "childImageSharp": {
              "fixed": {
                "src": "/static/8e3a47b77ddf6636755d7be661d7b019/0ad16/angela-bailey-jlo7Bf4tUoY-unsplash.jpg",
                "srcSet": "/static/8e3a47b77ddf6636755d7be661d7b019/0ad16/angela-bailey-jlo7Bf4tUoY-unsplash.jpg 1x,n/static/8e3a47b77ddf6636755d7be661d7b019/44157/angela-bailey-jlo7Bf4tUoY-unsplash.jpg 1.5x,n/static/8e3a47b77ddf6636755d7be661d7b019/7fddd/angela-bailey-jlo7Bf4tUoY-unsplash.jpg 2x"
              }
            }
          }
        },
        "extensions": {}
      }
      

      In this query you have a fixed version of the image, with the crop focus set to center. Your return value is the location of the image and a set of different image sizes (1x, 1.5x, 2x respectively).

      Now that you have tested out the GraphQL query using GraphiQL and the childImageSharp node, you will next add the queried image to a template and further optimize it using Gatsby’s Image API.

      Step 3 — Optimizing Your Image’s Performance for the Web

      In this section you are going to transfer your GraphQL image to the index.js page of your project and perform more image optimizations.

      From your terminal in the root of your Gatsby project, open the image component in your favorite text editor:

      • nano src/components/image.js

      Now, use the query that you tried out in the GraphiQL interface. Delete "gatsby-astronaut.png" and replace it with "angela-bailey-jlo7Bf4tUoY-unsplash.jpg". Also replace maxWidth: 300 with maxWidth: 750:

      gatsby-image-project/src/components/image.js

      import React from "react"
      import { useStaticQuery, graphql } from "gatsby"
      import Img from "gatsby-image"
      
      /*
       * This component is built using `gatsby-image` to automatically serve optimized
       * images with lazy loading and reduced file sizes. The image is loaded using a
       * `useStaticQuery`, which allows us to load the image from directly within this
       * component, rather than having to pass the image data down from pages.
       *
       * For more information, see the docs:
       * - `gatsby-image`: https://gatsby.dev/gatsby-image
       * - `useStaticQuery`: https://www.gatsbyjs.com/docs/use-static-query/
       */
      
      const Image = () => {
        const data = useStaticQuery(graphql`
          query {
            placeholderImage: file(relativePath: { eq: "angela-bailey-jlo7Bf4tUoY-unsplash.jpg" }) {
              childImageSharp {
                fluid(maxWidth: 750) {
                  ...GatsbyImageSharpFluid
                }
              }
            }
          }
        `)
      
        if (!data?.placeholderImage?.childImageSharp?.fluid) {
          return <div>Picture not found</div>
        }
      
        return <Img fluid={data.placeholderImage.childImageSharp.fluid} />
      }
      
      export default Image
      

      ...GatsbyImageSharpFluid is a GraphQL fragment. This syntax allows you to obtain all of the different return values for childImageSharp and fluid. You will use this as the return value instead of src and srcSet.

      GraphiQL explorer list of return values for `childImageSharp` and `fluid`

      In the image.js file, after the GraphQL query there is an if statement:

      gatsby-image-project/src/components/image.js

      ...
        if (!data?.placeholderImage?.childImageSharp?.fluid) {
          return <div>Picture not found</div>
        }
      
        return <Img fluid={data.placeholderImage.childImageSharp.fluid} />
      }
      
      export default Image
      

      placeholderimage is the alias that is given in the query and returned in <Img fluid={data.placeholderImage.childImageSharp.fluid} />. In GraphQL you are able to name your queries. In the conditional statement, if you don’t have an image, then the words Picture not found will appear on the landing page.

      Save and close this file.

      Once you build your Gatsby site, the image will be processed and optimized by the Gatsby Image API. This will decrease the size of the image file to decrease loading time for your site. To test this out, navigate to the images directory to find the original file size:

      Now list out the files with the following command:

      The -sh flag will show you the memory size of the files in a human-readable format. You will receive the following output:

      Output

      total 5.0M 4.8M angela-bailey-jlo7Bf4tUoY-unsplash.jpg 164K gatsby-astronaut.png 24K gatsby-icon.png

      Without any optimization, the image is 4.8M. Now you will look at how big the image is after you’ve used Gatsby’s Image API.

      Navigate to the root of your project and start the development server:

      Once the development server has started, place the local address into the browser. Once the site has loaded, right-click the image and select Inspect.

      Image with Inspect dropdown menu

      Now navigate to the Network tab of your browser’s developer tools. This tutorial will use Google Chrome DevTools:

      Local image size

      Your image went from 4.8 MB to 68.4 kB. That is significantly smaller than if you hadn’t used the Gatsby Image API.

      Note: If the HTTP status for the image request is 304, the image may be significantly smaller due to caching. To get a more reliable view of the image size, clear the cache and refresh the page.

      Keep developer tools open and head over to the Elements tab. Hover over the image. You will find the HTML element <picture>...</picture> and its child <source>...</source>:

      Rendered HTML of the Gatsby site

      In the source tag, you can find the srcSet attribute (the same one you queried for in GraphQL). You will also find that the different heights and widths of the image were automatically generated. These different images ensure that angela-bailey-jlo7Bf4tUoY-unsplash.jpg is fluid, without needing to change CSS.

      Note: While hovering over the image you might have noticed that the image is not keyboard-focusable, which could be an accessibility problem. If you want to learn more about accessibility, you can check out the Ally Project checklist.

      In this section you used the GraphQL Image query in your Gatsby template. You also optimized angela-bailey-jlo7Bf4tUoY-unsplash.jpg without having to write extra CSS.

      In the next section, you will visually transform the image by using childSharpImage.

      Step 4 — Styling Your Image with childSharpImage

      In this section, you will transform the look of angela-bailey-jlo7Bf4tUoY-unsplash.jpg with the help of childSharpImage. To test this, you will change your image to grayscale.

      Open image.js in a text editor:

      • nano src/components/image.js

      Go into your placeholderImage GraphQL query and inside of fluid set grayscale to true:

      gatsby-image-project/src/components/image.js

      import React from "react"
      import { useStaticQuery, graphql } from "gatsby"
      import Img from "gatsby-image"
      
      /*
       * This component is built using `gatsby-image` to automatically serve optimized
       * images with lazy loading and reduced file sizes. The image is loaded using a
       * `useStaticQuery`, which allows us to load the image from directly within this
       * component, rather than having to pass the image data down from pages.
       *
       * For more information, see the docs:
       * - `gatsby-image`: https://gatsby.dev/gatsby-image
       * - `useStaticQuery`: https://www.gatsbyjs.com/docs/use-static-query/
       */
      
      const Image = () => {
        const data = useStaticQuery(graphql`
          query {
            placeholderImage: file(relativePath: { eq: "angela-bailey-jlo7Bf4tUoY-unsplash.jpg" }) {
              childImageSharp {
                fluid(
                  maxWidth: 750
                  grayscale: true
                  ) {
                  ...GatsbyImageSharpFluid
                }
              }
            }
          }
        `)
      
        if (!data?.placeholderImage?.childImageSharp?.fluid) {
          return <div>Picture not found</div>
        }
      
        return <Img fluid={data.placeholderImage.childImageSharp.fluid} tabIndex='0' />
      }
      
      export default Image
      

      Save and close the file.

      Go back to your terminal and restart the server. You will find your image changed using childImageSharp, without writing and maintaining unnecessary CSS:

      Grayscale image

      Grayscale is just one of the many ways you can process your image using childImageSharp. Go to Gatsby’s documentation if you are curious about the other childImageSharp props.

      In this section you implemented grayscale by using childImageSharp. With this knowledge, you can perform many more image manipulations by leveraging the Gatsby Image API.

      Conclusion

      In this tutorial, you set your Gatsby project up to use the Gatsby Image API, query your Image using GraphQL, optimize your image’s performance, and style your image using childImageSharp. If you would like to learn more about Gatsby, check out the official Gatsby documentation.



      Source link

      How To Build a GraphQL API with Prisma and Deploy to DigitalOcean’s App Platform


      The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      GraphQL is a query language for APIs that consists of a schema definition language and a query language, which allows API consumers to fetch only the data they need to support flexible querying. GraphQL enables developers to evolve the API while meeting the different needs of multiple clients, for example iOS, Android, and web variants of an app. Moreover, the GraphQL schema adds a degree of type safety to the API while also serving as a form of documentation for your API.

      Prisma is an open-source database toolkit. It consists of three main tools:

      • Prisma Client: Auto-generated and type-safe query builder for Node.js & TypeScript.
      • Prisma Migrate: Declarative data modeling & migration system.
      • Prisma Studio: GUI to view and edit data in your database.

      Prisma facilitates working with databases for application developers who want to focus on implementing value-adding features instead of spending time on complex database workflows (such as schema migrations or writing complicated SQL queries).

      In this tutorial, you will use GraphQL and Prisma in combination as their responsibilities complement each other. GraphQL provides a flexible interface to your data for use in clients, such as frontends and mobile apps—GraphQL isn’t tied to any specific database. This is where Prisma comes in to handle the interaction with the database where your data will be stored.

      DigitalOcean’s App Platform provides a seamless way to deploy applications and provision databases in the cloud without worrying about infrastructure. This reduces the operational overhead of running an application in the cloud; especially with the ability to create a managed PostgreSQL database with daily backups and automated failover. App Platform has native Node.js support streamlining deployment.

      You’ll build a GraphQL API for a blogging application in JavaScript using Node.js. You will first use Apollo Server to build the GraphQL API backed by in-memory data structures. You will then deploy the API to the DigitalOcean App Platform. Finally you will use Prisma to replace the in-memory storage and persist the data in a PostgreSQL database and deploy the application again.

      At the end of the tutorial, you will have a Node.js GraphQL API deployed to DigitalOcean, which handles GraphQL requests sent over HTTP and performs CRUD operations against the PostgreSQL database.

      You can find the code for this project in the DigitalOcean Community respository.

      Prerequisites

      Before you begin this guide you’ll need the following:

      Basic familiarity with JavaScript, Node.js, GraphQL, and PostgreSQL is helpful, but not strictly required for this tutorial.

      Step 1 — Creating the Node.js Project

      In this step, you will set up a Node.js project with npm and install the dependencies apollo-server and graphql.

      This project will be the foundation for the GraphQL API that you’ll build and deploy throughout this tutorial.

      First, create a new directory for your project:

      Next, navigate into the directory and initialize an empty npm project:

      • cd prisma-graphql
      • npm init --yes

      This command creates a minimal package.json file that is used as the configuration file for your npm project.

      You will receive the following output:

      Output

      Wrote to /Users/yourusaername/workspace/prisma-graphql/package.json: { "name": "prisma-graphql", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }

      You’re now ready to configure TypeScript in your project.

      Execute the following command to install the necessary dependencies:

      • npm install apollo-server graphql --save

      This installs two packages as dependencies in your project:

      • apollo-server: The HTTP library that you use to define how GraphQL requests are resolved and how to fetch data.
      • graphql: is the library you’ll use to build the GraphQL schema.

      You’ve created your project and installed the dependencies. In the next step you will define the GraphQL schema.

      Step 2 — Defining the GraphQL Schema and Resolvers

      In this step, you will define the GraphQL schema and corresponding resolvers. The schema will define the operations that the API can handle. The resolvers will define the logic for handling those requests using in-memory data structures, which you will replace with database queries in the next step.

      First, create a new directory called src that will contain your source files:

      Then run the following command to create the file for the schema:

      Now add the following code to the file:

      prisma-graphql/src/schema.js

      const { gql } = require('apollo-server')
      
      const typeDefs = gql`
        type Post {
          content: String
          id: ID!
          published: Boolean!
          title: String!
        }
      
        type Query {
          feed: [Post!]!
          post(id: ID!): Post
        }
      
        type Mutation {
          createDraft(content: String, title: String!): Post!
          publish(id: ID!): Post
        }
      `
      

      Here you define the GraphQL schema using the gql tagged template. A schema is a collection of type definitions (hence typeDefs) that together define the shape of queries that can be executed against your API. This will convert the GraphQL schema string into the format that Apollo expects.

      The schema introduces three types:

      • Post: Defines the type for a post in your blogging app and contains four fields where each field is followed by its type, for example, String.
      • Query: Defines the feed query which returns multiple posts as denoted by the square brackets and the post query which accepts a single argument and returns a single Post.
      • Mutation: Defines the createDraft mutation for creating a draft Post and the publish mutation which accepts an id and returns a Post.

      Note that every GraphQL API has a query type and may or may not have a mutation type. These types are the same as a regular object type, but they are special because they define the entry point of every GraphQL query.

      Next, add the posts array to the src/schema.js file, below the typeDefs variable:

      prisma-graphql/src/schema.js

      ...
      const posts = [
        {
          id: 1,
          title: 'Subscribe to GraphQL Weekly for community news ',
          content: 'https://graphqlweekly.com/',
          published: true,
        },
        {
          id: 2,
          title: 'Follow DigitalOcean on Twitter',
          content: 'https://twitter.com/digitalocean',
          published: true,
        },
        {
          id: 3,
          title: 'What is GraphQL?',
          content: 'GraphQL is a query language for APIs',
          published: false,
        },
      ]
      

      You define the posts array with three pre-defined posts. Notice that the structure of each post object matches the Post type you defined in the schema. This array holds the posts that will be served by the API. In a subsequent step, you will replace the array once the database and Prisma Client are introduced.

      Next, define the resolvers object below the posts array you just defined:

      prisma-graphql/src/schema.js

      ...
      const resolvers = {
        Query: {
          feed: (parent, args) => {
            return posts.filter((post) => post.published)
          },
          post: (parent, args) => {
            return posts.find((post) => post.id === Number(args.id))
          },
        },
        Mutation: {
          createDraft: (parent, args) => {
            posts.push({
              id: posts.length + 1,
              title: args.title,
              content: args.content,
              published: false,
            })
            return posts[posts.length - 1]
          },
          publish: (parent, args) => {
            const postToPublish = posts.find((post) => post.id === Number(args.id))
            postToPublish.published = true
            return postToPublish
          },
        },
        Post: {
          content: (parent) => parent.content,
          id: (parent) => parent.id,
          published: (parent) => parent.published,
          title: (parent) => parent.title,
        },
      }
      
      
      module.exports = {
        resolvers,
        typeDefs,
      }
      

      You define the resolvers following the same structure as the GraphQL schema. Every field in the schema’s types has a corresponding resolver function whose responsibility is to return the data for that field in your schema. For example, the Query.feed() resolver will return the published posts by filtering the posts array.

      Resolver functions receive four arguments:

      • parent: The parent is the return value of the previous resolver in the resolver chain. For top-level resolvers, the parent is undefined, because no previous resolver is called. For example, when making a feed query, the query.feed() resolver will be called with parent’s value undefined and then the resolvers of Post will be called where parent is the object returned from the feed resolver.
      • args: This argument carries the parameters for the query, for example, the post query, will receive the id of the post to be fetched.
      • context: An object that gets passed through the resolver chain that each resolver can write to and read from, which allows the resolvers to share information.
      • info: An AST representation of the query or mutation. You can read more about the details in part III of this series: Demystifying the info Argument in GraphQL Resolvers.

      Since the context and info are not necessary in these resolvers, only parent and args are defined.

      Save and exit the file once you’re done.

      Note: When a resolver returns the same field as the resolver’s name, like the four resolvers for Post, Apollo Server will automatically resolve those. This means you don’t have to explicitly define those resolvers.

      -  Post: {
      -    content: (parent) => parent.content,
      -    id: (parent) => parent.id,
      -    published: (parent) => parent.published,
      -    title: (parent) => parent.title,
      -  },
      

      Finally, you export the schema and resolvers so that you can use them in the next step to instantiate the server with Apollo Server.

      Step 3 — Creating the GraphQL Server

      In this step, you will create the GraphQL server with Apollo Server and bind it to a port so that the server can accept connections.

      First, run the following command to create the file for the server:

      Now add the following code to the file:

      prisma-graphql/src/server.js

      const { ApolloServer } = require('apollo-server')
      const { resolvers, typeDefs } = require('./schema')
      
      const port = process.env.PORT || 8080
      
      new ApolloServer({ resolvers, typeDefs }).listen({ port }, () =>
        console.log(`Server ready at: http://localhost:${port}`),
      )
      

      Here you instantiate the server and pass the schema and resolvers from the previous step.

      The port the server will bind to is set from the PORT environment variable and if not set, it will default to 8080. The PORT environment variable will be automatically set by App Platform and ensure your server can accept connections once deployed.

      Save and exit the file.

      Your GraphQL API is ready to run. Start the server with the following command:

      You will receive the following output:

      Output

      Server ready at: http://localhost:8080

      It’s considered good practice to add a start script to your package.json so that the entry point to your server is clear. Moreover, this will allow App Platform to start the server once deployed.

      To do so, add the following line to the "scripts" object in package.json:

      package.json

      {
        "name": "prisma-graphql",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
          "test": "echo "Error: no test specified" && exit 1",
          "start": "node ./src/server.js"
        },
        "keywords": [],
        "author": "",
        "license": "ISC",
        "dependencies": {
          "apollo-server": "^2.18.2",
          "graphql": "^15.3.0"
        }
      }
      

      Save and exit the file once you’re finished.

      Now you can start the server with the following command:

      To test the GraphQL API, open the URL from the output, which will lead you to the GraphQL Playground.

      GraphQL Playground

      The GraphQL Playground is an IDE where you can test the API by sending queries and mutations.

      For example, to test the feed query which only returns published posts, enter the following query to the left side of the IDE and send the query by pressing the play button:

      query {
        feed {
          id
          title
          content
          published
        }
      }
      

      The response will show a title of Subscribe to GraphQL Weekly with its URL and Follow DigitalOcean on Twitter with its URL.

      GraphQL query

      To test the createDraft mutation, enter the following mutation:

      mutation {
        createDraft(title: "Deploying a GraphQL API to DigitalOcean") {
          id
          title
          content
          published
        }
      }
      

      After you submit the mutation, using the play button, you will receive Deploying a GraphQL API to DigitalOcean within the title field as part of the response.

      GraphQL mutation

      Note: You can choose which fields to return from the mutation by adding or removing fields within the curly braces following createDraft. For example, if you wanted to only return the id and title you could send the following mutation:

      mutation {
        createDraft(title: "Deploying a GraphQL API to DigitalOcean") {
          id
          title
        }
      }
      

      You have successfully created and tested the GraphQL server. In the next step, you will create a GitHub repository for the project.

      Step 4 — Creating the GitHub Repository

      In this step, you will create a GitHub repository for your project and push your changes so that the GraphQL API can be automatically deployed from GitHub to App Platform.

      Begin by initializing a repository from the prisma-graphql folder:

      Next, use the following two commands to commit the code to the repository:

      • git add src package-lock.json package.json
      • git commit -m 'Initial commit'

      Now that the changes have been committed to your local repository, you will create a repository in GitHub and push your changes.

      Go to GitHub to create a new repository. For consistency, name the repository prisma-graphql and then click Create repository.

      After the repository was created, push the changes with the following commands, which includes renaming the default local branch to main:

      • git remote add origin git@github.com:your_github_username/prisma-graphql.git
      • git branch -M main
      • git push --set-upstream origin main

      You have successfully committed and pushed the changes to GitHub. Next, you will connect the repository to App Platform and deploy the GraphQL API.

      Step 5 — Deploying to App Platform

      In this step, you will connect the GitHub repository you created in the previous step to DigitalOcean and configure App Platform so that the GraphQL API can be automatically deployed when you push changes to GitHub.

      First, go to the App Platform and click on the Launch Your App button.

      You will see a button to link your GitHub account.

      Link Your GitHub Acccount

      Click on it, and you will be redirected to GitHub.

      Click Install & Authorize and you will be redirected back to DigitalOcean.

      Choose the repository your_github_username/prisma-graphql and click Next.

      Name your app and pick a branch to deploy from

      Choose the region you want to deploy your app to and click Next.

      Configure your app

      Here you can customize the configuration for the app. Ensure that the Run Command is npm start. By default, App Platform will set the HTTP port to 8080, which is the same port that you’ve configured your GraphQL server to bind to.

      Click Next and you will be prompted to pick the plan.

      Select Basic and then click Launch Basic App. You will be redirected to the app page, where you will see the progress of the initial deployment.

      Once the build finishes, you will get a notification indicating that your app is deployed.

      App page

      You can now visit your deployed GraphQL API at the URL below the app’s name. It will be under the ondigitalocean.app subdomain. If you open the URL, the GraphQL Playground will open the same way as it did in Step 3 of the tutorial.

      You have successfully connected your repository to App Platform and deployed your GraphQL API. Next you will evolve your app and replace the in-memory data of the GraphQL API with a database.

      Step 6 — Setting Up Prisma with PostgreSQL

      So far the GraphQL API you built used the in-memory posts array to store data. This means that if your server restarts, all changes to the data will be lost. To ensure that your data is safely persisted, you will replace the posts array with a PostgreSQL database and use Prisma to access the data.

      In this step, you will install the Prisma CLI, create your initial Prisma schema, set up PostgreSQL locally with Docker, and connect Prisma to it.

      The Prisma schema is the main configuration file for your Prisma setup and contains your database schema.

      Begin by installing the Prisma CLI with the following command:

      • npm install --save-dev @prisma/cli

      The Prisma CLI will help with database workflows such as running database migrations and generating Prisma Client.

      Next, you’ll set up your PostgreSQL database using Docker. Create a new Docker Compose file with the following command:

      Now add the following code to the newly created file:

      prisma-graphql/docker-compose.yml

      version: '3.8'
      services:
        postgres:
          image: postgres:10.3
          restart: always
          environment:
            - POSTGRES_USER=test-user
            - POSTGRES_PASSWORD=test-password
          volumes:
            - postgres:/var/lib/postgresql/data
          ports:
            - '5432:5432'
      volumes:
        postgres:
      

      This Docker Compose configuration file is responsible for starting the official PostgreSQL Docker image on your machine. The POSTGRES_USER and POSTGRES_PASSWORD environment variables set the credentials for the superuser (a user with admin privileges). You will also use these credentials to connect Prisma to the database. Finally, you define a volume where PostgreSQL will store its data, and bind the 5432 port on your machine to the same port in the Docker container.

      Save and exit the file.

      With this setup in place, go ahead and launch the PostgreSQL database server with the following command:

      You can verify that the database server is running with the following command:

      This will output something similar to:

      Output

      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 198f9431bf73 postgres:10.3 "docker-entrypoint.s…" 45 seconds ago Up 11 seconds 0.0.0.0:5432->5432/tcp prisma-graphql_postgres_1

      With the PostgreSQL container running, you can now create your Prisma setup. Run the following command from the Prisma CLI:

      Note that as a best practice, all invocations of the Prisma CLI should be prefixed with npx. This ensures it’s using your local installation.

      After running the command, the Prisma CLI created a new folder called prisma in your project. It contains the following two files:

      • schema.prisma: The main configuration file for your Prisma project (in which you will include your data model).
      • .env: A dotenv file to define your database connection URL.

      To make sure Prisma knows about the location of your database, open the .env file:

      Adjust the DATABASE_URL environment variable to look as follows:

      prisma-graphql/prisma/.env

      DATABASE_URL="postgresql://test-user:test-password@localhost:5432/my-blog?schema=public"
      

      Note that you’re using the database credentials test-user and test-password, which are specified in the Docker Compose file. To learn more about the format of the connection URL, visit the Prisma docs.

      You have successfully started PostgreSQL and configured Prisma using the Prisma schema. In the next step, you will define your data model for the blog and use Prisma Migrate to create the database schema.

      Step 7 — Defining the Data Model with Prisma Migrate

      Now you will define your data model in the Prisma schema file you’ve just created. This data model will then be mapped to the database with Prisma Migrate, which will generate and send the SQL statements for creating the tables that correspond to your data model.

      Since you’re building a blog, the main entities of the application will be users and posts. In this step, you will define a Post model with a similar structure to the Post type in the GraphQL schema. In a later step, you will evolve the app and add a User model.

      Note: The GraphQL API can be seen as an abstraction layer for your database. When building a GraphQL API, it’s common for the GraphQL schema to closely resemble your database schema. However, as an abstraction, the two schemas won’t necessarily have the same structure, thereby allowing you to control which data you want to expose over the API. This is because some data might be considered sensitive or irrelevant for the API layer.

      Prisma uses its own data modeling language to define the shape of your application data.

      Open your schema.prisma file from the project’s folder where package.json is located:

      • nano prisma/schema.prisma

      Note: You can verify from the terminal in which folder you are with the pwd command, which will output the current working directory. Additionally, listing the files with the ls command will help you navigate your file system.

      Add the following model definitions to it:

      prisma-graphql/prisma/schema.prisma

      ...
      model Post {
        id        Int     @default(autoincrement()) @id
        title     String
        content   String?
        published Boolean @default(false)
      }
      

      You are defining a model called Post with a number of fields. The model will be mapped to a database table; the fields represent the individual columns.

      The id fields have the following field attributes:

      • @default(autoincrement()): This sets an auto-incrementing default value for the column.
      • @id: This sets the column as the primary key for the table.

      Save and exit the file once you’re done.

      With the model in place, you can now create the corresponding table in the database using Prisma Migrate. This is a two-step process that involves creating the migration files and running them.

      Open up your terminal again and run the following command:

      • npx prisma migrate save --experimental --create-db --name "init"

      This command creates a new migration on your file system. Here’s a quick overview of the three options that are provided to the command:

      • --experimental: Required because Prisma Migrate is currently in an experimental state.
      • --create-db: Enables Prisma Migrate to create the database named my-blog that’s specified in the connection URL.
      • --name "init": Specifies the name of the migration (will be used to name the migration folder that’s created on your file system).

      Your prisma/migrations directory will now be populated with the files necessary to carry out the migration.

      Note: If you’ve already used Prisma Migrate with the my-blog database and there is an inconsistency between the migrations in the prisma/migration folder and the database schema you will enounter the following error:

      Output

      Error: There are more migrations in the database than locally. This must not happen.

      You can resolve this error by dropping the database with the following command:

      • psql postgresql://test-user:test-password@localhost:5432/postgres -c "DROP DATABASE "my-blog""

      Alternatively, you can stop the PostgreSQL container and remove the postgres volume defined in docker-compose.yml, which contains the data for the database. Beware that this will delete all data in the database. To do so, run the following command:

      The down command will stop the PostgreSQL container and the -v option will remove all volumes, thereby deleting all databases.

      To start PostgreSQL again, run the following command:

      To run the migration against your database and create the tables for your Prisma models, run the following command in your terminal:

      • npx prisma migrate up --experimental

      Prisma Migrate now generates the SQL statements that are required for the migration and sends them to the database. You will receive the following if the migration was carried out successfully:

      Output

      🚀 Done with 1 migration in 234ms.

      You’ve now created your database schema. In the next step, you will install Prisma Client and use it in your GraphQL resolvers.

      Step 8 — Using Prisma Client in the GraphQL Resolvers

      Prisma Client is an auto-generated and type-safe query builder that you can use to programmatically read and write data in a database from a Node.js application. In this step, you’ll install Prisma Client in your project.

      Open up your terminal again and install the Prisma Client npm package:

      • npm install @prisma/client

      Note: Prisma Client gives you rich auto-completion by generating code based on your Prisma schema to the node_modules folder. To generate the code you use the npx prisma generate command. This is typically done after you create and run a new migration. On the first install, however, this is not necessary as it will automatically be generated for you in a postinstall hook.

      With the database and GraphQL schema created, and Prisma Client installed, you will now use Prisma Client in the GraphQL resolvers to read and write data in the database. You’ll do this by replacing the posts array, which you’ve used so far to hold your data.

      Begin by creating the following file:

      Add the following:

      prisma-graphql/src/db.js

      const { PrismaClient } = require('@prisma/client')
      
      module.exports = {
        prisma: new PrismaClient(),
      }
      

      This imports Prisma Client, creates an instance of it, and exports the instance that you’ll use in your resolvers.

      Now save and close the src/db.js file.

      Next, you will import the prisma instance into src/schema.js. To do so, open src/schema.js:

      Then import prisma from ./db at the top of the file:

      prisma-graphql/src/schema.js

      const { prisma } = require('./db')
      ...
      

      Then delete the posts array:

      prisma-graphql/src/schema.js

      -const posts = [
      -  {
      -    id: 1,
      -    title: 'Subscribe to GraphQL Weekly for community news ',
      -    content: 'https://graphqlweekly.com/',
      -    published: true,
      -  },
      -  {
      -    id: 2,
      -    title: 'Follow DigitalOcean on Twitter',
      -    content: 'https://twitter.com/digitalocean',
      -    published: true,
      -  },
      -  {
      -    id: 3,
      -    title: 'What is GraphQL?',
      -    content: 'GraphQL is a query language for APIs',
      -    published: false,
      -  },
      -]
      

      Now you will update the Query resolvers to fetch published posts from the database. Update the resolvers.Query object with the following resolvers:

      prisma-graphql/src/schema.js

      ...
      const resolvers = {
        Query: {
          feed: (parent, args) => {
            return prisma.post.findMany({
              where: { published: true },
            })
          },
          post: (parent, args) => {
            return prisma.post.findOne({
              where: { id: Number(args.id) },
            })
          },
        },
      

      Here, you’re using two Prisma Client queries:

      • findMany: Fetches posts whose publish field is false.
      • findOne: Fetches a single post whose id field equals the id GraphQL argument.

      Note, that as per the GraphQL specification, the ID type is serialized the same way as a String. Therefore you convert to a Number because the id in the Prisma schema is an int.

      Next, you will update the Mutation resolver to save and update posts in the database. Update the resolvers.Mutation Object with the following resolvers:

      prisma-graphql/src/schema.js

      const resolvers = {
        ...
        Mutation: {
          createDraft: (parent, args) => {
            return prisma.post.create({
              data: {
                title: args.title,
                content: args.content,
              },
            })
          },
          publish: (parent, args) => {
            return prisma.post.update({
              where: {
                id: Number(args.id),
              },
              data: {
                published: true,
              },
            })
          },
        },
      }
      

      You’re using two Prisma Client queries:

      • create: Create a Post record.
      • update: Update the published field of the Post record whose id matches the one in the query argument.

      Your schema.js should now look as follows:

      prisma-graphql/src/schema.js

      const { gql } = require('apollo-server')
      const { prisma } = require('./db')
      
      const typeDefs = gql`
        type Post {
          content: String
          id: ID!
          published: Boolean!
          title: String!
        }
      
        type Query {
          feed: [Post!]!
          post(id: ID!): Post
        }
      
        type Mutation {
          createDraft(content: String, title: String!): Post!
          publish(id: ID!): Post
        }
      `
      
      const resolvers = {
        Query: {
          feed: (parent, args) => {
            return prisma.post.findMany({
              where: { published: true },
            })
          },
          post: (parent, args) => {
            return prisma.post.findOne({
              where: { id: Number(args.id) },
            })
          },
        },
        Mutation: {
          createDraft: (parent, args) => {
            return prisma.post.create({
              data: {
                title: args.title,
                content: args.content,
              },
            })
          },
          publish: (parent, args) => {
            return prisma.post.update({
              where: {
                id: Number(args.id),
              },
              data: {
                published: true,
              },
            })
          },
        },
      }
      
      module.exports = {
        resolvers,
        typeDefs,
      }
      

      Save and close the file.

      Now that you’ve updated the resolvers to use Prisma Client, start the server to test the flow of data between the GraphQL API and the database with the following command:

      Once again, you will receive the following output:

      Output

      Server ready at: http://localhost:8080

      Open the GraphQL playground at the address from the output and test the GraphQL API using the same queries from Step 3.

      Now you will commit your changes so that the changes can be deployed to App Platform.

      To avoid committing the node_modules folder and the prisma/.env file, begin by creating a .gitignore file:

      Add the following to the file:

      prisma-graphql/.gitignore

      node_modules
      prisma/.env
      

      Save and exit the file.

      Then run the following two commands to commit the changes:

      • git add .
      • git commit -m 'Add Prisma'

      Next you’ll add a PostgreSQL database to your app in App Platform.

      Step 9 — Creating and Migrating the PostgreSQL Database in App Platform

      In this step, you will add a PostgreSQL database to your app in App Platform. Then you will use Prisma Migrate to run the migration against it so that the deployed database schema matches your local database.

      First, go to the App Platform console and choose the prisma-graphql project you created in Step 5.

      Next, go to the Components tab.

      Component Tab

      Click on + Create Component and select Database, which will lead you to a page to configure your database.

      Configure your database

      Choose Dev Database and click Create and Attach.

      You will be redirected back to the Components page, where there will be a progress bar for creating the database.

      Creating database

      After the database has been created, you will run the database migration against the production database on DigitalOcean from your local machine. To run the migration, you will need the connection string of the hosted database. To get it, click on the db icon in the components tab.

      Database information

      Under Connection Details select Connection String in the dropdown and copy the database URL, which will have the following structure:

      postgresql://db:some_password@unique_identifier.db.ondigitalocean.com:25060/db?sslmode=require
      

      Then, run the following command in your terminal and ensure that you set DATABASE_URL to the same URL you copied:

      • DATABASE_URL="postgresql://db:some_password@unique_identifier.db.ondigitalocean.com:25060/db?sslmode=require" npx prisma migrate up --experimental

      This will run the migrations against the live database with Prisma Migrate.

      If the migration succeeds you will receive the following:

      Output

      🚀 Done with 1 migration in 234ms.

      You have successfully migrated the production database on DigitalOcean, which now matches the Prisma schema.

      Now you can deploy your app by pushing your Git changes with the following command:

      Note: App Platform will make the DATABASE_URL environment variable available to your application at run-time. Prisma Client will use that environment variable using the env("DATABASE_URL") in the datasource block of your Prisma schema.

      This will automatically trigger a build. If you open App Platform console, you will have a Deploying progress bar.

      Deploying

      Once the deployment succeeds, you will receive a Deployed successfully message.

      You’ve now backed up your deployed GraphQL API with a database. Open the Live App, which will lead you to the GraphQL Playground. Test the GraphQL API using the same queries from Step 3.

      In the final step you will evolve the GraphQL API by adding the User model.

      Step 10 — Adding the User Model

      Your GraphQL API for blogging has a single entity named Post. In this step, you’ll evolve the API by defining a new model in the Prisma schema and adapting the GraphQL schema to make use of the new model. You will introduce a User model with a one-to-many relation to the Post model. This will allow you to represent the author of posts and associate multiple posts to each user. Then you will evolve the GraphQL schema to allow creating users and associating posts with users through the API.

      First, open the Prisma schema and add the following:

      prisma-graphql/prisma/schema.prisma

      ...
      model Post {
        id        Int     @id @default(autoincrement())
        title     String
        content   String?
        published Boolean @default(false)
        author    User?   @relation(fields: [authorId], references: tag:www.digitalocean.com,2005:/community/tutorials/how-to-build-a-graphql-api-with-prisma-and-deploy-to-digitalocean-s-app-platform)
        authorId  Int?
      }
      
      model User {
        id    Int    @id @default(autoincrement())
        email String @unique
        name  String
        posts Post[]
      }
      

      You’ve added the following to the Prisma schema:

      • The User model to represent users.
      • Two relation fields: author and posts. Relation fields define connections between models at the Prisma level and do not exist in the database. These fields are used to generate the Prisma Client and to access relations with Prisma Client.
      • The authorId field, which is referenced by the @relation attribute. Prisma will create a foreign key in the database to connect Post and User.

      Note that the author field in the Post model is optional. That means you’ll be able to create posts unassociated with a user.

      Save and exit the file once you’re done.

      Next, save and run the migration locally with the following commands:

      • npx prisma migrate save --experimental --name "add-user"
      • npx prisma migrate up --experimental

      After the migration has succeeded, generate Prisma Client so that you can make use of the new fields in the next step:

      Now you will run the migration against the production database on App Platform so that the database schema is the same as your local database. Run the following command in your terminal and set DATABASE_URL to the connection URL from App Platform:

      • DATABASE_URL="postgresql://db:some_password@unique_identifier.db.ondigitalocean.com:25060/db?sslmode=require" npx prisma migrate up --experimental

      You will receive the following:

      Output

      🚀 Done with 1 migration in 274ms.

      You will now update the GraphQL schema and resolvers to make use of the updated database schema.

      Open the src/schema.js file and add update typeDefs as follows:

      prisma-graphql/src/schema.js

      ...
      const typeDefs = gql`
        type User {
          email: String!
          id: ID!
          name: String
          posts: [Post!]!
        }
      
        type Post {
          content: String
          id: ID!
          published: Boolean!
          title: String!
          author: User
        }
      
        type Query {
          feed: [Post!]!
          post(id: ID!): Post
        }
      
        type Mutation {
          createUser(data: UserCreateInput!): User!
          createDraft(authorEmail: String, content: String, title: String!): Post!
          publish(id: ID!): Post
        }
      
        input UserCreateInput {
          email: String!
          name: String
          posts: [PostCreateWithoutAuthorInput!]
        }
      
        input PostCreateWithoutAuthorInput {
          content: String
          published: Boolean
          title: String!
        }
      `
      ...
      

      In this updated code, you’re adding the following changes to the GraphQL schema:

      • The User type, which returns an array of Post.
      • The author field to the Post type.
      • The createUser mutation, which expects the UserCreateInput as its input type.
      • The PostCreateWithoutAuthorInput input type used in the UserCreateInput input for creating posts as part of the createUser mutation.
      • The authorEmail optional argument to the createDraft mutation.

      With the schema updated, you will now update the resolvers to match the schema.

      Update the resolvers object as follows:

      prisma-graphql/src/schema.js

      ...
      const resolvers = {
        Query: {
          feed: (parent, args) => {
            return prisma.post.findMany({
              where: { published: true },
            })
          },
          post: (parent, args) => {
            return prisma.post.findOne({
              where: { id: Number(args.id) },
            })
          },
        },
        Mutation: {
          createDraft: (parent, args) => {
            return prisma.post.create({
              data: {
                title: args.title,
                content: args.content,
                published: false,
                author: args.authorEmail && {
                  connect: { email: args.authorEmail },
                },
              },
            })
          },
          publish: (parent, args) => {
            return prisma.post.update({
              where: { id: Number(args.id) },
              data: {
                published: true,
              },
            })
          },
          createUser: (parent, args) => {
            return prisma.user.create({
              data: {
                email: args.data.email,
                name: args.data.name,
                posts: {
                  create: args.data.posts,
                },
              },
            })
          },
        },
        User: {
          posts: (parent, args) => {
            return prisma.user
              .findOne({
                where: { id: parent.id },
              })
              .posts()
          },
        },
        Post: {
          author: (parent, args) => {
            return prisma.post
              .findOne({
                where: { id: parent.id },
              })
              .author()
          },
        },
      }
      

      Let’s break down the changes to the resolvers:

      • The createDraft mutation resolver now uses the authorEmail argument (if passed) to create a relation between the created draft and an existing user.
      • The new createUser mutation resolver creates a user and related posts using nested writes.
      • The User.posts and Post.author resolvers define how to resolve the posts and author fields when the User or Post are queried. These use Prisma’s Fluent API to fetch the relations.

      Save and exit the file.

      Start the server to test the GraphQL API:

      Begin by testing the createUser resolver with the following GraphQL mutation:

      mutation {
        createUser(data: { email: "natalia@prisma.io", name: "Natalia" }) {
          email
          id
        }
      }
      

      This will create a user.

      Next, test the createDraft resolver with the following mutation:

      mutation {
        createDraft(
          authorEmail: "hello@prisma.io"
          title: "Deploying a GraphQL API to App Platform"
        ) {
          id
          title
          content
          published
          author {
            id
            name
          }
        }
      }
      

      Notice that you can fetch the author whenever the return value of a query is Post. In this example, the Post.author resolver will be called.

      Finally, commit your changes and push to deploy the API:

      • git add .
      • git commit -m "add user model"
      • git push

      You have successfully evolved your database schema with Prisma Migrate and exposed the new model in your GraphQL API.

      Conclusion

      In this article, you built a GraphQL API with Prisma and GraphQL, and deployed it to DigitalOcean’s App Platform. You defined a GraphQL schema and resolvers with Apollo Server. You then used Prisma Client in your GraphQL resolvers to persist and query data in the PostgreSQL database.

      As a next step, you can further extend the GraphQL API with a query to fetch individual users and a mutation to connect an existing draft to a user.

      If you’re interested in exploring the data in the database, check out Prisma Studio. Be sure to visit the Prisma documentation to learn about different aspects of Prisma and explore some ready-to-run example projects in the prisma-examples repository.

      You can find the code for this project in the DigitalOcean Community repository.





      Source link

      How To Set Up a Ruby on Rails GraphQL API


      The author selected Free Press to receive a donation as part of the Write for DOnations program.

      Introduction

      GraphQL is a strongly typed query language for APIs and a server-side runtime for executing those queries with your existing data. GraphQL allows clients to fetch multiple resources from the server in a single request by giving clients the ability to specify the exact data needed in the query. This removes the need for multiple API calls. GraphQL is language and database independent, and thus can be implemented in almost every programming language alongside any database of choice.

      In this tutorial, you will build a GraphQL-powered Ruby on Rails API for taking notes. When you are finished, you will be able to create and view notes from the API using GraphQL.

      GraphiQL IDE

      If you would like to take a look at the code for this tutorial, check out the companion repository for this tutorial on the DigitalOcean Community GitHub.

      Prerequisites

      To follow this tutorial, you’ll need:

      • The Ruby programming language and the Ruby on Rails framework installed on your development machine. This tutorial was tested on version 2.6.3 of Ruby and version 6.0.2.1 of Rails, so make sure to specify these versions during the installation process. Follow one of these tutorials to install Ruby and Rails:
      • PostgreSQL installed. To follow this tutorial, use PostgreSQL version 11.2. Install PostgreSQL by following Steps 1 and 2 of one of the following tutorials:

      Step 1 — Setting Up a New Rails API Application

      In this step, you will set up a new Rails API application and connect it to a PostgreSQL database. This will serve as the foundation for the note-taking API.

      Rails provides commands that make building modern web applications faster for developers. These commands can perform actions that range from creating a new Rails application to generating files required for app development. For a full list of these commands and what they do, run the following command in your terminal window:

      This command yields an extensive list of options you can use to set the parameters of your application. One of the commands listed is the new command, which accepts an APP_PATH and creates a new Rails application at the specified path.

      Create a new Rails application using the new generator. Run the following command in your terminal window:

      • rails new rails_graphql -d=postgresql -T --api

      This creates a new Rails application in a directory named rails_graphql and installs the required dependencies. Let’s go over the flags associated with the new command:

      • The -d flag pre-configures the application with the specified database.
      • The -T flag instructs Rails to not generate test files since you won’t be writing tests in this tutorial. You can also use this flag if you plan to use a different testing framework other than the one provided by Rails.
      • The --api flag configures a Rails application with only the files required for building an API with Rails. It skips configuring settings needed for browser applications.

      Once the command is done running, switch to the newly created rails_graphql directory, which is the application’s root directory:

      Now that you have successfully set up a new Rails API application, you have to connect it to a database before you can run the app. Rails provides a database.yml file found in config/database.yml, which contains configurations for connecting your app to a different database for different development environments. Rails specifies a database name for different development environments by appending an underscore (_) followed by the environment name to your app’s name. You can always change any environment database name to whatever you choose.

      Note: You can alter config/database.yml to choose the PostgreSQL role you would like Rails to use to create your database. If you created a role that is secured by a password, follow the instructions in Step 4 of How To Use PostgreSQL with Your Ruby on Rails Application on Ubuntu 18.04 or How To Use PostgreSQL with Your Ruby on Rails Application on macOS to configure your role.

      Rails includes commands for creating and working with databases. With your database credentials in place, run the following command in your terminal window to create your databases:

      The db:create command creates a development and test database based on the information provided in the config/database.yml file. Running the command yields the following output:

      Output

      Created database 'rails_graphql_development' Created database 'rails_graphql_test'

      With your application now successfully connected to a database, you can test the application to ensure it works. Start your server with the following command if you are working locally:

      If you are working on a development server, you can start your application by specifying the IP address the server should bind to:

      • bundle exec rails server --binding=your_server_ip

      Note: The server listens on port 3000. If you’re working on a development server, ensure that you have opened port 3000 in your firewall to allow connections.

      The rails server command launches Puma, a web server for Ruby distributed with Rails. The --binding=your_server_ip command binds the server to any IP you provide.

      Once you run this command, your command prompt will be replaced with the following output:

      Output

      => Booting Puma => Rails 6.0.2.1 application starting in development => Run `rails server --help` for more startup options Puma starting in single mode... * Version 4.3.1 (ruby 2.6.3-p62), codename: Mysterious Traveller * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://127.0.0.1:3000 * Listening on tcp://[::1]:3000 Use Ctrl-C to stop

      To run your application, navigate to localhost:3000 or http://your_server_ip:3000 in your browser. You’ll see the Rails default welcome page:

      Rails welcome page

      The welcome page means you have properly set up your Rails application.

      To stop the server, press CTRL+C in the terminal window where the server is running.

      You have successfully set up a Rails API application for a note-taking API. In the next step, you will set up your Rails API application to receive and execute GraphQL queries.

      Step 2 — Setting Up GraphQL for Rails

      In this step, you will configure your Rails API application to work with GraphQL. You will install and set up the necessary gems required for GraphQL development in Rails.

      As previously mentioned, GraphQL is language agnostic and is implemented in many programming languages. The graphql-ruby gem is the Ruby implementation for GraphQL. GraphQL also provides an interactive in-browser IDE known as GraphiQL for running GraphQL queries. The graphiql-rails gem helps you add GraphiQL to your development environment.

      To install these dependencies, open the project’s Gemfile for editing, using nano or your favorite text editor:

      Add the graphql and graphiql-rails gems to your Gemfile. You can add the graphiql gem anywhere, but the graphiql-rails gem should be added under the development dependencies:

      ~/rails_graphql/Gemfile

      ...
      group :development do
        gem 'listen', '>= 3.0.5', '< 3.2'
        # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
        gem 'spring'
        gem 'spring-watcher-listen', '~> 2.0.0'
        gem 'graphiql-rails'
      end
      
      gem 'graphql', '1.9.18'
      ...
      

      Save and close the file when you are done adding the gems.

      In your terminal window, use the following command to install the gems:

      The output shows that the gems are installed.

      The graphql gem provides generators to create various files. To view the available generators, run the following command in your terminal window:

      The generators prefixed with graphql: are the ones associated with the graphql gem.

      You will use the graphql:install command to add graphql-ruby boilerplate code to the application and mount GraphiQL in your development environment. The boilerplate code will include all the files and directory needed for the graphql-ruby gem to work with Rails.

      In your terminal window, run the following commands:

      This command generates several files, including a graphql_controller.rb file located at app/controllers/graphql_controller.rb and a graphql directory at app/graphql which contains files required to get started with GraphQL in Rails. It also adds a /graphql HTTP POST route in the routes file located at config/routes.rb. This route is mapped to the app/controllers/graphql_controller.rb#execute method which handles all queries to the GraphQL server.

      Before you can test the GraphQL endpoint, you need to mount the GraphiQL engine to the routes file so you can access the GraphiQL in-browser IDE. To do this open the routes file located at config/routes.rb:

      • nano ~/rails_graphql/config/routes.rb

      Add the following code to the file to mount the GraphiQL engine in the development environment:

      ~/rails_graphql/config/routes.rb

      Rails.application.routes.draw do
        if Rails.env.development?
          mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "graphql#execute"
        end
        post "/graphql", to: "graphql#execute"
        # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
      end
      

      This mounts the GraphiQL engine to the /graphiql path and directs all queries to the graphql#execute method.

      Since this is an API application created with the --api flag, it does not expect to render any page in the browser. To make the GraphiQL editor show up in the browser, you need to make a couple of small changes to your application’s configuration.

      First, open the application.rb file located at config/application.rb:

      • nano ~/rails_graphql/config/application.rb

      Next, uncomment the require "sprockets/railtie" line:

      ~/rails_graphql/config/application.rb

      require_relative 'boot'
      
      require "rails"
      # Pick the frameworks you want:
      require "active_model/railtie"
      require "active_job/railtie"
      require "active_record/railtie"
      require "active_storage/engine"
      require "action_controller/railtie"
      require "action_mailer/railtie"
      require "action_mailbox/engine"
      require "action_text/engine"
      require "action_view/railtie"
      require "action_cable/engine"
      require "sprockets/railtie"
      # require "rails/test_unit/railtie"
      
      ...
      

      Save and close the file after uncommenting the line.

      Now create a config directory at app/assets:

      • mkdir -p app/assets/config

      Next, create a manifest.js file in the newly created config directory. The manifest.js file specifies additional assets to be compiled and made available to the browser:

      • nano app/assets/config/manifest.js

      Add the following code to the file which tells Rails to precompile the graphiql/rails/application.css and graphiql/rails/application.js files so Rails can serve them to your browser:

      ~/rails_graphql/app/assets/config/manifest.js

      //= link graphiql/rails/application.css
      //= link graphiql/rails/application.js
      

      Save and close the file.

      With that done, you can test your GraphQL endpoint. Restart your development server, and in your browser, navigate to localhost:3000/graphiql or http://your_server_ip:3000/graphiql. The GraphiQL query editor displays in your browser:

      GraphiQL IDE

      The left side of the GraphiQL IDE accepts GraphQL queries and the right side displays results of the run query. The GraphiQL query editor also has a syntax highlighter and a typeahead hinter powered by your GraphQL Schema. Together, these help you make a valid query.

      To try a Hello World example, clear out the default text in the editor’s left pane and type in the following query:

      query {
          testField
      }
      

      Click the Play icon button in the header and you’ll recieve a successful response on the screen, as shown in the following figure:

      GraphiQL IDE Response successful response

      You have successfully set up your Rails API application to work with GraphQL and tested your GraphQL endpoint to confirm it works. In the next step, you will create GraphQL types for your application.

      Step 3 — Creating Types for the Application

      GraphQL depends on its Types and Schema to validate and respond to queries. In this step, you will create a Note model and the GraphQL types required in your note-taking API.

      A GraphQL type consists of fields and arguments which, in turn, define the fields and arguments that can appear in any GraphQL query that operates on that type. These types make up a GraphQL Schema. GraphQL defines the following types:

      • The Query and Mutation types: These are special types that define the entry point of every GraphQL query. Every GraphQL service has a query type and may or may not have a mutation type.
      • Object types: These are the basic components of a GraphQL schema. These represent the objects you can fetch from a GraphQL service and the fields each object holds.
      • Scalar types: These are default types that come with GraphQL out of the box. They include Int, Float, String, Boolean, and ID.
      • Enumeration types: These are types that define a particular set of allowed values.
      • Input types: These are similar to object types, with the only difference being that they define objects that you can pass to queries as arguments.

      There are other types, including Union, List, Non-Null, and Interface. You can find a list of available GraphQL types in the official GraphQL documentation.

      For this application, you will create a Note model and a Note object and input type. The Note model will represent the database table that will store your notes while the Note object and input type will define the fields and arguments that exists on a Note object.

      First, create a Note model using the generate model subcommand provided by Rails and specify the name of the model along with its columns and data types. Run the following command in your terminal window:

      • rails generate model note title:string:index body:text

      This command creates a Note model with two fields: title, with the type string, and body, with the type text. The command also adds a database index on the title column. It generates these two files:

      • A note.rb file located at app/models/note.rb. This file will hold all model-related logic.
      • A 20200617173228_create_notes.rb file (the number at the beginning of the file will differ, depending on the date you run the command) located at db/migrate/20200617173228_create_notes.rb. This is a migration file that holds the instruction for creating a corresponding notes table in the database.

      To execute the instructions in the migration file, you’ll use the db:migrate subcommand which executes the instruction in your migration files. Run the following command in your terminal window:

      Once the command runs successfully, you will see output similar to the following:

      Output

      == 20200617173228 CreateNotes: migrating ====================================== -- create_table(:notes) -> 0.0134s -- add_index(:notes, :title) -> 0.0073s == 20200617173228 CreateNotes: migrated (0.0208s) =============================

      With the note model in place, next you’ll create a NoteType. A valid note object is expected to have an id, a title, and text. Run the following command in your terminal window to create a NoteType:

      • rails generate graphql:object Note id:ID! title:String! body:String!

      The command instructs Rails to create a GraphQL object type called Note with three fields: an id field with a type of ID, and the title and body fields, each with a String type. The exclamation point (!) appended to the field type indicates that the field should be non-nullable, meaning that the field should never return a null value. Non-nullable fields are important, as they serve as a form of validation that guarantees which fields must be present whenever GraphQL objects are queried.

      Running the preceding command creates a note_type.rb file located at app/graphql/types/note_type.rb containing a Types::NoteType class with three non-nullable fields.

      Lastly, you will create a NoteInput type to define the arguments required to create a note. Start by creating an input directory under app/graphql/types. The input directory will house input types:

      • mkdir ~/rails_graphql/app/graphql/types/input

      Note: It’s not a requirement to create input types in the input directory; it is merely a common convention. You can decide to keep all your types under the types directory and exclude nesting the class under an Input module whenever you’re accessing it.

      In the ~/rails_graphql/app/graphql/types/input directory, create a note_input_type.rb file:

      • nano ~/rails_graphql/app/graphql/types/input/note_input_type.rb

      Add the following code to the file to define the fields for the Input type:

      ~/rails_graphql/app/graphql/types/input/note_input_type.rb

      module Types
        module Input
          class NoteInputType < Types::BaseInputObject
            argument :title, String, required: true
            argument :body, String, required: true
          end
        end
      end
      

      In the note_input_type.rb file, you added a Types::Input::NoteInputType class that inherits from the Types::BaseInputObject class and accepts two required arguments; title and body, both of a string type.

      You’ve created a model and two GraphQL types for your note-taking app. In the next step, you will create queries to fetch existing notes.

      Step 4 — Creating Queries for the Application

      Your GraphQL-powered API is gradually coming together. In this step you’ll create two queries; one to fetch a single note by id and another to fetch all notes. The GraphQL query type handles the fetching of data and can be likened to a GET request in REST.

      First, you’ll create a query to fetch all notes. To start, create a queries directory to house all queries:

      • mkdir ~/rails_graphql/app/graphql/queries

      In the app/graphql/queries directory, create a base_query.rb file from which all other query classes will inherit:

      • nano ~/rails_graphql/app/graphql/queries/base_query.rb

      Add the following code to the base_query.rb file to create a BaseQuery class that other query classes will inherit from:

      ~/rails_graphql/app/graphql/queries/base_query.rb

      module Queries
        class BaseQuery < GraphQL::Schema::Resolver
        end
      end
      

      In the base_query.rb file, you added a Queries::BaseQuery class that inherits from the GraphQL::Schema::Resolver class. The GraphQL::Schema::Resolver class is a container that can hold logic belonging to a field. It can be attached to a field with the resolver: keyword.

      The Queries::BaseQuery class can also contain any code you intend to reuse across multiple query classes.

      Next, create a fetch_notes.rb file in the queries directory. This file will hold the logic for fetching all existing notes, and will be attached to a field in the query type file:

      • nano ~/rails_graphql/app/graphql/queries/fetch_notes.rb

      Add the following code to the file to define the return object type and resolve the requested notes:

      ~/rails_graphql/app/graphql/queries/fetch_notes.rb

      module Queries
        class FetchNotes < Queries::BaseQuery
      
          type [Types::NoteType], null: false
      
          def resolve
            Note.all.order(created_at: :desc)
          end
        end
      end
      

      In the fetch_notes.rb file, you created a Queries::FetchNotes class that inherits the Queries::BaseQuery previously created. The class has a return type declaration that declares that the data returned by this query should be an array of the already created NoteType.

      The Queries::FetchNotes also contains a resolve method that returns an array of all existing notes sorted by their created date in descending order.

      The FetchNotes query is ready to receive and return requests for notes, but GraphQL is still unaware of its existence, to fix that, open the GraphQL query type file located at app/graphql/types/query_type.rb:

      • nano ~/rails_graphql/app/graphql/types/query_type.rb

      The query_type.rb file is the entry point for all GraphQL query types. It holds the query fields, and their respective resolver methods. Replace the sample code in the file with the following:

      ~/rails_graphql/app/graphql/types/query_type.rb

      module Types
        class QueryType < Types::BaseObject
          # Add root-level fields here.
          # They will be entry points for queries on your schema.
      
          field :fetch_notes, resolver: Queries::FetchNotes
        end
      end
      

      In the query_type.rb file, you added a fetch_notes field and attached it to the Queries::FetchNotes class using a resolver:. This way whenever the fetch_notes query is called, it executes the logic in the resolve method of the Queries::FetchNotes class.

      In order to test your query, you need some data to fetch, but you currently don’t have any notes in your database. You can fix that by adding some seed data to your database. Open the seeds.rb file located at db/seeds.rb:

      • nano ~/rails_graphql/db/seeds.rb

      Add the following code to the file to create five notes:

      ~/rails_graphql/db/seeds.rb

      5.times do |i|
        Note.create(title: "Note #{i + 1}", body: 'Lorem ipsum saves lives')
      end
      

      Save and close the file after adding the code.

      Open your project’s root directory in another terminal window and run the following command to run the code in the seed.rb file:

      This creates 5 notes in the database.

      With data in your database, and your development server running, navigate to localhost:3000/graphiql or http://your_server_ip:3000/graphiql in your browser to open your GraphiQL IDE. In the left side of the editor, type in the following query:

      query {
        fetchNotes {
          id
          title
          body
        }
      }
      

      This GraphQL query declares a query operation, indicating you want to make a query request. In the query operation, you called a fetchNotes field that matches the fetch_notes query field declared in the API, and included the fields on a note that you want to be returned in your response.

      Click the Play icon button in the header. You’ll see a response similar to the following in the output pane:

      {
        "data": {
          "fetchNotes": [
            {
              "id": "5",
              "title": "Note 5",
              "body": "Lorem ipsum saves lives"
            },
            {
              "id": "4",
              "title": "Note 4",
              "body": "Lorem ipsum saves lives"
            },
            {
              "id": "3",
              "title": "Note 3",
              "body": "Lorem ipsum saves lives"
            },
            {
              "id": "2",
              "title": "Note 2",
              "body": "Lorem ipsum saves lives"
            },
            {
              "id": "1",
              "title": "Note 1",
              "body": "Lorem ipsum saves lives"
            }
          ]
        }
      }
      

      The response contains an array of 5 notes that match the fields declared in the query on the left. If you remove some fields in the query on the left side of the editor and re-run the query, you get a response with only the fields you requested. That’s the power of GraphQL.

      Next, you’ll create another query to fetch notes by id. This query will be similar to the fetch_notes query, only that it’ll accept an id argument. Go ahead and create a fetch_note.rb file in the queries directory:

      • nano ~/rails_graphql/app/graphql/queries/fetch_note.rb

      Add the following code to the file to find and return a note with the provided id:

      ~/rails_graphql/app/graphql/queries/fetch_note.rb

      module Queries
        class FetchNote < Queries::BaseQuery
          type Types::NoteType, null: false
          argument :id, ID, required: true
      
          def resolve(id:)
            Note.find(id)
          rescue ActiveRecord::RecordNotFound => _e
            GraphQL::ExecutionError.new('Note does not exist.')
          rescue ActiveRecord::RecordInvalid => e
            GraphQL::ExecutionError.new("Invalid attributes for #{e.record.class}:"
              " #{e.record.errors.full_messages.join(', ')}")
          end
        end
      end
      

      This defines a Queries::FetchNote class that inherits from the Queries::BaseQuery class. This class not only returns a single item that must be of a NoteType, it also accepts an id argument with an ID type. The resolve method receives the provided id argument, then finds and returns a note with the provided id. If no note exists or an error occurs, it is rescued and returned as a GraphQL::ExecutionError.

      Next, you will attach the Queries::FetchNote class to a query field in the query type file. Open the query_type.rb file in your editor:

      • nano ~/rails_graphql/app/graphql/types/query_type.rb

      Add the following code to the file which defines a resolver for fetch_notes:

      ~/rails_graphql/app/graphql/types/query_type.rb

      module Types
        class QueryType < Types::BaseObject
          # Add root-level fields here.
          # They will be entry points for queries on your schema.
      
          field :fetch_notes, resolver: Queries::FetchNotes
          field :fetch_note, resolver: Queries::FetchNote
        end
      end
      

      To test your new query, ensure your server is running and navigate to localhost:3000/graphiql or http://your_server_ip:3000/graphiql in your browser to open your GraphiQL IDE. In the left side of the editor, type in the following query:

      query {
        fetchNote(id: 1) {
          id
          title
          body
        }
      }
      

      This query operation requests a fetchNote field, which corresponds to the fetch_note query field, and is passed an id argument. It specifies that we want three fields to be returned in the response.

      Run the query by clicking the Play icon button in the header. You will get a response like the following in the output pane:

      {
        "data": {
          "fetchNote": {
            "id": "1",
            "title": "Note 1",
            "body": "Lorem ipsum saves lives"
          }
        }
      }
      

      The response contains a single note that matches the requested id with fields matching the ones in the request.

      In this step, you created GraphQL queries to fetch notes from your API. Next you’ll write mutations to create notes.

      Step 5 — Creating GraphQL Mutations to Modify Notes

      In addition to queries, GraphQL also defines a mutation type for operations that modify server-side data. Just as REST provides POST, PUT, PATCH, and DELETE requests for creating, updating and deleting resources, GraphQL’s mutation type defines a convention for operations that cause writes on the server-side. In this step, you’ll create a mutation for adding new notes.

      graphQL-ruby includes two classes for writing mutations. They are:

      • GraphQL::Schema::Mutation: This is the generic base class for writing mutations. If you don’t want an input argument required in your mutations, you should use this class.
      • GraphQL::Schema::RelayClassicMutation: This is a base class with some conventions; an argument called clientMutationId that is always inserted to the response, and mutations that accepts one argument called input. This class is used by default when you use the install generator to add boilerplate GraphQL files to your project.

      Create an add_note.rb file in the mutations directory located at app/graphql/mutations:

      • nano ~/rails_graphql/app/graphql/mutations/add_note.rb

      Add the following code to the file to define the mutation for adding new notes:

      ~/rails_graphql/app/graphql/mutations/add_note.rb

      module Mutations
        class AddNote < Mutations::BaseMutation
          argument :params, Types::Input::NoteInputType, required: true
      
          field :note, Types::NoteType, null: false
      
          def resolve(params:)
            note_params = Hash params
      
            begin
              note = Note.create!(note_params)
      
              { note: note }
            rescue ActiveRecord::RecordInvalid => e
              GraphQL::ExecutionError.new("Invalid attributes for #{e.record.class}:"
                " #{e.record.errors.full_messages.join(', ')}")
            end
          end
        end
      end
      

      This defines a Mutations::AddNote class that inherits from the Mutations::BaseMutation class, which is one of the classes created when you ran the install generator while installing the GraphQL-Ruby gem. The Mutations::AddNote class receives an argument with the name params and a type of NoteInputType, which you created in Step 3. It also returns a field called note that must be a non-null NoteType type.

      The resolve method of the class receives the params and converts it to a hash which it uses to create and return a new hash containing the new note. If there’s an error while creating the note, the error is rescued and returned as a GraphQL::ExecutionError.

      Note: The resolve method in a mutation must return a hash whose symbol matches the field names.

      Like with queries, the Mutations::AddNote mutation has to be attached to a mutation field using the mutation: keyword.

      Open the mutation type file located at app/graphql/types/mutation_type.rb in your editor:

      • nano ~/rails_graphql/app/graphql/types/mutation_type.rb

      Replace the code in the file with the following code, which adds a field for the add_note with its corresponding mutation class:

      ~/rails_graphql/app/graphql/types/mutation_type.rb

      module Types
        class MutationType < Types::BaseObject
          field :add_note, mutation: Mutations::AddNote
        end
      end
      

      In this code, you added an add_note field to the mutation type file and attached it to the Mutations::AddNote class using the mutation: keyword. When the add_note mutation is called, it runs the code in the resolve method of the Mutations::AddNote class.

      To test your new mutation, navigate to localhost:3000/graphiql or http://your_server_ip:3000/graphiql in your browser to open your GraphiQL IDE. In the left side of the editor, type in the following query:

      mutation {
        addNote(input: { params: { title: "GraphQL notes", body: "A long body of text about GraphQL"  }}) {
          note {
            id
            title
            body
          }
        }
      }
      

      This declares a mutation operation with an addNote field that accepts a single input argument, which in turn accepts a param object with keys that match the NoteInputType. The mutation operation also includes a note field that matches the note field returned by the Mutations::AddNote class.

      Run the mutation in GraphiQL and you’ll see the following results in the output pane:

      {
        "data": {
          "addNote": {
            "note": {
              "id": "6",
              "title": "GraphQL notes",
              "body": "A long body of text about GraphQL"
            }
          }
        }
      }
      

      The response returned is the newly created note with the fields requested in the mutation request.

      With your add_note mutation now working, your API can fetch and create notes using GraphQL queries and mutations.

      Conclusion

      In this tutorial, you created a note-taking API application with Ruby on Rails using PostgreSQL as your database and GraphQL as your API query language. You can learn more about GraphQL on its official website. The GraphQL-Ruby gem website also contains some guides to help you work with GraphQL in Rails.



      Source link