forked from neo4j-graphql/neo4j-graphql-java
-
Notifications
You must be signed in to change notification settings - Fork 0
/
GraphQLServer.kt
118 lines (103 loc) · 4.65 KB
/
GraphQLServer.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package demo
// Simplistic GraphQL Server using SparkJava
// curl -H content-type:application/json -d'{"query": "{ movie { title, released }}"}' http://localhost:4567/graphql
// GraphiQL: https://neo4j-graphql.github.io/graphiql4all/index.html?graphqlEndpoint=http%3A%2F%2Flocalhost%3A4567%2Fgraphql&query=query%20%7B%0A%20%20movie%20%7B%20title%7D%0A%7D
import com.fasterxml.jackson.databind.ObjectMapper
import com.sun.net.httpserver.HttpExchange
import com.sun.net.httpserver.HttpServer
import graphql.ExecutionInput
import graphql.GraphQL
import graphql.schema.DataFetcher
import graphql.schema.DataFetchingEnvironment
import org.neo4j.driver.AuthTokens
import org.neo4j.driver.Config
import org.neo4j.driver.GraphDatabase
import org.neo4j.driver.Values
import org.neo4j.graphql.*
import java.net.InetSocketAddress
import java.util.stream.Collectors
const val schema = """
type Person {
name: ID!
born: Int
actedIn: [Movie] @relation(name:"ACTED_IN")
}
type Movie {
title: ID!
released: Int
tagline: String
}
"""
val mapper = ObjectMapper()
fun main() {
fun query(payload: Map<*, *>) = (payload["query"]!! as String).also { println(it) }
fun params(payload: Map<*, *>): Map<String, Any?> = payload["variables"]
.let {
@Suppress("UNCHECKED_CAST")
when (it) {
is String -> if (it.isBlank()) emptyMap<String, Any?>() else mapper.readValue(it, Map::class.java)
is Map<*, *> -> it
else -> emptyMap<String, Any?>()
} as Map<String, Any?>
}.also { println(it) }
val driver = GraphDatabase.driver("bolt://localhost", AuthTokens.basic("neo4j", "test"), Config.builder().withoutEncryption().build())
val graphQLSchema = SchemaBuilder.buildSchema(schema, dataFetchingInterceptor = object : DataFetchingInterceptor {
override fun fetchData(env: DataFetchingEnvironment, delegate: DataFetcher<Cypher>): Any? {
val (cypher, params, type, variable) = delegate.get(env)
println(cypher)
println(params)
return driver.session().use { session ->
try {
val result = session.run(cypher, Values.value(params))
when {
type?.isList() == true -> result.stream().map { it[variable].asObject() }.collect(Collectors.toList())
else -> result.stream().map { it[variable].asObject() }.findFirst().orElse(emptyMap<String, Any>())
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
})
val schema = GraphQL.newGraphQL(graphQLSchema).build()
val server: HttpServer = HttpServer.create(InetSocketAddress(4567), 0)
server.createContext("/graphql") { req ->
when {
req.requestMethod == "OPTIONS" -> req.sendResponse(null)
req.requestMethod == "POST" && req.requestHeaders["Content-Type"]?.contains("application/json") == true -> {
val payload = mapper.readValue(req.requestBody, Map::class.java)
val query = query(payload)
val response = if (query.contains("__schema")) {
schema.execute(query).let { println(mapper.writeValueAsString(it));it }
} else {
try {
val queryContext = QueryContext(optimizedQuery = setOf(QueryContext.OptimizationStrategy.FILTER_AS_MATCH))
schema.execute(ExecutionInput
.newExecutionInput()
.query(query)
.graphQLContext(mapOf(QueryContext.KEY to queryContext))
.variables(params(payload))
.build())
} catch (e: OptimizedQueryException) {
schema.execute(ExecutionInput
.newExecutionInput()
.query(query)
.variables(params(payload))
.build())
}
}
req.sendResponse(response)
}
}
}
server.start()
}
private fun HttpExchange.sendResponse(data: Any?) {
val responseString = data?.let { mapper.writeValueAsString(it) }
// CORS
this.responseHeaders.add("Access-Control-Allow-Origin", "*")
this.responseHeaders.add("Access-Control-Allow-Headers", "*")
this.responseHeaders.add("Content-Type", "application/json")
this.sendResponseHeaders(200, responseString?.length?.toLong() ?: 0)
if (responseString != null) this.responseBody.use { it.write(responseString.toByteArray()) }
}