🌸 GraphQL

nexus 이해하기3 (공식문서 참고)

ji-hyun 2022. 2. 26. 19:57

api 에 mutation 추가하기

 

mutation 이란 

Mutation 은 데이터베이스 상태가 변할 때 사용되는 것이다.

 

 

 

 

mutation 을 설정하는 context 와 입력 받는 인자와 같은 arg 에 대해서 배워볼 것이다.

 

  • Writing GraphQL mutations
  • Exposing GraphQL objects for mutation operations
  • Working with GraphQL Context
  • Working with GraphQL arguments

 

 

 


context 연결

 

https://nexusjs.org/docs/getting-started/tutorial/chapter-adding-mutations-to-your-api/

 

3. Adding mutations to your API

3. Adding mutations to your API

nexusjs.org

 

 

이 부분은 자세한 방법은 생략. 

 

 

// api/server.ts

import { ApolloServer } from 'apollo-server'
import { context } from './context'
import { schema } from './schema'
export const server = new ApolloServer({
  schema,
  context    // 추가
})

 

 

 

 

 

// api/schema.ts

import { makeSchema } from 'nexus'
import { join } from 'path'
import * as types from './graphql'
export const schema = makeSchema({
  types,
  outputs: {
    typegen: join(__dirname, '..', 'nexus-typegen.ts'),
    schema: join(__dirname, '..', 'schema.graphql')
  },
  contextType: {                                    // 1
    module: join(__dirname, "./context.ts"),        // 2
    export: "Context",                              // 3
  },
})

 

  1. 컨텍스트 유형을 설정하는 옵션
  2. 컨텍스트 유형을 내보낸 모듈의 경로
  3. 해당 모듈의 내보내기 이름

 

 

 

 


context 사용

 

 

이제 이 데이터를 이렇게 바꿔보자.

 

 

예전

 

// api/graphql/Post.ts
export const PostQuery = extendType({
  type: 'Query',
  definition(t) {
    t.list.field('drafts', {
      type: 'Post',
      resolve() {
        return [{ id: 1, title: 'Nexus', body: '...', published: false }]
      },
    })
  },
})

 

 

 

현재

 

// api/graphql/Post.ts
export const PostQuery = extendType({
  type: 'Query',
  definition(t) {
    t.list.field('drafts', {
      type: 'Post',
      resolve(_root, _args, ctx) {                              // 1
        return ctx.db.posts.filter(p => p.published === false)  // 2
      },
    })
  },
})

 

  1. context 는 일반적으로 다음과 같이 식별되는 세 번째 매개변수입니다.   ->   ctx
  2. 반환 : unpubliched 된 post -> draft. 

 

 

 


첫번째 mutation

 

 

자, 이제 컨텍스트에 연결하는 방법을 알았으므로 첫 번째 mutation를 구현해 보겠다. API 클라이언트가 새 drafts 을 만들 수 있도록 하겠다.

 

 

이 mutation 은 이름이 필요하다.

createPost 라고 하자.

 

 

 

리졸버를 완료하려면 클라이언트의 입력 데이터를 가져와야 한다.

이것은 우리에게 새로운 개념인 GraphQL args 를 제공한다. GraphQL의 모든 필드는 이를 받아들일 수 있다. 

 

효과적으로 GraphQL의 각 필드를 함수처럼 생각할 수 있다.

일부 입력을 수락하고, 무언가를 수행하고, 출력을 반환한다. 

 

대부분의 경우 "무언가 수행"은 읽기와 유사한 작업의 문제이지만... Mutation필드에서 "무언가 수행"은 일반적으로 부작용이 있는 프로세스(예: 데이터베이스에 쓰기)를 수반한다.

 

 

 

 

 

 

 

 

GraphQL args 로 구현을 수정해 보겠다.

 
import { objectType, extendType } from 'nexus'
import { objectType, extendType, stringArg, nonNull } from 'nexus'
export const PostMutation = extendType({
  type: 'Mutation',
  definition(t) {
    t.nonNull.field('createDraft', {
      type: 'Post',
      args: {                                        // 1
        title: nonNull(stringArg()),                 // 2
        body: nonNull(stringArg()),                  // 2
      },
      resolve(_root, args, ctx) {
        const draft = {
          id: ctx.db.posts.length + 1,
          title: args.title,                         // 3
          body: args.body,                           // 3
          published: false,
        }
        ctx.db.posts.push(draft)
        return draft
      },
    })
  },
})

 

  1. args필드 정의에 속성을 추가하여 해당 인수를 정의합니다. 인수 이름이고 값은 type 사양입니다.
  2. arg 유형을 정의하기 위해 Nexus 헬퍼를 사용하십시오. intArg및 와 같은 모든 GraphQL 스칼라에 대해 이러한 도우미가 하나 있습니다 booleanArg. 일부 InputObject와 같은 유형을 참조하려면 arg({ type: "..." }). 도우미를 사용 nonNull하고 nullable -> arg의 null 허용 여부 유형을 조정할 수 있습니다. 기능적 도우미 list를 사용하여 arg를 목록 유형으로 바꿀 수도 있습니다.
  3. 리졸버에서 위에서 지정한 args에 액세스하고 사용자 지정 논리에 전달합니다. 매개변수 위로 마우스를 가져가면 정의되지 않을 수 있다는 사실을 포함하여 Nexus가 올바르게 입력한 것을 볼 수 있습니다.

 

 

 

Mutation {
  createDraft(title: String!, body: String!): Post!
}

 

클라이언트가 title 과 body 를 입력하면 draft 가 추가 된다.

 

 


도메인 모델링 2부

 

이 장을 마무리하기 전에 스키마를 좀 더 플러시하겠습니다. publish mutation 을 추가해보겠다.

초안을 실제 게시된 게시물로 변환하는 mutation 을 추가한다 

 

 

import { objectType, extendType, stringArg, nonNull, intArg } from 'nexus'
export const PostMutation = extendType({
  type: 'Mutation',
  definition(t) {
    // ...
    t.field('publish', {
      type: 'Post',
      args: {
        draftId: nonNull(intArg()),
      },
      resolve(_root, args, ctx) {
        let draftToPublish = ctx.db.posts.find(p => p.id === args.draftId)
        
        if (!draftToPublish) {
          throw new Error('Could not find draft with id ' + args.draftId)
        }
        
        draftToPublish.published = true
        
        return draftToPublish
      },
    })
  },
})

 

type Mutation {
  createDraft(body: String!, title: String!): Post!
  publish(draftId: Int!): Post    // 추가
}

 

 

 

 

 

 

 

 

 

 

 

Then, we'll let API clients read these published posts.

 

// api/graphql/Post.ts

import { extendType } from 'nexus'
export const PostQuery = extendType({
  type: 'Query',
  definition(t) {
    // ...
    
    t.list.field('posts', {
      type: 'Post',
      resolve(_root, _args, ctx) {
        return ctx.db.posts.filter(p => p.published === true)
      },
    })
  },
})

 

type Query {
  drafts: [Post]!
  posts: [Post]     // 추가
}

 

 


사용해보기

 

좋습니다. 이제 GraphQL Playground로 이동하여 이 쿼리를 실행합니다(왼쪽). 모든 것이 잘 되었다면 다음과 같은 응답이 표시되어야 합니다(오른쪽).

 

 

 

posts이제 게시된 초안이 쿼리 를 통해 표시되어야 한다 . 이 쿼리를 실행하고(왼쪽) 다음 응답을 기대하세요(오른쪽).