Node, Nest, Deno/🦁 Nest - Series

Nest + graphql (2) : ObjectType, Resolvers(Query, @Args)

DarrenKwonDev 2020. 11. 21. 00:41

docs.nestjs.com/graphql/resolvers

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reac

docs.nestjs.com

 

@ObjectType, @Field

docs.nestjs.com/graphql/resolvers#object-types

 

Most of the definitions in a GraphQL schema are object types. Each object type you define should represent a domain object that an application client might need to interact with.

 

code first 방식으로 접근할 때는 Object Type을 만들어 schema가 자동 생성되게끔합니다. 

 

nest에서 Object Type을 만들어보겠습니다. Object Type을 @nestjs/graphql에서 제공해줍니다.

아래와 같이 class를 작성하고, 들어갈 부분을 @Field로 작성해줍니다. 

 

The @Field() decorator accepts an optional type function (e.g., type => Int), and optionally an options object.

 

또, @Field 부분에서 옵션을 줄 수 있습니다.

The options object can have any of the following key/value pairs:

  • nullable: for specifying whether a field is nullable (in SDL, each field is non-nullable by default); boolean
  • description: for setting a field description; string
  • deprecationReason: for marking a field as deprecated; string

nullable을 자주쓰게 될 것 같네요.

import { Field, ObjectType } from '@nestjs/graphql';

@ObjectType()
export class Restaurant {
  @Field(() => String) // nullable이 없으므로 required가 됨
  name: string;

  @Field(() => Boolean, { nullable: true }) // nullable이 있으므로 optional
  isGood?: boolean; // optional이므로 ?를 적어주자
}

 

정의한 Object Type을 resolver에서 불러와 타입으로 사용할 수 있습니다.

import { Query, Resolver } from '@nestjs/graphql';
import { Restaurant } from './entities/restaurant.entity';

@Resolver(() => Restaurant) // 빈 값으로 둬도 됨 딱히 의미는 없음
export class RestaurantResolver {
  @Query(() => Restaurant) // myRestaurant 쿼리는 Restaurant를 반환해야 함
  myRestaurant() {
    ... 내부 로직
  }
}

 

 

Code first resolver @Resolver, @Args

docs.nestjs.com/graphql/resolvers#code-first-resolver

 

앞서 간단한 resolver를 작성해보았습니다만 파라미터를 넘겨주지 않는 단순한 query였습니다. 인자를 받을 수 있는 형태의 resolver를 작성해봅시다.

 

 

@Args

 

docs.nestjs.com/graphql/resolvers#args-decorator-options

 

@Args를 추가하여 인자를 받을 수 있습니다. 아래와 같은 꼴이죠.

This works in a very similar fashion to REST route parameter argument extraction. 라고하는데, 말 그대로 Nest의 Controller에서 @Body, @Res 등을 통해 정보를 받아온 것과 비슷합니다.

@Args('id') id: string

 

그런데 TS에서 number로 지정한 것이 graphql 에서는 Int일 수도, Float일 수도 있습니다. 이 같은 경우에는 아래와 각ㅌ이 직접 graphql의 타입을 넣어주면 됩니다.

 

The number TypeScript type doesn't give us enough information about the expected GraphQL representation (e.g., Int vs. Float). Thus we have to explicitly pass the type reference. We do that by passing a second argument to the Args() decorator, containing argument options, as shown below:

@Query(returns => Author, { name: 'author' }) // 이 쿼리는 Author를 반환해야 함
async getAuthor(@Args('id', { type: () => Int }) id: number) {
  return this.authorsService.findOneById(id);
}

 

type외에도 줄 수 있는 부분도 많습니다.

  • type: a function returning the GraphQL type
  • defaultValue: a default value; any
  • description: description metadata; string
  • deprecationReason: to deprecate a field and provide metadata describing why; string
  • nullable: whether the field is nullable

아래와 같은 꼴로 사용할 수 있습니다.

getAuthor(
  @Args('firstName', { nullable: true }) firstName?: string,
  @Args('lastName', { defaultValue: '' }) lastName?: string,
) {}

 

 

@Args의 실제 사용 사례는 다음과 같겠네요

import { Args, Query, Resolver } from '@nestjs/graphql';
import { Restaurant } from './entities/restaurant.entity'; // @ObjectType임

@Resolver((of) => Restaurant)
export class RestaurantResolver {
  @Query(() => [Restaurant]) // grapqhl의 문법
  // 로직에서는 TS의 문법
  restaurants(@Args('veganOnly') veganOnly: boolean): Restaurant[] { 
    if (veganOnly) {
      return [];
    } else {
      return [];
    }
  }
}