GraphQL - 1

doodream·2022년 2월 5일
0

GraphQL

목록 보기
2/5
post-thumbnail

GraphQL 이란?

그에 앞서서 REST-ful Routing 이라는 개념을 살펴보면
REST-ful Routing 이란 URL과 HTTP 요청 메소드를 이용해서 서버에서 제공되는 데이터 모음들을 사용하게 하는 데이터 모음집 입니다. 이는 HTTP 요청을 사용하는 상황에서 가장 일반적인 방법입니다.

쉽게 설명하자면 REST-ful API와 관련된 정보들을 모아놓은 모음집이라고 이해하면 편할 것 같습니다. 하지만 일정한 규칙이 정해진 HTTP 요청 메소드들 (REST-ful API → 리소스가 표현되는 규칙을 )들의 경우 여러 데이터들이 중첩되거나 관련성이 높은데이터들에 대한 요청을 보내려고 할때 만들어지는 URL을 생각해보면 매우 복잡해집니다.

아래와 같은 예를 살펴봅시다.



각 데이터 테이블의 관계성에 따른 REST 규칙으로 url 을 형성하려고 해보면 Current User 부터 Friend 까지는 잘 형성되는 것을 볼수 있습니다.
하지만 더 나아가 그 하위 단계의 url은 어떻게 이름을 지어야 할까?

`/users/${id}/friends/companies`
`/users/${id}/friends/positions`

데이터의 끝에 얻는 데이터의 이름마다 다른 Url을 생성 해야하는 번거로움이 생깁니다..
또한 이렇게 되면 HTTP 요청이 더 많아지게 됩니다.

GraphQL 쿼리

query {
	user(id: "23"){
    	friends{
        company{
        	name
        }
    }
}

위 코드는 그래프 큐엘의 쿼리문 입니다.
가장 아래의 데이터를 보면 결국 회사의 이름을 가져오는 것을 알 수 있는데, 이는 위에서 보여준 restful url 과 대응 되는 규칙으로 만들어진 쿼리문입니다.
데이터를 그래프 방식으로 연결지으면서 쿼리문을 생성해서 데이터를 가져오는 문법을 만든 것 입니다.
이러한 쿼리문을 만듬으로서 새로운 엔드포인트를 생성할 필요가 없습니다.

GraphQL의 작동방식

위 사진은 전체적인 그래프 큐엘의 모습입니다. 프론트엔드에서 쿼리문을 백엔드 서버에 보내면 이와 연동해있는 데이터 베이스에서 데이터를 가공하여 데이터를 보내는 형태 입니다.
실습을 통해서 배우는 단계이기에 백엔드를 node expressjs를 사용해 구축하는 단계에서 표현한 것이지만 어느 백엔드단이나 이해하는 환경은 같습니다. 백엔드안에서 graphql이 동작하고 grapql 요청이면 graphql에서 처리하고 아니면 다른 요청으로 판단해 처리해서 response를 만들어 통신하는 환경은 같습니다.


그래프 큐엘의 장점은 뿐만 아닙니다. Facebook이나 다른 거대한 사이트인 경우 하나의 데이터베이스만을 가지고 있지 않습니다. 이렇게 다양한 데이터 베이스에 접근을 할때 자체 데이터베이스가 있는 외부 서버의 API와 HTTP 통신을 통한 데이터 연계가 가능합니다.

express 에서 동작하는 graphQL의 형태

server.js

const express = require("express");
const { graphqlHTTP } = require("express-graphql");
const app = express();

app.use("/graphql", graphqlHTTP({ graphiql: true }));
app.listen(4000, () => {
  console.log("listening...");
});

위 코드로 가장 기본적인 서버를 생성하고 /graphql 로 들어오는 요청은 그래프 큐엘로 처리한다고 했을때에 node server.js 명령어로 서버를 작동시키고 /localhost:4000/graphql url로 접속을 한다면

위와 같은 에러메세지가 나옵니다. 그래프 큐엘의 미들웨어에 스키마가 없다는 것인데 스키마가 무엇일까요?

스키마
스키마란 데이터베이스에서 다루고 있는 데이터들과의 관계를 정의한 파일입니다. 그래프 큐엘에서는 이 스키마 파일을 통해서 데이터들의 유형과 관계를 파악하게 됩니다.

위 데이터 관계도를 스키마로 표현해봅시다.

먼저 스키마는 그래프 큐엘에서 데이터들의 유형과 관계를 파악한다고 했습니다. 그렇다면 그래프 큐엘이 데이터에 진입하는 진입점또한 데이터의 관계를 이루고 있을텐데 이러한 진입점을 Root Query라고 합니다.

const graphql = require("graphql");
const _ = require("lodash");
const { GraphQLObjectType, GraphQLString, GraphQLInt, GraphQLSchema } = graphql;

const users = [
  { id: "23", firstName: "doodream", age: 29 },
  { id: "17", firstName: "uni", age: 26 },
];

const UserType = new GraphQLObjectType({
  name: "User",
  fields: {
    id: { type: GraphQLString },
    firstName: { type: GraphQLString },
    age: { type: GraphQLInt },
  },
});

const RootQuery = new GraphQLObjectType({
  name: "RootQueryType",
  fields: {
    user: {
      type: UserType,
      args: { id: { type: GraphQLString } },
      resolve(parentValue, args) {
        return _.find(users, { id: args.id });
        // lodash 문법 : users 에서 id가 args.id 인 사용자를 반환
      },
    },
  },
});

module.exports = new GraphQLSchema({ query: RootQuery });
// 쿼리를 루트 쿼리로 받아서 그래프 큐엘 스키마 객체로 반환합니다. 

UserType 이라는 이름으로 그래프 큐엘 객체타입을 정의 합니다. 해당 객체타입의 이름은 User 이 되며 해당 데이터의 속성 값들을 정의 할때 field 라는 프로퍼티 객체를 정의해서 그안에 속성값들을 type 을 정의하며 채워넣습니다.

중요한 것은 RootQuery 입니다. 이부분은 쿼리의 진입점으로서의 역할을 합니다. args 속성은 인수를 나타내며 resolve 라는 것은 데이터에 접근해서 데이터를 반환하는 핵심적인 역할을 하는 함수가 됩니다.

이후 그래프 큐엘 객체로 반환해서 server.js 파일에 불러옵니다.

위 코드에서 스키마로 그래프 큐엘 객체를 불러와서 app의 미들웨어인 그래프 큐엘 HTTP 함수안에 스키마로 넣습니다.

이제 서버를 재실행시키면
node server.js

위 모습을 볼수 있게 됩니다. 위 화면은 그래프 큐엘에 쿼리를 보낼때 스키마를 기반으로 데이터들의 문서를 미리보여주면서 쿼리에 자동완성까지 제공해주는 툴입니다. 심지어는 쿼리문의 문법요소 까지 감지해서 알려줍니다.

여기서 말하는 Name 이란 인수의 이름을 의미 합니다.

Query

쿼리문을 작성한후 재생버튼을 누르면 됩니다.
쿼리문

{
  user(id: "23"){
    firstName,
    age,
    id
  }
}

위 쿼리문은 그래프 큐엘에서 제공하는 그래프큐엘 문법입니다. 간단한 쿼리문을 작성하는 독립적인 언어입니다. 자바스크립트나 파이썬같은 언어와는 다릅니다. 그래프 큐엘만의 언어입니다. 이렇게 서버로 부터 받은 JSON 파일의 구조와 상당히 흡사한 구조입니다. 중요한 점은 이러한 쿼리를 여러가지로 바꿈으로서 반환받는 데이터 모양을 원하는대로 바꿀 수 있습니다.

{
  user(id: "47"){
    id
  }
}

이러한 점에서 RESTful API의 단점을 극복하는 부분이 보입니다. 특정한 데이터를 사용하기 위해서 다른 데이터까지 오버해서 불러오지 않아도 됩니다. 딱, 사용할 데이터만 요청할 수 있습니다.

외부 DB와 연동하기

아주 간단하게 DB를 구성하는 방법에 대해 알아봅시다.
json-server

사용방법에 대해 알아보자면 아주 간단합니다. 프로젝트에 패키지 하나를 설치해줍니다.
npm install --save json-server
이후 루트 디렉토리에 db.json 파일을 생성해주고 안에 JSON 형태의 데이터를 쌓아둡니다.

같은 호스팅방법으로 같은 프로젝트 안에서 작동하게 되는 db 이지만 외부 DB 처럼 만들 수 있습니다. mysql을 이용한 외부 서버 구축방법이 있지만 해당 방법은 추후에 연동해보기로 합니다.


이후 package.json 파일에서 스크립트 명령어를 추가해줍니다.

터미널을 두개를 만들어서 db를 따로 실행시켜줍니다.
npm run json:server

결론적으로 우리가 만들 간단한 앱의 구조는 다음과 같습니다.

express 서버 내부의 GraphQL 에서 JSON 서버(외부 DB서버) 와 비동기 통신(HTTP)를 하면서 데이터를 주고 받아 response를 만들어 클라이언트에 반환하는 방식입니다.
실제 graphql과 외부서버가 비동기 통신을 하는 단계는 이 부분입니다.
server.js

const graphql = require("graphql");
const axios = require("axios");
const { GraphQLObjectType, GraphQLString, GraphQLInt, GraphQLSchema } = graphql;

const UserType = new GraphQLObjectType({
  name: "User",
  fields: {
    id: { type: GraphQLString },
    firstName: { type: GraphQLString },
    age: { type: GraphQLInt },
  },
});

const RootQuery = new GraphQLObjectType({
  name: "RootQueryType",
  fields: {
    user: {
      type: UserType,
      args: { id: { type: GraphQLString } },
      resolve(parentValue, args) {
        // DB와 json API 통신을 하며 데이터를 가져오는 모습
        const data = axios
          .get(`http://localhost:3000/users/${args.id}`)
          .then((res) => res.data);
        return data;
      },
    },
  },
});

module.exports = new GraphQLSchema({ query: RootQuery });
// 쿼리를 루트 쿼리로 받아서 그래프 큐엘 스키마 객체로 반환합니다.

다음 블로깅

다음 블로깅에서는 우리가 예시로 들었던 데이터 베이스의 관계도를 바탕으로 데이터베이스에 데이터를 구축하고 클라이언트에서 graphQL을 이용해서 데이터를 fetching 하는 주제에 대해서 포스팅하겠습니다.

profile
일상을 기록하는 삶을 사는 개발자 ✒️ #front_end 💻

0개의 댓글