데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      GraphQL에 대하여 (장점 & Schema & Type)

      너구리킹 23.04.24
      9,603 21 3

      GraphQL이란

      GraphQL은 Facebook에서 개발된 오픈소스 기술로 데이터 질의 (Query + Schema) 언어이다.

      클라이언트는 GraphQL 서버로 쿼리를 전송하고, 서버는 해당 쿼리를 해석하고 데이터를 반환한다.

      이 때, 클라이언트가 요청한 필드만 반환되므로 over fetching을 줄여 효율적이다. 

      또한, GraphQL은 스키마를 사용하여 데이터 모델을 정의하기 때문에 클라이언트와 서버 간의 일관성 있는 데이터 통신을 보장한다.

      이를 통해 클라이언트가 서버가 제공하는 데이터 중 원하는 데이터를 가져오는 것이 가능해진다.

      graphql


      GraphQL vs Rest API

      Rest API는 HTTP 요청방식 (GET, POST, PUT DELETE 등)을 사용하여 데이터를 요청하고 응답받는다.

      이 때, 상황에 따라 다른 Method를 사용해야하고 api별로 각각의 end point를 갖는다.

      GraphQL은 동일하게 HTTP 요청방식을 사용하지만 POST만 사용하고 단일 end point를 사용한다.

      그리고 요청 시 body에 Schema에 맞춰 Query를 사용하여 요청하기 때문에 일관성 있는 통신이 가능하다.


      User라는 data에 대해 CRUD API를 구현을 통해 간단한 예를 들어보자

      • REST API의 경우 아래와 같은 4개의 end point가 필요하고 client <-> server 간 data type을 명시적으로 보여줄 수 없다.

        • [GET] /api/v1/user

        • [POST] /api/v1/user

        • [PUT] /api/v1/user/:id

        • [DELETE] /api/v1/user/:id

      • GraphQL의 경우 아래와 같은 1개의 end point만 사용하고 client <-> server간의 data 일관성을 유지할 수 있다.

        • [POST] /graphql

      //body의 내용
      //create
      mutation{
      	createUser(input: createUserDto){ // createUserDto == {name: string, email: string}
          	id
              name
              email
          }
      }
      #read
      query{
      	getUser{
          	id
              name
              email
          }
      }
      #update
      mutation{
      	updateUser(input: updateUserDto){ // updateUserDto == {name: string, email: string}
          	id
              name
              email
          }
      }
      #delete
      mutation{
      	deleteUser(id: $id)
      }

      Data 효율성

      • Rest API를 사용하면 같은 url을 사용할 경우 항상 동일한 정보를 받게 된다. 하지만 이 경우 모든 data가 필요하지 않을 수 있는데 이 때 over fetching이 발생한다.

      • GraphQL을 사용한다면 설정한 query에 따라 정보를 받게 된다. 만약 id, name, email을 요청하지 않고 name만 요청할 경우 서버에서는 name만 reponse에 담아서 준다. 따라서 overfetching을 막을 수 있다.

      캐싱

      • Rest API는 [GET]을 사용할 경우 캐싱이 가능하다.

      • GraphQL은 캐싱을 하기 위해서는 client 혹은 server 개발자가 따로 캐싱 처리를 해주어야 한다.


      정리

      지금까지는 Rest API를 대체할 수 있는 무언가가 있고 그게 GraphQL이 될 수 있다고 말씀 드렸습니다.

      요약해보면 GraphQL에 대한 두 가지 장점이 있다.

      • Schema를 정해 데이터의 일관성을 보장할 수 있다.

      • Client에서 필요한 data만을 요청하기에 overfetching을 줄일 수 있다.

      그럼 이제부터 GraphQL에 대해 더 자세히 알아보도록 하자.


      Schema & Type

      우선 설명에 앞서 아래와 같은 User에 대한 예시 Shema을 작성하겠다.

      #user.graphqls
      
      #enum type 선언
      enum Gender {
        MALE
        FEMALE
      }
      
      #user type 선언
      type User {
        uid: Int!
        email: String!
        name: String!
        phone: String
        gender: Gender!
        favorite_friends:[Int!]
        birth_date: Time!
        created_at: Time!
        updated_at: Time!
      }
      
      #user input 선언
      input UserInput { 
        uid: Int64!
      }
      
      #create user input 선언
      input CreateUserInput {
        email: String!
        name: String!
        phone: String
        gender: gender!
        birth_date: Time!
      }
      
      #update user input 선언
      input UpdateUserInput {
        email: String!
        name: String!
        phone: String
        gender: gender!
        birth_date: Time!
      }
      
      input UpdateUserFavoriteFiendsInput {
        uid: Int!
        friends: [Int!]!
      }
      
      #delete user input 선언
      input DeleteUserInput {
        uid: Int64!
      }

      여기서 type User와 같이 type으로 선언된 경우 요청 시 사용하는 field들을 정의한 것이고 input으로 선언될 경우 argument를 정의한 것이다.

      field뒤에 "!"를 붙이는 이유는 "!"가 있을 경우 non-null field이고 "!"가 없을 경우 nullable이다.

      예를 들어 user.name의 경우 반드시 존재해야 하는 값이기 때문에 null일 시 문제가 있기 때문에 "!"를 붙였고 phone의 경우 없을 수 있기 때문에 "!"가 제외되어 있다.

      배열의 경우 [Int!]!와 같이 사용할 수 있는데 배열 내부에 "!"가 있을 경우 배열의 요소는 항상 Int값(선언한 타입의 값)이어야 한다.

      또한 배열 뒤에 "!"가 있을 경우 [something]! 배열은 null이 아니고 0개 이상의 항목을 포함한 값이어야 한다.

      Query & Mutation

      Rest API의 경우 API의 사용 용도에 따라 GET, POST, PUT, DELETE 등과 같이 Method를 달리 사용한다. 

      GET method는 read 시에 사용, POST method는 create시에 사용, PUT Method는 update에 사용, Delete Method는 delete 시에 사용한다. 

      GraphQL 또한 Query / Mutation으로 이를 구분한다. Query는 read 용 그 외의 용도는 Mutation을 사용하면 된다.

      여기서는 간단하게 위에 선언한 Schema를 다루기 위한 Query & Mutation을 선언하겠다.

      scalar Time
      scalar Int64
      
      type Query {
        users: [User!]!
        user(input: userInput): User!
      }
      
      type Mutation {
        createUser(input: createUserInput!): User!
        updateUser(input: updateUserInput!): User!
        updateUserFavoriteFriends(input: updateUserFavoriteFriendsInput!): User!
        deleteUser(input: deleteUserInput!): String!
      }

      Type system

      graphql은 type system이다. graphql은 field를 select 함으로써 overfetching을 방지할 수 있다.

      query{
        users{
          uid
          name
        }
      }

      위의 요청 예시를 보면 실제로 User에는 uid,name 뿐아니라 email, phone, gender 등이 있는데 이와 같이 uid, name만 요청하면 아래와 같이 uid, name의 정보만 받을 수 있다.


      Query에서 선언한 Type 대로 users는 user의 배열을 받을 수 있다.

      {
        "data":{
          "users":{
            {
              "uid":1
              "name":"zzihyeon"
            },
            {
              "uid":2
              "name":"jihyeon"
            }
          }
        }
      }

      이와 같이 요청한 정보와 그 결과의 값의 형태가 일정하기 때문에 일관성이 유지된다.

      모든 요청은 선언된 Schema내에서만 가능하기 때문에 Client는 요청 시 Schema를 먼저 확인해야 한다.

      Argument

      우리는 Schema를 정의할 때 "input"을 통해서 argument type을 정의했다. 그럼 이는 어떻게 사용할 수 있을까?

      예를 들어서 uid가 1인  user를 찾고 싶을 때 위에 선언한 "input UserInput" 을 사용할 수 있다.

      만약 user 중 uid가 1인 user 정보만 받고 싶다면 아래와 같이 사용한다.

      query {
        user(input: {uid: 1}){
          uid
          name
        }
      }

      user query를 요청할 때 input에 UserInput을 넣으면 된다.

      {
        "data":{
          "user":{
            "uid":1
            "name":"zzihyeon"
          }
        }
      }

      Scalar

      GraphQL에서는 아래와 같은 Type만을 지원한다.

      • Int: A signed 32‐bit integer.

      • Float: A signed double-precision floating-point value.

      • String: A UTF‐8 character sequence.

      • Boolean: true or false.

      • ID: The ID scalar type represents a unique identifier, often used to refetch an object or as the key for a cache.

        The ID type is serialized in the same way as a String; however, defining it as an ID signifies that it is not intended to be human‐readable.

      따라서 우리가 원하는 type을 사용하기 위해서는 Scalar를 선언해야만 한다.

      본인의 경우 Schema 선언 시 "Time"이라는 type을 사용했으며 이는 Query & Mutation선언에 나와 있듯이 아래와 같이 선언할 수 있다.

      scalar Time

      다음 번 블로그에는 interface & Union Type에 대해서 알아보려고 합니다. To be continue...

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      너구리킹 님의 최신 블로그

      더보기
      동영상 기고하기