[개념 설명] GraphQL

혜빈·2024년 8월 10일

보충내용

목록 보기
13/38

GraphQL VS RESTful API

  • RESTful API에서는 전송에 사용된 HTTP 메소드, URI를 통해 각 작업을 구분함
  • 이 방식은 요청의 내용을 직관적으로 알 수 있다는 장점이 있지만, 단점으로는 많은 엔드포인트를 관리해야한다는 점이 있음

엔드포인트

  • 특정 리소스나 서비스를 접근하기 위한 서버의 경로를 의미

  • GraphQL은 SOAP과 같이 하나의 엔드포인트를 사용하고, 일반적으로 모든 요청은 POST 메소드를 사용해서 실어보냄
POST  https://api.happybeenbooks.com/graphql
  • 이렇게 하면 API의 버전 관리가 보다 용이해짐

  • RESTful API는 '어느 책들'의 데이터에 대한 요청인지는 명확하게 나타낼 수 있지만
    각각에서 어떤 항목들을 받아올 것인지는 특정하지 못함

GET  https://api.happybeenbooks.com/v1/books
GET  https://api.happybeenbooks.com/v1/books/1
  • 클라이언트앱에서 책의 목록이 간략한 정보와 함께 나타난 화면을 보여주려면 서버로부터 각 책의 제목과 작가만 받아오면 되지만
    RESTful API의 규격대로 만든 API에서는 각 리소스의 모든 데이터가 반환됨

  • 때문에 필요 이상의 데이터가 전송되는 overfetching 문제가 발생함

  • 우리가 사용하는 각종 서비스들에는 이러한 요청과 응답들이 지속적으로 교환되기 때문에 그 과정에서 데이터 낭비, 오버헤드 발생할 수 있음

  • GraphQL에서는 POST 메소드로 이와 같은 요청을 실어보냄

// POST
query {
	books {
    	title
        author
    }
}
  • 책들의 제목과 저자 정보를 요청하면 아래와 같이 쿼리에서 요청한 데이터만 담고 그 외에는 포함되지 않음
{
	"data": {
    	"books": [
          {
          	"title": "Clean Code",
            "author": "been"
          },
          {
          	"title": "Good Code",
            "author": "happybeen"
          },
          {
          	"title": "Love Code",
            "author": "bini"
          }
        ]
    }
}
  • 이처럼 GraphQL에서는 클라이언트가 필요로 하는 정보만을 선택해서 서버에 요청할 수 있음

  • GraphQL로 해결할 수 있는 RESTful API의 또 다른 문제는 Underfetching임(요청을 여러번 보내야 하는 문제)

  • 각 책의 상세 화면에 독자의 리뷰, 닉네임이 나와있는 화면이 있다고 가정해보자
  • 이를 보여주기 위해서는 책의 정보와 그 책에 달린 리뷰들의 정보, 리뷰를 올린 사용자의 정보가 필요함
    (Book info, User info, Review info)
  • RESTful API에서는 이들을 각각 다른 요청을 통해 받아와야함
  1. 먼저 해당 책의 색인 정보를 담은 요청을 통해 해당 책의 정보들을 받아오고
GET https://api.happybeenbooks.com/v1/books/1
  1. 같은 색인 번호를 기준으로 책에 달린 리뷰들의 정보를 받아옴
GET https://api.happybeenbooks.com/v1/books/1/reviews
  1. 그에 포함된 사용자의 색인 번호를 통해 각 리뷰를 작성한 사용자들의 정보를 그 명수만큼 요청해서 받아와야 함
GET https://api.happybeenbooks.com/v1/users/1

GET https://api.happybeenbooks.com/v1/users/2
  • 이처럼 한 화면을 띄우기 위해 여러차례 요청을 보내야 하는 문제를 Underfetching이라고 함

  • RESTful API는 하나의 요청으로는 충분한 데이터를 받아오지 못하는 Underfetching 문제와
    각 요청들에서 필요 이상의 데이터까지 받아와지는 Overfetching 문제도 발생함

  • 하지만 이 과정을 GraphQL로는 이렇게 진행할 수 있음

query {
	book(id: "1") {
    	title
        author
        reviews {
        	comment
            rating
            user {
            	name
            }
        }
    }
}
  • 위 쿼리에는 앱 화면에 필요한 정보들이 계층적으로 나타나 있음
  • 색인번호가 1인 책의 제목, 저자, 해당 책의 리뷰 정보를 보내줄 것
  • 각 리뷰에는 comment와 별점, 이를 작성한 사용자의 정보를 보내줄 것
  • 그 사용자 정보에는 이름만 포함시킬 것을 요청함
{
	"data": {
    	"book": {
        	"title": "Clean Code",
            "author": "been",
            "reviews": [
              {
              	"coment": "This book is very good",
                "rating": 5,
                "user": {
                	"name": "Kim"
                }
              },
              {
              	"coment": "Excellent",
                "rating": 4,
                "user": {
                	"name": "Lee"
                }
            ]
        }
    }
}
  • 한 번의 요청으로 필요한 정보만 모두 받아오게 됨

책을 추가하는 요청

mutation {
	addBook(
    	title: "Effective JS",
      	author: "Jhon",
      	publishedDate: "2024-08-10",
      	isbn: "1234567890",
      	status: "available"
    ) {
    	id
        title
        author
        publishedDate
        isbn
        status
    }
}
  • 데이터의 조회 -> query

  • 데이터의 추가, 수정, 삭제 -> mutation

  • addBook이라고 이름지어진 작업에 추가될 데이터를 담고, 응답으로 받아오고자 하는 데이터도 명시하면 다음과 같은 응답을 받을 수 있음

{
   "data": {
      "addBook" : {
          "id": "123",
          "title" : "Effective JS",
          "author" : "Jhon",
          "publishedDate": "2024-08-10",
          "isbn": "1234567890",
          "status": "available"
  }
}

Subscription (구독)

  • GraphQL의 또 다른 요소
  • 책 정보 화면에서 새 리뷰가 달릴 때 실시간으로 감지해서 표시해야 한다고 가정해보기
  • RESTful API에서는 수시로 서버에 리뷰 목록을 받아오는 요청을 보내야 함
  • 하지만 GraphQL에서는 특정 리소스가 데이터에 업데이트 될 때마다 알림을 받을 수 있음
  • 해당 리소스에 대한 '구독'을 신청하는 것과 같음
subscription {
	reviewAdded(bookId: "1") {
    	comment
        rating
        user {
        	name
        }
    }
}
  • 색인번호가 1인 책에 관한 리뷰가 추가되면 해당 리뷰의 comment, rating, user에 대한 정보를 보내달라고 하는 것임
  • 누군가 리뷰를 추가하면 이와 같은 데이터가 바로 전송되고
    프론트엔드에서는 이에 반응하여, 반환된 결과로 업데이트한 화면을 보여줌
{
	"data": {
    	"reviewAdded": {
           "coment": "Excellent",
           "rating": 4,
           "user": {
               "name": "Lee"
          }
    	}
    }  
}
  • 이 과정은 웹 소켓을 통해서 이루어짐

구현 방법

  • Graph Query Language은 '질의를 하기 위한 언어'임
  • 이 언어로 작성된 메시지를 통해 서버 또는 클라이언트의 작업을 수행해주는 라이브러리 들이 있음
  • GraphQL 공식 사이트에서 언어, 환경마다 사용할 수 있는 GraphQL 라이브러리들을 확인할 수 있음

Schema (스키마)

  • Schema는 GraphQL을 사용하는 서비스에서 어떤 데이터들이 사용될 수 있고
    어떤 요청 및 구독이 전달 및 실행될 수 있는지 정의해둔 계획도임
type Book {
	id: ID!
  	title: String!
  	author: String!
  	PublishedDate: String!
  	isbn: String!
    status: String
    reviews: [Review]
}

type User {
	id: ID!
    name: String!
    email: String!
}
    
type Review {
	id: ID!
    bookId: ID!
    userId: ID!
    rating: Int!
    comment: String
    user: User
    book: Book
}
  • 이처럼 서비스에서 사용될 리소스들이 각각 타입으로 정의되고
    각 타입에는 어떤 데이터가 포함될 수 있는지 나와있음
  • 이들 중 어느 것을 받아올지 요청 메시지에 적어 명시하면 됨
  • 그리고 이들을 활용하여 어떤 Query, Mutation, Subscription을 구현할 수 있는지 아래와 같이 정의함
type Query {
	books(Status: String): [Book]
  	book(id: ID): Book
    users: [User]
  	user(id: ID!): User
}

type Mutation {
	addBook)
    	title: String!, author: String!, publishedDate: String!, isbn: String!, status: String): Book
        deleteBook(id: ID!): Book
    )
}
    
type Subscription {
	bookAdded: Book
    bookUpdate: Book
    bookDeleted: ID
}
  • 위 코드는 각 작업들을 선언만 해둔 것이고
    이를 구현하는 코드는 사용 언어, 환경, GraphQL 라이브러리에 따라 작성하면 됨

궁금한 점 : 느낌표는 뭘까?

  • GraphQL에서 타입 뒤에 붙은 느낌표(!)는 해당 필드가 널이 될 수 없음을 나타냄
  • 즉, 이 필드는 항상 값을 가져야 하며 null일 수 없다는 의미임
  • 만약 필드가 느낌표로 표시되어 있다면, 서버는 그 필드에 대해 항상 값을 반환할 것을 보장하며, 값이 없을 경우 에러가 발생함

GraphQL의 단점

1. Caching의 어려움

  • 요청들이 복잡한 GraphQL 메시지로 되어있기 때문에
    이를 기준으로 캐싱을 하기가 어려움

2. 성능문제

  • 복잡한 쿼리를 해석해서 작업들을 실행하기 때문에
    RESTful API에 비해 서버에 부담을 줄 수 있음

3. 학습곡선

  • RESTful API에 비해 배우기 어렵게 느껴짐(진입장벽 높음)

적합한 서비스

  1. 복잡하고 방대한 데이터 모델을 가진 서비스
  • Overfetching과 Underfetching으로 발생하는 오버헤드가 큰 서비스들에는 GraphQL을 사용하는 것이 성능에 유리함
  1. 클라이언트가 데이터 요청이 많은 제어권을 가진 서비스들
  1. 데이터의 업데이트에 대한 실시간 반응이 필요한 서비스
  • GraphQL의 구독을 활용하면 따로 기능을 구현할 필요 없이 실시간으로 최신 정보를 나타낼 수 있기 때문임
profile
최강 개발자를 꿈꾸는 병아리

0개의 댓글