[240104 인턴일지] GraphQL 서버 만들어보기 공부 기록기

osohyun0224·2024년 1월 4일
0

슬기로운 인턴생활

목록 보기
4/13
post-thumbnail

안녕하세요, 대학생 개발인턴 garden입니다:)
이번 포스팅에서는 GraphQL 서버를 직접 만들어보면서 공부해보는 시간을 가져보도록 하겠습니다.

1. Apollo 서버를 구축하기

const database = require('./database')
const { ApolloServer, gql } = require('apollo-server')
const typeDefs = gql`
  type Query {
    teams: [Team]
  }
  type Team {
    id: Int
    manager: String
    office: String
    extension_number: String
    mascot: String
    cleaning_duty: String
    project: String
  }
`
const resolvers = {
  Query: {
    teams: () => database.teams
  }
}
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`🚀  Server ready at ${url}`)
})

이 파일을 가지고 직접 공부를 시작해보자.

const { ApolloServer, gql } = require('apollo-server')
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {

위의 이 모듈에서 가져온 아폴로 서버 클래스가 존재한다. 이 클래스는 typedef와 리졸버 인자로 받아서 이렇게 생성자로 서버를 생성하고 listen 명령어로 실행한다.

여기서 용어정리를 한번 해보고 가자

typedef란,

  • graphql 명세에서 사용될 데이터, 요청의 타입을 지정한다.
  • gal(tempelete literal tag)로 생성된다.

위의 코드에서 예로 들자면 type Team에서 이 팀이란 데이터가 어떤 항목들로 구성되어 있는지 그리고 이를 요청할 쿼리에도 어떤 형식으로 요청이 들어가는지 이런 데이터의 구조가 선언되어있다고 보면된다.

resolver

  • 서비스의 액션들을 함수로 지정한다.
  • 요청에 따라 데이터를 반환하고, 입력하고, 수정하고 삭제한다.

나는 이 용어 정리로도 잘 이해가지 않아서 더 공부를 해보았다.
리졸버 함수는 graphql 쿼리에 대한 구체적인 동작을 정의한다. 클라이언트에서 온 요청에 따라 적절한 데이터를 반환해야하는데 이를 리졸버가 담당한다. 엄청 중요해보이는데 난 왜이리 이해가 안가지ㅜㅠㅜ암튼 계속 공부해보자

다시,
리졸버는 필드에 요청이 들어온 경우 그 값을 제공한다. 쿼리 타입에 users라는 필드를 정의한 경우 query { users } 라는 질의로 값을 요청할 수 있고 이 경우에 리졸버 함수가 호출된다.

Query 구현하기

const database = require('./database')
const { ApolloServer, gql } = require('apollo-server')
const typeDefs = gql`
  type Query {
    teams: [Team]
  }
  type Team {
    id: Int
    manager: String
    office: String
    extension_number: String
    mascot: String
    cleaning_duty: String
    project: String
  }
`
const resolvers = {
  Query: {
    teams: () => database.teams
  }
}
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`🚀  Server ready at ${url}`)
})

앞서서 실습한 이 코드를 다시 살펴보면서 쿼리를 구현해보자.

특히 이 부분을 주목해서 살펴보면

const typeDefs = gql`
  type Query { 
    teams: [Team]
  }
  //쿼리의 루트타입 지정
  // 자료요청에 사용될 쿼리들을 정의하고, 쿼리 명령문마다 반환될 데이터 형태를 지정한다.
  type Team { //type 살펴보기
    id: Int
    manager: String
    office: String
    extension_number: String
    mascot: String
    cleaning_duty: String
    project: String
  }
  //반환될 데이터의 형태를 지정하고 자료형을 가진 필드들로 구성되어있다.
`

쿼리의 루트 타입을 열고, 자료 요청에 사용될 쿼리를 정의한다. 이 쿼리 명령문 마다 반환될 데이터들을 지정한다.

이 쿼리라는 타입 안에 어떤 요청들이들어오고 어떤 형식의 데이터들이 반환될 지가 위와 같은 형태로 지정되어있다. [Team] 이 복수로 여러개가 반환이 된다는 것이다. 팀이 여러개가 날아온다. 각 항목들 마다 각각의 적합한 데이터 형이 지정되어있다.

리졸버 다시 이해하기

GraphQL Federation 이란?

GraphQL Federationd이란 여러 GraphQL 서비스의 GraphQL 스키마를 조합하여 하나의 큰 GraphQL 스키마로 만드는 방식을 말합니다.

하나의 router가 각 서비스에서 제공하는 Graphql 스키마를 합친 통합 GraphQL 스키마를 제공하고 클라이언트는 이 스키마를 보고 쿼리를 작성해 요청하면 된다. 라우터는 요청된 쿼리문을 분리하고, 각 분리된 쿼리문을 담당하는 서비스에 보낸 뒤, 돌아온 데이터들을 합쳐서 클라이언트에게 돌려준다.

GraphQL Federation을 이해하기 위해서 ...

Object type과 field

GraphQL에서는 그래프의 형식으로 데이터를 표현한다. 그래프의 가장 기본 단위는 여러 필드를 포함하는 오브젝트 타입입니다.

예를 들어 상품의 아이디와 이름 가격을 포함하는 상품 데이터는 다음과 같은 GraphQL 스키마로 정의할 수 있다.

type Product {
	id: ID!
	name: String!
	price(in: Currency = KRW): Float!
}

enum Currency {
	KRW
	USD
}

여기서 Product는 Object type, id, name, price는 필드이다. 각 필드는 타입으르 가지고 기본적으로 String, Int, Float, Boolean 그리고 ID type을 제공한다. price field는 in이라는 Currency enum type의 argument를 가지며, in argument의 기본값은 KRW입니다.

Object type간의 관계

GraphQL을 데이터를 그래프 형식으로 표현합니다. 그래프의 정점이 Object type이라고 한다면 엣지는 Object type의 관계입니다. 한 상품에 대한 아이디와 본문을 포함하는 리뷰를 여러개 가질 수 있다면

type Review {
	id: ID!
	rating: Float!
  body: String!
	product: Product!
}


type Product {
	...
	reviews: [Review!]!
}

위와 같이 정의 할 수 있다. 한 상품은 여러개의 리뷰를 가질 수 있고, 한 리뷰는 하나의 상품에 대한 것이라는 상품과 리뷰간의 관계를 정의한 것입니다.

profile
학부생 Frontend Developer

0개의 댓글