graphql学习(一)graphql-java文档初步阅读

来源:互联网 发布:linux编译程序 编辑:程序博客网 时间:2024/06/05 20:19

由于公司的原因,最近在学习GraphQL。

这次的学习主要是从graphql-java文档上入手,对语言的文档有初步的认识;

GraphQL简介

在 2015 React 欧洲大会上,Lee Byron 介绍了 Facebook 的 GraphQL ,包含 GraphQL 背后的故事,查询语句的示例,还有核心的概念。GraphQL 非常易懂,直接看查询语句就能知道查询出来的数据是什么样的。你可以把 GraphQL 的查询语句想成是没有值,只有属性的对象,返回的结果就是对应的属性还有对应值的对象。
故事

从 2011 开始,Facebook 开始越来越重视移动端,一支很小的团队开始去做 Android 与 iOS 应用。Facebook 的强项是 Web,也非常的了解 Web ,而且在这方面储备了大量的技术。当年 Facebook 的主要平台就是传统的 浏览器 Web 服务器 数据服务 的组合,Web 服务器响应浏览器的请求,到数据服务那里提供出数据,然后再交给浏览器去显示。

他们打算尽可能的使用现有的代码去实施移动端的应用,所以一开始 Facebook 的移动应用就是一个浏览器,加上了一个本地的壳,内容基本上就是简单的定制以后的移动 Web 网站。这样的好处就是可以使用所有的现有的 Web 平台上的东西。这样工程师们也可以使用平时创建东西的方法。这种方法在短时间内也得到了很大的成功,并且让公司把重点放在移动端上。

一开始都还好,不过在移动应用上添加越来越多的功能以后,就有点吃力了,移动浏览器经常会消耗掉所有的内存,让应用崩溃。另一面,在 Web 上,Facebook 仍然快速的生成,而移动端有点跟不上脚步了。这让他们决定要去做真正的本地的移动应用。

2012 年开始,Facebook 要开始开发真正的本地应用。 这跟 Web 很不一样,所以开始重新思考应用的平台。Web 就是请求一个 URL ,返回一堆 HTML。而本地移动应用,为了给应用提供需要的数据,填充数据模型 ,显示视图,要想的问题是,怎么去请求,准备,传递这些数据。而当时 Facebook 现有的服务器主要功能还是只提供 HTML。

工程师们试了一些方法,比如 RESTful API,对于 Facebook 这种复杂的应用,可能需要定义很多的端点,不同的端点返回来的数据只是略有不同,造成了资源浪费,而且还需要大量的逻辑去处理这些数据。后来他们又试了 FQL, 这是 Facebook 的公共接口,应该是一种查询语言。功能很强大,而且返回来的数据也有很好的结构。不好的地方是,查询用的语言非常难理解,比如多个 JOIN ,主键什么的,所以经常会出错。

除了这些表面上遇到的问题,工程师们也非常不喜欢这些方法表达数据的形式,比如我们平时想像的数据并不是一大堆查询语言,LEFT JOIN,RIGHT JOIN .. 也不是资源的地址。而对象的形式非常适合表达数据,一个对象,里面有一些属性,不同的属性对应不同的值。几个工程师开始了现在的 GraphQL,一种用对象,属性,关系的,有点像图形的方式来表达想要的数据。

三年前,Facebook 用了 GraphQL 做了第一款真正的本地移动应用,现在,应用每天会接受 260 亿的请求。

关于GraphQL的简介主要是从https://ninghao.net/blog/2857上复制过来的。


GraphQL-java文档相关

//以下全是个人的理解,目前只是初学,如果有错误欢迎指正。


jdk1.8以上才支持graphql-java

1、maven拉取所需要的graphql-java包,现在已经更新到3.0.0版本了

<dependency>    <groupId>com.graphql-java</groupId>    <artifactId>graphql-java</artifactId>    <version>3.0.0</version></dependency>

2、这是官网给出的,也是很多博客网站给出的graphql最经典的java例子:

import graphql.GraphQL;import graphql.schema.GraphQLObjectType;import graphql.schema.GraphQLSchema;import java.util.Map;import static graphql.Scalars.GraphQLString;import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;import static graphql.schema.GraphQLObjectType.newObject;public class HelloWorld {    public static void main(String[] args) {        GraphQLObjectType queryType = newObject()                .name("helloWorldQuery")                .field(newFieldDefinition()                        .type(GraphQLString)                        .name("hello")                        .staticValue("world"))                .build();        GraphQLSchema schema = GraphQLSchema.newSchema()                .query(queryType)                .build();        GraphQL graphQL = GraphQL.newGraphQL(schema).build();        Map<String, Object> result = graphQL.execute("{hello}").getData();        System.out.println(result);        // Prints: {hello=world}    }}

3、graphql-java定义了两种schema语言,一种是标准的java语言的,一种是IDL,类似json格式的语言;
下面是两种的示例:
IDL(目前个人的理解是用于前端的)

type Foo {    bar: String}

Java(目前个人理解是用于后台)

GraphQLObjectType fooType = newObject()    .name("Foo")    .field(newFieldDefinition()            .name("bar")            .type(GraphQLString))    .build();

比较一下两种语言还是很好理解,这里需要说一下,newFieldDefinition和newObject都是静态方法,需要引入或者声明变量调用,感觉graphql中都是用引入的方法:

import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;import static graphql.schema.GraphQLObjectType.newObject;

方法属于哪个包中,在eclipse中可以通过ctrl+H查找;idea中还没有试过;


4、DataFetcher和TypeResolver
DataFetcher有点不是很理解,每一个搜索域可以指定DataFetcher,如果没有指定的话,就是用默认的PropertyDataFetcher, PropertyDataFetcher主要是Map或者JavaBeans中获取数据,与Map中的Key对应,和JavaBeans中的变量名对应;
TypeResolver就是数据的类型
官网给出的IDL示例

schema {    query: QueryType}type QueryType {    hero(episode: Episode): Character    human(id : String) : Human    droid(id: ID!): Droid}enum Episode {    NEWHOPE    EMPIRE    JEDI}interface Character {    id: ID!    name: String!    friends: [Character]    appearsIn: [Episode]!}type Human implements Character {    id: ID!    name: String!    friends: [Character]    appearsIn: [Episode]!    homePlanet: String}type Droid implements Character {    id: ID!    name: String!    friends: [Character]    appearsIn: [Episode]!    primaryFunction: String}

Java代码
目前这里面的内容不懂的部分还是很多的
①loadSchema这个方法是在哪里定义的至今没有找到;
②starWarsSchema.graphqls这个文件怎么定义的?里面的内容是什么;
③StarWarsData理解上应该是一个entity类,但是为什么没有申明变量就可以直接使用里面getter和setter,还是需要申明了,但是文档觉得没有必要给出这部分代码;
④CustomScalar定义在哪里?

SchemaParser schemaParser = new SchemaParser();SchemaGenerator schemaGenerator = new SchemaGenerator();File schemaFile = loadSchema("starWarsSchema.graphqls");TypeDefinitionRegistry typeRegistry = schemaParser.parse(schemaFile);RuntimeWiring wiring = buildRuntimeWiring();GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, wiring);RuntimeWiring buildRuntimeWiring() {    return RuntimeWiring.newRuntimeWiring()            .scalar(CustomScalar)            // this uses builder function lambda syntax            .type("QueryType", typeWiring -> typeWiring                    .dataFetcher("hero", new StaticDataFetcher(StarWarsData.getArtoo()))                    .dataFetcher("human", StarWarsData.getHumanDataFetcher())                    .dataFetcher("droid", StarWarsData.getDroidDataFetcher())            )            .type("Human", typeWiring -> typeWiring                    .dataFetcher("friends", StarWarsData.getFriendsDataFetcher())            )            // you can use builder syntax if you don't like the lambda syntax            .type("Droid", typeWiring -> typeWiring                    .dataFetcher("friends", StarWarsData.getFriendsDataFetcher())            )            // or full builder syntax if that takes your fancy            .type(                    newTypeWiring("Character")                            .typeResolver(StarWarsData.getCharacterTypeResolver())                            .build()            )            .build();}

官网还给出了另外一种buildDynamicRuntimeWiring,根据名字为动态的RuntimeWiring,但是里面的方法也不是很懂,有人懂得望告知:

RuntimeWiring buildDynamicRuntimeWiring() {    WiringFactory dynamicWiringFactory = new WiringFactory() {        @Override        public boolean providesTypeResolver(TypeDefinitionRegistry registry, InterfaceTypeDefinition definition) {            return getDirective(definition,"specialMarker") != null;        }        @Override        public boolean providesTypeResolver(TypeDefinitionRegistry registry, UnionTypeDefinition definition) {            return getDirective(definition,"specialMarker") != null;        }        @Override        public TypeResolver getTypeResolver(TypeDefinitionRegistry registry, InterfaceTypeDefinition definition) {            Directive directive  = getDirective(definition,"specialMarker");            return createTypeResolver(definition,directive);        }        @Override        public TypeResolver getTypeResolver(TypeDefinitionRegistry registry, UnionTypeDefinition definition) {            Directive directive  = getDirective(definition,"specialMarker");            return createTypeResolver(definition,directive);        }        @Override        public boolean providesDataFetcher(TypeDefinitionRegistry registry, FieldDefinition definition) {            return getDirective(definition,"dataFetcher") != null;        }        @Override        public DataFetcher getDataFetcher(TypeDefinitionRegistry registry, FieldDefinition definition) {            Directive directive = getDirective(definition, "dataFetcher");            return createDataFetcher(definition,directive);        }    };    return RuntimeWiring.newRuntimeWiring()            .wiringFactory(dynamicWiringFactory).build();}

5、类型:
GraphQL提供一下类型:
- Scalar
- Object
- Interface
- Union
- InputObject
- Enum

Scalar
- GraphQLString
- GraphQLBoolean
- GraphQLInt
- GraphQLFloat
- GraphQLID
- GraphQLLong
- GraphQLShort
- GraphQLByte
- GraphQLFloat
- GraphQLBigDecimal
- GraphQLBigInteger

Object

type SimpsonCharacter {    name: String    mainCharacter: Boolean}
GraphQLObjectType simpsonCharacter = newObject().name("SimpsonCharacter").description("A Simpson character").field(newFieldDefinition()        .name("name")        .description("The name of the character.")        .type(GraphQLString)).field(newFieldDefinition()        .name("mainCharacter")        .description("One of the main Simpson characters?")        .type(GraphQLBoolean)).build();

Interface

interface ComicCharacter {    name: String;}
GraphQLInterfaceType comicCharacter = newInterface()    .name("ComicCharacter")    .description("A abstract comic character.")    .field(newFieldDefinition()            .name("name")            .description("The name of the character.")            .type(GraphQLString))    .build();

Union

interface ComicCharacter {    name: String;}
GraphQLUnionType PetType = newUnionType()    .name("Pet")    .possibleType(CatType)    .possibleType(DogType)    .typeResolver(new TypeResolver() {        @Override        public GraphQLObjectType getType(TypeResolutionEnvironment env) {            if (env.getObject() instanceof Cat) {                return CatType;            }            if (env.getObject() instanceof Dog) {                return DogType;            }            return null;        }    })    .build();

Enum

enum Color {    RED    GREEN    BLUE}
GraphQLEnumType colorEnum = newEnum()    .name("Color")    .description("Supported colors.")    .value("RED")    .value("GREEN")    .value("BLUE")    .build();

ObjectInputType

input Character {    name: String}
GraphQLInputObjectType inputObjectType = newInputObject()    .name("inputObjectType")    .field(newInputObjectField()            .name("field")            .type(GraphQLString))    .build();

6、递归类型
每个人都是有朋友的,每个人的朋友都是人,然后每个人又都有朋友,朋友又会有朋友的朋友,就是一直递归下去,graphql-java不会出现这种情况

GraphQLObjectType person = newObject()    .name("Person")    .field(newFieldDefinition()            .name("friends")            .type(new GraphQLList(new GraphQLTypeReference("Person"))))    .build();

7、对于查询的类可进行扩展
java代码上是这样是实现的

SchemaParser schemaParser = new SchemaCompiler();SchemaGenerator schemaGenerator = new SchemaGenerator();File schemaFile1 = loadSchema("starWarsSchemaPart1.graphqls");File schemaFile2 = loadSchema("starWarsSchemaPart2.graphqls");File schemaFile3 = loadSchema("starWarsSchemaPart3.graphqls");TypeDefinitionRegistry typeRegistry = new TypeDefinitionRegistry();// each registry is merged into the main registrytypeRegistry.merge(schemaParser.compile(schemaFile1));typeRegistry.merge(schemaParser.compile(schemaFile2));typeRegistry.merge(schemaParser.compile(schemaFile3));GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, buildRuntimeWiring());

在IDL中大概就是下面这种情况

type Human {    id: ID!    name: String!}#Another part of your system can extend this type to add more shape to it.extend type Human implements Character {    id: ID!    name: String!    friends: [Character]    appearsIn: [Episode]!}#You can have as many extensions as you think sensible. extend type Human {    homePlanet: String}#With all these type extensions in place the Human type now looks like this at runtime.type Human implements Character {    id: ID!    name: String!    friends: [Character]    appearsIn: [Episode]!    homePlanet: String}

今天的工作暂时就这么多,明天研究研究graphql-java源代码,再看看IDL语言,看看能不能对graphq-java有更深的了解,目前了解的情况还无法根本无法用来写代码。




如果文章中有任何侵犯到您的,望告知642646522@qq.com,一定在第一时间删改。

原创粉丝点击