GraphQL - a type system for your API
by Oleg Ilyenko / @easyangel
a.k.a. BFF (Backend For a Frontend)
A Data Query Language
query MyProduct {
product(id: 123) {
name
description
picture {
width
height
url
}
}
}
{
"data": {
"product": {
"name": "Delicious Cake",
"description": "Just taste it!"
"picture": {
"width": 150,
"height": 150,
"url": "http://..."
}
}
}
}
query MyProduct {
products {
picture(size: 300) {
width, height, url
}
}
}
{
"data": {
"products": [
{
"picture": {
"width": 300,
"height": 300,
"url": "http://..."
}
},
...
]
}
}
query MyProduct {
products {
thumb: picture(size: 100) {
width
}
fullSize: picture(size: 500) {
width
}
}
}
{
"data": {
"products": [
{
"thumb": {
"width": 100
},
"fullSize": {
"width": 500
}
},
...
]
}
}
A Scala GraphQL Implementation
type Picture {
width: Int!
height: Int!
url: String
}
case class Picture(
width: Int,
height: Int,
url: Option[String]
)
val PictureType = ObjectType(
"Picture",
"The product picture",
fields[Unit, Picture](
Field("width", IntType,
resolve = _.value.width),
Field("height", IntType,
resolve = _.value.height),
Field("url", OptionType(StringType),
description = Some("Picture CDN URL"),
resolve = _.value.url)))
type Picture {
width: Int!
height: Int!
url: String
}
case class Picture(
width: Int,
height: Int,
url: Option[String]
)
val PictureType =
deriveObjectType[Unit, Picture](
ObjectTypeDescription("The product picture"),
DocumentField("url", "Picture CDN URL"))
interface Identifiable {
id: String!
}
trait Identifiable {
def id: String
}
val IdentifiableType = InterfaceType(
"Identifiable",
"Entity that can be identified",
fields[Unit, Identifiable](
Field("id", StringType,
resolve = _.value.id)))
type Product
implements Identifiable {
id: String!
name: String!
description: String
picture(size: Int!): Picture
}
case class Product(
id: String,
name: String,
description: String
) extends Identifiable {
def picture(size: Int): Picture =
Picture(
width = size,
height = size,
url = Some(
s"//cdn.com/$size/$id.jpg"))
}
val ProductType =
deriveObjectType[Unit, Product](
Interfaces(IdentifiableType),
IncludeMethods("picture"))
type Query {
product(id: Int!): Product
products: [Product]
}
class ProductRepo {
val Products = List(
Product("1", "Cheesecake", "Tasty"),
Product("2", "Health Potion", "+50 HP"))
@GraphQLField
def product(id: String) =
Products find (_.id == id)
}
case class Ctx(repo: ProductRepo)
val QueryType =
deriveContextObjectType[Ctx, ProductRepo, Unit](
_.repo, ObjectTypeName("Query"))
val query =
graphql"""
query MyProduct {
product(id: 2) {
name
description
picture(size: 500) {
width, height, url
}
}
}
"""
val schema = Schema(QueryType)
val result: Future[Json] =
Executor.execute(schema, query, Ctx(new ProductRepo))
{
hero {
id
name
}
}
// Response
{
"data": {
"hero": {
"id": "2001",
"name": "R2-D2"
}
}
}