gqlField
gqlField
annotates a property or method to indicate that it should be exposed as a GraphQL Field on the source object.
For example, to expose howLong
as a non-nullable integer on the User
object, we do the following:
export class User extends UserBase {
@gqlField({
class: 'User',
type: GraphQLInt,
})
howLong(): number {
return Interval.fromDateTimes(this.createdAt, new Date()).count('seconds')
}
}
which updates the GraphQL schema as follows:
type User implements Node {
id: ID!
firstName: String!
lastName: String!
emailAddress: String!
howLong: Int!
}
To expose fullName
as a string either as a property or a method, we can do the following:
export class User extends UserBase {
@gqlField({
class: 'User',
type: GraphQLString,
})
get fullName(): string {
return this.firstName + " " + this.lastName;
}
// OR
@gqlField({
class: 'User',
type: GraphQLString,
})
fullName(): string {
return this.firstName + " " + this.lastName;
}
}
which updates the GraphQL schema as follows:
type User implements Node {
id: ID!
firstName: String!
lastName: String!
emailAddress: String!
fullName: String!
}
gqlField supports a few options which we'll go into below.
class
Used to associate this field with the class the function/property is in since the TypeScript decorator API doesn't provide this information. It should be the name of the TypeScript class as opposed to the name of the GraphQL object if they're different.
args
Indicates arguments of the function which will be converted to GraphQL field arguments on the generated GraphQL field.
gqlFieldArg
A simplified definition of gqlFieldArg
's API is:
interface gqlFieldArg {
name: string;
nullable?: boolean | NullableListOptions;
description?: string;
type?: Type | Array<Type> | GraphQLConnection<Type>; // types or lists of types
}
nullable
, description
and type
are similar to the values passed to gqlField
and will be discussed later in this section.
An example usage is as follows:
class User {
@gqlField({
class: "User",
type: "[Contact]",
name: "contactsGivenDomain",
args: [
{
name: "domain",
type: GraphQLString,
},
],
async: true,
})
async getContactsGivenDomain(domain: string): Promise<Contact[]> {
return [];
}
}
gqlContextType
gqlContextType
annotates a method to indicate that it needs the RequestContext and the generated GraphQL code should pass it down to the method.
It's a pre-defined gqlFieldArg
because it'll be used so often in custom queries and mutations.
type
Indicates the GraphQL type of the field.
interface ClassType<T = any> {
new (...args: any[]): T;
}
export interface CustomType {
type: string;
importPath: string;
tsType?: string;
tsImportPath?: string;
}
export type GraphQLConnection<T> = { node: T };
declare type Type = GraphQLScalarType | ClassType | string | CustomType;
interface gqlFieldOptions {
type: Type | Array<Type> | GraphQLConnection<Type>; // types or lists of types or GraphQLConnectionType
}
Supported type formats:
GraphQLScalarType
GraphQLScalarType
refers to a GraphQL Scalar like GraphQLInt
, GraphQLFloat
, GraphQLBoolean
like seen above in howLong
.
ClassType
refers to objects such as Ents which are exposed to GraphQL.
For example, this contrived example:
class User {
@gqlField({ class: 'User', type: User, name: "self", async: true })
async loadSelf(): Promise<User> {
return new User();
}
}
updates the GraphQL schema as follows:
type User implements Node {
id: ID!
firstName: String!
lastName: String!
emailAddress: String!
self: User!
}
And the list version:
class User {
@gqlField({ class: 'User', type: [User], name: "selves", async: true })
async loadSelf(): Promise<User[]> {
return [new User()];
}
}
updates the GraphQL schema as follows:
type User implements Node {
id: ID!
firstName: String!
lastName: String!
emailAddress: String!
selves: [User!]!
}
string
refers to the names of objects such as Ents which are exposed to GraphQL. This is usually needed in weird cases where there's circular-ish references between classes and the object isn't in scope. We're not going to dive into the intricacies here but this provides a workaround in that scenario.
For example:
class User {
@gqlField({
class: 'User',
async: true,
type: "Contact",
nullable: true,
name: "contactSameDomain",
})
async getFirstContactSameDomain(): Promise<Contact | null> {
return null;
}
}
updates the GraphQL schema as follows:
type User implements Node {
id: ID!
firstName: String!
lastName: String!
emailAddress: String!
contactSameDomain: Contact
}
To provide the list version of this:
class User {
@gqlField({
class: 'User',
type: "[Contact]",
name: "contactsSameDomain",
async: true,
})
async getContactsSameDomain(): Promise<Contact[]> {
return [];
}
}
updates the GraphQL schema as follows:
type User implements Node {
id: ID!
firstName: String!
lastName: String!
emailAddress: String!
contactsSameDomain: [Contact!]!
}
CustomType
This allows the flexibility for custom types that are not the built-in GraphQL Scalar Types.
We'll dive into a specific example of this in gqlFileUpload.
name
Indicates the name of the GraphQL field. Should be used when we want a different name than the name of the function, method or property.
description
Indicates the description of the GraphQL field. Will be added to the Schema and exposed in tools like GraphiQL or Playground.
nullable
Indicates this field is nullable.
If true
and a list, means the list is nullable even if the contents of the list isn't:
class User {
@gqlField({
class: "User",
type: "[Contact]",
name: "contactsSameDomain",
nullable: true,
async: true
})
async getContactsSameDomain(): Promise<Contact[] | null> {
return [];
}
}
updates the GraphQL schema as follows:
type User implements Node {
id: ID!
firstName: String!
lastName: String!
emailAddress: String!
contactsSameDomain: [Contact!]
}
If not true
and a list, there are two other options:
contents
Indicates that the contents of the list is nullable.
class User {
@gqlField({
class: "User",
type: "[Contact]",
name: "contactsSameDomain",
nullable: "contents",
async: true
})
async getContactsSameDomain(): Promise<(Contact | null)[]> {
return [];
}
}
updates the GraphQL schema as follows:
type User implements Node {
id: ID!
firstName: String!
lastName: String!
emailAddress: String!
contactsSameDomain: [Contact]!
}
contentsAndList
Indicates that both the list and its contents are nullable.
class User {
@gqlField({
class: "User",
type: "[Contact]",
name: "contactsSameDomain",
nullable: "contents",
async: true,
})
async getContactsSameDomain(): Promise<(Contact | null)[] | null> {
return [];
}
}
updates the GraphQL schema as follows:
type User implements Node {
id: ID!
firstName: String!
lastName: String!
emailAddress: String!
contactsSameDomain: [Contact]
}
View the GraphQL documentation to learn more about lists and null in GraphQL.
async
Indicates that this method is async and an async caller should be generated in the generated GraphQL code.