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 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 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 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 Types
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
Evolve your schema without worrying about changes, be a rebel 🤘, pull all your new commits! The generated #TypeScript types based on your #GraphQL type definitions & resolvers will 🔎 all possible errors for you!16:23 PM - 01 Jan 2019
🔎 the arguments
Don't waste your ⏳ looking into your self-documented API, don't leave the IDE 🙌, don't leave @vscode. Explore all your #GraphQL arguments with the generated #TypeScript resolvers types!16:23 PM - 01 Jan 2019
Catch Misspellings
"I just spent like 30 minutes trying to figure out why something I was writing went to the catch statement and it turns out I wrote `.toLowerCase()` wrong 🤦♀️" by @NikkitaFTW
Even great devs do misspellings, avoid them using #TypeScript into your #GraphQL resolvers 🚀16:23 PM - 01 Jan 2019
🔎 the context
If you didn't know it, DRY ♻️, use context! for having access to your needed functions inside of your #GraphQL resolvers. The generated #TypeScript types will help you to know which ones are available as well as their respective types ✨16:23 PM - 01 Jan 2019
Discover your data
Not sure 🤨 about your resolvers returned data? Destructure it, mock it, change it 😲, you'll be able to do so thanks to the generated #TypeScript types based on your #GraphQL schema 😍16:23 PM - 01 Jan 2019
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!
🔮 GraphQL prediction for 2019: Resolver-first server frameworks will begin to replace the currently popular schema-first approach.
Main reasons:
◆ No code redundancy (i.e. single definition of resolvers and types)
◆ Better code reuse & type-safety
◆ Superior DX09:49 AM - 02 Jan 2019
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!
Top comments (0)