qr

fistfulofbytes

GraphQL and g2sd

permalink: ffbyt.es/C39Q

24 June 2015

Index

This article is about my GraphQL language implementation and how it's compiled to SQL with g2sd.

What is GraphQL?

GraphQL is meant to be a replacement to rest, in the sense that instead of writing a query such as /users/get/3500401 you'd write something like

{
  user(id: 3500401) {
    id,
    name,
    isViewerFriend,
    profilePicture(size: 50)  {
      uri,
      width,
      height
    }
  }
}

which would return something like;

{
  "user" : {
    "id": 3500401,
    "name": "Jing Chen",
    "isViewerFriend": true,
    "profilePicture": {
      "uri": "http://someurl.cdn/pic.jpg",
      "width": 50,
      "height": 50
    }
  }
}

as opposed to dumping the entire table. How you get that data, process it and use what backends to store it is entirely up to you.

However since GraphQL isn't yet ready for finalization and there are impatient people like me who have jumped the gun and interpreted what this would be by not reading the entire article and tried to infer what it is from the two code snippets that were published.

What my implementation gives you is a graph, an abstract syntax tree to be more specific, what you do with it is entirely up to you.

This isn't a complete implementation of GraphQL seeing at the moment of writing this it wasn't released. If you want to know more about the thing I highly recommend you check out

g2sd (Graph to SQL Daemon)

GraphQL to SQL for instance takes in a GraphQL and prints it as SQL for instance

{
  Products(ProductID: 3) {
    ProductName,
    UnitsInStock
  }
}

and converts it to

select ProductName, UnitsInStock from Products where ProductID = 3;

which is a better query language because it does look like what we will get back in JSON form, we've also gotten rid of the select and where clauses, but it's not a graph.

Can we represent more complex data structures like this in SQL?

{
  Products(ProductID: 3) {
    ProductName,
    UnitsInStock,
    Categories() {
       CategoryName
    }
  }
}

for instance this query will be turned in to two queries.

select ProductName, UnitsInStock from Products where ProductID = 3;
select CategoryName from Categories ;

since there are no params in the second query it will return all the categories in the DB. I'm sure someone will correct me on this because there is a esoteric way this can be achieved I'm not aware off (I'll be happy if you send me a pull request) but at this stage I'm not entirely concerned with writing good SQL queries.

{
    "Categories": [
        {
            "CategoryName": "Beverages"
        },
        {
            "CategoryName": "Condiments"
        },
        {
            "CategoryName": "Confections"
        },
        {
            "CategoryName": "Dairy Products"
        },
        {
            "CategoryName": "Grains/Cereals"
        },
        {
            "CategoryName": "Meat/Poultry"
        },
        {
            "CategoryName": "Produce"
        },
        {
            "CategoryName": "Seafood"
        }
    ],
    "CategoryID": 2,
    "ProductName": "Aniseed Syrup",
    "UnitsInStock": 13
}

Enter variables.

Clearly this is stupid, we won't be needing this all this, we'll be needing the one that carries the same CategoryID as our original query. GraphQL allows us to have Variables these are marked with $, in g2sd they are able to access their parent result set and use the parents result as a param so this

{
  Products(ProductID: 3) {
    ProductName,
    UnitsInStock,
    CategoryId,
    Categories(CategoryID: $CategoryID) {
       CategoryName
    }
  }
}

becomes this

select ProductName, UnitsInStock, CategoryId from Products where ProductID = 3;
select CategoryName from Categories where CategoryID = 2;

and we get

{
    "Categories": {
        "CategoryName": "Condiments"
    },
    "CategoryID": 2,
    "ProductName": "Aniseed Syrup",
    "UnitsInStock": 13
}

great, you say! You've done something that could have been done with a join and you did it with two queries and wasted all those cycles. You are a jerk.

First of all dear reader no need for name calling. Secondbly we are not finished.

How about we make this a bit more interesting?

{
  Products(ProductID: 11) {
    ProductName,
    UnitsInStock,
    ProductID,
    OrderDetails(ProductID: $ProductID) {
       OrderID,
       Orders(OrderID: $OrderID) {
         EmployeeID,
         Employees(EmployeeID: $EmployeeID) {
            FirstName
         }
       }
    }
  }
}

And We'll get something like

{
    "OrderDetails": [
        {
            "OrderID": 10420,
            "Orders": {
                "EmployeeID": 3,
                "Employees": {
                    "FirstName": "Janet"
                }
            }
        },
        ( omitted )
        {
            "OrderID": 10848,
            "Orders": {
                "EmployeeID": 7,
                "Employees": {
                    "FirstName": "Robert"
                }
            }
        }
    ],
    "ProductID": 9,
    "ProductName": "Mishi Kobe Niku",
    "UnitsInStock": 29
}

Here is the SQL that gets us this result.

select ProductName, UnitsInStock, ProductID from Products where ProductID = 9;
select OrderID from OrderDetails where ProductID = 9;
select EmployeeID from Orders where OrderID = 10420;
select FirstName from Employees where EmployeeID = 2;
( omitted )

Vision for g2sd

So far what we have done is not amazing, and it is certainly not production ready. If you don't see the benefit of writing a declarative queries, how it can speed up your prototyping, or not needing to write any server-side glue code, it's still OK. Because I haven't talked about the vision yet. For that I'm going to borrow, most if not all the features of vitess. I want

In addition to vitess I want to re-write most of the GraphQL to SQL bits so they make better use of existing SQL language features. If nothing else comes out of this, I've made a great prototyping tool for my self. And I'm happy with that.

Vision for GraphQL (Go implementation)

I think there is a happy place where GraphQL can live in the SOA world. Things like CloudEndpoints and go-kit use registration mechanisms for handlers, I am trying to figure out the best way to integrate this in to such a work flows. More on that later. b

By Sevki

Related articles