GraphQL is a query language :
搭建server, 供前端与后端使用的时候 参考:howtoGraphQL
简单的语法学习: learn
GraphQL 是一个新的API标准, 可以比Rest更有效的 强大的 灵活;它是由FaceBook开发并开源
API defines how a clientcan load data from a server.
Graph QL是一种都API的查询语言, 不是数据库查询语言, 比Rest更优越
GraphiQL An in-browser IDE for exploring GraphQL.
自己创建参看: readme
简单的搭建一个自己的server
参考 Getting started with GraphQL Java and Spring Boot
- 安装Java: download JDK1.8, 然后安装JDK与JRE, 配置环境变量
- 安装Gradle: download zip文件, 解压到相关路径, 并配置环境变量; 参考install
显示如下便成功了:
gradle -v
Welcome to Gradle 5.6!
- 按照文档中的示例, 创建spring app: https://start.spring.io/.
选择
--Gradle Project
--Java
--Spring Boot 2.1.x
--Group: com.graphql-java.tutorial
--Artifact: book-details
-- select Web.这个我自己选择的是
- 点击后, 会生成一个项目文件的压缩包, 直接解压到电脑中, 然后倒入Idea IDE, 注意导入后, 自己去seeting中设置JDK与Gradle为自己电脑上安装的location
- 粘贴文档中的代码 作者放在了github中
- build 项目
代码分析
报错了:
在浏览器中输入: http://localhost:8080/graphql
显示的结果是:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Aug 27 14:59:09 CST 2019
There was an unexpected error (type=Bad Request, status=400).
Required String parameter 'query' is not present
在idea中显示如下:
"D:\Install\IdeaUI\IntelliJ IDEA 2019.2.1\jbr\bin\java.exe" -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:D:\Install\IdeaUI\IntelliJ IDEA 2019.2.1\lib\idea_rt.jar=59523:D:\Install\IdeaUI\IntelliJ IDEA 2019.2.1\bin" -Dfile.encoding=UTF-8 -classpath D:\springBoot\book-details\build\classes\java\main;D:\springBoot\book-details\build\resources\main;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-web\2.1.7.RELEASE\fa43baf40bde3ecdb93ac9c545dd39f82ab29c35\spring-boot-starter-web-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.session\spring-session-core\2.1.8.RELEASE\2fe4df49293b18373c1050649192ff444be65f6\spring-session-core-2.1.8.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.graphql-java\graphql-java-spring-boot-starter-webmvc\1.0\4cf4fe366b11da5db76127a6b0607909b16977c5\graphql-java-spring-boot-starter-webmvc-1.0.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.graphql-java\graphql-java-spring-webmvc\1.0\93bd3420e9fd1c9e03cf2de0f438f9da2af923b4\graphql-java-spring-webmvc-1.0.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.graphql-java\graphql-java\11.0\1f670532643686b9816a871e2c9b9e5dce205eb6\graphql-java-11.0.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.google.guava\guava\26.0-jre\6a806eff209f36f635f943e16d97491f00f6bfab\guava-26.0-jre.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-json\2.1.7.RELEASE\9c12f046a7c4ae110d89163a491ad0d7cf036e79\spring-boot-starter-json-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter\2.1.7.RELEASE\e23f4e9460e0e2220b444e40fc7fd6e95f66e0fe\spring-boot-starter-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-tomcat\2.1.7.RELEASE\11f2a86aefefba72a4efe5ff18f4165a4b4e78b\spring-boot-starter-tomcat-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.hibernate.validator\hibernate-validator\6.0.17.Final\af73055fc4a103ab347c56e7da5a143d68a0170\hibernate-validator-6.0.17.Final.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-webmvc\5.1.9.RELEASE\b9d4a2140488f0e6f9aa231e7938ae18da77b637\spring-webmvc-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-web\5.1.9.RELEASE\9fe4390420fdd0b63dc4ed90d9027dafa9f74f80\spring-web-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-autoconfigure\2.1.7.RELEASE\2c9d3e2c6ea3cb435e99e2973009636b62a9d816\spring-boot-autoconfigure-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot\2.1.7.RELEASE\1599a2ad1fc6d36dbfc2a7c0dd5dab3a0bb27c61\spring-boot-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-context\5.1.9.RELEASE\c37f8fe15a5ae4ea1f351bd46167fd492a84eefa\spring-context-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-aop\5.1.9.RELEASE\bc2312ffad02251b9d472e4a7c0e472a58f50fbf\spring-aop-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-beans\5.1.9.RELEASE\5a03b3983108d73978aec2fa3e681aedad6782c\spring-beans-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-expression\5.1.9.RELEASE\db3a2468c1b7d697ec3b3ec6e5652dc282994fe3\spring-expression-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-core\5.1.9.RELEASE\dc3815439579b4fa0c19970e6b8e5d774af8d988\spring-core-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework\spring-jcl\5.1.9.RELEASE\7c372790c999777d20f364960cf557dd74f890cf\spring-jcl-5.1.9.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.antlr\antlr4-runtime\4.7.1\946f8aa9daa917dd81a8b818111bec7e288f821a\antlr4-runtime-4.7.1.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-logging\2.1.7.RELEASE\6e829f739992a7f368c0af44a08ed89ad2a1972f\spring-boot-starter-logging-2.1.7.RELEASE.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-classic\1.2.3\7c4f3c474fb2c041d8028740440937705ebb473a\logback-classic-1.2.3.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-to-slf4j\2.11.2\6d37bf7b046c0ce2669f26b99365a2cfa45c4c18\log4j-to-slf4j-2.11.2.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.slf4j\jul-to-slf4j\1.7.26\8031352b2bb0a49e67818bf04c027aa92e645d5c\jul-to-slf4j-1.7.26.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.slf4j\slf4j-api\1.7.26\77100a62c2e6f04b53977b9f541044d7d722693d\slf4j-api-1.7.26.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.graphql-java\java-dataloader\2.1.1\2ac1e4f0764030853195bf89eb4bd0bbe2151eb2\java-dataloader-2.1.1.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.reactivestreams\reactive-streams\1.0.2\323964c36556eb0e6209f65c1cef72b53b461ab8\reactive-streams-1.0.2.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.google.code.findbugs\jsr305\3.0.2\25ea2e8b0c338a877313bd4672d3fe056ea78f0d\jsr305-3.0.2.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.checkerframework\checker-qual\2.5.2\cea74543d5904a30861a61b4643a5f2bb372efc4\checker-qual-2.5.2.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.google.errorprone\error_prone_annotations\2.1.3\39b109f2cd352b2d71b52a3b5a1a9850e1dc304b\error_prone_annotations-2.1.3.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.google.j2objc\j2objc-annotations\1.1\ed28ded51a8b1c6b112568def5f4b455e6809019\j2objc-annotations-1.1.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.codehaus.mojo\animal-sniffer-annotations\1.14\775b7e22fb10026eed3f86e8dc556dfafe35f2d5\animal-sniffer-annotations-1.14.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\javax.annotation\javax.annotation-api\1.3.2\934c04d3cfef185a8008e7bf34331b79730a9d43\javax.annotation-api-1.3.2.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.datatype\jackson-datatype-jdk8\2.9.9\4b04126963103216c9c43b0f34bbc36315654204\jackson-datatype-jdk8-2.9.9.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.datatype\jackson-datatype-jsr310\2.9.9\a33df137557793b0404a486888dbe049f7abeeeb\jackson-datatype-jsr310-2.9.9.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.module\jackson-module-parameter-names\2.9.9\a92facb55a2538e7b2fe14294570a18b823ad431\jackson-module-parameter-names-2.9.9.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.yaml\snakeyaml\1.23\ec62d74fe50689c28c0ff5b35d3aebcaa8b5be68\snakeyaml-1.23.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-databind\2.9.9\d6eb9817d9c7289a91f043ac5ee02a6b3cc86238\jackson-databind-2.9.9.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-websocket\9.0.22\45974d3443cc15ad9d10239d762d5e15759e6364\tomcat-embed-websocket-9.0.22.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-core\9.0.22\79f39903498b28adacb18fe2ea046edd306295a6\tomcat-embed-core-9.0.22.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-el\9.0.22\4da4b778b635a7e78ca7cd7288253e2e47b88a9f\tomcat-embed-el-9.0.22.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\javax.validation\validation-api\2.0.1.Final\cb855558e6271b1b32e716d24cb85c7f583ce09e\validation-api-2.0.1.Final.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.jboss.logging\jboss-logging\3.3.2.Final\3789d00e859632e6c6206adc0c71625559e6e3b0\jboss-logging-3.3.2.Final.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml\classmate\1.4.0\291658ac2ce2476256c7115943652c0accb5c857\classmate-1.4.0.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-annotations\2.9.0\7c10d545325e3a6e72e06381afe469fd40eb701\jackson-annotations-2.9.0.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-core\2.9.9\bfff5af9fb8347d26bbb7959cb9b4fe9a2b0ca5e\jackson-core-2.9.9.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-core\1.2.3\864344400c3d4d92dfeb0a305dc87d953677c03c\logback-core-1.2.3.jar;C:\Users\Winfery_Wen\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-api\2.11.2\f5e9a2ffca496057d6891a3de65128efc636e26e\log4j-api-2.11.2.jar com.graphqljava.tutorial.bookdetails.BookDetailsApplication
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.7.RELEASE)
2019-08-27 16:20:05.959 INFO 12308 --- [ main] c.g.t.b.BookDetailsApplication : Starting BookDetailsApplication on EPCNSZUW0073 with PID 12308 (D:\springBoot\book-details\build\classes\java\main started by Winfery_Wen in D:\springBoot\book-details)
2019-08-27 16:20:05.960 INFO 12308 --- [ main] c.g.t.b.BookDetailsApplication : No active profile set, falling back to default profiles: default
2019-08-27 16:20:06.639 INFO 12308 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-08-27 16:20:06.658 INFO 12308 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-08-27 16:20:06.659 INFO 12308 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.22]
2019-08-27 16:20:06.743 INFO 12308 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-08-27 16:20:06.749 INFO 12308 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 757 ms
2019-08-27 16:20:07.035 INFO 12308 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-08-27 16:20:07.178 INFO 12308 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-08-27 16:20:07.181 INFO 12308 --- [ main] c.g.t.b.BookDetailsApplication : Started BookDetailsApplication in 1.444 seconds (JVM running for 1.923)
2019-08-27 16:21:15.060 INFO 12308 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-08-27 16:21:15.060 INFO 12308 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2019-08-27 16:21:15.066 INFO 12308 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 6 ms
2019-08-27 16:21:15.092 WARN 12308 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'query' is not present]
Resolution
follow the log
install GraphQL Playground; open new workspace and
use url: http://localhost:8080/graphql?query=%7B__schema%20%7B%20types%20%7Bname%7D%20%7D%7D
一下的结果是在浏览器的url中输入的结果
{"data":{
"__schema":
{"types":
[
{"name":"__TypeKind"},
{"name":"__Field"},
{"name":"Query"},
{"name":"__Schema"},
{"name":"__Type"},
{"name":"__EnumValue"},
{"name":"__DirectiveLocation"},
{"name":"String"},
{"name":"Int"},
{"name":"Book"},
{"name":"Author"},
{"name":"ID"},
{"name":"__InputValue"},
{"name":"Boolean"},
{"name":"__Directive"}
]
}
}
}
打开GraphQL playground后就能进行使用; 但是只能使用他规定的query语句
{
bookById(id:"book-1"){
id
name
author{
firstName
lastName
}
}
}
return:
{
"data": {
"bookById": {
"id": "book-1",
"name": "Harry Potter and the Philosopher's Stone",
"author": {
"firstName": "Joanne",
"lastName": "Rowling"
}
}
}
}
schema:
directive @defer on FIELD
type Author {
id: ID
firstName: String
lastName: String
}
type Book {
id: ID
name: String
pageCount: Int
author: Author
}
type Query {
bookById(id: ID): Book
}
introspection
在该示例代码中, 其实是使用了GraphQL的schema来定义了只能使用的query; 其实就是使用了graphQL中的introSpection(自我检测);我们定义了type, 但是有时候我们并不知道里面包含了哪些type, 这个时候我们就可以通过query: __schema来获取这个系统相关的信息:
{
__schema {
types {
name
}
}
}
对应的结果就是
{
"data": {
"__schema": {
"types": [
{
"name": "Query"
},
{
"name": "Episode"
},
{
"name": "Character"
},
{
"name": "ID"
},
{
"name": "String"
},
{
"name": "Int"
},
{
"name": "FriendsConnection"
},
{
"name": "FriendsEdge"
},
{
"name": "PageInfo"
},
{
"name": "Boolean"
},
{
"name": "Review"
},
{
"name": "SearchResult"
},
{
"name": "Human"
},
{
"name": "LengthUnit"
},
{
"name": "Float"
},
{
"name": "Starship"
},
{
"name": "Droid"
},
{
"name": "Mutation"
},
{
"name": "ReviewInput"
},
{
"name": "__Schema"
},
{
"name": "__Type"
},
{
"name": "__TypeKind"
},
{
"name": "__Field"
},
{
"name": "__InputValue"
},
{
"name": "__EnumValue"
},
{
"name": "__Directive"
},
{
"name": "__DirectiveLocation"
}
]
}
}
}
而上面的例子中, 其实输入的就是该query。
现在, 我们需要知道哪些query是我们可以做的,当我们定义type系统的时候, 我们需要指定所有query的起始type, 这个时候需要使用introspection来帮我们得到:
所以query 是我们开始的类型;
查询某个type对象的信息
{
__type(name:"Author"){
name
kind
description
}
}
{
"data": {
"__type": {
"name": "Author",
"kind": "OBJECT",
"description": null
}
}
}
查询type内容中子域的type信息
{
__type(name:"Author"){
name
kind
fields{
name
type{
name
kind
}
}
}
}
return
{
"data": {
"__type": {
"name": "Author",
"kind": "OBJECT",
"fields": [
{
"name": "id",
"type": {
"name": "ID",
"kind": "SCALAR"
}
},
{
"name": "firstName",
"type": {
"name": "String",
"kind": "SCALAR"
}
},
{
"name": "lastName",
"type": {
"name": "String",
"kind": "SCALAR"
}
}
]
}
}
}
创建一个GraphQL service就是通过定义type和field, 然后为每一个type中的每一个field提供functions, 例如:
type Query {
me: User
}
type User {
id: ID
name: String
}
function Query_me(request) {
return request.auth.user;
}
function User_name(user) {
return user.getName();
}
一旦一个service开始运行(一般是web sevice上的url), 这个服务器上就能发送query并执行, 收到的query首先会被检查并确保所涉及的type都是正确的, 然后运行代码中对应的函数来得到结果。
例如:
{
me {
name
}
}
return
{
"me": {
"name": "Luke Skywalker"
}
}
具体语法参照