데이터베이스에는 없지만 로직을 통해 리턴해내야 하는 값이 있다면?

dynamic field 로 해결할 수 있다.

let users = [
  {
    id: '1',
    firstName: 'nico',
    lastName: 'last',
  },
];

const typeDefs = gql`
  type User {
    id: ID!
    firstName: String!
    lastName: String!
    fullName: String!
  }
  type Tweet {
    id: ID!
    text: String!
    author: User
  }
  type Query {
    allUsers: [User!]!
    allTweets: [Tweet!]!
    tweet(id: ID!): Tweet
  }
  type Mutation {
    postTweet(text: String!, userId: ID!): Tweet!
    deleteTweet(id: ID!): Boolean!
  }
`;

allUsers는 User 타입의 배열을 리턴해야 한다.

그리고 User 타입에는 id, firstName, lastName, fullName 이라는 4개의 프로퍼티가 있다.

그렇지만 우리가 만든 가짜 데이터베이스에는 fullName이 존재하지 않는다.

이때 fullName이라는 타입에 대한 함수를 resolver에 만들어주면 된다.

const resolvers = {
  Query: {
    allTweets() {
      return tweets;
    },
    tweet(root, { id }) {
      return tweets.find((tweet) => tweet.id === id);
    },
    allUsers() {
      console.log('allUsers called');
      return users;
    },
  },
  Mutation: {
    // ...
  },
  User: {
    fullName() {
      console.log('fullName called!');
      return 'hello!';
    },
  },
};

이 상태로 아래의 쿼리를 실행하면,

{
	allUsers {
		id
		firstName
		lastName
		fullName
	}
}

fullName까지 정상적으로 출력이 된다.

allUsers()와 fullName() 에 추가한 console.log를 확인해보면

allUsers()의 console.log 가 먼저 출력되고, fullName()에서 작성한 console.log가 출력되는데

graphql은 다음과 같이 동작하기 때문이다.

  1. 일단 graphql은 allUsers resolver를 먼저 확인하여 모든 데이터를 가지고 온다.
  2. allUsers()가 return 하는 data에 fullName field가 없다는 것을 확인
  3. 그럼 graphql은 다시 resolver를 확인하여 type User의 field 이름이 fullName인 것을 찾는다.