본문 바로가기
부트캠프교육중/HTTP, 네트워크

GraphQL 구조

by 뭉지야 2023. 3. 28.
728x90

<GraphQL 구조>
#Query: 저장된 데이터 가져오기 , 원하는 데이터를 요청(REST API의 GET과 비슷)
#Mutation: 저장된 데이터 수정.
-Create: 새로운 데이터 생성
-Update: 기존의 데이터 수정
-Delete: 기존의 데이터 삭제
#Subscription 구독: 실시간 업데이트를 구현. 특정 이벤트가 발생 시 서버가 대응하는 데이터를 실시간으로 클라이언트에게 전송.

-Query, Mutation은 전통적인 Client(요청)-Server(응답) 모델을 따른다.
-Subscription는 발행/구독(pub/sub) 모델을 따릅니다.


<Query 쿼리 > 데이터 조회

#필드(field)

// hero의 name을 쿼리

{
  hero {
    name
  }
}

----------------------------------------------------------------
//쿼리를 실행했을 때의 결과

{
  "data": {
    "hero": {
      "name": "R2-D2"
    }
  }
}

-필드의 name은 String 타입을 반환한다.
-쿼리와 결과가 정확하게 같은 모양을 하고 있음을 확인할 수 있는데, 이 부분은 GraphQL에 있어서 필수적이다.
 GraphQL은 서버에 요청했을 때 예상했던 대로 돌려받고, 서버는 GraphQL을 통해 클라이언트가 요구하는 필드를 정확히 알기 때문입니다.

//히어로의 이름과 히어로의 친구 이름을 같이 쿼리

{
  hero {
    name
    # 이런 식으로 GraphQL 내에서 주석도 작성할 수 있습니다.
    friends {
      name
    }
  }
}

----------------------------------------------------------------
//히어로의 이름과 히어로의 친구의 이름이 조회되어 나옵니다.

{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}

-원하는 필드를 중첩하여 쿼리하는 것도 가능하다.
-GraphQL 쿼리는 관련 객체 및 필드를 순회할 수 있기 때문에 고전적인 REST API에서 그러했듯 다양한 endpoint를 만들어 각기 요청을 보내는 대신 클라이언트가 하나의 요청을 보냄으로써 관련 데이터를 가져올 수 있습니다.

 

#전달인자(Arguments)
-필드에 인수를 전달하는 부분을 추가하게 되면 쿼리의 필드 및 중첩된 객체들에 전달하여 원하는 데이터만 받아올 수 있습니다.

//  id가 1000인 human의 name과 height를 쿼리

{
  human(id: "1000") {
    name
    height
  }
}

------------------------------------------------
//쿼리 결과

{
  "data": {
    "human": {
      "name": "Luke Skywalker",
      "height": 1.72
    }
  }
}

 

#별명(Aliases)
-필드 이름을 중복해서 사용할 수 없으므로, 필드 이름을 중복으로 사용해서 쿼리를 해야 할 때는 별명을 붙여서 쿼리를 합니다.

-다른 이름으로 별명을 지정하면 한 번의 요청으로 두 개의 결과를 모두 얻어낼 수 있습니다.

//이런 식으로 중복해 쿼리할 수 없습니다.

{
  hero(episode: EMPIRE) {
    name
  }
  hero(episode: JEDI) {
    name
  }
}
--------------------------------------------------
//앞에 알아볼 수 있는 별명을 붙여주면 쿼리할 수 있습니다.

{
  empireHero: hero(episode: EMPIRE) {
    name
  }
  jediHero: hero(episode: JEDI) {
    name
  }
}
--------------------------------------------------
//쿼리 결과를 받아볼 수 있습니다.

{
  "data": {
    "empireHero": {
      "name": "Luke Skywalker"
    },
    "jediHero": {
      "name": "R2-D2"
    }
  }
}

#오퍼레이션 네임(Operation name)

-밑의 query는 오퍼레이션 타입이다. 오퍼레이션 타입에는 query 뿐만 아니라 mutation, subscription, describes 등이 있습니다.

-쿼리를 약식으로 작성하지 않는 한 이런 오퍼레이션 타입은 반드시 필요합니다. 오퍼레이션 네임을 작성할 때는 오퍼레이션 타입에 맞는 이름으로 작성하는 것이 가독성이 좋습니다.

//이런 식으로 query keyword와 query name을 작성합니다.

query HeroNameAndFriends {
  hero {
    name
    friends {
      name
    }
  }
}
-------------------------------------------------------
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}

#변수(Variables)
-인수들을 동적으로 받고 싶을 때 사용합니다.

-오퍼레이션 네임 옆에 변수를 $변수 이름: 타입 형태 로 정의합니다.

- 밑의 예시처럼 $episode: Episode 일 때, 뒤에 !가 붙는다면 episode는 반드시 Episode여야 한다는 뜻입니다. !는 옵셔널한 사항입니다.

//변수를 써서 작성된 쿼리

query HeroNameAndFriends($episode: Episode) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}

<Mutation 뮤테이션 > 데이터 수정

-GraphQL은 대개 데이터를 가져오는 데에 중점을 두고 있지만 서버측 데이터를 수정하기도 합니다.

-REST API에서 GET 요청을 사용하여 데이터를 수정하지 않고, POST 혹은 PUT 요청을 사용하는 것처럼 GraphQL도 유사합니다. GraphQL은 mutation이라는 키워드를 사용하여 서버 측 데이터를 수정합니다.

mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}

 

# 스키마/타입(Schema/Type)

-GraphQL 스키마의 가장 기본적인 구성 요소는 서비스에서 가져올 수 있는 객체의 종류, 그리고 포함하는 필드를 나타내는 객체 유형입니다.

-Character는 GraphQL 객체 타입이며, 즉 필드가 있는 타입임을 의미합니다. 스키마에 있는 대부분의 타입은 객체 타입입니다.
-name 과 appearIn 은 Character 타입의 필드 입니다. 즉 name 과 appearIn 은 GraphQL 쿼리의 Character 타입 어디서든 사용할 수 있는 필드입니다.
-String은 내장된 스칼라 타입 중 하나입니다. 이는 단일 스칼라 객체로 확인되는 유형이며 쿼리에서 하위 선택을 가질 수 없습니다. 스칼라 타입에는 ID, Int도 있습니다.
- !가 붙는다면 이 필드는 nullable하지 않고 반드시 값이 들어온다는 의미입니다. 이것을 붙여 쿼리한다면 반드시 값을 받을 수 있을 것이란 예상을 할 수 있습니다.
- [ ]는 배열을 의미합니다. 배열에도 !가 붙을 수 있습니다. 여기서는 ! 이 뒤에 붙어 있어 null 값을 허용하지 않으므로 항상 0개 이상의 요소를 포함한 배열을 기대할 수 있게 됩니다.

type Character {
  name: String!
  appearsIn: [Episode!]!
}


# 리졸버(Resolver)

-요청에 대한 응답을 결정해주는 함수

-GraphQL의 여러 가지 타입 중 Query, Mutation, Subscription과 같은 타입의 실제 일하는 방식 즉 로직을 작성합니다.

-스키마를 정의하면 그 스키마 필드에 사용되는 함수의 실제 행동을 Resolver에서 정의합니다. 또한 이러한 함수들이 모여 있기 때문에 보통 Resolvers라 부릅니다.

-GraphQL에서는 데이터를 가져오는 구체적인 과정을 직접 구현해야 하는데 이와 같은 작업(e.g. 데이터베이스 쿼리, 원격 API 요청)을 Resolver가 담당하게 됩니다.

const db = require("./../db")
const resolvers = {
  Query: { // **Query :** 저장된 데이터 가져오기 (REST 에 GET 과 비슷합니다.)
		getUser: async (_, { email, pw }) => {
			db.findOne({
				where: { email, pw }
			}) ... // 실제 디비에서 데이터를 가져오는 로직을 작성합니다. 
			...
		}
  },
  Mutation: { // **Mutation :** 저장된 데이터 수정하기 ( Create , Update , Delete )
		createUser: async (_, { email, pw, name }) => {
			...
		}
  }
  Subscription: { // **Subscription :** 실시간 업데이트
    newUser: async () => {
      ...
		}
  }
};

출처

코드스테이츠

728x90

'부트캠프교육중 > HTTP, 네트워크' 카테고리의 다른 글

프록시 Proxy 사용법  (0) 2023.04.04
GraphQL VS Rest API  (0) 2023.03.28
GraphQL  (0) 2023.03.28
HTTPS  (0) 2023.03.12
OAuth  (0) 2023.03.09