written by yechoi

[GraphQL] 스키마 작성 방식 - Code first vs Schema first 본문

Born 2 Code/Node Modules

[GraphQL] 스키마 작성 방식 - Code first vs Schema first

yechoi 2021. 6. 29. 11:02
반응형

Code first

이 방법은 TypeScript로만 작업하고 언어 구문 간의 컨텍스트 전환을 피하려는 경우 유용합니다. 타입스크립트로 클래스를 짜면 해당 클래스에 해당하는 graphql 스키마를 만들어 줍니다.

코드 우선 접근 방식에서는 데코레이터와 TypeScript 클래스를 사용하여 해당 GraphQL 스키마를 생성합니다.

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

@ObjectType()
export class Recipe {
  @Field(type => ID)
  id: string;

  @Field()
  title: string;

  @Field({ nullable: true })
  description?: string;

  @Field()
  creationDate: Date;

  @Field(type => [String])
  ingredients: string[];
}

 

설정하기

(1) 코드 우선 접근 방식을 사용하려면 먼저 옵션 객체에 autoSchemaFile 속성을 추가합니다. autoSchemaFile 속성 값은 자동으로 생성된 스키마가 생성될 경로입니다.

(2) 또는 스키마를 메모리에서 즉석에서 생성할 수 있습니다. 이를 활성화하려면 autoSchemaFile 속성을 true로 설정합니다.

// (1)
GraphQLModule.forRoot({
  autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
}),
// (2)
GraphQLModule.forRoot({
  autoSchemaFile: true,
}),

👉 code first 공식 nest.js 샘플 (en/github)

 

 

Schema first

스키마 우선 접근 방식에서 진실의 소스는 GraphQL SDL (Schema Definition Language) 파일입니다. SDL은 서로 다른 플랫폼간에 스키마 파일을 공유하는 언어에 구애받지 않는 방법입니다. Nest는 GraphQL 스키마를 기반으로 TypeScript 정의 (클래스 또는 인터페이스 사용)를 자동으로 생성하여 중복된 상용구 코드를 작성할 필요성을 줄입니다.

아래처럼 .graphql 로 스키마를 직접 작성해줘야 합니다.

// cat.graphql
type Query {
  cats: [Cat]
  cat(id: ID!): Cat
}

type Mutation {
  createCat(createCatInput: CreateCatInput): Cat
}

type Subscription {
  catCreated: Cat
}

type Owner {
  id: Int!
  name: String!
  age: Int
  cats: [Cat!]
}

type Cat {
  id: Int
  name: String
  age: Int
  owner: Owner
}

input CreateCatInput {
  name: String
  age: Int
}

스키마 우선주의란?

스키마 우선주의는 디자인 방법론의 일종이다. 개발시 스키마를 우선 개발하는 것이다. 여기서 스키마란 데이터 타입의 집합이다. 이를 미리 정의하면 스키마 정의는 API 문서와 같은 역할을 하며, 프론트와 백엔드 개발자의 의사소통 비용을 줄일 수 있다. 백엔드 개발자는 어떤 데이터를 전달해야 하는지, 프론트엔드 개발자는 인터페이스 작업을 할 때 필요한 데이터를 정의할 수 있는 것이다.

🔗GraphQl 스키마 정의(ko/blog)

 

SDL(Schema Definision Language)란

REST가 엔드포인트 집합이었다면, GraphQL은 타입 집합. 그리고 이런 데이터 타입 집합을 스키마라고 부른다. 스키마를 정의하는 언어는 줄여서 SDL.

GraphQL은 아래에서 설명하는 SDL을 사용하여 스키마를 작성한다. 이 스키마는 클라이언트와 서버 사이에서 어떻게 클라이언트가 데이터에 접근할 수 있는지를 알려주게 된다. 한번 스키마가 정의되면 추가적인 커뮤니케이션 없이 클라이언트, 서버는 어떤 식으로 데이터 구조가 정의되어 있는지 알 수 있다는 장점이 있다.

GraphQL은 API의 스키마를 정의할 때 사용하는 타입시스템을 가지고 있다. 스키마를 작성하는 문법을 SDL이라고 한다. SDL에서 ! 은 필수 값을 나타내는 기호로 사용된다. 아래와 같은 스키마가 있다면, !가 있는 name, age, title은 필수 값이 된다.
```
type Person {
  name: String!
  age: Int!
}
type Post {
  title: String!
}
```

이를 비롯해 query, mutation, subscription도 SDL의 일부.

🔗GraphQL이란?(ko/blog)

👉 schema first 공식 nest.js 샘플(en/github)
🔗 code first vs. schema fisrt(ko/docs)

 

네스트JS 한국어 매뉴얼 사이트

네스트JS 한국, 네스트JS Korea 한국어 매뉴얼

docs.nestjs.kr

 

 

 

+ resolver

리졸버는 "스키마의 개별 필드을 다루는 데 책임이 있는 함수"다. 클라이언트가 특정 필드에 대해 쿼리를 날리면, 해당 필드의 리졸버는 적절한 데이터 소스로부터 요청된 데이터를 패치한다.

리졸버는 다음 중 하나를 반환한다*(번역 불완전, 아래 원문을 참고)* :

  • 리졸버에 상응하는 스키마 필드가 필요로 하는 타입의 데이터
  • Data of the type required by the resolver's corresponding schema field (string, integer, object, etc.)
  • 필요로 하는 타입의 데이터를 충족하는 프로미스
  • A promise that fulfills with data of the required type

🔗 Write query resolvers (en/docs)

gql 에서는 데이터를 가져오는 구체적인 과정을 직접 구현 해야 합니다. gql 쿼리문 파싱은 대부분의 gql 라이브러리에서 처리를 하지만, gql에서 데이터를 가져오는 구체적인 과정은 resolver(이하 리졸버)가 담당하고, 이를 직접 구현 해야 합니다. 프로그래머는 리졸버를 직접 구현해야하는 부담은 있지만, 이를 통해서 데이터 source의 종류에 상관 없이 구현이 가능 합니다. 예를 들어서, 리졸버를 통해 데이터를 데이터베이스에서 가져 올 수 있고, 일반 파일에서 가져 올 수 있고, 심지어 http, SOAP와 같은 네트워크 프로토콜을 활용해서 원격 데이터를 가져올 수 있 습니다. 덧붙이면, 이러한 특성을 이용하면 legacy 시스템을 gql 기반으로 바꾸는데 활용 할 수 있습니다.

gql 쿼리에서는 각각의 필드마다 함수가 하나씩 존재 한다고 생각하면 됩니다. 이 함수는 다음 타입을 반환합니다. 이러한 각각의 함수를 리졸버(resolver)라고 합니다. 만약 필드가 스칼라 값(문자열이나 숫자와 같은 primitive 타입)인 경우에는 실행이 종료됩니다. 즉 더 이상의 연쇄적인 리졸버 호출이 일어나지 않습니다. 하지만 필드의 타입이 스칼라 타입이 아닌 우리가 정의한 타입이라면 해당 타입의 리졸버를 호출되게 됩니다.

🔗 GraphQL 개념잡기 - kakao Tech(ko/blog)

반응형