Documentation

Agatee/CLI


If you have any questions that are beyond the scope of this documentation, Please feel free to email via niainaratsima@gmail.com.


Installation

Prerequisites

First assumed that you have installed :

  1. Node.js 8+ or higher and NPM 5+
  2. Typescript
  3. ts-node-dev

Install Agatee CLI

To install the Agatee CLI just hit the command :
npm install -g @agatee/cli
If permission error occured, you can try to run the command as sudo
sudo npm install -g @agatee/cli
Print the installed agatee version

            $> gat version
1.3.1-beta.0
          


Create your first Agatee App

  • New App using GraphQL API :

    gat create my-app -api graphql
  • New App using REST API :

    gat create my-app

Go to your App directory then serve it
cd my-app && gat serve
You can specify the port using --port option, default is 3000

Congratulation 🎉 your first Agatee App is now running !


GraphQL Component

Generate component

To generate component just hit
gat generate component hero
It will generate 3 files at app/components/hero directory :

  1. hero.graphql : to put GraphQL schema and field
  2. hero.resolver.ts : to put resolvers
  3. hero.service.ts : to put service
You can also add moongoose model file by adding --moongoose-model option when generating component (just assumed that you already add mongoose feature)

After generating the component you need to add the resolver to @GatGraphql resolvers array at app/graphql/index.ts

import { ApolloServer } from "apollo-server-express";
import { GatGraphql, FinalResolvers, FinalTypeDefs, FinalPermissions } from "@agatee/graphql";
import { makeExecutableSchema } from "@graphql-tools/schema";
import { applyMiddleware } from "graphql-middleware";
import { shield } from "graphql-shield";

import { Server } from "../server";
import { HeroResolver } from "../components/hero/hero.resolver";

@GatGraphql({
    resolvers: [HeroResolver]
})
export class GatGraphqlModule {
...

Let's add Query

Open the project with your favorite editor and let's add hero field in our app/components/hero/hero.graphql

type Hero {
    name: String
    power: Int
    id: Int
}

Then let's create sample data and getAll method in our service app/components/hero/hero.service.ts

import { Injectable } from '@agatee/core';

export interface IHero {
    name: string;
    power: number;
    id: number;
}
// Sample data
const heroes: IHero[] = [
    {
        name: 'Super Man',
        power: 10,
        id: 1
    },
    {
        name: 'Hulk',
        power: 9,
        id: 2
    }
]
@Injectable()
export class HeroService {

    // Get all heroes
    getAll(): IHero[] {
        return heroes;
    }
}

Now let's add Query resolver to get all heroes in our HeroResolver at app/components/hero/hero.resolver.ts

import { GatGqlResolver, Query } from "@agatee/graphql";

import { HeroService, IHero } from "./hero.service";

@GatGqlResolver({
    schema: "./hero.graphql",
})
export class HeroResolver {
    constructor(private service: HeroService) {}

    // Get all heroes resolver
    @Query('heroes: [Hero]')
    heroes(): IHero[] {
        return this.service.getAll();
    }
}

Here, we decorate the resolver method heroes by the Query decorator.
The parameter need by Query decorator is the GQL Query Field. The decorator will add this field to the final GQL type Query field

Now let's test our Query by opening localhost:3000/graphql

Adding Mutation

It's like adding Query but instead of Query decorator just use Mutation decorator from @agatee/graphql

Setup GQL context

you can config the GQL context at app/graphql/index.ts in setupApolloServer method

...
    setupApolloServer() {

        const schema = applyMiddleware(
            makeExecutableSchema({typeDefs: this.typeDefs, resolvers: this.resolvers}),
            shield(this.permissions)
        )
        this.appoloServer = new ApolloServer({
            typeDefs: this.typeDefs,
            resolvers: this.resolvers,
            schema,
            /// Here you can config the context
            context: ({req}) => {
                return {body: req.body, headers: req.headers, params: req.params};
            }
        });
....

Query Permission

To create Query with Permission, decorate the resolver method with Permission decorator.
The decorator need a rule as params.
For example let's create isAdmin rule and add it to heroes resolver at app/components/hero/hero.resolver.ts

import { GatGqlResolver, Permission, Query } from "@agatee/graphql";
import { rule } from "graphql-shield";

import { HeroService, IHero } from "./hero.service";

// Define isAdminRule
// Assumed that you've already setted up context in app/graphql/index.ts and add body field equal to req.body
const isAdmin = rule()((_, __, {body}) => {
    return body.variables.admin;
})

@GatGqlResolver({
    schema: "./hero.graphql",
})
export class HeroResolver {
    constructor(private service: HeroService) {}

    // Get all heroes resolver
    @Permission(isAdmin) // Permission for the this Query
    @Query('heroes: [Hero]')
    heroes(): IHero[] {
        return this.service.getAll();
    }
}


Rest Component

Generate component

To generate component just hit
gat generate component hero
It will generate 3 files at app/components/hero directory :

  1. hero.router.ts : to put routers
  2. hero.controller.ts : to put controllers
  3. hero.service.ts : to put service
You can also add moongoose model file by adding --moongoose-model option when generating component (just assumed that you already add mongoose feature)

After generating the component you need to add the router to @GatModule routes array at app/app.ts

...
import { HeroRouter } from "./components/hero/hero.router";
...
@GatModule({
    // IMport all component's router here to make them reachable
    routes: [HeroRouter],
    middlewares
})
export class AppModule {
    constructor(private server: Server) {}

    bootstrap() {
        this.server.start();
    }
}

Generate component with crud endpoint

Before adding component with crud endpoint assumed that you've already add mongoose feature
gat generate component super-hero --moongoose-model --endpoint crud
or
gat g c super-hero -mm -e crud
All CRUD endpoint will be generated for the new component.

If you need to omit an specifique endpoint just remove the char coresponding to it from crud
For example to omit delete endpoint, the command become :
gat g c super-hero -mm -e crud

Let's take a look to the app/components/super-hero/super-hero.router.ts file

import { Request, Response } from "express";
import { GatRouterModule, GET, POST, PUT, DELETE } from "@agatee/core";

import { SuperHeroController } from './super-hero.controller';

@GatRouterModule({
    path: "/api/super-hero",
})
export class SuperHeroRouter {
    constructor(private controller: SuperHeroController) {}

    // Create endpoint using POST method reachable from '/api/super-hero'
    @POST("/")
    create(req, res) {
    this.controller.create(req, res);
    }

    // Read endpoint using GET method reachable from '/api/super-hero'
    @GET("/")
    list(req, res) {
    this.controller.list(req, res);
    }
    @GET("/:id")
    read(req, res) {
    this.controller.read(req, res);
    }

    // Update endpoint using PUT method reachable from '/api/super-hero'
    @PUT("/:id")
    update(req, res) {
    this.controller.update(req, res);
    }

    // Delete endpoint using DELETE method reachable from '/api/super-hero'
    @DELETE("/:id")
    delete(req, res) {
    this.controller.delete(req, res);
    }
}

Add middlewares to a route

To add middlewares to a route method just decorate it with the Middlewares decorator from @agatee/core
The Middlewares decorator need an array of middlewares as params

For example let's add isAdmin middleware to the Create router of SuperHero component :
app/components/super-hero/super-hero.router.ts

...
import { GatRouterModule, GET, POST, PUT, DELETE, Middlewares } from "@agatee/core";

import { SuperHeroController } from './super-hero.controller';

const isAdmin = (req, res, next) => {
    if (req.body.isAdmin) {
        next();
    } else {
        res.status(403).send('Forbidden');
    }
}

@GatRouterModule({
    path: "/api/super-hero",
})
export class SuperHeroRouter {
    constructor(private controller: SuperHeroController) {}

    @Middlewares([isAdmin]) // MIddleware for create endpoint
    @POST("/")
    create(req, res) {
    this.controller.create(req, res);
    }

    @GET("/")
    list(req, res) {
    this.controller.list(req, res);
    }

Add Mongoose to your App

To add mongoose hit:
gat add mongoose ${options}
Options:

  • -db-uri : SRV string
  • -db-host : DB host (not need if using --db-uri)
  • -db-port : DB port (not need if using --db-uri)
  • -db : DB name (not need if using --db-uri)
  • -db-user : DB username (not need if using --db-uri)
  • -db-pass : DB password (not need if using --db-uri)
The DB config will be stored and can be changed in .env file.

Add Socket.io to your App

To add Socket.io hit:
gat add socket.io
The socket server port is add to .env (by default 3001)
Then you need to add the MainSocket to @GatModule imports array

...
import { MainSocket } from "./modules/socket/main.socket";
...

@GatModule({
    routes: [
        ...
    ],
    middlewares,
    imports: [
        MainSocket // IMPORT OF MAINSOCKET
    ]
})
export class AppModule {
    constructor(private server: Server) {
        this.setStaticFolders();
    }

    ...

Listen to event @On(eventName)

To listen an event just create a method to MainSocket at app/modules/socket/main.socket.ts
For example to listen event named 'event-test' :
import {Server, Socket} from 'socket.io';

// Add the On decorator
import { GatSocket, onConnection, On } from '@agatee/socket';

@GatSocket
export class MainSocket implements onConnection {
    public readonly io: Server;

    ...

    @On('event-test')
    test(socket: Socket, data: any) {
        console.log('Client with id ', socket.id, ' send a data ', data);
    }
}

Create a new Socket Instance

To generate new socket instance named chat for example, hit :
gat g socket-instance chat
Then like the MainSocket, you need to import ChatSocket to the @GatModule imports array

Add GraphQL

If you create an app using --api graphql option, the GraphQL has been already added

To add GraphQL hit :
gat add graphql