[S2GRAPH-172]: Suggest to implement GraphQL as standard web interface for
S2Graph.
JIRA:
[S2GRAPH-172] https://issues.apache.org/jira/browse/S2GRAPH-172
Pull Request:
Closes #131
Author
daewon <[email protected]>
Project: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/commit/6a7e58a4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/tree/6a7e58a4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/diff/6a7e58a4
Branch: refs/heads/master
Commit: 6a7e58a463d110f438c478962ad6fc1df44d8e8f
Parents: 8f9214e 1f1dee3
Author: DO YUNG YOON <[email protected]>
Authored: Tue Feb 13 18:23:30 2018 +0900
Committer: DO YUNG YOON <[email protected]>
Committed: Tue Feb 13 18:25:29 2018 +0900
----------------------------------------------------------------------
CHANGES | 1 +
build.sbt | 8 +-
project/plugins.sbt | 3 +-
.../org/apache/s2graph/core/Management.scala | 4 +-
.../org/apache/s2graph/core/mysqls/Label.scala | 3 +
.../apache/s2graph/core/mysqls/LabelMeta.scala | 8 +
.../apache/s2graph/core/mysqls/Service.scala | 1 +
s2graphql/README.md | 550 +++++++++++++++++++
s2graphql/build.sbt | 40 ++
s2graphql/project/build.properties | 18 +
s2graphql/project/plugins.sbt | 19 +
s2graphql/src/main/resources/application.conf | 25 +
s2graphql/src/main/resources/log4j.properties | 26 +
s2graphql/src/main/scala/GraphQLServer.scala | 110 ++++
s2graphql/src/main/scala/GraphRepository.scala | 164 ++++++
s2graphql/src/main/scala/HttpServer.scala | 61 ++
s2graphql/src/main/scala/S2Type.scala | 519 +++++++++++++++++
.../main/scala/SangriaPlayJsonScalarType.scala | 76 +++
s2graphql/src/main/scala/SchemaDef.scala | 36 ++
s2graphql/src/test/resources/application.conf | 18 +
.../rest/play/controllers/AdminController.scala | 8 +-
21 files changed, 1688 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/6a7e58a4/CHANGES
----------------------------------------------------------------------
diff --cc CHANGES
index 2dcdfcf,8384bdc..0a46c3b
--- a/CHANGES
+++ b/CHANGES
@@@ -55,6 -55,7 +55,7 @@@ Release Notes - S2Graph - Version 0.2.
* [S2GRAPH-125] - Add options field on Label model for controlling
advanced options.
* [S2GRAPH-166] - Provide embeddable storage backend using RocksDB.
* [S2GRAPH-175] - Provide Elastic Search Index Provider.
- * [S2GRAPH-172] - Suggest to implement GraphQL as standard web interface
for S2Graph.
++ * [S2GRAPH-172] - Suggest to implement GraphQL as standard web interface
for S2Graph.
** Task
* [S2GRAPH-162] - Update year in the NOTICE file.
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/6a7e58a4/s2core/src/main/scala/org/apache/s2graph/core/mysqls/LabelMeta.scala
----------------------------------------------------------------------
diff --cc s2core/src/main/scala/org/apache/s2graph/core/mysqls/LabelMeta.scala
index 920b432,c715c47..5018285
--- a/s2core/src/main/scala/org/apache/s2graph/core/mysqls/LabelMeta.scala
+++ b/s2core/src/main/scala/org/apache/s2graph/core/mysqls/LabelMeta.scala
@@@ -187,13 -187,15 +187,21 @@@ object LabelMeta extends Model[LabelMet
val cacheKey = s"labelId=${labelId}"
cacheKey -> ls
}.toList)
+
+ ls
+ }
+
+ def updateStoreInGlobalIndex(id: Int, storeInGlobalIndex: Boolean)(implicit
session: DBSession = AutoSession): Try[Long] = Try {
+ sql"""
+ update label_metas set store_in_global_index =
${storeInGlobalIndex} where id = ${id}
+ """.updateAndReturnGeneratedKey.apply()
}
+
+ def updateStoreInGlobalIndex(id: Int, storeInGlobalIndex: Boolean)(implicit
session: DBSession = AutoSession): Try[Long] = Try {
+ sql"""
+ update label_metas set store_in_global_index =
${storeInGlobalIndex} where id = ${id}
+ """.updateAndReturnGeneratedKey.apply()
+ }
}
case class LabelMeta(id: Option[Int],
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/6a7e58a4/s2graphql/README.md
----------------------------------------------------------------------
diff --cc s2graphql/README.md
index 0000000,4146e8e..56d9645
mode 000000,100644..100644
--- a/s2graphql/README.md
+++ b/s2graphql/README.md
@@@ -1,0 -1,530 +1,550 @@@
++<!---
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements. See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership. The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License. You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing,
++ * software distributed under the License is distributed on an
++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++ * KIND, either express or implied. See the License for the
++ * specific language governing permissions and limitations
++ * under the License.
++ */
++--->
+ # Suggest to implement GraphQL as standard web interface for S2Graph.
+
+ - To support GraphQL i used [Akka HTTP](https://github.com/akka/akka-http)
and [Sangria](https://github.com/sangria-graphql). each is an HTTP Server and
GraphQL Scala implementation.
+ - I also used [GraphiQL](https://github.com/graphql/graphiql) as a tool for
GraphQL queries.
+
+ ## Wroking example
+
+

+
+

+
+
+ ## Overview
+
+ The reason I started this work is because the `Label` used by S2Graph has a
strong type system, so I think it will work well with the `schema` provided by
GraphQL.
+
+ To do this, we converted S2Graph Model (Label, Service ...) into GraphLQL
schema whenever added (changed).
+
+ ## Setup
+ Assume that hbase is running on localhost.
+ If the hbase environment is not set up, you can run it with the following
command
+
+ ```bash
+ sbt package
+ target/apache-s2graph-0.2.1-SNAPSHOT-incubating-bin/bin/hbase-standalone.sh
start
+ ```
+
+ If hbase is running well, run the following command after cloning the project
locally.
+
+ `GraphiQL` is not directly related to the `GraphQL` implementation, but is
recommended for convenient queries.
+ Because of the license problem, you should download the file through the
following command.
+
+ ```bash
+ cd s2graphql/src/main/resources
+ wget
https://raw.githubusercontent.com/sangria-graphql/sangria-akka-http-example/master/src/main/resources/graphiql.html
+ ```
+
+ You can see that the `graphiql.html` file is added to the
`s2graphql/src/main/resources` folder as shown below.
+
+ ```
+ $ls
+ application.conf graphiql.html log4j.properties
+ ```
+
+ And let's run http server.
+
+ ```bash
+ sbt -DschemaCacheTTL=-1 -Dhttp.port=8000 'project s2graphql' '~re-start'
+ ```
+
+ When the server is running, connect to `http://localhost:8000`. If it works
normally, you can see the following screen.
+
+ 
+
+ ## API List
+ - createService
+ - createLabel
+ - addEdges
+ - addEdge
+ - query (You can recursively browse the linked labels from the service and
any other labels that are linked from that label)
+
+ ## Your First Grpah (GraphQL version)
+
+ [S2Graph
tutorial](https://github.com/apache/incubator-s2graph#your-first-graph)
+ I have ported the contents of `Your first graph` provided by S2Graph based on
GraphQL.
+
+ ### Start by connecting to `http://localhost:8000`.
+
+ The environment for this example is Mac OS and Chrome.
+ You can get help with schema-based `Autocompletion` using the `ctrl + space`
key.
+
+ If you add a `label` or `service`, you will need to `refresh` (`cmd + r`)
your browser because the schema will change dynamically.
+
+ 1. First, we need a name for the new service.
+
+ The following POST query will create a service named "KakaoFavorites".
+
+ Request
+ ```graphql
+ mutation {
+ createService(
+ name: "KakaoFavorites",
+ compressionAlgorithm: gz
+ ) {
+ isSuccess
+ message
+ created {
+ id
+ }
+ }
+ }
+ ```
+
+ Response
+ ```json
+ {
+ "data": {
+ "createService": {
+ "isSuccess": true,
+ "message": "Created successful",
+ "created": {
+ "id": 1
+ }
+ }
+ }
+ }
+ ```
+
+ To make sure the service is created correctly, check out the following.
+
+ > Since the schema has changed, GraphiQL must recognize the changed schema.
To do this, refresh the browser several times.
+
+ Request
+ ```graphql
+ query {
+ Services(name: KakaoFavorites) {
+ id
+ name
+ }
+ }
+ ```
+
+ Response
+ ```json
+ {
+ "data": {
+ "Services": [
+ {
+ "id": 1,
+ "name": "KakaoFavorites"
+ }
+ ]
+ }
+ }
+ ```
+
+ 2. Next, we will need some friends.
+
+ In S2Graph, relationships are organized as labels. Create a label called
friends using the following createLabel API call:
+
+ Request
+
+ ```graphql
+ mutation {
+ createLabel(
+ name: "friends",
+ sourceService: {
+ name: KakaoFavorites,
+ columnName: "userName",
+ dataType: string
+ },
+ targetService: {
+ name: KakaoFavorites,
+ columnName: "userName",
+ dataType: string
+ }
+ consistencyLevel: strong
+ ){
+ isSuccess
+ message
+ created {
+ id
+ name
+ }
+ }
+ }
+ ```
+
+ Response
+ ```json
+ {
+ "data": {
+ "createLabel": {
+ "isSuccess": true,
+ "message": "Created successful",
+ "created": {
+ "id": 1,
+ "name": "friends"
+ }
+ }
+ }
+ }
+ ```
+
+ Check if the label has been created correctly
+ > Since the schema has changed, GraphiQL must recognize the changed schema.
To do this, refresh the browser several times.
+
+ Request
+ ```graphql
+ query {
+ Labels(name: friends) {
+ id
+ name
+ srcColumnName
+ tgtColumnName
+ }
+ }
+ ```
+
+ Response
+ ```json
+ {
+ "data": {
+ "Labels": [
+ {
+ "id": 1,
+ "name": "friends",
+ "srcColumnName": "userName",
+ "tgtColumnName": "userName"
+ }
+ ]
+ }
+ }
+ ```
+
+ Now that the label friends is ready, we can store the friendship data.
+ Entries of a label are called edges, and you can add edges with edges/insert
API:
+
+ > Since the schema has changed, GraphiQL must recognize the changed schema.
To do this, refresh the browser several times.
+
+ Request
+ ```graphql
+ mutation {
+ addEdges(
+ friends: [
+ {from: "Elmo", to: "Big Bird"},
+ {from: "Elmo", to: "Ernie"},
+ {from: "Elmo", to: "Bert"},
+ {from: "Cookie Monster", to: "Grover"},
+ {from: "Cookie Monster", to: "Kermit"},
+ {from: "Cookie Monster", to: "Oscar"},
+ ]
+ ) {
+ isSuccess
+ }
+ }
+ ```
+
+ Response
+ ```json
+ {
+ "data": {
+ "addEdges": [
+ {
+ "isSuccess": true
+ },
+ {
+ "isSuccess": true
+ },
+ {
+ "isSuccess": true
+ },
+ {
+ "isSuccess": true
+ },
+ {
+ "isSuccess": true
+ },
+ {
+ "isSuccess": true
+ }
+ ]
+ }
+ }
+ ```
+
+ Query friends of Elmo with getEdges API:
+
+ Request
+
+ ```graphql
+ query {
+ KakaoFavorites(id: "Elmo") {
+ friends {
+ to
+ }
+ }
+ }
+ ```
+
+ Response
+
+ ```json
+ {
+ "data": {
+ "KakaoFavorites": [
+ {
+ "friends": [
+ {
+ "to": "Bert"
+ },
+ {
+ "to": "Ernie"
+ },
+ {
+ "to": "Big Bird"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ```
+
+ Now query friends of Cookie Monster:
+
+ ```graphql
+ query {
+ KakaoFavorites(id: "Cookie Monster") {
+ friends {
+ to
+ }
+ }
+ }
+ ```
+
+ 3. Users of Kakao Favorites will be able to post URLs of their favorite
websites.
+
+ Request
+
+ ```graphql
+ mutation {
+ createLabel(
+ name: "post",
+ sourceService: {
+ name: KakaoFavorites,
+ columnName: "userName",
+ dataType: string
+ },
+ targetService: {
+ name: KakaoFavorites,
+ columnName: "url",
+ dataType: string,
+ }
+ consistencyLevel: strong
+ ) {
+ isSuccess
+ message
+ created {
+ id
+ name
+ }
+ }
+ }
+ ```
+
+ Response
+
+ ```json
+ {
+ "data": {
+ "createLabel": {
+ "isSuccess": true,
+ "message": "Created successful",
+ "created": {
+ "id": 2,
+ "name": "post"
+ }
+ }
+ }
+ }
+ ```
+
+ Now, insert some posts of the users:
+
+ > Since the schema has changed, GraphiQL must recognize the changed schema.
To do this, refresh the browser several times.
+
+
+ Request
+
+ ```graphql
+ mutation {
+ addEdges(
+ post: [
+ { from: "Big Bird", to: "www.kakaocorp.com/en/main" },
+ { from: "Big Bird", to: "github.com/kakao/s2graph" },
+ { from: "Ernie", to: "groups.google.com/forum/#!forum/s2graph" },
+ { from: "Grover", to: "hbase.apache.org/forum/#!forum/s2graph" },
+ { from: "Kermit", to: "www.playframework.com"},
+ { from: "Oscar", to: "www.scala-lang.org"}
+ ]
+ ) {
+ isSuccess
+ }
+ }
+ ```
+
+ Response
+ ```json
+ {
+ "data": {
+ "addEdges": [
+ {
+ "isSuccess": true
+ },
+ {
+ "isSuccess": true
+ },
+ {
+ "isSuccess": true
+ },
+ {
+ "isSuccess": true
+ },
+ {
+ "isSuccess": true
+ },
+ {
+ "isSuccess": true
+ }
+ ]
+ }
+ }
+ ```
+
+ 4. So far, we have designed a label schema for the labels friends and post,
and stored some edges to them.+
+
+ This should be enough for creating the timeline feature! The following
two-step query will return the URLs for Elmo's timeline, which are the posts of
Elmo's friends:
+
+ Request
+
+ ```graphql
+ query {
+ KakaoFavorites(id: "Elmo") {
+ friends {
+ post {
+ from
+ to
+ }
+ }
+ }
+ }
+ ```
+
+ Response
+ ```json
+ {
+ "data": {
+ "KakaoFavorites": [
+ {
+ "friends": [
+ {
+ "post": []
+ },
+ {
+ "post": [
+ {
+ "from": "Ernie",
+ "to": "groups.google.com/forum/#!forum/s2graph"
+ }
+ ]
+ },
+ {
+ "post": [
+ {
+ "from": "Big Bird",
+ "to": "www.kakaocorp.com/en/main"
+ },
+ {
+ "from": "Big Bird",
+ "to": "github.com/kakao/s2graph"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ```
+
+ Also try Cookie Monster's timeline:
+
+ Request
+ ```graphql
+ query {
+ KakaoFavorites(id: "Cookie Monster") {
+ friends {
+ post {
+ from
+ to
+ }
+ }
+ }
+ }
+ ```
+
+ Response
+ ```json
+ {
+ "data": {
+ "KakaoFavorites": [
+ {
+ "friends": [
+ {
+ "post": [
+ {
+ "from": "Oscar",
+ "to": "www.scala-lang.org"
+ }
+ ]
+ },
+ {
+ "post": [
+ {
+ "from": "Kermit",
+ "to": "www.playframework.com"
+ }
+ ]
+ },
+ {
+ "post": [
+ {
+ "from": "Grover",
+ "to": "hbase.apache.org/forum/#!forum/s2graph"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ```
+
+
+ 
+
+ The example above is by no means a full blown social network timeline, but it
gives you an idea of how to represent, store and query graph data with S2Graph.
+
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/6a7e58a4/s2graphql/build.sbt
----------------------------------------------------------------------
diff --cc s2graphql/build.sbt
index 0000000,d344892..22cde81
mode 000000,100644..100644
--- a/s2graphql/build.sbt
+++ b/s2graphql/build.sbt
@@@ -1,0 -1,21 +1,40 @@@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements. See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership. The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License. You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing,
++ * software distributed under the License is distributed on an
++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++ * KIND, either express or implied. See the License for the
++ * specific language governing permissions and limitations
++ * under the License.
++ */
++
+ name := "s2graphql"
+
+ version := "0.1"
+
+ description := "GraphQL server with akka-http and sangria and s2graph"
+
+ scalacOptions ++= Seq("-deprecation", "-feature")
+
+ libraryDependencies ++= Seq(
+ "org.sangria-graphql" %% "sangria" % "1.3.3",
+ "org.sangria-graphql" %% "sangria-spray-json" % "1.0.0",
+
+ "com.typesafe.akka" %% "akka-http" % "10.0.10",
+ "com.typesafe.akka" %% "akka-http-spray-json" % "10.0.10",
+
+ "com.typesafe.akka" %% "akka-slf4j" % "2.4.6",
+
+ "org.scalatest" %% "scalatest" % "3.0.4" % Test
+ )
+
+ Revolver.settings
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/6a7e58a4/s2graphql/project/plugins.sbt
----------------------------------------------------------------------
diff --cc s2graphql/project/plugins.sbt
index 0000000,4f78e51..7dab336
mode 000000,100644..100644
--- a/s2graphql/project/plugins.sbt
+++ b/s2graphql/project/plugins.sbt
@@@ -1,0 -1,1 +1,19 @@@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements. See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership. The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License. You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing,
++ * software distributed under the License is distributed on an
++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++ * KIND, either express or implied. See the License for the
++ * specific language governing permissions and limitations
++ * under the License.
++ */
+ addSbtPlugin("io.spray" % "sbt-revolver" % "0.9.1")
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/6a7e58a4/s2graphql/src/main/resources/application.conf
----------------------------------------------------------------------
diff --cc s2graphql/src/main/resources/application.conf
index 0000000,71e8a99..45eb1b7
mode 000000,100644..100644
--- a/s2graphql/src/main/resources/application.conf
+++ b/s2graphql/src/main/resources/application.conf
@@@ -1,0 -1,7 +1,25 @@@
++#
++# Licensed to the Apache Software Foundation (ASF) under one
++# or more contributor license agreements. See the NOTICE file
++# distributed with this work for additional information
++# regarding copyright ownership. The ASF licenses this file
++# to you under the Apache License, Version 2.0 (the
++# "License"); you may not use this file except in compliance
++# with the License. You may obtain a copy of the License at
++#
++# http://www.apache.org/licenses/LICENSE-2.0
++#
++# Unless required by applicable law or agreed to in writing,
++# software distributed under the License is distributed on an
++# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++# KIND, either express or implied. See the License for the
++# specific language governing permissions and limitations
++# under the License.
++#
+ akka {
+ loggers = ["akka.event.slf4j.Slf4jLogger"]
+ event-handlers = ["akka.event.slf4j.Slf4jEventHandler"]
+ loglevel = "INFO"
+ }
+
+
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/6a7e58a4/s2graphql/src/test/resources/application.conf
----------------------------------------------------------------------
diff --cc s2graphql/src/test/resources/application.conf
index 0000000,e69de29..5fb2552
mode 000000,100644..100644
--- a/s2graphql/src/test/resources/application.conf
+++ b/s2graphql/src/test/resources/application.conf
@@@ -1,0 -1,0 +1,18 @@@
++#
++# Licensed to the Apache Software Foundation (ASF) under one
++# or more contributor license agreements. See the NOTICE file
++# distributed with this work for additional information
++# regarding copyright ownership. The ASF licenses this file
++# to you under the Apache License, Version 2.0 (the
++# "License"); you may not use this file except in compliance
++# with the License. You may obtain a copy of the License at
++#
++# http://www.apache.org/licenses/LICENSE-2.0
++#
++# Unless required by applicable law or agreed to in writing,
++# software distributed under the License is distributed on an
++# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++# KIND, either express or implied. See the License for the
++# specific language governing permissions and limitations
++# under the License.
++#