# Differences with TypeGraphQL

This framework is based on the same principle as TypeGraphQL, however it corrects and changes some operating modes which can sometimes be restrictive.

# API

The main change is that this module is split into two separate modules instead of one heavier one, which also provides you with a compositing API called graphql-composer.

# Field decorators

There are also additional decorators such as @ObjectField @InputField and @InterfaceField, which allow you to set up a field for a certain GraphQL type of the class.

# ArgsType

It does not have an ArgsType, as it does not exist in GraphQL. On the other hand, it is on the query argument declaration side that we will be able to use a whole input type to declare all the arguments with the @Args decorator (just like ArgsType):

@InputType()
class User {
  @Field()
  username: string;

  @Field()
  email: string;
}

@Resolver()
class Resolver {
  @Query()
  getUser(@Args() user: User): Boolean {
    // ...
  }
}

which gives in SDL:

input User {
  username: String
  email: String
}

type Query {
  getUser(username: String, email: String): Bool
}

# Nullable or Required

The definition of nullable and required types is very restrictive with TypeGraphQL, which has been set here using two functions: Nullable(type: Type) (N(type: Type)) and Required(type: Type) (R(type: Type)). Let's take the example of declaring an array with required internal content (by being explicit, you can of course specify whether your types are null or required by default):

@InputType()
class User {
  @Field(type => [Required(String)])
  // or shorter with @Field(type => [R(String)])
  username: string[];

  @Field(type => Nullable([Required(String)])
  // or shorter with @Field(type => N([R(String)]))
  email: string[];
}

It is not possible to do this with TypeGraphQL at the moment, because the nullable parameter is applied to the set of @Field.

# Subscriptions

The @Subscription decorator works in a different way, not being satisfied with imposing grahphql-subscriptions as a subscription manager (so the way subscriptions work is not very free for the developer) and not leaving the choice to the developer, I opted for a slightly different way.

Both choices are defensible, but I prefer to be free to manage my subscription mechanism via my application, and it doesn't add much complexity.

With graphql-composer-decorators

import { PubSub } from "graphql-subscriptions";

const pubsub = new PubSub();

@Resolver() class Resolver {
  Subscription({
    subscription: (args) => pubsub.asyncIterator("NOTIFICATION"),
  })
  mySubscription(): Boolean {
    // ...
  }

  @Query()
  trigger(): Boolean {
    pubsub.publish("NOTIFICATION");
    // ...
  }
}

With TypeGraphQL:

@Resolver()
class Resolver {
  Subscription({ topics: "NOTIFICATION" })
  mySubscription() {
    // ...
  }

  @Query()
  trigger(@PubSub() pubSub): Boolean {
    pubsub.publish("NOTIFICATION");
    // ...
  }
}

# The context

Arguments specific to the GraphQL context (info, source, root, etc...) are injected via decorators with TypeGraphQL (@Root, @Source, @Infos, ...) which can make the declaration of your methods pretty huge. Here we have opted to inject an object containing all this information after your arguments:

import { Context } from "graphql-composer";

@Resolver()
class Resolver {
  @Query()
  trigger(
    @Arg("username") username: string,
    context: Context, // Injected here (after all your arguments)   
  ): Boolean {
    // ...
  }
}