지난 번에 작성한 TypeORM 코드에 GraphQL을 추가해보자.
프로젝트 구조는 다음과 같다.
├── src
│ ├── entity
│ │ ├── Follow.ts
│ │ └── User.ts
│ ├── graphql
│ ├── repository
│ │ ├── Follower
│ │ │ ├── FollowerRepository.test.ts
│ │ │ └── FollowerRepository.ts
│ │ ├── User
│ │ │ ├── UserRepository.test.ts
│ │ │ ├── UserRepository.ts
│ │ │ └── index.ts
│ │ └── index.ts
│ ├── index.ts
│ └── startServer.ts
├── tsconfig.json
├── yarn.lock
├── README.md
├── jest.config.js
├── ormconfig.json
├── ormconfigSample.json
└── package.json
이번에 작업할 graphql
폴더의 구조는 아래와 같다.
├── follow
│ ├── followResolver.ts
│ ├── followSchema.ts
│ └── index.ts
├── user
│ ├── index.ts
│ ├── userResolver.ts
│ └── userSchema.ts
└── index.ts
먼저 user schema와 follow schema를 정의한다. user, follow schema는 TypeORM에서 정의한 Entity와 유사하다.
// src/graphql/user/userSchema.ts
import { gql } from 'apollo-server-express';
const userSchema = gql`
extend type Query {
signin(email: String!, password: String!): AuthPayload!
me: User!
user(id: ID!): User!
users: [User]!
}
extend type Mutation {
signup(input: signupInput): User!
}
type AuthPayload {
user: User!
token: String!
}
type User {
id: ID!
email: String!
nickname: String!
following: [Follow]!
followers: [Follow]!
}
input signupInput {
email: String!
password: String!
nickname: String!
}
`;
export { userSchema };
최소한의 행위만 구현했다.
유저는 로그인을 하고, 자신의 정보를 확인할 수 있고, 다른 사용자의 정보를 확인할 수 있다. (다른 사용자의 정보를 확인하는 것은 나중에 친구만 가능하도록 변경해보자.)
그리고 follower, following의 정보를 확인할 수 있다.
User Type은 TypeORM에서 정의한 Entity와 유사하다.
// src/graphql/follow/followSchema.ts
import { gql } from 'apollo-server-express';
const followSchema = gql`
extend type Query {
getFollowers(id: ID!): [Follow]!
getFollowing(id: ID!): [Follow]!
}
extend type Mutation {
setFollowing(id: ID!): Follow!
deleteFollowing(id: ID!): Follow!
deleteFollower(id: ID!): Follow!
checkFollower(id: ID!): Follow!
}
type Follow {
id: ID!
following: User!
follower: User!
checked: Boolean!
createdAt: String!
updatedAt: String!
}
`;
export { followSchema };
유저는 회원가입을 할 수 있고, 다른 유저를 following 할 수 있다.
자신의 following, follower를 삭제할 수 있고, checkFollower를 이용하여 follower들 중 확인하지 않은 대상을 확인한 대상으로 변경할 수 있다.
일단 프로그램을 실행하기 위해 schema에 해당하는 resolver signature만을 만들어두자.
// src/graphql/user/userResolver.ts
const userResolver = {
Query: {
signin: () => {},
me: () => {},
user: () => {},
users: () => {},
},
User: {
following: () => {},
followers: () => {},
},
Mutation: {
signup: () => {},
},
};
export { userResolver };
// src/graphql/follow/followResolver.ts
const followResolver = {
Query: {
getFollowers: () => {},
getFollowing: () => {},
},
Follow: {
following: () => {},
follower: () => {},
},
Mutation: {
setFollowing: () => {},
deleteFollowing: () => {},
deleteFollower: () => {},
checkFollower: () => {},
},
};
export { followResolver };
마지막으로 schema와 resolver를 각각 하나로 엮어서 Apollo Server에 전달하자.
// src/graphql/user/index.ts
export { userResolver } from './userResolver';
export { userSchema } from './userSchema';
// src/graphql/follow/index.ts
export { followResolver } from './followResolver';
export { followSchema } from './followSchema';
// src/graphql/index.ts
import { gql } from 'apollo-server-express';
import { userResolver, userSchema } from './user';
import { followResolver, followSchema } from './follow';
const linkSchema = gql`
type Query {
_: Boolean
}
type Mutation {
_: Boolean
}
type Subscription {
_: Boolean
}
`;
const schemas = [linkSchema, userSchema, followSchema];
const resolvers = [userResolver, followResolver];
export { resolvers, schemas };
// src/startServer.ts
import 'reflect-metadata';
import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import { schemas, resolvers } from './graphql';
import connectDB from './repository';
export const startServer = async () => {
try {
await connectDB();
const PORT = 9999;
const app = express();
const server = new ApolloServer({
typeDefs: schemas,
resolvers,
});
server.applyMiddleware({ app, cors: false });
app.listen(PORT, () => {
console.log(`Server: http://localhost:${PORT}${server.graphqlPath}`);
});
} catch (error) {
console.error(error);
}
};
이제 yarn dev
로 프로그램을 실행할 수 있다.