이 포스팅은 기존의 GraphQL-Yoga 에서 탈피하여
GraphQL, Express, Apollo 를 활용하여 서버 구성을 했던 과정을 기록한 요약한것이다.
# GraphQL-Yoga
GraphQL 을 처음 배웠을때는, graphql-yoga 를 이용해서 배웠었다.
yoga 는 서버 환경 설정시에 겪게 되는 여러 오류 사항에서 벗어나
편하게 프로그래밍 할 수 있는 환경을 제공해줬다.
그러나, 왜 그런지는 모르겠지만,
꽤 오랜 시간 yoga 패키지에 대한 업데이트가 없었고,
yoga 로 만든 프로젝트를 깃헙에 올리면 패키지 보안 취약성 오류를 내고 있었다.
그리고 단순히 npm audit fix 로는 yoga 패키지 자체가 가지고 있는
여러 의존 패키지들에 대한 보안 취약성 문제를 처리 할 수 없었다.
yoga 패키지 자체를 수정해야 했고, 그렇게 하는것 보단 yoga 대신에 직접 서버를 구축하는게 낫다고 생각했다.
# 패키지 탐색
1. Apollo
Apollo 는 GraphQL 기반의 플랫폼으로, 위 그림에서도 볼 수 있듯, 웹 뿐 아니라, 다양한 클라이언트 환경에 맞는 플랫폼을 제공하며, GraphQL 서버를 구축함에 있어서 꼭 필요한 요소이다.
Apollo 의 최대 장점은 기존의 Redux 방식보다 SSR 을 간소화 했다는 점이다.
(참조 : d2.naver.com/helloworld/2838729)
가장 먼저 해야할일은 apollo server 를 구축해야 했다.
그래서 apollo-server 패키지를 설치해줘야하고,
나는 Express 를 기반으로 할 것이기 때문에
apollo-server-express 를 설치했다.
npm install apollo-server-express
|
cs |
(github.com/apollographql/apollo-server 를 보면 Express 대신에 다른 패키지도 여러개 존재한다.)
설치 후에, 가장 기본적인 객체 생성은 다음과 같이하고,
schema 와 resolver 값은 필수로 객체 안에 들어가야 한다.
- server.js
import { ApolloServer, gql } from "apollo-server-express";
const typeDefs = gql`
type Query {
test: String
}
`;
const resolvers = gql`
Query: {
test: () => "good",
}
`;
const server = new ApolloServer({
typeDefs,
resolvers,
});
server.listen().then(({url}) => {
console.log(`server listening : ${url}`);
})
|
cs |
그러나 이렇게 작성하면, 리졸버와 스키마의 양이 많아지면 가독성이 상당히 떨어진다.
그래서, @graphql-tools 를 사용해서 리졸버와 스키마 파일을 한꺼번에 묶어서 처리하려 했다.
먼저, 관련 패키지들을 설치한다.
npm install @graphql-tools/schema @graphql-tools/merge @graphql-tools/load-files
|
cs |
그 후, schema.js 파일을 작성하고 아래와 같이 코드를 작성했다.
- schema.js
import path from "path";
import { makeExecutableSchema } from "@graphql-tools/schema";
import { mergeTypeDefs, mergeResolvers } from "@graphql-tools/merge";
import { loadFilesSync } from "@graphql-tools/load-files";
const allTypes = loadFilesSync(path.join(__dirname, "api/**/*.graphql"));
const allResolvers = loadFilesSync(path.join(__dirname, "api/**/*.js"));
const schema = makeExecutableSchema({
typeDefs: mergeTypeDefs(allTypes),
resolvers: mergeResolvers(allResolvers),
});
export default schema;
|
cs |
@graphql-tools/schema 는 스키마와 리졸버를 한번에 묶어서 하나의 스키마로 처리하기 위한 패키지이고,
@graphql-tools/merge 는 리졸버와 스키마 각각 파일을 묶어서 통합하기 위한 패키지이며,
@graphql-tools/load-files 는 파일 로딩을 위한 패키지이다.
이렇게 작성하게되면,
"앞으로 모든 스키마와 리졸버 파일을 api 폴더 내에만 작성해야 한다."
(이 경로를 벗어나면 파일을 찾지 못하게 되어서 null 로 리턴된다)
기존 server.js 코드에 있는 리졸버와 스키마 코드를 걷어내고 schema.js 를 불러와서 처리한다.
- server.js
import { ApolloServer } from "apollo-server-express";
import schema from "./schema";
const server = new ApolloServer({
schema,
});
server.listen().then(({url}) => {
console.log(`server listening : ${url}`);
})
|
cs |
2. Express
이전까지는 스키마와 리졸버에 대한 처리를 담당하는 서버를 구성했을뿐
완전한 백엔드 서버를 구성하지는 못했다.
그래서 express 와 관련된 여러 패키지들을 설치해주었다.
npm install express helmet body-parser morgan graphql graphql-playground-middleware-express
|
cs |
그리고 나서 server.js 를 다음과 같이 수정했다.
- server.js
import dotenv from "dotenv";
dotenv.config();
import express from "express";
import bodyParser from "body-parser";
import helmet from "helmet";
import expressPlayground from "graphql-playground-middleware-express";
import { ApolloServer } from "apollo-server-express";
import morgan from "morgan";
import schema from "./schema";
const PORT = process.env.PORT;
const server = new ApolloServer({
schema,
});
const app = express();
app.use(helmet());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(morgan("dev"));
app.get("/", expressPlayground({ endpoint: "/graphql" }));
server.applyMiddleware({ app });
const handleListening = () => {
console.log(`Server ready at http://localhost:${PORT}`);
};
app.listen(PORT, handleListening);
|
cs |
graphql-playground-middleware-express 는
express 환경에서 GraphQL Playground 를 사용하기 위해 필요한 패키지 이다.
그러나 이대로만 코드를 짜서 실행하면
content security policy 에 의해 실행이 되지 않을 것이다.
그래서 이에 대한 해결책으로
helmet-csp 패키지를 설치하여
npm install helmet-csp
|
cs |
다음과 같은 코드를 server.js 에 추가해줬다.
import csp from "helmet-csp";
app.use(
csp({
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
styleSrcElem: [
"'self'",
"fonts.googleapis.com",
"cdn.jsdelivr.net",
"'unsafe-inline'",
],
imgSrc: ["'self'", "cdn.jsdelivr.net"],
scriptSrcElem: ["'self'", "cdn.jsdelivr.net", "'unsafe-inline'"],
fontSrc: ["'self'", "'unsafe-inline'", "fonts.gstatic.com"],
},
})
);
|
cs |
이후 서버를 실행시키면
아래 그림처럼 정상적으로 Playground 가 나오게 되었다.
- References
1. d2.naver.com/helloworld/2838729
2. github.com/apollographql/apollo-server
3. github.com/prisma-labs/graphql-playground
'JS' 카테고리의 다른 글
schema.prisma 정리 (0) | 2020.09.10 |
---|---|
prisma 2 query 문제 (0) | 2020.09.09 |
webpack (1) (0) | 2020.09.06 |
Prisma Migration 관련 오류 (0) | 2020.09.03 |
Prisma 란? (0) | 2020.08.30 |