Why You Should Be Using TypeScript + GraphQL

Learning Outcomes from Using this Powerful Combination.

Sean Dearnaley
Level Up Coding

--

Introduction

Today I’m going to be writing about TypeScript and GraphQL. I will give a quick introduction to the technologies and then jump straight into learning outcomes.

I’ve been working with this stack for almost 2 years now. I started with GraphQL first and that inspired me to dig into TypeScript. There is still loads to learn, the technology is evolving, interest is growing rapidly especially in the enterprise space, and new applications are released every day.

GraphQL + TypeScript

What is GraphQL?

There are many introductory GraphQL articles out there. If you ask 10 different people what GraphQL is, you will get 10 different answers. I won’t spend too much time explaining it in this article. I recommend reading a few different opinions and then getting your hands dirty with some GraphQL code.

GraphQL (Graph Query Language) is a language that describes what you have, what you want, and provides an algorithm to resolve those requests.

The server provides a definition of the entire available data and the associated types for that data. The data is presented as an object where we know the name of all the keys and the type of the associated values. This means your backend is fully documented, and we can easily inspect it using tools.

There is a single endpoint to make requests to a GraphQL server. The client sends the keys for the data that it needs, and the server responds with the resulting key-value pairs as a JSON object. Simply, the client asks for what it wants.

It’s been called a replacement for REST (representational state transfer), but it extends beyond that specification conceptually.

There are substantial benefits on the server-side. You can define your API schema using SDL (Schema Definition Language), then you get automatic introspection and self-documentation. There are resolvers which are functions for mapping the data to the requests, and field resolvers act recursively. If a field produces a scalar value like a string or number, resolver execution completes. However, if a field produces an object value then the query will contain another selection of fields that apply to that object.

What is TypeScript?

TypeScript is a programming language and set of tools for application development. It was created by Microsoft, released 7 years ago, and interest has been growing ever since.

JavaScript has always been criticized for lacking type safety for variables, but that has changed with TypeScript by providing a (strict) super-set of ECMAScript features. It transpiles to JavaScript, so it includes all the standard features and adds new things like type annotations and object-orientated concepts like classes and interfaces. It also supports new future JavaScript features like async functions and decorators.

TypeScript offers compile-time checking and strong static typing. This allows IDE tools like VS Code to be “smarter”, offering inline code completion and error checking.

I thought I understood API development, but GraphQL and TypeScript have made me a better API developer.

Learning Outcomes

Here are some of the outcomes you can expect from learning TypeScript and GraphQL. I’ve tried to emphasize concepts that I consider beyond REST and traditional JavaScript.

Develop a strong understanding of APIs

I’ve been developing APIs (Application Programming Interfaces) since before REST. I’ve seen a few different approaches come and go, there were other specifications like SOAP (XML), CORBA, and Hateoas. I’ve worked on hundreds of REST endpoints. I thought I understood API development, but GraphQL and TypeScript have made me a better API developer.

GraphQL API’s are intrinsically introspective. You can get a fully-typed schema of all the data available, making it self-documenting. This allows you to develop strong intuition about APIs, and enhance your consciousness of data types, entities, and abstractions.

You aren’t overloading endpoints, you’re not over-fetching or under-fetching. You’re not jumping around different tech stacks, subscriptions are in the same shape as queries (based on JSON), mutations are also the same shape except by denoting it a ‘mutation’ you’re explicitly stating the query can have side effects. It is more readable by humans and machines.

REST lacked proper standards so no industry standardization gained favor, there were too many flavors, too many signatures and documentation went out of date quickly. With GraphQL you learn best practices from industry veterans who are committed to adopting a standard approach and rolling that out across the industry, standards allow common tooling because systems share a common interface.

There are tools like Swagger for REST that provide similar API introspection, but with GraphQL that process is automatic. The tool Swagger-to-GraphQL converts your existing Swagger schema to an executable GraphQL schema.

These tools combined give you the ability to construct powerful and practical programming interfaces that can be used by all GraphQL consumers.

TypeScript extends this concept by following through with type checks from the GraphQL API boundaries. It’s much harder to misuse an endpoint when it is fully typed. It encourages you to make better abstractions for your data and design your UI properly to accommodate that data.

Develop an understanding of type safety, and how that conveys a programmer’s true intentions

Type annotations give you a stronger sense of a programmer’s intentions. The opportunity to have end-to-end typing should be a huge motivating factor for anyone considering TypeScript+GraphQL.

In a modern web development stack, the power of typing can be experienced at multiple levels. Types allow your IDE to be smarter, suggesting the correct types as you develop. It can enhance your developer experience tremendously.

If you’re using a modern IDE like VS Code, TypeScript has strong guidelines and typed guard rails as you develop. Type errors are a huge source of bugs in JavaScript, and typing properly tends to improve your code quality.

It’s far better to identify a bug during development than to have a client discover it in production.

TypeScript at the language level combined with GraphQL at the API boundaries offers a high level of code introspection and safety. Type definitions make you a better developer.

Code generation offers the cherry on the cake. There are different packages available but most offer type generation for your client, which means you can get type definitions generated from your GraphQL API for your client code.

Since you are creating a typed data graph, you can generate TypeScript types for free.

You can even generate things like React components and GraphQL client hooks!

TypeScript enhances productivity and reduces insanity, it increases in value over time.

Analyze your code base with an integrated development environment (code completion, IntelliSense)

Intrinsic API introspection is significant because you’re effectively getting [some] documentation and run-time type checking for free. It’s far harder to make a mistake. Often you can autocomplete with just a ctrl-space key sequence, and things like field deprecations are presented in real-time. Most servers provide integrated API explorers like GraphQL Playground or GraphiQL.

VS Code features IntelliSense, it is a code-completion aid. It helps you learn more about the code you’re using. It keeps track of parameters as you’re typing, and add calls to properties and methods with only a few keystrokes. IntelliSense gets smarter with updates and is more intelligent when you provide good type definitions. There are tools for GraphQL that can automatically generate type definitions.

Generate code automatically

You should use a code generator to auto-generate your types from your GraphQL API, but you can also generate other things like hooks for React and Apollo. You can even write your own plugins to generate your own code, don’t forget you have access to static type definitions and schema introspection.

There are different generators to try: I recommend GraphQL Code Generator, but there is also TypeGraphQL, and Apollo tools provides Apollo code-gen.

Imagine the future of code generation. It’s not hard to envision integrated components generated as templates, but what about entire client applications! With machine learning, this seems highly probable.

Identify bugs earlier with compile-time safety and static typing

If you change something, you’ll immediately see errors and warnings, Anything that is broken will be highlighted. You get contract validation across features, this produces extremely clean code because basic errors are much harder to make and breaking changes are immediately apparent.

Validate and comply with contracts across features/teams

Consider how code generation can create type definitions from a GraphQL API and how GraphQL facilitates bringing together different data sources into a single data graph. Micro-services are easier to manage.

Several frameworks have working implementations of “schema stitching” also known as “federation” (Apollo) or “remote schema” (Hasura). There is still some work to be done on things like scaling and subscriptions, but these tools effectively bring multiple graphs from different silos into a single concise data graph.

With TypeScript type definitions and GraphQL APIs, it’s possible to have end-to-end contract validation across features. This is very powerful, if a team breaks an integration the error be detected at compile-time and your continuous integration environment (CI) can be configured to do compile-time checks across the remote schema.

This is an exciting concept because you can imagine how this could evolve across the entire web. Consider ES modules developed by different groups.

Access new features before they are available to JavaScript

TypeScript supports everything in ECMAScript 2015 and adds an additional set of features:

In addition to these special TypeScript features, there are also future ECMAScript features that would only normally be available if you used something like Babel plugins. TypeScript includes popular ES next features like:

Don’t forget TypeScript compiles down to regular ECMAScript so these features should work with today's JavaScript containers (browser, Node.js etc).

Understand the impact of code changes

Schema change validation can be implemented as part of your build process. Apollo Graph Manager can even validate server schema changes against clients. There is a GitHub integration where you can monitor client requests, if there are clients requesting a deprecated field on the data graph, you can trace them, or remove them when they’re no longer in use.

TypeScript can measure impact almost immediately, it won’t even transpile if there are errors. If your regular CI workflow just runs test or build, TypeScript will do a compile-time check. If you are running code-gen against your API’s this will flag a problem even it’s on the other side of the organization.

Apply principled decisions to standardized application development

It’s subjective, but having an opinion is generally a good thing. It’s a mistake to approach GraphQL with first principles. You should follow best practices wherever possible and actively seek out opinions and opinionated software. Jump on an existing open-source implementation if you need to extend it.

Principled GraphQL, written by Geoff Schmidt and Matt DeBergalis of the Apollo team is a guide inspired by The Twelve-Factor App (another great best practices guide you should read). It’s a really good starting point for understanding how to approach your GraphQL application with experience from the field.

The cool thing about opinionated software is that you don’t have to waste your time formulating your own opinion and arguing about it with your colleagues, often solutions for your problem have already been considered.

Prettier is one of my favorite open-source projects, it’s a fantastic example of opinionated software, it aims to stop all on-going debates about code formatting by accepting a common style guide.

Develop applications with common tooling

GraphQL + TypeScript offers introspection of your entire code base, a GraphQL introspection schema can be used to drive many applications.

There are entire frameworks that are built around GraphQL introspection. Consider tools like Apollo Client, it builds a comprehensive normalized data cache in the browser which can be queried directly or incorporated into a local link state for local state management.

There are GraphQL API explorers like GraphQL Playground or GraphiQL. There are graph visualizers like GraphQL Voyager, design tools like GraphQL Editor, headless content management tools like GraphCMS. New tools are being released daily.

It’s far better to identify a bug during development than to have a client discover it in production.

Gain the ability to evolve an API without versioning

Over-fetching is when more data is fetched than required. It’s common with REST endpoints to serve up everything and allow the client to cherry-pick that. Whereas under-fetching is the opposite, when not enough data is delivered upon fetching, then the client has to fetch more data from somewhere else.

Let’s say you have to add a new field or rename an old one, if you want to make more optimized endpoints or change an endpoint, with REST it would be normal to employ versioned endpoints /v1/ /v2/ etc. You could have mobile apps or other clients that haven’t been updated and you can’t update their code.

GraphQL makes it easy to evolve an API without having to resort to endpoint versioning, you can mark fields for deprecation.

TypeScript makes API updates cleaner, you can see errors at compile-time and interfaces define the expected shape of the objects you are working with.

Acquire knowledge about your information architecture and business decisions

“Single Source of Truth” is a term from information systems theory you hear a lot when discussing GraphQL. It’s a concept that an organization can apply as part of its information architecture to ensure that everyone in the organization uses the same data when making business decisions.

The data graph provided by GraphQL is a new layer in the modern application development stack. It’s useful across your whole organization, it can be used by managers as well as developers, it can be useful for domain modeling, and provide an accurate self-documented data representation for cross-team functionality.

GraphQL reduces friction and improves communication. It promotes a single data graph rather than having different data silos throughout your company. If you have data in many places, you have to synchronize and aggregate which leads to complexities that result in costly errors. It also makes it challenging to decide what/who is the authoritative source of data.

Understand different approaches to API development

From the Apollo GraphQL docs:

Because the schema sits directly between your application clients and your underlying data services, front-end and back-end teams should collaborate on its structure. When you develop your own data graph, practice schema-first development and agree on a schema before you begin implementing your API.

Schema-first is an approach where schema design is given the highest priority. It’s useful because it unblocks front-end and back-end teams. An API doesn’t have to be working before the front end team can start developing the client and vice versa. API data can be mocked if a schema is present.

Code-first (a.k.a. resolver-first) is another popular approach. This is where the schema is generated programmatically. There is some debate about the right approach, with different advocates on either side of the fence. It can be very confusing, and it’s one of those things where you welcome a strong opinion.

There are some special challenges choosing schema-first if you’re using TypeScript.

Building a GraphQL API in Node.js with TypeScript can be difficult because you have to create your schema types in SDL (Schema Definition Language) as well as data models for your ORM (i.e. classes in TypeORM) and then write resolvers for your queries/mutations/subscriptions. The problem here is that you’re forced to create your TypeScript interfaces before you can implement resolvers because otherwise, you get type errors, it’s not trivial to just stub out your methods.

There is also a rather serious problem with redundancy and management. Just adding a new field, you’ll find yourself updating many files, you have to modify the model, the schema, the resolvers, the type definitions, and your unit test interfaces before you can update your client interface. It’s difficult to manage and prone to error. If you could establish a single code-first source of truth, you could potentially eliminate this issue.

Conclusion

I’ve learned a lot from using TypeScript and GraphQL. One of the most remarkable things about my experience is that I’ve learned concepts that I can apply to any application development stack. A lot of what I’ve learned could easily apply to REST and regular JavaScript applications.

It’s given me an appreciation of data types and taught me to be careful about over-fetching and under-fetching. It’s given me good advice about how to approach API design. I’ve learned things about dependency injection and how that affects automated testing. I’ve learned the importance of introspection and self-documenting code.

I am a strong believer this stack will become far more popular, especially in the enterprise space. The downsides are (like always), having to learn a new thing. TypeScript adds a bit of code, and I remember how JavaScript developers would laugh at Java and C++ developers for their huge function signatures, access modifiers, etc. TypeScript is starting to look similar, which is understandable as the demand for scalable and maintainable web software grows. TypeScript enhances productivity and reduces insanity, it increases in value over time.

The future is exciting and in many ways, this is just the ground floor.

I highly recommend you learn TypeScript and GraphQL, especially if you’re working on production APIs. Good luck with your endeavors!

Resources

Apollo Client / Apollo Graph Manager /

Principled GraphQL / The Twelve-Factor App

GraphQL Playground / GraphiQL / GraphQL Voyager

GraphQL Editor / GraphCMS

GraphQL Code Generator / TypeGraphQL / Apollo code-gen.

Swagger / Swagger-to-GraphQL

--

--

I have worked on different applications for the music industry, government, education and agriculture.