티스토리 뷰

Skill

[GraphQL] - GraphQL 개념과 특징

영지는 달리는중 2021. 6. 16. 10:28

GraphQL 이란 ? 

  • 페이스북에서 개발하여 발표한  "API를 위한 쿼리 언어"

→ GraphQL은 API에  있는 데이터에 대해서 이해하기 쉬운 설명을 제공하고 클라이언트에게 필요한 것을 정확하게 요청할 수 있는 기능을 제공한다 

핵심 : 클라이언트가 직접 어떤데이터가 필요한지 명시할  수 있도록 한다 

 


탄생 배경 (REST API 와 비교)

 

  • OverFetching

기존의 REST API를  사용할  경우 클라이언트는 불필요한 정보를 전달받는 문제점이 있었다.

가령 MemberList 중 id 만을 필요로 한다면 API를 새로 생성하거나 List를 받은 후 2차 가공을 해야하는 불필요한 작업 시간이 낭비되었다.

graphQL은 클라이언트 측에서 받고싶은 데이터만을 정의하므로 이러한 OverFetching 문제를 해결할 수 있다.

 

  • UnderFetching

다른 두개의 정보가 필요한 경우 → REST API의 경우에는 필요한 데이터를 만들기 위해 여러번의 API 호출 + 추가적인 가공 작업이 발생한다.

하지만 graphQL을 사용하게 된다면 쿼리문을 통해 한번의 호출로 원하는 데이터를 얻을 수 있게된다. 

 

  • EndPoint

REST API는 각 API마다 다른 엔드포인트가 존재했다. 만약 엔드포인트가 수십 수백개가 된다면 이를 관리하는 것은 매우 어려울 것이다.

graphQL은 /graphql이라는 하나의 엔드포인트로 모든 쿼리문 요청 받기 때문에 관리가 용이하며 주소가 심플해진다. 

→ default  endpoint : /graphql (설정파일을 사용하여 커스터마이징 가능)

 


GraphQL을 사용 중인 기업(이외에도 수많은 곳에서 사용중이다. )

출처 : GraphQL 한국 공식 홈페이지

 


GraphQL의  핵심 요소 

 

1. 스키마 

  • 데이터  타입의 집합

API 문서와 같은 역할을 하며 리턴 타입 인풋 타입 정의, 조회를 위한 루트  쿼리에 대한 정의  마지막으로 등록, 수정, 삭제를 위한 루트 뮤테이션에 대한 정의를 나타낸다.

또한 어플리케이션 시작시 스키마에 정의된 내용들을 SpringBoot의 각 필드와 메소드에 매핑을 시켜주는 역할을 한다. → DataFetcher 내부로직의 실행  

예를 들면 우선 아래처럼 스키마 파일을 .graphqls 라는 확장자로 작성한다.

# GraphQL Schema 정의
 
input Cat {
    id: ID!
    name: String!
    owner: String!
}
 
type Post {
    id: ID!
    title: String!
    text: String!
    category: String
    author: Author!
}
  
type Author {
    id: ID!
    name: String!
    posts: [Post]!
}
  
# 루트 쿼리 (Root Query)
type Query {
    recentPosts(count: Int, offset: Int): [Post]!
    findOwner(cat: Cat): String
}
  
# 루트 뮤테이션 (Root Mutation)
type Mutation {
    writePost(title: String!, text: String!, category: String) : Post!
}

이 스키마 파일에는 질의문에 사용될 Cat, Post, Author 이름의 Input, Type형 자료, Query, Mutation  내에 사용할 질의문이 정의돼있다. (Query, Mutation도 type으로 정의돼있지만 쿼리문을 정의하기 위한 것이다. 쿼리문을 보내기 위해선  반드시 "Query", "Mutation" 이름을 가진 type이 있어야 한다.)

이렇게 정의된 내용들을 처리하는 방법은 사용할 의존성(라이브러리)에 따라 조금씩 다르지만 공통적으로 아래처럼 매핑된다.

  •  input, type형 → 인자, 반환 타입에 사용되는 객체와 해당 객체 내 필드
  •  쿼리, 뮤테이션 →  질의문에 해당하는 메서드(인자, 반환 타입이 어떤 것인지)

 

이 때 질의문에 해당하는 메서드를 Resolver로 처리한 예시를 통해 보면 아래와 같다.

@Component
@RequiredArgsConstructor
public class RootQueryResolver implements GraphQLQueryResolver {
    private final PostRepository postRepository;


    public List<PostResponse> getRecentPosts(int count, int offset) {
        final List<Post> all = postRepository.findAll();
        return PostResponse.from(all);
    }
     
    public String findOwner(Cat cat){
        return "Mike Lee";
    }
}

이 Resolver는 Query질의문만 처리하는데, 내부 메서드를 보면 스키마에서 정의한 질의문과 동일한 이름, 인자형과 이름, 반환형을 가진 recentPosts, findOwner 메서드가 있다.

스키마에서 정의한 Query의 recentPosts필드는 getRecentPosts()메소드가 처리하게 된다.

메소드의 이름의 명명규칙은 다음과 같고, 해당 규칙에 따라 매핑되는 것이다. (스키마에 정의된 질의문들도 Query, Mutation타입내에 있어 필드로 분류된다.)

  1. <필드명>
  2. is<필드명> - (필드 반환 타입이 boolean 인 경우)
  3. get<필드명>

 

2. Resolver 인터페이스

  • 실제 데이터를 조회 & 가공하는 비즈니스 로직을 수행하는 부분

클라이언트로부터 요청된 쿼리 혹은 뮤테이션에 대하여 반환할  결과를 생성하는 로직을 구현한 부분으로 GraphQL의  서버가 Resolver 구현체를 찾아 쿼리와 뮤테이션에 해당하는 함수로 진입하여 수행하게 된다.

 

graphQL은 세가지 Resolver  인터페이스를  제공하며 아래와 같다 

Interfacedescription

GraphQLResolver<T> query, mutation 로직 구현
→ 스키마의 input 타입에 대하여  보다 정교한 작업이 필요할 때 사용
GraphQLMutationResolver mutation 로직 구현
GraphQLQueryResolver query 로직 구현

 

 

3. DataFetcher

  • 스키마에 정의된 필드를 데이터베이스의 필드와 매핑하여 실제로 값을 사용할 수 있도록 작업을 수행하는 부분

스키마에 정의된 이름을 바탕으로 데이터베이스의 테이블 필드와 매핑되어 내부로직이 수행되고 Resolver에서 데이터를 사용할 수 있게 된다.

 


 

GraphQl의 작업 종류 - 2가지

 

1. Query 

  • 데이터베이스로부터 데이터를 얻어오기 위해 사용하는 것으로 

type Query {

         쿼리명  : 반환 타입 (!)

}

의 형태로 선언한다. 조회 기능을 수행하는 쿼리라고 보면 된다.

# 스키마 정의 - 루트 쿼리 (Root Query)
type Query {
    recentPosts(count: Int, offset: Int): [Post]!
}


# FE에서의 쿼리문 요청
Query {
    recentPosts(count : 1, offset : 3) {
        title
        text
    }
}

2. Mutation

  • 서버, 데이터베이스 혹은 메모리에서 데이터를 변경할 때 사용하며

type Mutation  {

       쿼리명(인자명 : 인자타입) : 반환 타입 (!)

}

의 형태로 선언한다. CRUD 중 CUD 요청을 담당한다고 보면 된다. 

# 스키마 정의 - 루트 뮤테이션 (Root Mutation)
type Mutation {
    writePost(title: String!, text: String!, category: String) : Post!
}


# FE에서의 쿼리문 요청
Mutation {
    writePost(title : "title", text: "text", category  : "A") {
        id
        title
        text
        category
        author
    }
}

 참고 블로그(1) 참고 블로그(2) 참고 블로그(3)  

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함