Òscar Vilaplana
Software, Writing, Music
Python, Golang, NodeJS, React
@grimborg
http://oscarvilaplana.cat
―Harro van der Klauw, Engineer at Zupr
# GET /friends
[{
"id": "Aevae2wi",
"name": "Wilbur Whateley",
"avatar": "https://images.fakeurl.com/wilbur-whateley.png"
},
...
]
# GET /plans?creator=Aevae2wi
[{
"id": "huk8Phie",
"creator": "Aevae2wi",
"name": "Go check out weird color in forest",
"date": "2017-06-17T11:48:25.333Z",
"attendees": ["Aevae2wi", "Yah2sava", "thi2ooNg"],
"location": "ooNahx7r"
},
...
]
# Fetch the upcoming plans
- GET /plans
# Fetch the creator names
- GET /friends/Aevae2wi
- GET /friends/Yah2sava
- GET /friends/thi2ooNg
- GET /friends/Aevae2wi
...
# Fetch the attendees names
- GET /friends/Xudou6Oo
- GET /friends/goe8Rae2
- GET /friends/eiphooR8
- GET /friends/iGee8kei
...
# Fetch the locations
- GET /locations/ooNahx7r
- GET /locations/tai0jeiF
...
# Embed the attendees
GET /friends/Aevae2wi/plans?include=attendees
# Only some fields
GET /friends/Aevae2wi/plans?include=attendees&fields=name,attendees
# Bulk fetch
GET /friends?id=Aevae2wi,Yah2sava,thi2ooNg,Aevae2wi
―Harro van der Klauw, Engineer at Zupr
# Embed the attendees
GET /friends/Aevae2wi/plans?include=attendees
# Only some fields
GET /friends/Aevae2wi/plans?include=attendees&fields=name,attendees
# Bulk fetch
GET /friends?id=Aevae2wi,Yah2sava,thi2ooNg,Aevae2wi
{
plans {
name
description
creator {
name
}
location {
name
coordinates
}
attendees {
name
}
}
}
{
plans: [{
name: "Go check out weird color at the forest"
description: "It's freaking me out"
creator: {
name: "Wilbur Whateley"
}
location: {
name: "Forest out of town"
coordinates: "I don't know them"
}
attendees: [
{ name: "Wilbur Whateley" }, { name: "Randolph Carter" }, ...
]
}, ...]
}
type Query {
plans: [Plan]
}
type Plan {
id: ID!
name: String!
description: String
creator: Friend!
attendees: [Friend]!
location: Location!
}
type Friend {
id: ID!
name: String!
avatarUrl: String
}
type Location {
id: ID!
name: String!
coordinates: String!
}
type Query {
plans(limit: Integer, maxDays: Integer): [Plan]
}
{
plans(limit: 10, maxDays: 7) {
name
creator {
name
}
}
}
import graphene
class Query(graphene.ObjectType):
myself = graphene.String()
def resolve_myself(self, args, context, info):
return 'I am Groot'
schema = graphene.Schema(query=Query)
>>> result = schema.execute('''
query {
myself
}
''')
>>> result.data
OrderedDict([('myself', 'I am Groot')])
import graphene
class Plan(graphene.ObjectType):
name = graphene.String()
...
class Query(graphene.ObjectType):
plans = graphene.Field(Plan)
def resolve_plans(self, args, context, info):
return get_plans_from_db()
schema = graphene.Schema(query=Query)
class Friend(models.Model):
name = models.CharField(max_length=200)
class Location(models.Model):
name = models.CharField(max_length=200)
class Plan(models.Model):
name = models.CharField(max_length=200)
datetime = models.DateTimeField()
description = models.CharField(max_length=1000)
location = models.ForeignKey(Location)
creator = models.ForeignKey(Friend)
attendees = models.ManyToManyField('Friend', related_name="plan_attendees")
import graphene
from graphene import Schema, resolve_only_args
from graphene_django import DjangoConnectionField, DjangoObjectType
from plans import models
class Friend(DjangoObjectType):
class Meta:
model = models.Friend
class Location(DjangoObjectType):
class Meta:
model = models.Location
class Plan(DjangoObjectType):
attendees = graphene.List(Friend)
@graphene.resolve_only_args
def resolve_attendees(self):
return self.attendees.all()
class Meta:
model = models.Plan
class CreatePlan(graphene.Mutation):
class Input:
name = graphene.String(description='Name of the plan')
description = graphene.String(description='Extended description of what the creator is up to')
creator_id = graphene.String(description='ID of the friend who creates the plan')
ok = graphene.Boolean()
plan = graphene.Field(Plan)
@staticmethod
def mutate(root, args, context, info):
try:
creator = models.Friend.objects.get(id=args.get('creator_id'))
except models.Plan.DoesNotExist:
return CreatePlan(ok=False)
plan = models.Plan(
name=args.get('name'),
description=args.get('description'),
creator=creator
)
plan.save()
return CreatePlan(plan=plan, ok=True)
class Mutation(graphene.ObjectType):
create_plan = CreatePlan.Field()
// queries.js
module.exports = {
fetchItems: gql`
query items {
items {
id
name
}
}`,
createItem: gql`
mutation createItem($name: String!, $duration: Int!) {
createItem(name: $name, duration: $duration) {
id
}
}
`
};
class ItemList extends Component {
render() {
const { loading, error, items, refetch } = this.props.fetchItems;
if (loading) {
return <LoadingSpinner />
}
if (error) {
return <ErrorPage />
}
return (
<div>
<ul>
{items.map(item => <li><Item key={item.id} name={item.name} /></li>)}
</ul>
<Button onClick={refetch}>Refresh</Button>
</div>
)
}
}
const ItemListWithData = graphql(queries.fetchItems)(ItemList);
```
class ItemCreator extends Component {
handleSubmit = async ({ name }) => {
const result = await mutate({
variables: {
name,
duration,
},
refetchQueries: [
{
query: queries.fetchItems,
},
],
});
}
// ...
}
const ItemCreatorWithMutation = graphql(queries.createItem)(ItemCreator);