반응형
TypeScript로 GraphQL 사용할 때의 문제
문제
- graphQL은 gql을 사용해 graphQL에서 사용할 데이터의 타입을 다음과 같은 형태로 지정해줘야 한다. (숫자는 Int, 문자열은 String)
사실 이것만 생각하면 별 문제가 없지만 TypeScript와 (or TypeORM) 함께 사용하게되면 귀찮은 일이 발생한다.
바로 TypeScript와 graphQL의 타입 형태가 다르다는 점이다.
// graphQL에서의 타입 정의
type User {
id: ID!
userId: Int
name: String
email: String
company: String
}
// TypeScript에서의 타입 정의
interface User {
id: string;
userId: number;
name: string;
email: string;
company: string;
}
- 보이는 것처럼 타입의 형태가 달라 각각 따로 지정해줘야하기 때문에 귀찮아진다. 하지만 당연하게 이런 중복된 타입 지정을 도와주는 프레임워크가 존재한다. 바로 Type-GraphQL이다. (Prisma써도 됨)
Type-GraphQL
- 설치 (reflect-metadata, type-graphql)
npm i reflect-metadata type-graphql
- reflect-metadata는 데코레이터 문법을 사용하기 위해 설치하는 라이브러리.
- 예제 코드
// 기타 apollo-server나 express등은 생략함...
import 'reflect-metadata';
import { ObjectType, ID, buildSchema, Resolver, Query } from 'type-graphql';
import { Inject, Service, Container } from 'typedi';
@Service()
class UserRepository {
async getUserss() {
const [rows] = await connection.query(`
SELECT *
FROM Users
`);
return rows;
}
}
@ObjectType()
class User {
@Field(() => ID)
userId!: string;
@Field()
name!: string;
@Field({ nullable: true })
email!: string;
@Field()
company!: string;
}
@Service()
@Resolver()
class UserResolver {
constructor(private dependencies: UserRepository) {}
@Query(() => [User])
async getUsers() {
const rows = await this.dependencies.getUserss();
return rows;
}
}
Promise.resolve()
.then(() =>
buildSchema({
resolvers: [UserResolver],
container: Container,
}),
)
.then(schema => new ApolloServer({ schema }))
.then(apolloServer => {
apolloServer.start().then(res => {
apolloServer.applyMiddleware({
app,
path: '/graphql',
});
app.listen(3000, () => {
console.log(`server listening on port 3000`);
});
});
});
- 사실 계층화를 해줘야하지만 코드설명을 위해 그냥 한 파일에 나열함.
- 코드를 하나하나 살펴보면 먼저 type-graphql 라이브러리에서 필요한 메서드들을 불러오고
- 비즈니스 로직과 데이터베이스 로직을 분리하기 위해서 UserRepository를 만들어주고
- 기존 gql에서 사용하던 타입선언을 User 클래스에서 @ObjectType()를 선언해 하나로 묶어주고
(이때 @Field가 graphQL 타입 선언 부분. String은 생략가능) - UserResolver 클래스에 비즈니스 로직을 작성함.
TypeDi
- 해당 코드를 의존성 주입 관점에서 보면 UserResolver 클래스의 생성자에서 UserRepository를 주입 받아 느슨하게 결합됨.
- 하지만 graphQL 특성상 UserResolver 클래스를 인스턴스화 하지 않고 알아서 Apollo-server에서 구현되기 때문에 UserRepository를 인식하지 못하는 문제가 발생함.
- 이를 해결하기 위해 TypeDi 라이브러리를 통해 의존성 주입을 할 수 있음.
- 의존성 주입을 하려는 클래스들에 @Service 데코레이터를 작성하고, buildSchema의 옵션으로 container:Container를 입력해주면 끝. 자세한건 아래 링크
Type-GraphQL docs
반응형
'GraphQL' 카테고리의 다른 글
nestjs-query_02_Hook, Authorize (0) | 2024.01.14 |
---|---|
nestjs-query_01_세팅 (1) | 2024.01.10 |
Nest + Graphql 구현하기 (0) | 2022.09.29 |
Express + Graphql 좀 더 구조적으로 짜기 (+ Type-graphql, Typegoose, Typedi) (0) | 2022.09.29 |