DEV Community

Cover image for Rakkit : create your GraphQL and REST APIs with TypeScript and decorators!
owen
owen

Posted on

Rakkit : create your GraphQL and REST APIs with TypeScript and decorators!

Wow, another new framework, really...? 😅

So, we can have a little history before 📜

After having developed many apis in pure JavaScript and was co-frontted to maintain them. I decided to review my ways of doing things for my future projects and it was a good thing because, in my company, we decided to create a headless CMS allowing a great freedom on the choice of APIs (GraphQL or REST) used and operating on a principle similar to strapi.io.
Several constraints arose for this project: We had to be able to be very reactive if we had a problem with our application (code), to be able to easily add functionality for our customers, to depend as little as possible on external modules and above all to have a relatively clean code and remain a maximum DRY.
So after some research and decisions we started to develop a framework that would be the basis of this CMS, this one allows us to create REST and GraphQL APIs (these two types of APIs can share the use of the same middleware) to create applications using websockets and also to do dependency injection.

Rakkit packages 📦

Rakkit allows you to create a backend with a lot of features, here is the list of them:

node_modules phobia 😫

We all know this famous file which can accumulate a lot of dependencies... We absolutely wanted to avoid this, even if it meant redeveloping dependencies ourselves. However, we need some modules to be able to make all this work! Here is Rakkit's recipe for each of the packages:

The advantage of having some dependencies is, if we take the example of koa, we can use modules made by the community for koa in order to use them in Rakkit!
You can use Rakkit in parallel with another dependency such as TypeORM !

Where? 📍

Then the project is accessible on GitHub here, the documentation is there, and you can of course install it on npm.
If you have any concerns we are all available to help you, just post an issue.
(a small star on GitHub motivates us to continue in this direction!).

Okay, but what does it look like? 🧐

So, it will eventually need some basics to understand the rest, so I advise you to check out TypeScript and possibly the decorators.
These are just very simple examples, not everything is shown...

REST API 🛣

The REST package uses koa internally, the way we handle data, the way we use middleware and the general behavior is the same as koa.

import { Router, Get, Post, IContext, NextFunction } from "rakkit";
// Middlewares that are used for REST and GraphQL
import { Auth, SayHello } from "./middlewares.ts";
import { users } from "./users.ts";

@Router("user")
@UseMiddleware(Auth)
export class UserRouter {
  @Get("/")
  getAll(context: IContext) {
    // To return a result, assign the context.body value
    // Please refer to koa documentation for more informations...
    context.body = users;
  }

  @Get("/:id")
  @UseMiddleware(SayHello)
  async getOne(context: IContext, next: NextFunction) {
    // Omit variables checks here, for clarity
    const { id } = context.params; // JS destructuring
    const foundUser = users.find((usr) => usr.id === id);
    context.body = foundUser;
    await next();
  }

  @Post("/")
  addUser(context: IContext) {
    // Use koa-bodyparser to parse the body into an object (Rakkit documentation)
    const user = context.request.body
    users.push(user);
    context.body = user;
  }
}
Enter fullscreen mode Exit fullscreen mode

Websockets 🔁

That's pretty simple, there is only two decorators !

import { Websocket, On, Socket } from "rakkit";

@Websocket()
export class UserWS {
  @On("connection")
  onConnection(socket: Socket) {
    // Please refer to the socket.io documentation
    socket.emit("welcome", "welcome !");
  }

  @On("message")
  onMessage(socket: Socket, message: string) {
    socket.server.emit("new:message", message);
  }
}
Enter fullscreen mode Exit fullscreen mode

GraphQL API 🔥

GraphQL is a huge package, This is just a very simple example to see what it looks like, so please refers to the Rakkit documentation for more informations.

import { ObjectType, Field } from "rakkit";

@ObjectType({ description: "Object representing an user" })
export class UserObjectType {
  @Field()
  id: string;

  @Field()
  email: string;

  @Field()
  username: string;

  @Field()
  activated: boolean;
}
Enter fullscreen mode Exit fullscreen mode

You can define your queries/mutation/subscriptions like this:

import { Resolver, Query, IContext, NextFunction } from "rakkit";
// Middlewares that are used for REST and GraphQL
import { Auth, SayHello } from "./middlewares.ts";
import { users } from "./users.ts";

@Resolver()
@UseMiddleware(Auth)
export class UserResolver {
  // Precise the type, TS cannot resolve the return type when it's an array (Please refer to Rakkit the documentation)
  @Query(returns => UserObjectType)
  users(): UserObjectType[] {
    return users;
  }

  @Query()
  @UseMiddleware(SayHello)
  async user(
    @Arg("id")
    id: string,
    context: IContext,
    next: NextFunction
  ): UserObjectType? {
    return users.find((usr) => usr.id === id);
    await next(); // Go the the middleware function
  }
}

Enter fullscreen mode Exit fullscreen mode

It compiles it as a GraphQL Schema (You can use it in with your favorite server implementation like Apollo or graphql-yoga). In SDL, it looks like that:

"""Object representing an user"""
type UserObjectType {
  id: String!
  email: String!
  username: String!
  activated: Bollean!
}

type Query {
  users: [UserObjectType]
  user(id: String!): UserObjectType
}
Enter fullscreen mode Exit fullscreen mode

Dependency Injection 🤯

This notion may seem abstract if you have never heard of it, it is particularly present with Angular, so I advise you to go and find out beforehand in order to be able to understand (more infos here).

import { Service, Inject } from "rakkit";

@Service()
export class CronService {
  start() {
    // ...
  }
}

@Service()
export class UserService {
  @Inject()
  private cronService: CronService;

  constructor() {
    this.cronService.start();
    // ...
  }
}
Enter fullscreen mode Exit fullscreen mode

More advanced examples are available here and more will come in the near future! 😉

Et voilà! Thank you for taking the time to read this article! 👋

Top comments (0)