[GraphQL] SchemaLink 사용법 - 서버없는 클라이언트
GraphQL 서버 없이도 클라이언트에서 GraphQL API를 호출할 수 있도록 도와주는 Aollo Client의 SchemaLink
에 대해서 알아보겠습니다.
일반적인 Apollo Client 생성
일반적으로 Apollo Client를 사용할 때는 다음과 같이 GraphQL 서버로 HTTP 요청을 보내기 위해서 HttpLink
를 사용합니다.
import { ApolloClient } from "apollo-client";
import { HttpLink } from "apollo-link-http";
const client = new ApolloClient({
link: new HttpLink({ uri: "https://www.my-server.com/graphql" }),
// 다른 옵션
});
client.query(/*...생략... */);
이렇게 HttpLink
를 사용할 때는 반드시 연동할 GraphQL API의 endpoint를 가진 GraphQL Server가 어딘가에 떠 있어야 합니다.
Apollo Client를 이용해서 GraphQL API 호출하는 기본적인 방법은 아래 포스팅를 참고 바랍니다.
Apollo Link
Apollo Client에는 Network Layer를 담당하는 Apollo Link라고 불리는 중요한 개념이 있습니다.
이 Apollo Link를 통해 Apollo Client는 GraphQL 요청을 어떤 과정을 거처 어떤 방식으로 처리할지에 대해서 유연하게 제어가 가능하도록 설계되어 있습니다.
이것이 ApolloClient
생성자가 link
옵션을 통해 다른 Apollo Link 객체를 받을 수 있는 이유입니다.
예를 들어, 방금 살펴본 HttpLink
는 원격 GraphQL Server와 HTTP 프로토콜을 통해 데이터를 송수신하도록 구현된 Apollo Link입니다.
Apollo Client는 HTTP 프로토콜이 아닌 WebSocket을 통해서 GraphQL Server와 연동할 수 있도록 WebSocketLink
도 제공합니다.
또한, 이제부터 자세히 살펴볼 SchemaLink
는 GraphQL Server 없이도 GraphQL API를 호출이 가능하도록 구현되어 있습니다.
Schema Link
SchemaLink
는 원격 서버를 필요로 하는 HttpLink
나 WebSocketLink
와 달리 단지 GraphQL 스키마만 있으면 GraphQL API를 사용할 수 있게 해줍니다.
즉, 서버 단에 두었던 GraphQL 스키마를 클라이언트 단에 옮겨놓을 수만 있다면 굳이 서버가 없이도 클라이언트 앱 개발이 가능하다는 말입니다.
이러한 SchemaLink
의 특징은 클라이언트 단에서 서버를 모킹하거나 Server-sdie rendering을 구현하는데 유용하게 쓰입니다.
패키지 설치
프로젝트에 GraphQL과 Apollo Client 관련 패키지를 설치합니다.
이 중, apollo-link-link
패키지가 SchemaLink
를 제공하며, graphql-tools
는 스키마 생성을 위해 쓰이는 유틸리티 함수인 makeExecutableSchema()
를 제공합니다.
$ npm i apollo-client apollo-cache-inmemory apollo-link-schema graphql graphql-tag graphql-tools
- package.json
"dependencies": {
"apollo-cache-inmemory": "1.6.3",
"apollo-client": "2.6.4",
"apollo-link-schema": "1.2.3",
"graphql": "14.4.2",
"graphql-tag": "2.10.1",
"graphql-tools": "4.0.5"
}
패키지 임포트
Apollo Client를 사용하기 위해 기본적으로 필요한 ApolloClient
, InMemoryCache
, gql
을 임포트 합니다.
추가적으로 SchemaLink
를 사용하기 위해 SchemaLink
와 makeExecutableSchema
을 임포트해야 합니다.
import { ApolloClient } from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import { SchemaLink } from "apollo-link-schema";
import { makeExecutableSchema } from "graphql-tools";
import gql from "graphql-tag";
스키마 생성
GraphQL 스키마는 타입에 대한 정의(typeDefs)와 리졸버(resolvers)로 이루어집니다. 타입 정의는 GraphQL 쿼리 언어(GQL)을 통해 데이터의 형태를 나타내며, 리졸버는 그 데이터가 어떻게 만들어져야 하는지 함수로 구현합니다.
예를 들어, 간단하게 항상 "pong"
이라는 문자열 타입의 데이터를 리턴하는 ping
쿼리에 대한 스키마는 다음과 같이 작성할 수 있습니다.
const typeDefs = `
type Query {
ping: String!
}
`;
const resolvers = {
Query: {
ping: () => "pong",
},
};
const schema = makeExecutableSchema({ typeDefs, resolvers });
여기서, graphql-tools
패키지에서 임포트한 makeExecutableSchema()
함수에 타입 정의와 리졸버를 넘기면 스키마가 만들어집니다.
클라이언트 생성
이제 SchemaLink
를 사용해서 ApolloClient
를 생성할 차례입니다.
위에서 생성한 스키마를 SchemaLink()
생성자의 인자로 넘긴 후에, 생성된 SchemaLink
객체를 다시 ApolloClient()
생성자에 넘겨주면 됩니다.
캐시는 가장 범용적으로 쓰이는 InMemoryCache
를 사용합니다.
const client = new ApolloClient({
link: new SchemaLink({ schema }),
cache: new InMemoryCache(),
});
GraphQL API 호출
ApolloClient
의 query()
함수를 사용해서 위에서 정의한 ping
쿼리를 호출하면,
(async function () {
const { loading, error, data } = await client.query({
query: gql`
query {
ping
}
`,
});
console.log("loading:", loading);
console.log("error:", error);
console.log("data:", data);
})();
다음과 같이 원하는 문자열 타입의 "pong"
이라는 데이터가 리턴되는 것을 알 수 있습니다.
loadig: false
error: undefined
data: {ping: "pong"}
async/await
키워드에 대한 자세한 설명은 관련 포스팅을 참고 바랍니다.
전체 코드
마치면서
이상으로 SchemaLink
를 사용해서 서버없이 클라이언트 단에서 직접 GraphQL 스키마를 만든 후 GraphQL API를 호출하는 방법에 대해서 알아보았습니다.
SchemaLink
에 넘길 스키마를 만들 때, 클라이언트 단에서 직접 스키마 생성하지 않고, 원격 서버에서 스키마 정보만 얻어오거나 로컬에 저장해놓은 스키마 파일을 읽어올 수도 있습니다.
이렇게 SchemaLink
를 다양하게 생성하고 여기에 mock 데이터까지 추가할 수 있는데 이러한 방법에 대해서는 추후 포스팅하도록 하겠습니다.