Graph QL by facebook

처음 GraphQL에 대해 인식한 계기는, Graph DataBase 시연회에서 d3 대신 GraphQL로 시각화된 결과를 보면서 였다. 당시에는 D3, Chart Js 와 같은 시각화 도구인줄 알고서 어렵겠구나 하고 지나치고 있었는데, 직접적인 계기는 아래의 동영상을 보면서였다. RestAPI 에서 GraphQL로 넘어간 이유

당시 (지난주 ㅜㅜ.) Django 를 RestAPI로 연결하고, 이를 Vue.js 로 클라이언트 관리하는 작업을 목표로 자료들을 찾고 있었고 생각보다 제대로 된 자세한 설명들이 없어서 고생하던 중이었다.

결론적으로 graphql은 복잡하고 다양한 작업의 query를 처리하는데 적합하고, 파일전송 등 안정화된 작업에 있어서는 RestAPI가 강점이 있는 등 블로그 상호 보완적인 역활을 함을 알 수 있다.

내가 하려는 간단한 작업에는 GraphQL을 사용하는 방법으로도 충분할 것으로 보이므로, 작업을 하는데 있어서 GraphQL을 적극적으로 활용해 보도록 하자. 결국에는 관련된 자료를 찾기 쉬운 내용으로 진행을 하는게 현실이다. restAPI 와 React Js 로 자료들이 잘 되어 있다. 하지만 jQuery 쓰듯 vue.js를 활용하여 작업은 진전시키자


Graphene link


이 글을 작성하게 된 진짜 이유로써, 이 동영상이 짧으면서도 GraphQL이 Python에서 어떻게 작동하는지를 잘 알려주는 동영상으로써 정리하고자 함이다


Introduction

Python 기본 환경에서 Graphene을 사용하여 호출하는 방법을 실습한다

import graphene

# 질의용 Query 로 is_stuff 변수를 활용
class Query(graphene.ObjectType):
    is_stuff = graphene.Boolean()
    # info : graphene 연결변수
    def resolve_is_staff(self, info):
        return True

schema = graphene.Schema(query=Query)
query  = "{ isStuff }"
result = schema.execute(query)
# print(result.data.items())      # raw 출력
items = dict(result.data.items()) 
print(items)                      # Query 출력
import json
print(json.dumps(items,indent=4)) # Json 출력

{
    "isStuff": null
}

질의 변수를 CarmelCase로 정의한 경우 { is_stuff } 로 질의시 오류를 출력한다. 이를 사용하고 싶은 경우에는 scheme 객체를 schema = graphene.Schema(query=Query, **auto_camelcase=False**) 로 변경해야 한다.


Basic Filter (slicing)


DataBase 구조를 정의한다

class User(graphene.ObjectType):
    id = graphene.ID()
    username = graphene.String()
    last_login = graphene.DateTime()


Query 객체를 정의한다

위에서 정의한 User() 클래스와 메서드로 구조화된 Query 질의문을 정의한다

from datetime import datetime

class Query(graphene.ObjectType):
    users = graphene.List(User, first=graphene.Int())

    def resolve_users(self, info, first):
        return [
            User(username='Alice', last_login=datetime.now()),
            User(username='Bob', last_login=datetime.now()),
            User(username='Steven', last_login=datetime.now()),
        ][:first]


사용자 정의 Query를 Test 한다

query3 = """ { users(first: 2) {
                username
                lastLogin } }""" 
schema = graphene.Schema(query=Query)
result = schema.execute(query3)
items  = dict(result.data.items())
print(json.dumps(items,indent=4))

{  "users": [
        { "username": "Alice",
          "lastLogin": "2018-11-19T11:12:40.767433" },
        { "username": "Bob",
          "lastLogin": "2018-11-19T11:12:40.767453" }, ] }

Mutations & Info

CRUD 와 같은 추가적인 기능을 작동하는 경우 아래의 부분 까지는 위와 동일하다

import graphene
from datetime import datetime

class User(graphene.ObjectType):
    id = graphene.ID()
    username = graphene.String()
    last_login =  graphene.DateTime(required=False)

class Query(graphene.ObjectType):
    users = graphene.List(User, first=graphene.Int())

    def resolve_users(self, info, first):
        return [
            User(username='Alice', last_login=datetime.now()),
            User(username='Bob', last_login=datetime.now()),
            User(username='Steven', last_login=datetime.now()),
        ][:first]


사용자 함수

추가적인 작업을 하는경우로써, mutate(self, **info**, username) 에서 info 매개변수는 사용자가 추가하는 설정들을 호출하는 용도로써 활용한다

class CreateUser(graphene.Mutation):

    class Arguments:
        username = graphene.String()

    user = graphene.Field(User)

    # mutate 내부에, 추가 mutate 정의 
    def mutate(self, info, username):

        if info.context.get('is_vip'):
            username = username.upper()
        user = User(username=username)
        return CreateUser(user=user)
class Mutations(graphene.ObjectType):
    create_user = CreateUser.Field()

schema = graphene.Schema(query=Query, mutation=Mutations)

user_info = {'username':'Bob'}
info_items = {'is_vip': True }

# JSX 문법을 활용하여 동적인 Control이 가능하다
query4 = """
    mutation createUser($username: String) {
        createUser(username: $username){
            user {
                username
                }
            }
        }"""

result = schema.execute(
    query4,
    variable_values=user_info,
    context=info_items
)
items = dict(result.data.items())
print(json.dumps(items,indent=4))

{
    "createUser": {
        "user": {
            "username": "BOB"
        }
    }
}


GraphQL 과 Django 연결

동영상에도 포함되어 있지만 단순 view기능 만 구현되어 있었다. 이 부분은 howtographql 에 정리된 내용을 통해서 추가적으로 정리해 보도록 한다