DEV Community

Cover image for GraphQL: Create your API using TypeScript and decorators with Rakkit
owen for daven

Posted on β€’ Edited on

15 7

GraphQL: Create your API using TypeScript and decorators with Rakkit

What?

Okay then, this is related to my previous article about Rakkit. So I'll advise you to go take a look around 😊.

So, here I will show you a more concrete example of what you can do using Rakkit to create a GraphQL API with a user management system.

But first: the installation of Rakkit πŸ’Ύ

So there are few dependencies that we must install to continue:

Here, I would use apollo-server but it's also possible to install apollo-server-koa if you use Rakkit for REST and GraphQL which allows you to link contexts.

Just run this command to install the required dependencies:

npm i rakkit graphql @types/graphql apollo-server reflect-metadata
Enter fullscreen mode Exit fullscreen mode

reflect-metadata allows us to use the decorators with TypeScript

Okay cool, now we just need to configure TypeScript to enable the decorators by creating a tsconfig.json file at the root of the project, containing this:

{
  "compileOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "module": "commonjs",
    "target": "es2016",
    "noImplicitAny": false,
    "sourceMap": true,
    "outDir": "build",
    "declaration": true,
    "importHelpers": true,
    "forceConsistentCasingInFileNames": true,
    "lib": [
      "es2016",
      "esnext.asyncitable"
    ],
    "moduleResolution": "node"
  }
}
Enter fullscreen mode Exit fullscreen mode

./tsconfig.json

The definitions of types 🚻

Okay then let's start by creating our User class, which we'll have to decorate with @ObjectType():

import { ObjectType, Field } from "rakkit";
import * as Crypto from "crypto";

@ObjectType()
export class User {
  @Field()
  username: string;

  @Field()
  email: string;

  @Field()
  id: string;

  // Just to show a computed property:
  @Field(type => String)
  get flatInfos(): string {
    return [this.name, this.email, this.id].join(":");
  }

  constructor(username: string, email: string) {
    this.username = username;
    this.email = email;
    this.id = Crypto.randomBytes(16).toString("hex");
  }
}
Enter fullscreen mode Exit fullscreen mode

./types/User.ts

You need a small "database" πŸ—‚

So we're going to have to play with some users in order to test our app, so I'm just going to create a list of user instances to make it clearer:

You can use a real database with an ORM like TypeORM for your projects

import { User } from "../types/User";

export const users = [
  new User("JohnDoe", "john@doe.com"),
  new User("JaneDoe", "jane@doe.com"),
  new User("Ben", "ben@doe.com")
];
Enter fullscreen mode Exit fullscreen mode

./db/users.ts

Resolver (Query, Mutation, Subscription) πŸš€

It is in the following class that we will define our query/mutation/subscription. It will contain a simple CRUD and a subscription to be notified when a user is registered:

import {
  Resolve,
  Query,
  Mutation,
  Subscription,
  IContext,
  Arg
} from "rakkit";
import { User } from "../types/User";
import { users } from "../db/users";

@Resolver()
export class UserResolver {
  @Query(returns => [User])
  getAllUsers() { {
    return users;
  }

  @Query({ nullable: true })
  getOneUserByName(@Arg("name") name: string): User {
    return users.find((user) => user.name ==== name);
  }

  @Mutation()
  addUser(
    // Defining the mutation arguments
    @Arg("name") name: string,
    @Arg("email") email: string,
    context: IContext
  ): User {
    const user = new User(name, email);
    users.push(user);
    // Publish the event for subscriptions with the created user
    context.gql.pubSub.publish("USER_ADDED", user);
    return user;
  }

  @Subscription({ topics: "USER_ADDED" })
  userAddedNotif(createdUser: User): User {
    // Send the created user to the client
    return createdUser;
  }
}
Enter fullscreen mode Exit fullscreen mode

./resolvers/UserResolver.ts

The point of entry πŸšͺ

Now we need to have an entry point for our application:

// It allows us to use decorators:
import "reflect-metadata";

import { Rakkit } from "rakkit";
import { ApolloServer } from "apollo-server";

async function bootstrap() {
  await Rakkit.start({
    gql: {
      // You give an array of glob string:
      resolvers: [`${__dirname}/resolvers/*Resolver.ts`]
    }
  });
  // Retrieve the GraphQL compiled schema:
  const schema = Rakkit.MetadataStorage.Gql.Schema;

  const server = new ApolloServer({
    schema
  });

  server.listen();
}

bootstrap();
Enter fullscreen mode Exit fullscreen mode

./bootstrap.ts

Done, so let's start and test it ! πŸŽ‰

To start it you must install ts-node globally to run directly your TypeScript app:

npm i -g ts-node
Enter fullscreen mode Exit fullscreen mode

Then just run this:

ts-node relative-path-to/bootstrap.ts
Enter fullscreen mode Exit fullscreen mode

And just go to http://localhost:4000 with your favorite browser to make some GraphQL queries! πŸ”₯

getAllUsers - Get all users:

getOneUserByName - Get a specific user by name:

addUser - Add an user:

userAddedNotif - Listen to the user creation event:

Et voilà! This example is available on GitHub 😊, thanks!

Top comments (3)

Collapse
 
marcus-sa profile image
Marcus S. Abildskov β€’ β€’ Edited

Oh wow, this looks just like an exact copy of @nestjs/graphql just without the big community to back it up.. lol

Collapse
 
owen profile image
owen β€’

Yes the GraphQL package looks like type-graphql (used by nest) but there is several differences that are mentioned in the docs πŸ™‚
For the community, every projects start from zero, we are building it πŸ˜‰

Collapse
 
marcus-sa profile image
Marcus S. Abildskov β€’ β€’ Edited

Well, IMO reinventing the wheel is never good :)
And especially in this case it makes absolutely no sense at all.
What would you rather use? A new framework which reinvents everything (not even better), or a battle production tested framework with several community backed packages?

The best way to debug slow web pages cover image

The best way to debug slow web pages

Tools like Page Speed Insights and Google Lighthouse are great for providing advice for front end performance issues. But what these tools can’t do, is evaluate performance across your entire stack of distributed services and applications.

Watch video

πŸ‘‹ Kindness is contagious

Please leave a ❀️ or a friendly comment on this post if you found it helpful!

Okay