본문 바로가기
쿤즈 Dev/GraphQL

[GraphQL] 스키마(Schema) 정의 방법 (5): Input type

by :)Koon 2021. 6. 6.

GraphQL의 스키마를 정의하는 방법을 다루고 있습니다. 앞선 포스팅에서는 Scalar type, Object type, Query type, Mutation type을 설명해 드렸어요. Scalar가 베이스를 이루고 여기서 애플리케이션에 맞게 Object type을 정의해서 Query type을 만들거나 Mutation type을 만듭니다.

이번 포스팅에서는 데이터를 받을 때 묶어서 받을 수 있는 Input type을 알아보겠습니다.


Input type

Input type은 이름 그대로 입력값을 정의하는 타입입니다. Query type, Mutation type, 아직 다루지 않은 Subscription type에서도 마찬가지로 parameter들을 받는 경우가 발생합니다. 이때, 값들을 묶어서 설정할 수 있는 타입이 바로 Input type입니다.

 

예를 들어서 게시판에 글을 쓰는 API를 실행시킨다면 다음과 같이 만들 수 있습니다.

type Mutation {
  createPost(title: String, body: String, mediaUrls: [String]): Post
}

Mutation type이며 createPost를 선언하고 parameter로는 title, body, mediaUrls를 클라이언트로부터 받습니다. 처리가 완료되면 결과로는 Post 형태를 내보냅니다.

 

이때, title, body, mediaUrls를 Input type으로 만들어서 다음과 같이 다시 정의할 수 있습니다.

type Mutation {
  createPost(post: PostAndMediaInput): Post
}

input PostAndMediaInput {
  title: String
  body: String
  mediaUrls: [String]
}

Input type으로 만들 때에는 input이라는 키워드를 사용하고 사용하고자 하는 이름을 만들어 줍니다. 예를 들어서 설정한 이름은 PostAndMediaInput입니다. 그리고 내부 값들은 title, body, mediaUrls를 여기에 넣어줍니다.

 

다시 createPost Mutation에서는 새로 만든 PostAndMediaInput type을 받겠다고 선언하고 이는 post라는 이름으로 받도록 만들어 주었습니다.

 

그럼 클라이언트에서는 어떻게 호출해야 할까요? GraphQL 호출을 사용하기 위해서 위에서 사용한 소스들을 기존 소스에 추가해 보도록 하겠습니다.


Mutation, Query, Object type 추가

기존 틀은 아래 포스팅들에서 순차적으로 진행했습니다.

2021.05.15 - [쿤즈 Dev/GraphQL] - [GraphQL] Apollo Server를 이용한 GraphQL 사용 방법

2021.05.18 - [쿤즈 Dev/GraphQL] - [GraphQL] 스키마(Schema) 정의 방법 (1): SDL과 Scalar types

2021.05.19 - [쿤즈 Dev/GraphQL] - [GraphQL] 스키마(Schema) 정의 방법 (2): Object types

2021.05.21 - [쿤즈 Dev/GraphQL] - [GraphQL] 스키마(Schema) 정의 방법 (3): Query type

2021.05.24 - [쿤즈 Dev/GraphQL] - [ GraphQL] 스키마(Schema) 정의 방법 (4): Mutation type

 

기본적인 Apollo Server의 구성에 createPost Mutation type을 추가해 보도록 하겠습니다.

# Mutation 타입
type Mutation {
  ...
  createPost(title: String, body: String, mediaUrls: [String]): Post
}

그리고 기존에는 Post라는 type이 없기 때문에 이를 반환할 수 없습니다. 따라서 Post type도 만들도록 하겠습니다.

# Post 타입
type Post {
  title: String
  body: String
  mediaUrls: [String]
}

type을 완성했습니다. Post type은 title, body, mediaUrls를 그대로 입력받도록 하는 타입입니다. 또 추가적으로 필요한 내용은 createPost를 호출했을 때 저장될 수 있도록 하기 위해서 변수가 필요합니다.

const post = [];

배열 변수 하나를 선언하도록 하겠습니다.

 

마지막으로 createPost의 본체인 resolver를 만들어 보도록 하겠습니다. 

const resolvers = {
    Mutation: {
        ..., 
        createPost: (_, args) => {
            const { title, body, mediaUrls } = args;

            const post = { title, body, mediaUrls };
            posts.push(post);

            return post;
        },
    },
};

resolver에 parameter로 들어오는 값 중에서 두 번째 값이 클라이언트로부터 받는 값입니다. 따라서 이 값을 받아서 우리가 원하는 값으로 가져올 수 있습니다. 이렇게 가져온 데이터는 posts라는 배열 변수에 Object 형식으로 담아줍니다. 그리고 현재 저장한 post를 반환하도록 합니다.

 

여기까지 하면 데이터를 넣을 수 있습니다. 확인해 볼게요. 아래 명령어로 apollo server를 실행합니다.

$ node index.js
🚀 Server ready at http://localhost:9000/

정상적으로 실행이 된다면 서버가 동작하게 됩니다. 그럼 위 url로 접속해서 다음과 같이 실행합니다.

mutation createPost($title: String, $body: String, $mediaUrls: [String]){
  createPost(title: $title, body: $body, mediaUrls: $mediaUrls) {
    title
    body
    mediaUrls
  }
}

그리고 하단 Query variables에는 다음과 같이 입력합니다.

{
  "title": "post title",
  "body": "post body",
  "mediaUrls": ["/my-post-1", "/my-post-2"]
}

실행해보면 아래 그림과 같이 데이터가 출력될 경우 정상입니다.

실제로 데이터가 입력되었는지 확인이 불가능하기 때문에 posts에 저장된 데이터를 가져오는 Query를 만들어 보겠습니다.


Query를 만들어 주기 위해서는 Query type에 가져오는 type을 아래와 같이 추가해 주도록 합니다.

type Query {
  ...
  posts: [Post]
}

그리고 동작을 위해서 resolver에 아래와 같이 추가해 줍니다.

const resolvers = {
    Query: {
        posts: () => posts, // Query 추가
    },
    Mutation: {
        createPost: (_, args) => {
            const { title, body, mediaUrls } = args;

            const post = { title, body, mediaUrls };
            posts.push(post);

            return post;
        },
    },
};

내부 변수 posts에 저장된 데이터를 출력해 주는 쿼리입니다. 서버를 다시 실행하고 결과를 확인해 보도록 하겠습니다.

서버를 재실행했다면 createPost를 먼저 실행하고 이후에 실행해야 데이터가 출력됩니다. 이유는 내부 변수에 저장되어 있기 때문에 서버가 재시작되면 기존 데이터는 삭제가 됩니다.


Input type으로 변경

createPost의 parameter로는 3가지 데이터가 입력됩니다. 때에 따라서는 그 이사의 데이터를 입력받을 수도 있습니다. 그래서 이 경우는 입력받는 parameter를 Input type을 이용해서 변경해줄 수 있습니다.

 

아래와 같이 Input type을 추가해 주도록 합니다.

input PostAndMediaInput {
  title: String
  body: String
  mediaUrls: [String]
}

이렇게 만든 Input type을 이용하도록 Mutation type도  아래와 같이 수정합니다.

type Mutation {
  createPost(post: PostAndMediaInput): Post
}

마지막으로 resolver를 수정해야 합니다. 기존 parameter는 title, body, mediaUrls라는 이름이 args에 담겨서 넘어오지만 이번에는 post라는 이름으로 넘겨주었기 때문에 이 값을 받아야 합니다. 그래서 아래와 같이 수정합니다.

createPost: (_, args) => {
  const { title, body, mediaUrls } = args.post; // 수정

  const post = { title, body, mediaUrls };
  posts.push(post);

  return post;
},

이렇게 수정했다면 서버를 재시작하고 테스트 화면으로 넘어가 보겠습니다.

 

기존 parameter는 title, body, mediaUrls를 각각 입력했다면 지금은 PostAndMediaInput이라는 타입으로 받고 이 이름은 post로 지정할 것입니다. 따라서 테스트에서도 다음과 같이 변경합니다.

mutation createPost($post: PostAndMediaInput){
  createPost(post: $post) {
    title
    body
    mediaUrls
  }
}

이에 맞춰서 Query variables도 변경이 필요합니다.

{
  "post": {
    "title": "post title2",
  	"body": "post body2",
  	"mediaUrls": ["/my-post-1", "/my-post-2"]
  }
}

이제 쿼리를 실행하고 결과를 보면 기존과 동일한 결과를 보실 수 있습니다.


이번 포스팅에서는 Input type을 사용하는 방법을 알아보았습니다. 기존의 Mutation, Query를 추가하고 parameter들을 변경해서 Input type으로 만들어주고 테스트까지 진행해 보았습니다. Apollo server를 이용하면서 사용하는 빈도가 높은 타입 중 하나가 바로 Input type입니다. 도움이 되셨으면 합니다. 이상입니다.

 

댓글