Getting started with GraphQL and TypeScript

Getting started with GraphQL and TypeScript

In this tutorial, I’ll be showing you how to use TypeScript with GraphQL using TypeGraphQL.

TypeScript is a superset of JavaScript, and its adoption has skyrocketed in recent years, as many apps are now being rewritten in it. If you have ever created a GraphQL server with TypeScript, then you would know it’s not as straightforward as in the JavaScript counterpart.


Prerequisites

This tutorial assumes the following:

  • Node.js and NPM installed on your computer
  • Basic knowledge of GraphQL
  • Basic knowledge of TypeScript
  • TypeScript installed on your computer, which you can get from the official website
What’s TypeGraphQL?

TypeGraphQL is a framework building GraphQL APIs in Node.js. It makes use of TypeScript classes and decorators for defining GraphQL schema and types as well as resolvers. With TypeGraphQL, we don’t need to manually define types in SDL or create interfaces for our GraphQL schema. TypeGraphQL allows us to have only one source of truth, that way reducing field type mismatches, typos etc.

Another interesting thing about TypeGraphQL is how well it integrates with decorator-based libraries, like TypeORM, sequelize-typescript or Typegoose. This allows us to define both the GraphQL type and the entity in a single class, so we don’t need to edit multiple files to add or rename some properties.


Getting started

To get started with TypeGraphQL, we need to first install it along with its dependencies. We’ll start by creating a new project:

    $ mkdir graphql-typescript
    $ cd graphql-typescript
    $ npm init -y

Then we install TypeGraphQL:

    $ npm install type-graphql

Next, we need to install TypeScript as a dev-dependency as well as types for Node.js:

    $ npm install typescript @types/node --save-dev

TypeGraphQL requires the reflect-metadata shim, so we need to install that as well:

    $ npm install reflect-metadata

Next, we need to define some TypeScript configurations for our project. Create a tsconfig.json file within the project’s root directory, and paste the snippet below into it:

    // tsconfig.json

{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "lib": ["dom", "es2016", "esnext.asynciterable"],
    "moduleResolution": "node",
    "outDir": "./dist",
    "strict": true,
    "strictPropertyInitialization": false,
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true
  },
  "include": ["./src/**/*"]
}

If you have ever worked with TypeScript before (which this tutorial assumes), then you should be familiar with some of the settings above. Since TypeGraphQL makes extensive use of decorators, which are an experimental feature of TypeScript, we need to set both emitDecoratorMetadata and experimentalDecorators as true. Also, we need to add esnext.asynciterable to the list of library files, since graphql-subscription uses AsyncIterator.


Defining the GraphQL schema

We can start defining the schema for our GraphQL server. Create a new src directory, then within it, create a new schemas directory. Inside the schemas directory, create a Project.ts file and add the following code in it:

    // src/schemas/Project.ts

import { Field, Int, ObjectType } from "type-graphql";
import Task from "./Task";

@ObjectType()
export default class Project {
  @Field(type => Int)
  id: number;

  @Field()
  name: string;

  @Field(type => [Task])
  tasks: Task[];
}

We define a Project class and use the @ObjectType() decorator to define it as a GraphQL type. The Project type has three fields: id, name and tasks. We use the @Field decorator to define these fields. The @Field decorator can also accept optional arguments. We can pass to it the type the field should be or an object containing other options we want for the field. We explicitly set the type of the id field to be Int while tasks is an array of the type Task (which we’ll create shortly).

Next, let’s define the schema for the Task type. Inside the schemas directory, create a Task.ts file and add the following code in it:

    // src/schemas/Task.ts

import { Field, Int, ObjectType } from "type-graphql";
import Project from "./Project";

@ObjectType()
export default class Task {
  @Field(type => Int)
  id: number;

  @Field()
  title: string;

  @Field(type => Project)
  project: Project;

  @Field()
  completed: boolean;
}

This is pretty similar to the Project schema. With our schema defined, we can move on to creating the resolvers.


Adding sample data

Before we get to the resolvers, let’s quickly define some sample data we’ll be using to test out our GraphQL server. Create a data.ts file directly inside the src directory, and paste the snippet below into it:

    // src/data.ts

export interface ProjectData {
  id: number;
  name: string;
}

export interface TaskData {
  id: number;
  title: string;
  completed: boolean;
  project_id: number;
}

export const projects: ProjectData[] = [
  { id: 1, name: "Learn React Native" },
  { id: 2, name: "Workout" },
];

export const tasks: TaskData[] = [
  { id: 1, title: "Install Node", completed: true, project_id: 1 },
  { id: 2, title: "Install React Native CLI:", completed: false, project_id: 1},
  { id: 3, title: "Install Xcode", completed: false, project_id: 1 },
  { id: 4, title: "Morning Jog", completed: true, project_id: 2 },
  { id: 5, title: "Visit the gym", completed: false, project_id: 2 },
];

Creating the resolvers

Create a new resolvers directory inside the src directory. Inside the resolvers directory, create a ProjectResolver.ts file and paste the code below in it:

    // src/resolvers/ProjectResolver.ts

import { Arg, FieldResolver, Query, Resolver, Root } from "type-graphql";
import { projects, tasks, ProjectData } from "../data";
import Project from "../schemas/Project";

@Resolver(of => Project)
export default class {
  @Query(returns => Project, { nullable: true })
  projectByName(@Arg("name") name: string): ProjectData | undefined {
    return projects.find(project => project.name === name);
  }

  @FieldResolver()
  tasks(@Root() projectData: ProjectData) {
    return tasks.filter(task => {
      return task.project_id === projectData.id;
    });
  }
}

We use the @Resolver() decorator to define the class as a resolver, then pass to the decorator that we want it to be of the Project type. Then we create our first query, which is projectByName, using the @Query() decorator. The @Query decorator accepts two arguments: the return type of the query and an object containing other options which we want for the query. In our case, we want the query to return a Project and it can return null as well. The projectByName query accepts a single argument (name of the project), which we can get using the @Arg decorator. Then we use find() on the projects array to find a project by its name and simply return it.

Since the Project type has a tasks field, which is a custom field, we need to tell GraphQL how to resolve the field. We can do that using the @FieldResolver() decorator. We are getting the object that contains the result returned from the root or parent field (which will be the project in this case) using the @Root() decorator.

In the same vein, let’s create the resolvers for the Task type. Inside the resolvers directory, create a TaskResolver.ts file and paste the code below in it:

    // src/resolvers/TaskResolver.ts

import { Arg, FieldResolver, Mutation, Query, Resolver, Root } from "type-graphql";
import { projects, tasks, TaskData } from "../data";
import Task from "../schemas/Task";

@Resolver(of => Task)
export default class {
  @Query(returns => [Task])
  fetchTasks(): TaskData[] {
    return tasks;
  }

  @Query(returns => Task, { nullable: true })
  getTask(@Arg("id") id: number): TaskData | undefined {
    return tasks.find(task => task.id === id);
  }

  @Mutation(returns => Task)
  markAsCompleted(@Arg("taskId") taskId: number): TaskData {
    const task = tasks.find(task => {
      return task.id === taskId;
    });
    if (!task) {
      throw new Error(`Couldn't find the task with id ${taskId}`);
    }
    if (task.completed === true) {
      throw new Error(`Task with id ${taskId} is already completed`);
    }
    task.completed = true;
    return task;
  }

  @FieldResolver()
  project(@Root() taskData: TaskData) {
    return projects.find(project => {
      return project.id === taskData.project_id;
    });
  }
}

We define two queries: fetchTasks and getTask. The fetchTasks simply returns an array of all the tasks that have been created. The getTask query is pretty similar to the projectByName query. Then we define a mutation for marking a task as completed, using the @Mutation. This mutation will also return a Task. Firstly, we get the task that matches the supplied taskId. If we can’t find a match, we simply throw an appropriate error. If the task has already been marked as completed, again, we throw an appropriate error. Otherwise, we set the task completed value to true and lastly return the task.

Just as we did with the Project type, we define how we want to resolve the project field.


Building the GraphQL server

With everything in place, all that is left now is to tie them together by building a GraphQL server. We will be using graphql-yoga for building our GraphQL server. First, let’s install it:

    $ npm install graphql-yoga

With that installed, create an index.ts file directly inside the src directory, and paste the code below in it:

    // src/index.ts

import { GraphQLServer } from "graphql-yoga";
import "reflect-metadata";
import { buildSchema } from "type-graphql";
import ProjectResolver from "./resolvers/ProjectResolver";
import TaskResolver from "./resolvers/TaskResolver";

async function bootstrap() {
  const schema = await buildSchema({
    resolvers: [ProjectResolver, TaskResolver],
    emitSchemaFile: true,
  });

  const server = new GraphQLServer({
    schema,
  });

  server.start(() => console.log("Server is running on http://localhost:4000"));
}

bootstrap();

Since we need to build our schema first before making use of it in our GraphQL server, we create an async function, which we call bootstrap() (you can name it however you like). Using the buildSchema() from type-graphql, we pass to it our resolvers and we set emitSchemaFile to true (more on this shortly). Once the schema has been built, we instantiate a new GraphQL server and pass to it the schema. Then we start the server. Lastly, we call bootstrap().

Sometimes, we might need to see or inspect the schema in SDL (Schema Definition Language) that TypeGraphQL will generate for us. One way we can achieve that is setting emitSchemaFile to true at the point of building the schema. This will generate a schema.gql file directly in project’s root directory. Of course, we can customize the path however we want.

Note: make sure to import reflect-metadata on top of your entry file (before you use/import type-graphql or your resolvers)
Testing it out

Before we start testing our GraphQL, we need to first compile our TypeScript files to JavaScript. For that, we’ll be using the TypeScript compiler. Running the command below directly from the project’s root directory:

    $ tsc

The compiled JavaScript files will be inside the dist directory, as specified in tsconfig.json. Now we can start the GraphQL server:

    $ node ./dist/index.js

The server should be running on http://localhost:4000, and we can test it out with the following query:

    # fetch all tasks

{
  fetchTasks {
    title
    project {
      name
    }
  }
}


Conclusion

In this tutorial, we looked at what is TypeGraphQL and it makes it easy to work with GraphQL and TypeScript. To learn more about TypeGraphQL and other advanced features it provides, do check out their official website as well as the GitHub repo.

The complete code for this tutorial is available on GitHub.


Learn More

Secure Node.js, Express.js and PostgreSQL API using Passport.js

MEAN Stack Tutorial MongoDB, ExpressJS, AngularJS and NodeJS

Full Stack Developers: Everything You Need to Know

Machine Learning In Node.js With TensorFlow.js

Build a Simple Web App with Express, Angular, and GraphQL

Build a Basic App with Spring Boot and JPA using PostgreSQL

The Complete Python & PostgreSQL Developer Course

SQL & Database Design A-Z™: Learn MS SQL Server + PostgreSQL

The Complete SQL Bootcamp

Originally published by Chimezie Enyinnaya at https://pusher.com

Introduction Boolean in JavaScript and TypeScript

Introduction Boolean in JavaScript and TypeScript

Boolean values are supported by both JavaScript and TypeScript and stored as true/false values .This is because, while JavaScript coerces an object to its primitive type, the TypeScript type system does not. TypeScript treats it like an object type.

Boolean in JavaScript

boolean can take the values of true and false. Values from other types can be truthy or falsy, like undefined or null.

let b = true
if(b) console.log('logged')

b = false
if(b) console.log('not logged')

b = undefined
if(b) console.log('not logged')

b = null
if(b) console.log('not logged')

Values other than undefined, null or false considered falsy are "" (empty string), -0 and 0, as well as NaN.

To get the boolean value of any value, you can use the Boolean function:

Boolean(false) // false
Boolean(true) // true
Boolean("false") // true ❗️
Boolean("Hey folks") // true
Boolean({}) // true
Boolean([]) // true
Boolean(123.4) // true
Boolean(Symbol()) // true
Boolean(function() {}) // true
Boolean(undefined) // false
Boolean(null) // false
Boolean(NaN) // false
Boolean(0) // false
Boolean("") // false

Rule of thumb: All empty values evaluate to false. Empty object {} and empty array [] (which is an object itself) do have value as they are containers for other values.

The Boolean function is really good to filter empty values from collections:

const collection = [
  { name: 'Stefan Baumgartner', age: 37 },
  undefined,
  { name: 'D.', age: 36 },
  false
  { name: 'C.', age: 2},
  false
]

collection.filter(Boolean) // handy!

Together with Number – which converts all values into their number counterpart or NaN, this is a really cool way of getting to actual values quickly:

const x = ["1.23", 2137123, "wut", false, "lol", undefined, null]
  .map(Number)
  .filter(Boolean) // [1.23, 2137123] 👍

Boolean exists as a constructor and has the same conversion rules as the Boolean function. However, with new Boolean(...) you create a wrapping object, making value comparisions truthy, but reference comparisions falsy:

const value = Boolean("Stefan") // true
const reference = new Boolean("Stefan") // [Boolean: true]

value == reference // true
value === reference // false

You get to the value via .valueOf():

value === reference.valueOf() // true

I have a REPL for you to check. The use of Boolean as a function is obviously great, but new Boolean has very limited use. If you know a practical use case, please let me know.

Boolean in TypeScript

boolean in TypeScript is a primitive type. Be sure to use the lower case version and don’t refer to
object instances from Boolean

const boolLiteral: boolean = false // 👍
const boolObject: Boolean = false // 👎

It works, but it’s bad practice as we really rarely need new Boolean objects.

You can assign true, false and undefined and null to boolean in TypeScript without strict null checks.

const boolTrue: boolean = true // 👍
const boolFalse: boolean = false // 👍
const boolUndefined: boolean = undefined // 👍
const boolNull: boolean = null // 👍

With that, boolean is the only one we can express fully through union types:

type MyBoolean = true | false | null | undefined // same as boolean

const mybool: MyBoolean = true
const yourbool: boolean = false

When we enable the strictNullChecks compiler flag, the set of values reduces to true and false.

const boolTrue: boolean = true // 👍
const boolFalse: boolean = false // 👍
const boolUndefined: boolean = undefined // 💥
const boolNull: boolean = null // 💥

So our set reduces to two values in total.

type MyStrictBoolean = true | false

We can also get rid of null values with the NonNullable helper type:

type NonNullable<T> = T extends null | undefined
  ? never
  : T;

type MyStrictBoolean = NonNullable<MyBoolean> // true | false

The fact that boolean consists of a limited set of values only used in conditions, allows for interesting conditional types.

Think of an mutation in a datastore through a function. You set a flag in a function that updates e.g. the user id. You have to provide the user ID then:

type CheckUserId<Properties, AddUserId> = 
    AddUserId extends true 
    ? Properties & { userId: string }
    : Properties & { userId?: string }

Depending on the value of our generic AddUserId, we expect the property userId to be set or to be optional.

We can make this type more explicit by extending our generics from the types we expect

- type CheckUserId<Properties, AddUserId> = 
+ type CheckuserId<
+  Properties extends {},
+  AddUserId extends boolean
+ >
     AddUserId extends true 
     ? Properties & { userId: string }
     : Properties & { userId?: string }

In use, it might declare a function like this:

declare function mutate<P, A extends boolean = false>
  (props: CheckUserId<P, A>, addUserId?: A): void

Note that I even set a default value for A to make sure CheckUserId gives the correct info depending on addUserId to be set or not.

The function in action:

mutate({}) // 👍
mutate({ data: 'Hello folks' }) // 👍
mutate({ name: 'Stefan' }, false) // 👍
mutate({ name: 'Stefan' }, true) // 💥 userId is missing
mutate({ name: 'Stefan', userId: 'asdf' }, true) // 👍 userId is here

Handy if your code relies a lot on truthy and falsy values. As always, there’s playground for you.

Originally published at fettblog.eu on 10 September 2019

Understanding void in JavaScript and TypeScript

Understanding void in JavaScript and TypeScript

void exists in both JavaScript as an operator and in TypeScript as a primitive type. And in both worlds void works a little bit different than most people are used to.

If you come from traditional, strongly typed languages you might be familiar with the concept of void: A type telling you that functions and methods return nothing when called.

void in JavaScript

void in JavaScript is an operator which evaluates the expression next to it. No matter which expression is evaluated, void always returns undefined.

let i = void 2; // i === undefined

Why would we need something like this? First, in earlier times, people were able to override undefined and giving it an actual value. void always returned the real undefined.

Second, it’s a nice way to call immediately invoked functions:

void function() {
  console.log('What')
}()

All without polluting the global namespace:

void function aRecursion(i) {
  if(i > 0) {
    console.log(i--)
    aRecursion(i)
  }
}(3)

console.log(typeof aRecursion) // undefined

Since void always returns undefined, and void always evaluates the expression next to it, you have a very terse way of returning from a function without returning a value, but still calling a callback for example:

// returning something else than undefined would crash the app
function middleware(nextCallback) {
  if(conditionApplies()) {
    return void nextCallback();
  }
}

Which brings me to the most important use case of void: It’s a security gate for your app. When your function is always supposed to return undefined, you can make sure that this is always the case.

button.onclick = () => void doSomething();

void in TypeScript

void in TypeScript is a subtype of undefined. Functions in JavaScript always return something. Either it’s a value, or undefined

function iHaveNoReturnValue(i) {
  console.log(i)
} // returns undefined

Since functions without a return value always return undefined, and void always returns undefined in JavaScript, void in TypeScript is a proper type for telling developers that this function returns undefined:

declare function iHaveNoReturnValue(i: number): void

void as type can also be used for parameters and all other declarations. The only value that can be passed is undefined:

declare function iTakeNoParameters(x: void): void

iTakeNoParameters() // 👍
iTakeNoParameters(undefined) // 👍
iTakeNoParameters(void 2) // 👍

So void and undefined are pretty much the same. There’s one little difference though, and this difference is significant: void as a return type can be substituted with different types, to allow for advanced callback patterns:

function doSomething(callback: () => void) {
  let c = callback() // at this position, callback always returns undefined
  //c is also of type undefiend
}

// this function returns a number
function aNumberCallback(): number {
  return 2;
}

// works 👍 type safety is ensured in doSometing
doSomething(aNumberCallback) 

This is desired behaviour and often used in JavaScript applications. Read more on this pattern called substitutability in my other articles.

If you want to make sure to pass functions who only return undefined (as in “nothing”), be sure to adapt your callback method signature:

- function doSomething(callback: () => void) {
+ function doSomething(callback: () => undefined) { /* ... */ }

function aNumberCallback(): number { return 2; }

// 💥 types don't match
doSomething(aNumberCallback)

You’ll propably be good with void most of the time.

Originally published at fettblog.eu on 06 September 2019