DEV Community

Carlos Rufo
Carlos Rufo

Posted on

Type-Safe GraphQL Servers 🔎

This post exhibits the motivations & steps for adding Type-Safety into GraphQL Servers 🎆

TL;DR

👉 The Repo & The API & The Docs & The Everything👇

Why should I add type-safety to my codebase?

Types enable developers to use highly-productive development tools and practices like static checking and code refactoring when developing JavaScript projects.

Building large scale applications, a static type checker can help safeguard your program, as well as helping you to eliminate existing errors (typos, misspellings, etc). TypeScript and Flow are both fantastic ways to limit technical debt in your JavaScript codebases, because folks,

JavaScript is DIFFICULT 🔥

At the same time it might be the best programming language to start with, since it doesn’t require to install and configure, but it doesn’t mean that it’s really hard to master and definitively, error prone!

JavaScript being weakly typed (in addition to being dynamically typed) poses a lot of problems. Note that a language is either statically or dynamically typed, let’s compare the differences between them.

Static 💥 Dynamic Typed

Static
A language is statically typed if the type of a variable is known at compile-time. For some languages this means that you as programmer must specify what type each variable is (e.g.: Java, C, C++).

Dynamic
A language is dynamically typed if the type is associated with run-time values. This means that you as programmer can write a little quicker because you do not have to specify types every time (e.g.: JavaScript, Python, Perl)

Remember❗️

Static 👉 Compile-Time 👉 Java

Dynamic 👉 Run-Time 👉 JavaScript

Speaking of these languages, in order to clarify their similarities, I’ve gotta mention one of my favorite JavaScript quotes written at the hands of the author of You Don’t Know JS saga (which I 💯 recommend to read):

“JavaScript is as related to Java as Carnival is to Car.” — Kyle Simpson

Definitely, they do not look alike. Let’s put focus on the most popular dynamically typed language…

Your 😑when you’re trying for 1st time JS coming from statically typed languagesYour 😑when you’re trying for 1st time JS coming from statically typed languages

Note that a language can be dynamically typed but also strongly typed, thus producing a much better language. How we could do that in JavaScript?

Type-Safety in JavaScript

Let’s review the most known tools for adding static typing into our JS codebases!

TypeScript

Typed superset of JavaScript that compiles to plain JavaScript on any browser, any host & any OS.
Microsoft/TypeScript
*TypeScript is a superset of JavaScript that compiles to clean JavaScript output. - Microsoft/TypeScript*github.com

Pros & Cons
👌 Community & Tooling
👍 Sub-second response times
👎 Learning curve

Flow

Static type checker for your JavaScript code. It does a lot of work to make you more productive, making you code faster, smarter, more confidently, and to a bigger scale.
Facebook/Flow
*Adds static typing to JavaScript to improve developer productivity and code quality. - Facebook/Flow*github.com

Pros & Cons
👌 Out-of-the-box utility
👍 Zero config
👎 Slower and buggier

TypeScript vs Flow

No matter if you are using TypeScript or Flow be aware of *you’re not writing plain JavaScript. **TypeScript implements both a *type checker and a transpiler that emits plain JavaScript. Flow only does type checking and relies on *Babel* (or other tools) to remove type annotations.

If you’d like to know more about the differences regarding syntax and usability, I totally recommend to read this comparison!

In this post we will use **TypeScript** in our examples, it has better support for type generation that we’ll need later on.

GraphQL as API

GraphQL is well know for being a strongly-typed specification for building APIs, it comes with a lot of benefits and we should take advantage of them.

Whether you’re following a Schema-First *or Resolver-first approach, you’d love to end up having a **Single Source of Truth **with which develop an *End-to-end Type-Safe Application.

Avoiding manual static typing because it can get too time-consuming as well as hard to keep in sync through versions, we might want to auto-generate all our types based on that Single Source of Truth.

In this post we’ll use the** Schema-First** approach, thus the static types will be generated based on our *GraphQL Schema *instead of from our resolvers!

In order to remove friction between type definitions we might introduce automation. Here is where the GraphQL Types Generators come in!

GraphQL Types Generators

Let’s review the most known tools for auto generating types based on our GraphQL Schema.

GraphQL Code Generator

Tool that generates different types code outputs of your GraphQL Schema & Documents whether you are developing client, server or database.
GraphQL Code Generator *Generate code from your GraphQL schema with a single function call*
graphql-code-generator.com

Pros & Cons
👌 Client, Server & DB support
👍 Docs & Community
👎 Early stage of development

GraphQLGen

Generate & scaffold type-safe resolvers based on your GraphQL Schema in TypeScript, Flow & Reason.
GraphQLGen
*Programming in type-safe environments provides a lot of benefits and gives you confidence about your code*oss.prisma.io/graphqlgen/

Pros & Cons
👌 Defaults resolvers generation
👍 Integrable with Prisma
👎 Only Server support

GraphQL Code Generator vs GraphQLGen

Both are great for generating TypeScript & Flow types although GraphQLGen doesn’t provide you the ability to generate them for the Client. Instead, GraphQL Code Generator does, also it provides you a tons of plugins/configurations & the possibility to create your custom type generation templates. I found out this really useful in order to have a modular GraphQL Schema configured as you wish!

In this post we will use **GraphQL Code Generator **in our examples, it has better customization that we’ll need later on.

Ok, I know, too much theory…

… let’s set this up 🚀

Setup TypeScript

[TypeScript](https://typescriptlang.org) main featuresTypeScript main features

Install it

yarn add -D typescript

Install Run libraries

In order to execute TypeScript with Node, you have to add the following tools:

*TS-Node: TypeScript execution and REPL for Node.js, with source map support.
*Nodemon
: Monitor for any changes in your Node.js application restarting automatically the server.

yarn add -D ts-node nodemon

You might want to use other configuration, setup whatever fits better for your app!

Include @types

Add your high quality type definitions of the libraries that you’re currently using over your codebase, such as graphql, lodash, etc. If you’re 🤨 about this, check the *DefinitelyTyped docs*!

yarn add -D @types/graphql

Create TypeScript config

This way TypeScript will include all the .ts files in your directory (and sub directories) as a part of the compilation context. It will also select a few sane default compiler options, you could check them out here!

**// tsconfig.json
**{
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "esModuleInterop": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.spec.ts"]
}

Create Run config

Nodemon supports local configuration files located in the current working directory where you have to specify things like which path to watch & the command to execute after any reload, which is your server. Check the sample config!

**// nodemon.json
**{
  "watch": ["src"],
  "ext": "ts",
  "ignore": ["src/**/*.spec.ts", "src/types/**/*.d.ts"],
  "exec": "ts-node ./src/index.ts"
}

Add Run config

**// package.json
**{
  ...
  "scripts": {
    ...
    "start": "nodemon",
    ...
  }
  ...
}

Rename .js files 👉 .ts

Modify all your JavaScript filename extensions to .ts, it’ll allow you take advantage of the all TypeScript features

Test your app

Run your GraphQL Server, as JavaScript is 100% compatible with TypeScript (not the opposite, TS types are not allowed on JS compilers), it should work!

yarn start

Weeding out Errors

It’s not unexpected to get error messages after conversion. The important thing is to actually go one by one through these and decide how to deal with the errors. Often these will be legitimate bugs, but sometimes you’ll have to explain what you’re trying to do a little better to TypeScript. Don’t hesitate to check this migration guide for help to fix the possible errors!

Setup GraphQL Code Generator

[GraphQL Code Generator](https://graphql-code-generator.com) main featuresGraphQL Code Generator main features

Install it

yarn add -D graphql-code-generator

Install Plugins

We’ll setup the common, server & *resolvers TypeScript *plugins, you might want to use others, check the plugins available!

yarn add -D graphql-codegen-typescript-common graphql-codegen-typescript-server graphql-codegen-typescript-resolvers

Create Context type

If you wish to use a custom type for your GraphQL context *and you don’t want to specify it each time that you declare your resolvers, you can create it manually and add it to the run config* file (as we’ll do it in the next step):

**// types/context.d.ts
**export type MyContext = {
  db: any;
  find: any;
  limit: any;
  order: any;
  project: any;
  sort: any;
};

Create Run config

The CLI will automatically detect the defined config file and will generate code accordingly, you could check the available options here!

**// codegen.yml***
*schema: src/schema/**/*.ts
overwrite: true
watch: true
require:
  - ts-node/register
generates:
  ./src/types/types.d.ts:
    config:
      contextType: ./context#MyContext
    plugins:
      - typescript-common
      - typescript-server
      - typescript-resolvers

Add Run config

**// package.json
**{
  ...
  "scripts": {
    ...
    "generate": "gql-gen",
    ...
  }
  ...
}

Generate Types ⚙️

Everything is setup for getting our desired static types 😍, let’s make that happen!

yarn generate

Add Resolver Types!

Now, you just have to include your *TypeScript *generated static types into your *GraphQL Resolvers *as here

Adding TypeScript types into GraphQL Resolvers & 🔎the Resolvers Data TypesAdding TypeScript types into GraphQL Resolvers & 🔎the Resolvers Data Types

It’s not 😂, take a look to your types.d.ts generated!It’s not 😂, take a look to your types.d.ts generated!

Recapping

In order to add Type-Safety into your GraphQL Server using Schema-First approach you could:

⚫ Setup TypeScript
↳ Install TypeScript, run libraries & @types
↳ Create TypeScript config & run config
↳ Add run config
⚫️ Rename .js 👉.ts files
⚫️ Setup GraphQL Code Generator
↳ Install GraphQL Code Generator & plugins
↳ Create context type & run config
↳ Add run config
⚫️ Generate Types ⚙️
⚫️ Add Resolver Types!

👀 the benefits

Discover some of the use cases where you’d take advantage of using TypeScript *together with *GraphQL!

Evolve your schema

🔎 the arguments

Catch Misspellings

🔎 the context

Discover your data

The Future

In order to talk about what the new era holds 😬, you cannot miss the motivations for which GraphQL was created, Dan Schafer resumed them perfectly 👇

Schema💥Resolver First approach,
Types💥Classes/Decorator generators,
Readability💥Composability,

… 2019 aims to be busy for GraphQL 😅,
read the first impressions about its future,
it’s as exciting as overwhelming,
but really, don’t miss it, 💯 thread!

I’ll be following this post up 🔜 with the respective Type-Safe GraphQL Clients 🔎 post, stay tuned!

Please, consider🙏🏻ing, contribut♻️ing and shar💜ing it!

Oldest comments (0)