GraphQL response formatting

신연우·2021년 4월 3일
0

에러만 하면 끝날 줄 알았지? 아니지롱! response도 있거든?

에러만 하면 끝날 줄 알았는데, response도 손봐야 할 필요가 있었다. 사실은 일반적으로 GraphQL을 생각하면 response부터 손을 봐야한다는 생각이 먼저 드는데, 처음 서버를 켤 때부터 에러가 나서 그런가, 에러를 먼저 손봤다.

무튼, 왜 response도 손을 봐야 하나면 기본적으로 resolver를 설정하면 반환되는 값이 그 resolver 대상 객체이기 때문이다.

@Mutation(() => User)
  async signup(
    @Arg("data") data: SignupRequest,
    @Ctx("ctx") ctx: Context
  ): Promise<User | null> {
    ctx.prisma.user.create({
      data: {
        username: data.username,
        password: data.password,
        email: data.email,
        nickname: data.nickname
      }
    });
  }

예를 들어, 회원가입을 위해 UserResolver를 위와 같이 만들었다고 하자. 공식 홈페이지의 GitHub 예시로 나와있는 코드를 참고해서 만들면 보통 이런 식으로 코드를 작성하게 될 것이다.

mutation {
  signup(data: {
    username: "test user"
    password: "I'am test user"
    email: "test@test.com"
    nickname: "test"
  })
}

GraphQL의 특성 상 요청을 보내면 반드시 반환받는 값을 명시를 해야 한다. 그래서 위와 같이 요청만 보내고 반환을 받지 않는 경우는 에러가 발생한다.

그래서 반환 값을 설정하려고 하면 내가 생성한 user 객체의 값들(username, password, email, nickname 등)을 가지고 오게 된다. 이는 곧 원하지 않는 동작으로 이어질 수 있다.

Postman으로 요청을 보내고, 암호화된 password를 돌려받을 수 있다는 뜻이다. 보통 암호화하는 코드는 GitHub에 올라가기 때문에 적어도 어떤 방식으로 암호화되는지는 알게 된다. 그렇다면 이는 악용될 가능성이 충분히 있다고 할 수 있다.

그럼 어떻게 이를 해결할 수 있는가?

그래서 위에서 정의한 메서드에서 반환되는 값을 Promise<string>과 같이 변경해서 반환해보았지만, 이렇게 해도 Error가 발생해서 몇 시간 정도 고민을 했다.

그러던 중 @Mutation()에서 지정한 반환값이 사실 중요한게 아닐까라는 생각이 들었다. 코드 상에서는 Promsie<User | null>이 당장의 typescript 컴파일에 걸리지만, GraphQL이 동작할 때 signup이 반환하는 값은 @Mutation()에서 지정한 값이 아닐까라는 생각을 하게 되었다.

import { ObjectType, Field } from "type-graphql";

@ObjectType()
export class HttpResponse {
  @Field()
  message!: string;

  @Field()
  status!: number;
}

그래서 위와 같이 필요한 Response 객체를 정의한 뒤, @Mutation()에 반환 값을 HttpResponse로 지정했다.

그 결과로, 요청을 보낼 때 기본적으로 에러가 발생하지 않는 것을 확인할 수 있다.

회고

사실 이 문제를 해결하는데 힌트를 얻은 곳은 바로 내가 2번째로 작성했던 글에서 얻었다. 읽다 보면 @Mutation()에서 반환값을 지정하지 않아 생긴 에러라는 문구를 볼 수 있다.

이처럼 전에 생겼던 이슈에 대한 상황과 해결 방법을 정리해두면 나중에 이런 식으로 도움을 얻을 수도 있다. 물론 이 때문이 아니더라도 이후 어떤 일이 생길지 모르기 때문에 발생한 이슈는 문서로 자세히 기록해두는 것이 좋다.

그리고, ApolloServer의 인스턴스를 만들 때 formatResponse라는 옵션이 있던데 이 옵션에 대해 알아보면 좋을 것 같다. 이 부분에서 전에 처리하지 못한 이슈를 처리할 수도 있으니까 말이다.

profile
남들과 함께하기 위해서는 혼자 나아갈 수 있는 힘이 있어야 한다.

0개의 댓글