Azure Functions 및 Graphene에서 CosmosDB 데이터 작업 수행 (2)

1. 소개



Azure Functions 및 Graphene에서 CosmosDB 데이터 작업 수행 」에서는 Azure Functions로 GraphQL API의 Query 오퍼레이션을 구현하고 있었습니다만, Mutation 오퍼레이션을 구현하고 있지 않았으므로, 이번은 Mutation의 구현을 진행해 나가고 싶습니다.

전회까지의 사전 준비나 실시 내용은 이 기사이 기사 를 참조해 주십시오.

2. GraphQL 쿼리의 뮤테이션 정의



Azure Functions 및 Graphene에서 CosmosDB 데이터 작업 수행 」로 실시해 온 것에 이어, Graphene 를 이용해 GraphQL의 Mutation을 구현해 갑니다. 구현에 대해서는 Graphene 공식 문서 를 참조해 갑니다.

뮤테이션은, 데이터 소스에의 기입과 그 실행 결과의 취득을 실시하는, GraphQL 오퍼레이션이 됩니다. (쿼리는 데이터 소스에 대한 읽기 결과 검색 전용)

스키마를 정의한 다음 해석기를 정의하고 마지막으로 해석기 내부에 데이터 소스에 대한 처리를 구현하는 흐름은 이전에 마찬가지입니다.

2.1. Mutation의 각 조작에 대응하는 해석기 정의



GraphQL의 Mutation형의 각 조작(필드)과 리졸버 함수를 대응짓기에 있어서, 조작마다 Mutation을 상속한 클래스를 준비해 둡니다.
#Mutation型の各操作と対応づけるリゾルバーの定義
class CreateItem(graphene.Mutation):
    class Arguments:
        item = ItemInput(required=True) #ミューテーションのAugument
    Output = Item #ミューテーションの実行結果の型
    def mutate(self, info, item): #Mutation実行時に呼び出される関数
        i = Itemオブジェクトを作成するDB操作
        return i

위의 예에서는 Input 형의 오브젝트를 이용하고 있습니다. 여기에서는 InputObjectType 을 상속한 클래스를 준비해, Query나 Mutation 의 각 조작에 Arguments로서 건네줄 수 있도록(듯이) 합니다.
#idとmessageというフィールドを持つinput型の定義
class ItemInput(graphene.InputObjectType): #inputの定義
    id = graphene.String(required=True)
    message = graphene.String()

2.2. Mutation 형의 정의



GraphQL의 Mutation형도 Query형과 같이 ObjectType를 상속한 클래스로서 준비합니다.
Mutation형에서는 필드명과 Mutation을 상속한 클래스를 대응시켜 두면, GraphQL 쿼리의 뮤테이션에 기술된 필드명에 대응하는 리졸버가 불려 가는 흐름이 됩니다. (Mutation형과 Mutation을 계승한 클래스로 혼동스럽다...)
#createItemというフィールドを持つMutation型の定義
class Mutation(graphene.ObjectType):
    create_Item = CreateItem.Field()

게다가 snake_case는 camelCase에 대체해 준다는 것 .

2.3. 루트 쿼리 선언 및 뮤테이션 수행



GraphQL의 쿼리를 실행할 때, Schema 클래스에서 mutation과 Mutation 타입을 대응시켜 (루트 쿼리 타입의 선언) 해 두는 것으로, 실제로 뮤테이션을 실행 (execute 메소드의 호출) 할 때에 대응하는 Mutation의 해석기 함수(또는 클래스)가 호출되어 처리가 실행됩니다. 이것은 Query 유형의 경우와 유사한 동작입니다.
schema = graphene.Schema(
    query=Query,
    mutation=Mutation #ここを追加
)
schema.execute("GraphQLのミューテーション")

2.4. GraphQL 관련 코드



이번에 새로 추가한 GraphQL 관련 코드는 다음과 같습니다.
# 전체 코드는 GitHub 에 PUSH하고 있지만 정리 중입니다.

graphql/graphql.py
# input DBItemInput
class DBItemInput(graphene.InputObjectType):
    id = graphene.String(required=True)
    owner = graphene.String(required=True)
    partitionKey = graphene.ID(required=True)
    message = graphene.String()
    addition = graphene.String()

class CreateItem(graphene.Mutation):
    class Arguments:
        item = DBItemInput(required=True)
    Output = DbItem
    def mutate(self, info, item):
        results = DatabaseConnection().create_item(item).pop()
        i = DbItem.__new__(DbItem)
        i.__dict__.update(results)
        return i

class DeleteItem(graphene.Mutation):
    class Arguments:
        item = DBItemInput(required=True)
    Output = DbItem
    def mutate(self, info, item):
        results = DatabaseConnection().delete_item(item)
        if results.__len__() > 0:
            i = DbItem.__new__(DbItem)
            i.__dict__.update(results[0])
            return i
        return None

class UpsertItem(graphene.Mutation):
    class Arguments:
        item = DBItemInput(required=True)
    Output = DbItem
    def mutate(self, info, item):
        results = DatabaseConnection().upsert_item(item)
        i = DbItem.__new__(DbItem)
        i.__dict__.update(results) 
        return i

# type Mutation
class Mutation(graphene.ObjectType):
    create_Item = CreateItem.Field()
    delete_Item = DeleteItem.Field()
    upsert_Item = UpsertItem.Field()

class GraphQL:
    def __init__(self):
        self.schema = graphene.Schema(
            query=Query,
            mutation=Mutation
        )
        pass

    def query(self, query):
        results = self.schema.execute(query)
        return json.dumps(results.data)


위의 스키마를 GraphQL 스키마 정의 언어로 작성하면 다음과 같은 느낌이 듭니다.
input DBItemInput {
  id: String!
  owner: String!
  partitionKey: String!
  message: String
  addition: String
}

type Mutation {
  createItem(DBItemInput!): DbItem
  deleteItem(DBItemInput!): DbItem
  upsertItem(DBItemInput!): DbItem
}

schema {
  query: Query
  mutation: Mutation
}


4. GraphQL 뮤테이션의 실행 확인



구현한 함수에 GraphQL의 뮤테이션을 발행해, 응답을 보고 싶습니다. 실행 방법에 대해서는
쿼리의 발행은 curl 명령을 사용하는 것 외에 GraphiQL 이나 Insomnia 를 사용하는 손이 있다고 생각합니다.
 
curl 명령의 경우 다음과 같이 쿼리를 실행할 수 있습니다.
curl -X POST -H "Content-Type: application/json" -d '{"query": "mutation { createItem (item: {id: "id1", owner: "testuser", partitionKey: 1, message: "test message1", addition: "addtion message 1"}) { id message } }"}' http://localhost:7071/api/MyFunction

이번에 발행한 GraphQL 뮤테이션은 다음과 같습니다. Insomnia의 경우 URL을 지정하고 다음 뮤테이션을 발행하면 응답을 얻을 수 있습니다.
mutation {
  createItem(item: {id: "id1", owner: "testuser", partitionKey: 1, message: "test message1", addition: "addtion message 1"}) { 
    id
    message
  } 
}

Insomnia에서 확인하면 다음과 같은 결과가 되었습니다.


GrahpQL의 이용이나 구현을 진행함에 있어서, GraphQL의 사양이나 용어에 대해서 보다 이해를 해 두고 싶네요.

참고 정보



Graphene
Graphene Mutation

좋은 웹페이지 즐겨찾기