Fields
You can define GraphQL fields by placing a @gqlField
directly before a:
- Method declaration
- Method signature
- Property declaration
- Property signature
- Parameter property
- Function declaration
- Arrow function declaration
- Static method
Class-based fields
When using classes or interfaces to define GraphQL types, fields can be defined using class properties or methods:
/** @gqlType */
class User {
/**
* A description of some field.
* @gqlField
*/
someField: string;
/** @gqlField */
myField(): string {
return "Hello World";
}
}
Fields can also be defined using TypeScript's parameter properties, wich is a short-hand for defining a field value that is passed to the class constructor:
/** @gqlType */
class User {
constructor(
/** @gqlField */
public name: string,
) {}
}
If you want to group root fields Query
Mutation
that return or modify a specific type, you can define them as part of that type's class using static methods:
- TypeScript
- GraphQL
/** @gqlType */
type Query = unknown;
/** @gqlType */
export class User {
constructor(
/** @gqlField */
public name: string,
) {}
/** @gqlField */
static getUser(_: Query): User {
return new User("Elizabeth");
}
}
type Query {
getUser: User
}
type User {
name: String
}
Grats will use the type of the first argument of the static method to determine which type is being extended. Even if you don't need access to any values on the parent object, you must type your first argument using the parent type so that Grats knows which type your field is on.
For more information about field resolves, see Resolver Signature.
Functional style fields
If you prefer to avoid classes, types can be defined using type literals. However, this approach does not allow you to define derived/resolver fields. To solve this, Grats also allows you to define derived fields using named, exported functions. Function resolvers:
- Accept an instance of the parent type as the first argument
- Have a return type that matches the field type
- Are exported named functions where the function name is the desired field name
/** @gqlType */
const User = {
/** @gqlField */
firstName: string,
/** @gqlField */
lastName: string,
};
export function fullName(user: User): string {
return `${user.firstName} ${user.lastName}`;
}
In addition to adding derived fields to type literals, functional fields are also
useful to define root fields on Query
or Mutation
next to the type they return or modify.
Even if you don't need access to any values on the parent object, you must type your first argument using the parent type so that Grats knows which type your field is on. So you might have a field that looks like this:
/** @gqlType */
type Query = unknown;
export function hello(_: Query): string {
return "Hello World!";
}
Extending Query:
const DB: any = {};
/** @gqlType */
type Query = unknown;
/** @gqlType */
type User = {
/** @gqlField */
name: string;
};
/** @gqlField */
export function userById(_: Query, id: string): User {
return DB.getUserById(id);
}
Extending Mutation:
const DB: any = {};
/** @gqlType */
type Mutation = unknown;
/** @gqlType */
type User = {
/** @gqlField */
name: string;
};
/** @gqlField */
export function deleteUser(_: Mutation, id: string): boolean {
return DB.deleteUser(id);
}
Note that Grats will use the type of the first argument to determine which type is being extended. So, as seen in the previous examples, even if you don't need access to the instance you should still define a typed first argument.
More field documentation
- Renaming for how to expose your field under a different name than your function/property/method
- Field Arguments for how to define arguments
- Descriptions for how to add descriptions to your fields
- Nullability for how to control the error handling and nullability of your field
- Deprecated for how to control the nullability of your field