Types and Fields

Introduction

@foadonis/graphql uses the "code-first" approach by automatically generating your GraphQL schema based on your code.

With the following Typescript class which represents our Recipe model with fields for storing the recipe data:

class Recipe {
  declare id: string
  declare title: string
  declare averageRating: number
}

By using the provided decorators you can turn your Typescript class into a GraphQL Type:

import { ObjectType, Field } from '@foadonis/graphql'

@ObjectType()
class Recipe {
  @Field()
  declare id: string

  @Field()
  declare title: string

  @Field()
  declare averageRating: number
}

Complex types

To generate the GraphQL we heavily rely on Typescript metadata to infer the type of a property. There are cases where this is not possible and require explicit type to be provided.

Nullable

import { ObjectType, Field } from '@foadonis/graphql'

@ObjectType()
class Recipe {
  @Field()
  declare title: string

  @Field(() => String, { nullable: true })
  declare description: string | null
}

Array

import { ObjectType, Field } from '@foadonis/graphql'

@ObjectType()
class Recipe {
  @Field(() => [String])
  declare tags: string[]
}

Scalars

import { ObjectType, Field, GraphQLBigInt } from '@foadonis/graphql'
import { GraphQLUUID, GraphQLJSON } from 'graphql-scalars'

@ObjectType()
class Recipe {
  @Field(() => GraphQLUUID, { nullable: true })
  declare authorId: string | null

  @Field(() => GraphQLJSON)
  declare meta: any
}

Objects

import { ObjectType, Field } from '@foadonis/graphql'

@ObjectType()
class User {
  @Field()
  name: string
}

@ObjectType()
class Recipe {
  @Field(() => [User])
  declare authors: User[]
}

Enums

You can generate GraphQL enums using Typescript enums with the registerEnumType function. Due to typescript limitations the name and the type must be explicitly defined.

import { ObjectType, Field, registerEnumType } from '@foadonis/graphql'

enum RecipeStatus {
  DRAFT = 'DRAFT',
  IN_REVIEW = 'IN_REVIEW',
  PUBLISHED = 'PUBLISHED',
}

registerEnumType(RecipeStatus, {
  name: 'RecipeStatus', // mandatory
})

@ObjectType()
class Recipe {
  @Field(() => Recipe) // mandatory
  declare status: RecipeStatus
}

For interoperability with databases the enum value is used. Meaning that if you want to share the types with your client you must map each key with the corresponding value.

Documentation

The description parameter on ObjectType and Field allows you to provide documentation to your GraphQL schema that will be shown in the introspection.

import { ObjectType, Field, ID } from '@foadonis/graphql'

@ObjectType({
  description: 'A cooking recipe',
})
class Recipe {
  @Field(() => ID, { description: 'Unique identifier in Uuid V4 format' })
  declare id: string
}

On this page