GraphQL - a type system for your API
by Oleg Ilyenko / @easyangel
a.k.a. BFF (Backend For a Frontend)
A Data Query Language
{
"data": {
"product": {
"name": "Delicious Cake",
"description": "Just taste it!"
"picture": {
"width": 150,
"height": 150,
"url": "http://..."
}
}
}
}
{
product {
name
description
picture {
width
height
url
}
}
}
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"))
class ProductRepo {
def products: List[Product] =
Product("1", "Cheesecake", "Tasty") ::
Product("2", "Health Potion", "+50 HP") :: Nil
def product(id: String): Option[Product] =
products find (_.id == id)
}
val IdArg = Argument("id", StringType)
val QueryType = ObjectType("Query", "Query entry point",
fields[ProductRepo, Unit](
Field("product", OptionType(ProductType),
description = Some("Get product by ID"),
arguments = IdArg :: Nil,
resolve = c ⇒ c.ctx.product(c arg IdArg)),
Field("products", ListType(ProductType),
description = Some("List all product"),
resolve = c ⇒ c.ctx.products)))
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, new ProductRepo)