GraphQL - minnie0531/fastapi-template GitHub Wiki
graphQL
Refer to graphene-python tutorial
SqlAlchemy์์ ์ ์ธํ table์ ์ฌ์ฉํ์ฌ graphQL์ ๊ตฌํ ํจ. - graphene_sqlalchemy๋ฅผ ์ค์น ํด์ผํจ.
์ธ์ ์ฐ๊ฒฐ
SqlAlchemyย ์์ ์ฌ์ฉํ ๋ด์ฉ ๊ทธ๋๋ก ์ฌ์ฉ ๊ฐ๋ฅ. Model query ๋ฅผ ์ด์ฉํ์ฌ query ๋ฅผ ์ํํ๊ธฐ ๋๋ฌธ์ ํด๋น ๋ถ๋ถ์ ๋ํ ์ ์ธ์ด ํ์ํจ.
import cx_Oracle
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker
dsn = cx_Oracle.makedsn(host="{HOST}", port=${PORT}, sid=${SID})
engine = create_engine("oracle+cx_oracle://${user_id}:${user_pw}@%s" % str(dsn))
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
# Below Parsts should be delcared in main or entry point!!
Base.metadata.create_all(bind=engine)
**#This part is for graphQL**
**Base.query = scoped_session(SessionLocal).query_property()**
Schema
SqlAlchemy์ ORM ๋ชจ๋ธ์ ์ด์ฉํ์ฌ representative model์ ๋ง๋ค์ด ์ค (๋น์ง๋์ค ๋ชจ๋ธ).
Relay๋ React ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ ๋ฐ์ดํฐ ๊ด๋ฆฌ ํ๋ ์์ํฌ. ๊ฐ ์ปดํฌ๋ํธ๋ง๋ค ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์ ์ธํ๊ณ , ์ปดํฌ๋ํธ์ ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ๋ฐ๋ผ์ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์์ ์ปดํฌ๋ํธ๋ก ์ ๋ฌ ๋ฐ ์กฐํฉํ์ฌ ๋จ์ผ GraphQL ์ฟผ๋ฆฌ๋ก ๋ง๋ค์ด ์ค.
(์ฌ๋ฌ๊ฐ์ query์์ฒญ ์ ์ํ๋ outputํํ๋ก ์ ๋ฌํ๊ธฐ ์ํ framework)
Node๋ ์ฐ๊ฒฐ๋ ์ปดํฌ๋ํธ๋ฅผ ์๋ฏธํจ. ์ฆ ๋ฆด๋ ์ด๋ก ์ ๋ฌ ํ ๋ ๋ค์ ์ฃผ์๋ฅผ ์๋ฏธํจ.
from app.model.item import Item
from graphene import relay, String
from graphene_sqlalchemy import SQLAlchemyConnectionField, SQLAlchemyObjectType
class UserGqlModel(SQLAlchemyObjectType):
class Meta:
model = User
interfaces = (relay.Node,)
class ItemGqlModel(SQLAlchemyObjectType):
class Meta:
model = Item
interfaces = (relay.Node,)
Query
SELECT or GET
db์ ๋ํ ์ ์ฒด ์กฐํ๋ ์๋์ ๊ฐ์ด all_users or all_items๋ฅผ ํตํด ์ ๊ทผ ๊ฐ๋ฅ
๋ง์ฝ ์กฑ๊ฑด์ด ์๋ ์กฐํ์ ๊ฒฝ์ฐ resolve๋ฅผ ์ด์ฉํด์ ๊ตฌํ ํด์ผ ํจ.
import graphene
from app.model.user import User
from app.model.item import Item
from graphene import relay, String
from graphene_sqlalchemy import SQLAlchemyConnectionField, SQLAlchemyObjectType
from app.graph_ql.gql_model import UserGqlModel, ItemGqlModel
import logging
import os
logger = logging.getLogger(os.environ.get("PROJECT"))
class Query(graphene.ObjectType):
node = relay.Node.Field()
user = SQLAlchemyConnectionField(UserGqlModel.connection, name=String())
all_users = SQLAlchemyConnectionField(UserGqlModel.connection)
all_items = SQLAlchemyConnectionField(ItemGqlModel.connection)
def resolve_user(self, info, **kwargs):
name = kwargs.get("name")
logger.info("resolve_user")
logger.info("name : %s" % name)
if name is not None:
return UserGqlModel.get_query(info).filter_by(name=name)
์๋์ ๊ฐ์ด graphQL์ ์์ฒญ ํ๋ฉด "user" interface๋ฅผ ์ด์ฉํ์ฌ user table์ email๊ณผ join๋ item ํ ์ด๋ธ์ architetureํญ๋ชฉ๋ง ๊ฐ์ ธ์ด.( ๐ฎ)
query {
user(name:"MinHeeKim") {
edges {
node {
**email**
item {
**architecutre**
}
}
}
}
}
Mutation
INSERT, UPDATE, DELETE or POST, PUT, PATCH, DELETE
๊ฐ behavior์ ๋ํ mutation์ ์ ์ํด์ ์ฌ์ฉํจ. ์๋๋ creation์ ๋ํด๋น๋๋ฉฐ, update, delete์ญ์ ๋น์ทํ๊ฒ ์ฌ์ฉ ๊ฐ๋ฅ.
Arguement class ๋ ์ ๋ ฅ๋ฐ์ field์ ์ ์ํ๊ณ , ๊ทธ ์๋ ์ด๋ค์์ return๋ฐ์์ง๋ฅผ ์ ์ํจ.
mutate ํจ์์์ ์ค์ DB ๋ฅผ ํตํด ์ํ๋๋ ๊ธฐ๋ฅ์ ์์ฑํ๊ณ ์์ ์ ์ํ return field ๋ฅผ ๋ฐํ ํ๋ค.
Mutaion class ํตํด ํด๋น class ์ ์ฐ๊ฒฐ ์์ผ์ค.
from graphene import String, Mutation, Int, Boolean, Field
import graphene
from app.graph_ql.gql_model import UserGqlModel
from app.model.user import User
from app.repository.sql_session import SessionLocal
import logging
import os
logger = logging.getLogger(os.environ.get("PROJECT"))
db = SessionLocal()
class CreateUser(Mutation):
# input parameters
class Arguments:
name = String(required=True)
department = String()
email = String()
age = Int()
phone = String()
address = String()
floor = Int()
# return fields definition
data = Field(User)
success = Boolean()
@staticmethod
def mutate(self, info, **kwars):
user = User(**kwars)
db.add(user)
db.commit()
db.refresh(user)
logger.info("mutation")
return CreateUser(data=user, success=True)
class Mutation(graphene.ObjectType):
logger.info("hello")
create_user = CreateUser.Field()
์๋์ ๊ฐ์ด mutation์ ์์ฒญํ๋ฉด ์๋ก์ด User ๊ฐ insert ๋๊ณ ๊ฒฐ๊ณผ์ ๋ํ result ์ User field์ค์์ name, department, age, email์ ๋ํ ๊ฐ์ ๋๋ ค์ค.
mutation{
createUser (
name : "UJHan",
department: "FrontEnd Service",
age: 27,
email: "[[email protected]](mailto:[email protected])",
phone: "000-9999-8888",
address: "Pankyo",
floor:17
){
success
data{
name
department
age
email
}
}
endpoint ์ฐ๊ฒฐ
GraphQLApp์ผ๋กquery์ mutation์ ์ฐ๊ฒฐ ์์ผ์ค๋ค.
...
# Add graphql endpoint
app.add_route(
"/graph", GraphQLApp(schema=graphene.Schema(query=Query, mutation=Mutation))
)
...