GraphQL 을 배워보자 - 1

준형정·2023년 10월 7일

GraphQL

목록 보기
1/2

graphql playground 설치

brew install --cask graphql-playground

API 엔드포인트를 플레이그라운드 툴에 붙여넣거나, 브라우저에서 URL 을 치고 인터페이스로 들어감

ex) 스노투스 GraphQL 플레이그라운드 인터페이스
- https://snowtooth.moonhighway.com/

기본 쿼리 작성법

조회

query {
  allLifts {
    name
  	status
  }
}

쿼리 작업 두개를 같은 문서에 쓰더라도 하나의 동작만 실행 가능

데이터를 한번에 모두 받아오고 싶다면

query listsAndTrails {
  liftCount(status: OPEN)
  allLifts {
    name
    status
  }
  allTrails {
    name
    difficulty
  }
}

Query - GraphQL 타입 == 루트 타입 (타입 하나가 곧 하나의 작업 -> 작업이 곧 쿼리 문서의 루트)

query 에 사용할 수 있는 필드는 API 스키마에 정의
API 문서에 Query 타입으로 선택할 수 있는 필드 나열

쿼리 작성 시 중요한 것은 필요한 필드만 요청하는 것

셀렉션 세트

셀렉션 세트 - 쿼리를 작성할 때 필요한 필드를 중괄호로 감싼 것
안에 들어간 필드는 GraphQL 타입(Query)와 직접적 연관이 있음 - 필드 모두 Query 타입 안에 정의됨
셀렉션 세트는 중첩가능

# 응답 객체의 필드명 다르게 받고 싶을경우 필드명에 별칭 부여
query listsAndTrails {
	...
  chairLits: allLifts {
    liftName: name
    status
  }
  ...
}

쿼리 인자

GraphQL 쿼리 결과에 대한 필터링 작업을 하고싶을 경우 쿼리 인자를 사용한다.

query listsAndTrails {
  liftCount(status: CLOSED)
  chairLits: allLifts(status:CLOSED) {
    liftName: name
    status
  }
	...
}

데이터를 선택하는 용도로 인자를 활용할 수도 있음

개별 리프트 상태에 대한 쿼리 작성을 원할 경우, 리프트의 아이디를 사용해 해당 리프트 선택

query jazzCatStatus {
  Lift(id: "jazz-cat"){
    name
    status
    night
    elevationGain
  }
}

GraphQL 스칼라 타입

다른 프로그래밍 언어에서 원시 타입과 비슷, 쿼리 셀렉션 세트의 잎(leaves)이 되어주는 타입

다섯가지 스칼라 타입

  1. 정수(Int)
  2. 실수(Float)
  3. 문자열(String)
  4. 불(Boolean)
  5. 고유 식별자(ID)

정수, 실수 -> JSON 숫자 데치터 반환
문자열, 고유 식별자 -> JSON 문자열 데이터 반환

GraphQL 객체 타입

스키마에 정의한 필드를 그룹으로 묶어 둔 것, 필드는 스칼라, 객체 타입 둘중 하나에 속함
응답으로 반환되어야 할 JSON 객체의 형태를 하고 있음

특정 객체가 있을 때, 이와 관련된 객체 세부 정보를 얻어내는 쿼리를 작성해 이들 객체를 서로 연결할 수 있음

# trailAccess는 Lift 타입 안에 있는 필드여서 API 에서는 부모 객체인 재즈 캣 Lift 의 정보를 활용해
# 특정 코스만 필터링
# 리프트와 코스 데이터 타입 사이의 일대다 연결 관계
query trailsAccessedByJazzCat {
  	Lift(id: "jazz-cat"){
    capacity
    trailAccess {
      name
      difficulty
    }
  }
}

프래그먼트

프래그먼트 - 셀렉션 세트의 일종, 여러번 재사용할 수 있음

프래그먼트는 fragment 식별자를 사용하여 만듬
프래그먼트는 특정 타입에 대한 셀렉션 세트이므로 어떤 타입에 대한 프래그먼트인지 정의에 꼭 써줘야 함
프래그먼트 필드를 다른 셀렉션 세트에 추가하려면 "...이름" 과 같이 사용
프래그먼트를 다른 필드와 함께 쓸수도 있음
같은 타입에 대한 프래그먼트를 여러 개 쓸 수도 있음
한 차례의 수정으로 쿼리의 셀렉션 세트를 한 번에 바꿀 수 있다는 것이 프래그먼트의 장점

#프래그먼트로 쿼리에서 중복되는 부분을 줄일 수 있음
아래 예시에서는 프래그먼트를 liftInfo 라고 명명했으며, Lift 타입에 대한 셀렉션 세트임

query {
  Lift(id: "jazz-cat"){
    ...liftInfo
    elevationGain
    trailAccess {
      name
      difficulty
    }
  }
  Trail(id: "river-run") {
    name
    difficulty
    accessedByLifts {
      ...liftInfo
    }
  }
}

fragment liftInfo on Lift {
  name
  status
  capacity
  night
  elevationGain
}

유니언 타입

타입 여러 개를 한 번에 리스트에 담아 반환하고 싶을때 사용함, 두 가지 타입을 하나의 집합으로 묶는 것

인라인 프래그먼트

이름이 없는 프래그먼트, 쿼리 안에서 특정 타입에 바로 셀렉션 세트를 넣어버린다.
유니언 타입에서 여러 타입의 객체를 반환할때, 각각의 객체가 어떤 필드를 반환할 것인지 정할 때 사용

# 이름이 있는 프래그먼트를 사용해도 된다.
query schedule{
  agenda {
  ...on Workout {
    name
    reps
    }
  ...on StudyGroup {
  name
  subject
  students
  }
 }
}

인터페이스

필드 하나로 객체 타입을 여러개 반환할 때 사용, 추상적인 타입이며 유사한 객체타입을 만들 때 구현해야 하는 필드 리스트를 모아둔 것

인터페이스를 가지고 타입을 구현할 때는 인터페이스에 정의된 필드를 모두 넣어야 하며
몇가지 고유한 필드도 넣을 수 있음

#agenda 필드의 항목은 모두 ScheduleItem 인터페이스를 반환함
#여기에는 name, start, end 필드가 정의 - 이들은 모두 ScheduleItem 인터페이스를 사용하여 만든 객체타입에 정의되어야 함
#agenda 가 반환하는 StudyGroup 과 Workout 타입이 이 인터페이스를 바탕으로 만들어 짐
#agenda 필드가 반환하는 타입 종류의 개수는 상관없음

# 프래그먼트를 사용하여 특정 객체 타입이 반환될 때, 필드가 더 들어갈 수 있도록 함

query schedule {
	agenda {
    name
    start
    end
    ...on Workout {
    reps  
		}
  }
}

뮤테이션

데이터를 새로 쓸때 사용, 뮤테이션 하는 방법은 쿼리 작성과 비슷하며 이름을 붙여야 함
객체 타입이나 스칼라 타입의 반환 값을 가지는 셀렉션 세트가 들어감
쿼리와 다른점은 데이터를 뮤테이션 하면 백엔드 데이터에 영향을 줌

삭제

# 위험한 코드
mutation burnItDown{
	deleteAllData
}

추가

mutation createSong{
	addSong(title: "No Scrubs", numberOne: true, performerName:"TLC") {
      id
      title
      numberOne
    }
}

뮤테이션 필드가 객체를 반환하도록 만들려면 셀렉션 세트를 추가해야 함
문제가 발생했다면 객체 대신 에러가 담긴 JSON 응답이 반환

수정

mutation closeLift {
    setLiftStatus (id: "jazz-cat", status: CLOSED) {
      name
      status
    }
}

쿼리 변수 사용하기

정적값을 변수로 대체하여 계속해서 바뀌는 동적인 값을 넣을수도 있음
변수명 앞에는 $ 문자가 붙는다

mutation createSong($title:String! $numberOne:Int $by:String!) { 
	addSong(title:$title, numberOne:$aunberOne, performerNsne:$by) { 
      id 
      title 
      runberOne 
	}
}

변수는 쿼리 변수용 창에 JSON 형식으로 따로 설정

{
  "title" : "No Scrubs",
  "numberOne" : true,
  "by" : "TLC"
}

서브스크립션

데이터 서브스크립션을 하면 GraphQL API를 사용해 실시간 데이터 변경 내용을 받을 수 있음 ex)Live Likes

클라이언트에서 받을 수 있는 데이터 변경 내용은 subscription 타입 아래 필드로 정의되어 API 스키마에 들어감

#뮤테이션을 실행하여 Lift 의 값을 변경하면 해당 리프트의 name, capacity, status 값이 서브스크립션에 전송된다.
subscription {
	liftStatusChange {
    	name
        capacity
        status
    }
}

인트로스펙션

API 스키마의 세부 사항에 관한 쿼리를 작성할 수 있음
GraphQL 플레이그라운드 인터페이스에서 GraphQL 문서를 보여 줄 수 있는 것도 이 덕분

어떤 GraphQL 타입을 사용할 수 있는지 알고 싶다면 __schema 쿼리 실행
루트 타입, 커스텀 타입, 스칼라 타입까지 나옴

query {
  __schema {
    types {
      name
      description
    }
  }
}

특정 타입에 관한 세부 사항만 보고 싶다면 __type 쿼리에 타입명을 인자로 넘기면 된다.

query {
  __type(name:"Lift"){
    name
    fields{
      name
      description
      type{
        name
      }
    }
  }
}

GraphQL API를 처음 사용할 때는 아래 쿼리를 통해 루트 타입에서 사용할 수 있는 필드가 무엇이 있는지 알아 보는 편이 좋음

query roots {
  __schema {
    queryType {
      ...typeFields
    }
    mutationType {
      ...typeFields
    }
    subscriptionType {
      ...typeFields
    }
  }
}
fragment typeFields on __Type {
  name
  fields {
    name
  }
}

인트로스펙션 쿼리문은 GraphQL 쿼리 언어의 규칙을 따름
따라서 프래그먼트를 사용하여 쿼리문 안의 중복되는 부분을 없앨 수 있음

추상 구문 트리(AST)

GraphQL API로 쿼리를 보낼 때, 문자열은 추상 구문 트리(abstract syntax tree) 로 파싱되어 명령 실행 전에 유효성 검사를 거침

쿼리에는 최소한 정의(definition)가 하나 이상 들어감, 여러개의 정의가 리스트로 들어 있을 수도 있음
정의는 두 타입으로 나뉘어 짐
1. OperationDefinition - mutation, query, subscription

  • 각 작업 정의에는 OperationType과 SelectionSet가 들어감
  1. FragmentDefinition
profile
접니다

0개의 댓글