FE/Angular

[Angular] GraphQL과 gql을 사용한 서버 요청

monkeykim 2024. 11. 12. 02:01

GraphQL의 개념부터 gql 태그를 사용해 클라이언트에서 서버로 데이터를 요청하는 방식까지 단계별로 한번 알아보겠습니다.


1. GraphQL이란?

GraphQL은 페이스북에서 개발한 데이터 질의 언어로, 클라이언트가 필요한 데이터의 형태를 지정하여 서버로 요청하고 원하는 응답을 받을 수 있게 합니다. GraphQL은 주로 REST API의 단점을 해결하기 위해 만들어졌습니다. 기존 REST API와 달리, 클라이언트는 한 번의 요청으로 필요한 데이터만 선택해서 가져올 수 있어 데이터 효율성을 크게 높일 수 있습니다.

GraphQL의 주요 개념

  • Query: 클라이언트가 서버에 데이터를 요청하는 방식입니다. 필요한 데이터의 필드만 선택해서 요청할 수 있습니다.
  • Mutation: 서버의 데이터를 변경하기 위한 요청입니다. 데이터를 생성하거나 수정, 삭제할 때 사용됩니다.
  • Schema: 서버가 제공하는 데이터의 구조와 규칙을 정의하는 곳입니다. 어떤 필드가 있고, 각 필드의 데이터 타입이 무엇인지를 정의합니다.

2. gql 태그란 무엇인가?

gql 태그는 GraphQL의 쿼리나 뮤테이션을 JavaScript/TypeScript 코드 안에 작성할 수 있도록 해주는 템플릿 리터럴 태그입니다. 이를 사용해 Apollo Client와 같은 GraphQL 클라이언트가 서버에 요청할 쿼리의 구조를 인식할 수 있도록 합니다.

gql 태그의 역할

gql은 쿼리나 뮤테이션을 서버 요청의 템플릿처럼 정의합니다. 이 템플릿은 서버에 어떤 요청을 보낼지, 또 어떤 데이터를 응답으로 받을지 명시합니다. 이를 통해 클라이언트는 서버에 전송할 데이터를 명확하게 지정할 수 있습니다.


예를 들어, 특정 데이터를 서버에 요청하기 위한 쿼리를 gql로 정의해보겠습니다.

import { gql } from '@apollo/client';

const MY_QUERY = gql`
  query {
    books {
      title
      author
    }
  }
`;

여기서 gql 태그는 서버에 요청할 쿼리의 형식을 정의한 것입니다. MY_QUERY는 클라이언트가 서버에 books 데이터를 요청하고, 각 책의 title과 author만 반환받겠다는 의미입니다. 이 방식으로 필요한 필드만 요청하여, 불필요한 데이터를 줄이고 네트워크 효율성을 높일 수 있습니다.


4. gql을 사용하는 이유

gql을 사용하면 클라이언트는 다음과 같은 이점을 얻을 수 있습니다.

  • 직관적인 요청: REST API처럼 여러 엔드포인트를 거치지 않고, 하나의 쿼리로 필요한 데이터만 명확하게 정의할 수 있습니다.
  • 데이터 절약: 원하는 데이터 필드만 요청하므로, 서버와 클라이언트 간의 데이터 전송량이 줄어듭니다.
  • 유형 검사: GraphQL 클라이언트는 스키마와의 일치 여부를 확인하므로, 잘못된 요청에 대해 컴파일 단계에서 오류를 알려줍니다.

5. 클라이언트에서 서버로 요청 보내기

이제 실제 클라이언트 코드에서 gql 태그로 요청을 작성하고 서버로 요청을 보내는 방식에 대해 알아보겠습니다.

Apollo Client를 사용한 요청 흐름

  1. 뮤테이션 작성: 서버에 전송할 뮤테이션을 gql로 정의합니다.
  2. Apollo Client 인스턴스 생성: Apollo Client를 사용해 서버와의 연결을 설정합니다.
  3. 서버 요청 전송: gql로 정의한 뮤테이션을 통해 서버에 데이터를 요청하거나 전달합니다.

예제 코드 (뮤테이션 예시)

다음 코드는 클라이언트에서 서버로 데이터를 전달하는 뮤테이션을 gql로 정의하고, Apollo Client로 요청을 전송하는 예시입니다.

import { Injectable } from '@angular/core';
import { Apollo } from 'apollo-angular';
import { gql } from '@apollo/client';
import { firstValueFrom } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class MyService {
  constructor(private apollo: Apollo) {}

  async updateData(input: any): Promise<any> {
    const mutation = gql`
      mutation UpdateData($input: MyInputType!) {
        updateData(input: $input) {
          success
          message
        }
      }
    `;

    return await firstValueFrom(
      this.apollo.mutate({
        mutation,
        variables: { input }
      })
    );
  }
}

코드 설명

  1. 뮤테이션 정의: gql을 사용하여 mutation UpdateData라는 뮤테이션을 정의합니다. 이 뮤테이션은 input이라는 매개변수를 받아 서버에 전달하고, 그 결과로 success와 message를 포함한 응답을 받도록 합니다.
  2. Apollo Client로 요청 전송: apollo.mutate() 메서드를 통해 서버에 요청을 전송합니다. 이때 variables 객체로 input 데이터를 서버에 전달합니다.
  3. firstValueFrom으로 Observable을 Promise로 변환: apollo.mutate()는 기본적으로 Observable을 반환합니다. firstValueFrom을 사용해 이를 Promise로 변환하여 비동기 방식으로 처리합니다.

6. 서버에서 클라이언트의 요청 처리

서버는 클라이언트가 보낸 쿼리나 뮤테이션 요청을 스키마와 비교하여 일치 여부를 검사합니다. 요청이 스키마와 일치하지 않거나 필요한 필드가 누락된 경우 서버는 오류 메시지를 반환합니다.

서버의 주요 역할

  • 필드 일치 검사: 클라이언트가 요청한 필드가 서버 스키마와 일치하지 않으면 오류를 반환합니다.
  • 필수 매개변수 확인: 클라이언트에서 정의한 매개변수 이름과 서버의 스키마가 일치하지 않으면 오류가 발생합니다.

서버는 스키마에 정의된 대로만 요청을 수락하므로, 클라이언트는 서버 스키마에 맞는 요청을 보내야 합니다.


요약

  1. GraphQL과 gql의 목적: 클라이언트가 원하는 데이터를 명확히 정의하고, 필요한 데이터만 가져옴으로써 효율적인 데이터 요청이 가능합니다.
  2. Apollo Client를 통한 요청 처리: gql로 정의된 뮤테이션이나 쿼리를 사용해 Apollo Client가 서버에 데이터를 요청하고 응답을 받습니다.
  3. 에러 방지: gql 태그를 사용해 서버 스키마에 맞는 형식으로 요청을 정의함으로써, 일치하지 않는 매개변수나 필드로 인해 발생할 수 있는 오류를 줄일 수 있습니다.