<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: santosh898</title>
    <description>The latest articles on DEV Community by santosh898 (@santosh898).</description>
    <link>https://dev.to/santosh898</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F257615%2Fa56d747f-5044-4a3d-8587-e498d1b88e95.png</url>
      <title>DEV Community: santosh898</title>
      <link>https://dev.to/santosh898</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/santosh898"/>
    <language>en</language>
    <item>
      <title>Fully typed API responses using GraphQL</title>
      <dc:creator>santosh898</dc:creator>
      <pubDate>Tue, 16 Mar 2021 17:23:58 +0000</pubDate>
      <link>https://dev.to/santosh898/typesafe-api-calls-using-graphql-2dmj</link>
      <guid>https://dev.to/santosh898/typesafe-api-calls-using-graphql-2dmj</guid>
      <description>&lt;p&gt;At my workplace, we were setting up the environment for a brand-new app and decided to go with typescript to get the most out of the static analysis it provides. We have a standard architecture, a REST API, and react/react-native frontend.&lt;/p&gt;

&lt;p&gt;Furthermore, we were able to make sure that the whole app is type-safe except for the part where we consume the API responses. I had to manually write the types for the API responses. The biggest problem with this approach is there is no way we can ensure the responses are type-safe because we are just "assuming" their types.&lt;/p&gt;

&lt;p&gt;Then I wondered what would happen if we have &lt;a href="https://graphql.org/" rel="noopener noreferrer"&gt;GraphQL&lt;/a&gt; in the picture and set out on a journey. If you don't know what GraphQL is, it's a Query language for your API, where you define what your API can provide as strictly typed schema and clients will consume a subset of it.&lt;/p&gt;

&lt;p&gt;I decided to build a POC using GraphQL with a complete type-safe frontend. You can access the full code(server and client) &lt;a href="https://github.com/santosh898/typesafe-graphql" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server-side
&lt;/h2&gt;

&lt;p&gt;I won't be dealing with the server-side aspect of this, and I won't go deep into GraphQL as well. The following is the schema of my API.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the server is written using node+typescript+apollo-sever&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Schema
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Book {
  id: Float!
  title: String!
  subtitle: String!
  author: String!
  published: String
  publisher: String
  pages: Int!
  description: String!
  website: String!
}

type Query {
  getBooks(limit: Int): [Book]
  getBookDetails(id: Float): Book
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above schema, &lt;code&gt;type Book&lt;/code&gt; is a resource, and &lt;code&gt;type Query&lt;/code&gt; is where we define what kind of queries are supported.&lt;code&gt;getBooks&lt;/code&gt; will respond with an array of &lt;code&gt;Books&lt;/code&gt; and &lt;code&gt;getBookDetails&lt;/code&gt; will respond with a &lt;code&gt;Book&lt;/code&gt; for the given &lt;code&gt;ID&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client-side
&lt;/h2&gt;

&lt;p&gt;So we have the following problems to crack.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connect front-end to GraphQL.&lt;/li&gt;
&lt;li&gt;Get Fully typed responses automatically.&lt;/li&gt;
&lt;li&gt;IntelliSense when writing the queries.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Connect the front-end to GraphQL
&lt;/h3&gt;

&lt;p&gt;I created a GraphQL powered react-app using &lt;a href="https://apolloapp.org/" rel="noopener noreferrer"&gt;Create Apollo app&lt;/a&gt; by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn create apollo-app client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It has out-of-the-box support for &lt;code&gt;.graphql&lt;/code&gt; files and the boilerplate code to connect to the backend.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;See client/src/index.tsx&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But later I found that the template is pretty old and upgraded &lt;code&gt;graphql&lt;/code&gt; and migrated from &lt;code&gt;react-apollo&lt;/code&gt; to &lt;code&gt;@apollo-client&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I used the create-apollo-app for generating the server codebase as well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can consume data by using the &lt;code&gt;useQuery&lt;/code&gt; hook from &lt;code&gt;@apollo/client&lt;/code&gt; like this.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;client/src/queries/getBooks.ts&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { gql } from "@apollo/client";

export const GET_BOOKS = gql`
query getBooks($limit: Int) {
  getBooks(limit: $limit) {
    id
    title
    subtitle
    author
  }
}
`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;client/src/ListBooks.tsx&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useQuery } from "@apollo/client";
import { GET_BOOKS } from './queries/getBooks.ts'

const ListBooks: React.FC&amp;lt;{}&amp;gt; = () =&amp;gt; {
 const { loading, error, data } = useQuery(GET_BOOKS,{
    variables: {
      limit: 5,
    },
  });
...render data
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works but the data isn't fully typed yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Get Strongly typed responses automatically
&lt;/h3&gt;

&lt;p&gt;To avoid writing the types for the responses manually we are going to use &lt;a href="https://graphql-code-generator.com/docs/getting-started/index" rel="noopener noreferrer"&gt;GraphQL Code Generator&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;graphql-codegen is a CLI tool that generates types automatically from the provided GraphQL Schema. They have a lot of plugins and options for generating the types for both frontend and backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;By using this we can have the server-side written GraphQL schema as a single source of truth for the whole application.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The setup is pretty straightforward. Refer to the &lt;a href="https://graphql-code-generator.com/docs/getting-started/installation" rel="noopener noreferrer"&gt;Installation page&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# install the cli as a dev-dependency
yarn add -D @graphql-codegen/cli

# Step by step walkthrough initialization
yarn graphql-codegen init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code adds relevant dev-dependencies based on our selection and creates a &lt;code&gt;codegen.yml&lt;/code&gt; file at the project root. My &lt;code&gt;codegen.yml&lt;/code&gt; file looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;overwrite: true
schema: "http://localhost:8080/graphql"
documents: "src/**/*.ts"
generates:
  src/queries/typedQueries.ts:
    plugins:
      - "typescript"
      - "typescript-operations"
      - "typescript-react-apollo"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'll walk you through the options.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;schema&lt;/strong&gt; - the URL for the schema. Can be a file, function, string as well. See the documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;documents&lt;/strong&gt; - where to search for the GraphQL queries and fragments. I asked it to search in the &lt;code&gt;.ts&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;generates&lt;/strong&gt; - the target file path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;plugins&lt;/strong&gt; - automatically added based on the options selected in the &lt;code&gt;init&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;typescript&lt;/strong&gt; - bare minimum plugin to generate types.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;typescript-operations&lt;/strong&gt; - to generate types for the &lt;a href="https://graphql.org/learn/queries/" rel="noopener noreferrer"&gt;GraphQL Operations&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;typescript-react-apollo&lt;/strong&gt; - to generate typed hooks for the queries written and other support for the &lt;a class="mentioned-user" href="https://dev.to/apollo"&gt;@apollo&lt;/a&gt;/client.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Now after running &lt;code&gt;yarn generate&lt;/code&gt; it'll generate the file &lt;code&gt;typedQueries.ts&lt;/code&gt;. And I updated my component to use the generated &lt;code&gt;hook&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";
import { useGetBooksQuery } from "./queries/typedQueries.ts";

const ListBooks: React.FC&amp;lt;{}&amp;gt; = () =&amp;gt; {
  const { loading, error, data } = useGetBooksQuery({
    variables: {
      limit: 5,
    },
  });
...render data
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What changed here? we are not importing the query anymore, the generated types will do that for us. and guess what? the &lt;code&gt;data&lt;/code&gt; is fully typed.🎊&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7zt0jwtli07ojpp6jg0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7zt0jwtli07ojpp6jg0.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of having to run &lt;code&gt;yarn generate&lt;/code&gt; every time we change a query, we can run the codegen-cli in watch mode as well.See &lt;a href="https://graphql-code-generator.com/docs/getting-started/development-workflow" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: If you are going to use node for the backend, codegen-cli will be helpful for generating types from Schema so that you don't need to define the types two times. Refer to server code in my codebase for reference.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  IntelliSense when writing the queries (in vscode)
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo" rel="noopener noreferrer"&gt;Apollo VS Code extension&lt;/a&gt; provides an all-in-one tooling experience for developing apps with Apollo.&lt;/p&gt;

&lt;p&gt;We will get the syntax highlighting by just installing the extension. But to have IntelliSense we have to add a config file to the project.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;client/apollo-config.js&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  client: {
    service: {
      name: "my-graphql-app",
      url: "http://localhost:8080/graphql",
    },
    excludes: ["**/src/queries/typedQueries.ts"],
  },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;after adding this config, the extension downloads the schema from the URL and provides the IntelliSense when you write the queries.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jhy8rknotismds6sdc7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jhy8rknotismds6sdc7.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One last thing! when I updated the schema, the extension didn't pick that up, so I had to run &lt;code&gt;reload schema&lt;/code&gt; manually. (&lt;code&gt;ctrl+shift+p&lt;/code&gt; to open command palette)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qpuoekgn4njmjo074oj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qpuoekgn4njmjo074oj.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I don't know if there's an option for this to happen automatically. I didn't go deep into the extension &lt;a href="https://www.apollographql.com/docs/devtools/editor-plugins/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That's it. Now I have a strong type system for API calls plus added benefits of GraphQL.&lt;/p&gt;

&lt;p&gt;This is my first ever post. If you are still here, thank you for having the patience to stay this long.&lt;/p&gt;

</description>
      <category>react</category>
      <category>graphql</category>
      <category>typescript</category>
      <category>vscode</category>
    </item>
  </channel>
</rss>
