2. Apollo Server Express Setup
2020-09-24
Apollo Server는 모든 GraphQL 클라이언트와 호환되는 GraphQL 서버다.
yarn add express apollo-server-express graphql type-graphql
yarn add -D @types/express
컴파일 타임에 데코레이터에 메타데이타를 전달하기 위해 reflect-metadata를 설치한다.
yarn add reflect-metadata
types.ts
import { EntityManager, IDatabaseDriver, Connection } from "@mikro-orm/core";
export type MyContext = {
em: EntityManager<any> & EntityManager<IDatabaseDriver<Connection>>;
};
Entity Manger의 타입인 MyContext를 정의한다.
@Ctx() { em }: MyContext
resolver의 context를 decorate할 때 em의 타입을 알려준다.
resolvers/post.ts
import { MyContext } from "../types";
import { Arg, Ctx, Mutation, Query, Resolver } from "type-graphql";
import { Post } from "../entities/Post";
@Resolver()
export class PostResolver {
@Mutation(() => Post)
async createPost(
@Arg("title") title: string,
@Ctx() { em }: MyContext
): Promise<Post> {
const post = em.create(Post, { title });
await em.persistAndFlush(post);
return post;
}
}
index.ts
import "reflect-metadata";
import express from "express";
import { ApolloServer } from "apollo-server-express";
import { buildSchema } from "type-graphql";
import { PostResolver } from "./resolvers/post";
const main = async () => {
const app = express();
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [PostResolver],
validate: false,
/*buildSchema의 validate를 false로 할 시
자동 validation과 기본 구성 개체 전달을
사용하지 않는다.*/
}),
// req, res는 나중에 사용한다. 미리 추가해두자.
context: ({ req, res }): MyContext => ({ em: orm.em, req, res }),
/*
context 인수는 인증(authentication scope), 데이터베이스 연결,
사용자 정의 가져오기(custom fetch) 기능 등과 같이
resolver가 필요로 하는 항목을 전달할 때 유용하다
*/
});
apolloServer.applyMiddleware({ app });
app.listen(4000, () => {
console.log("server started on localhost:4000");
});
};
context로 mikro-orm의 orm.em(entity manager)을 resolver에게 넘기고,
post.ts에서 em.create()로 post를 create한다.
resolvers/post.ts
@Resolver()
export class PostResolver {
@Query(() => [Post])
posts(@Ctx() { em }: MyContext): Promise<Post[]> {
return em.find(Post, {});
}
@Query(() => Post, { nullable: true })
post(@Arg("id") id: number, @Ctx() { em }: MyContext): Promise<Post | null> {
return em.findOne(Post, { id });
}
}
createPost로 생성한 post를 post(id){}로 조회한다.
posts{}는 생성된 모든 post를 보여준다.
resolvers/post.ts
import { MyContext } from "../types";
import { Arg, Ctx, Mutation, Query, Resolver } from "type-graphql";
import { Post } from "../entities/Post";
@Resolver()
export class PostResolver {
@Mutation(() => Post, { nullable: true })
async updatePost(
@Arg("id") id: number,
@Arg("title", () => String, { nullable: true }) title: string,
@Ctx() { em }: MyContext
): Promise<Post | null> {
const post = await em.findOne(Post, { id });
if (!post) {
return null;
}
if (typeof title !== "undefined") {
post.title = title;
await em.persistAndFlush(post);
}
return post;
}
@Mutation(() => Boolean)
async deletePost(
@Arg("id") id: number,
@Ctx() { em }: MyContext
): Promise<boolean> {
await em.nativeDelete(Post, { id });
return true;
}
}
delete와 update 기능을 추가했다.