Rakkit : create your GraphQL and REST APIs with TypeScript and decorators!
Tags: typescript, javascript, graphql, webdev
Published: 2019-06-25 19:46:32

**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](https://graphql.org/learn/) or REST) used and operating on a principle similar to [strapi.io](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:
- [GraphQL API](https://rakkit.dev/graphql/start/introduction.html)
- [REST API](https://rakkit.dev/rest/router.html)
- [Routing (middlewares for GraphQL and REST)](https://rakkit.dev/rest/middlewares.html)
- [Websocket application](https://rakkit.dev/ws/introduction.html)
- [Dependency Injection](https://rakkit.dev/di/introduction.html)

# 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:
- **GraphQL API:** [graphql](https://www.npmjs.com/package/graphql), [graphql-subscription](https://www.npmjs.com/package/graphql-subscriptions)
- **REST API:** [koa](https://koajs.com/), [koa-router](https://www.npmjs.com/package/koa-router), [koa-compose](https://www.npmjs.com/package/koa-compose)
- **Websocket application:** [socket.io](socket.io)   

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](typeorm.io) !

# Where? 📍
Then the project is accessible on GitHub [here](https://github.com/raccoonch/rakkit), the documentation is [there](https://rakkit.dev), and you can of course install it on [npm](https://www.npmjs.com/package/rakkit).
If you have any concerns we are all available to help you, just post an [issue](https://github.com/RaccoonCH/Rakkit/issues).
(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](koajs.com).
```typescript
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;
  }
}
```

## Websockets 🔁
That's pretty simple, there is only two decorators !
```typescript
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);
  }
}
```

## 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](https://rakkit.dev) for more informations.

```typescript
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;
}
```
You can define your queries/mutation/subscriptions like this:
```typescript
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
  }
}

```
It compiles it as a GraphQL Schema (You can use it in with your favorite server implementation like [Apollo](https://www.apollographql.com/) or [graphql-yoga](https://github.com/prisma/graphql-yoga)). In SDL, it looks like that:
```graphql
"""Object representing an user"""
type UserObjectType {
  id: String!
  email: String!
  username: String!
  activated: Bollean!
}

type Query {
  users: [UserObjectType]
  user(id: String!): UserObjectType
}
```

## Dependency Injection 🤯
This notion may seem abstract if you have never heard of it, it is particularly present with [Angular](https://angular.io/guide/dependency-injection), so I advise you to go and find out beforehand in order to be able to understand (more infos [here](https://rakkit.dev/di/introduction.html)).
```typescript
import { Service, Inject } from "rakkit";

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

@Service()
export class UserService {
  @Inject()
  private cronService: CronService;
  
  constructor() {
    this.cronService.start();
    // ...
  }
}
```

## More advanced examples are available [here](https://github.com/RaccoonCH/Rakkit/tree/master/examples) and more will come in the near future! 😉

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