Keith Yang, May 2018, PyCon
from future import __hope__
At the point of sale, the merchant calculates the amount owed by the customer, indicates that amount, may prepare an invoice for the customer, which may be a cash register printout, and indicates the options for the customer to make payment. -- Point of Sale, Wikipedia
/users
vs /users/
/pos/client/API/
vs alias /api/v1/pos
GET
, POST
, PUT
or ... PATCH
?400
, 403
, 429
or ... 302
?Disclaimer: not all caused by RESTful if carefully crafted with OpenAPI Specification (Swagger or Stoplight)
HTTP GET
/games/1
{
'status': 123,
'name': '🐲'
},
}
HTTP GET
/graphql?query={ restaurant(id: "1") \
{ name, category { primary } } }
{
'data': {
'category': {
'primary': 'Taiwanese Cuisine',
},
'name': 'Mazendo'
},
'errors': []
}
HTTP GET
/restaurants/1
{
'category': {
'primary': 'Taiwanese Cuisine',
'second': 'Beef Noodle',
},
'name': 'Mazendo'
},
}
GET
requests, andPOST/PATCH/PUT/DELETE
requestsGraphQL
is a keyword easier to find IMMO.For example, between ECMAScript and Python
query {
restaurant {
logoUrl: String!
}
}
differenceAmount
vs workingPrice
defaultPrice
vs startMoney
query {
restaurant {
settings {
...
}
}
}
errors
and data
{
"errors": [{
"message": String,
...
}],
"data": {
"restaurant": {
"settings": {...}
}
}
}
Where it takes time to learn
Grow with spec evolving
interface Restaurant {
id: ID!
name: String!
categories: [Category]!
}
type TaiwaneseRestaurant implements Restaurant {
id: ID!
name: String!
categories: [Category]!
tax_unique_identifier: String
}
pip install graphene
MAKE LIVE EASIER
import graphene
...
class ReportObject(graphene.ObjectType):
timestamp = graphene.Int()
uuid = graphene.UUID()
type = InventoryTypeGrapheneEnum()
...
purchase_amount = graphene.String()
counting_amount = graphene.Float()
▾ graphene/
▸ pyutils/
▸ relay/
▾ test/
__init__.py
▾ tests/
▸ issues/
__init__.py
▸ types/
▸ utils/
__init__.py
LICENSE
MANIFEST.in
mypy.ini
README.rst
setup.cfg
setup.py
...
UPGRADE-v2.0.md
▸ bin/
▸ docs/
▸ examples/
apollographql/graphql-tools
Looks fine to be with graphene-django
cookbook/urls.py
from django.conf.urls import url
from django.contrib import admin
from graphene_django.views import GraphQLView
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^graphql', GraphQLView.as_view(graphiql=True)),
]
cookbook/recipes/schema.py
from cookbook.recipes.models import Recipe, RecipeIngredient
from graphene import Node
from graphene_django.types import DjangoObjectType
class RecipeNode(DjangoObjectType):
class Meta:
model = Recipe
interfaces = (Node, )
filter_fields = ['title','amounts']
cookbook/recipes/schema.py
from graphene_django.filter import DjangoFilterConnectionField
class Query(object):
recipe = Node.Field(RecipeNode)
all_recipes = DjangoFilterConnectionField(RecipeNode)
recipeingredient = Node.Field(RecipeIngredientNode)
all_recipeingredients = DjangoFilterConnectionField(
RecipeIngredientNode)
It does provide SerializerMutation to help you with DRF. However in our case
from graphene_django.rest_framework.mutation import \
SerializerMutation
class MyAwesomeMutation(SerializerMutation):
class Meta:
serializer_class = MySerializer
ichef/queryfilter
To share same query interface between Django ORM, SQLAlchemy, GraphQL backend, and raw dict
queryfilter
dicts = [
{"age": None},
{"age": 1},
{"age": 2},
]
query_filter = QueryFilter({
"age": {
"type": "number",
"options": {"drop_none": True},
"min": 0, "max": 1,
}
})
assert len(query_filter.on_dicts(dicts)) == 1
queryfilter
import graphene
from queryfilter import (QueryFilter,
BirthFilterQueryType, TextFilterQueryType,
NumberRangeFilterQueryType)
class UserQueryFilter(graphene.InputObjectType):
name = TextFilterQueryType()
birth = BirthFilterQueryType()
total_login = NumberRangeFilterQueryType()
I’ve spent 2 years trying to get Apollo Server into prod,
now I’ll no doubt have to make changes.
r/graphql
graphene-python/*
Graphene-Mongo
ichef/queryfilter
Just like all other new or different technology you hope to have in the orgazination, it's more of team art and culture. Then it's not always someone's fault, in different condition it's just meant to be failed. It's just that if you didn't try, things surely won't happen. Sometimes it's just that the technology not worthy indead. For this one, I encourage you to try on.