Java bytea schema对应_graphql-java使用手册: part2 创建Schema

创建Schema

Schema的主要用途是定义所有可供查询的字段(field),它们最终组合成一套完整的GraphQL

API.

“graphql-java”提供两种方法来定义Schema。用java代码来定义、用GraphQL

SDL(即IDL)来定义。

注意:SDL(IDL)现在还不是 官方 graphql 规范. 本GraphQL实现,是基于

已有的JS参考实现

来开发的。但JS参考实现中的很多代码也是基于SDL(IDL)语法的,所以你可以认为这语法是可以长期使用的.

如果你不确认用“java代码”还是用“GraphQL

SDL(即IDL)”来定义你的Schema,那么我们建议你用SDL(IDL)

SDL example:

type Foo {

bar: String

}

java代码例子:

GraphQLObjectType fooType = newObject()

.name("Foo")

.field(newFieldDefinition()

.name("bar")

.type(GraphQLString))

.build();

DataFetcher 与 TypeResolver

对象 DataFetcher

作用是获取字段(field)对应的数据;另外,在修改(mutation)操作时,可以更新数据

每个字段都有自己的 DataFetcher. 如果未为字段指定DataFetcher,

那么自动使用默认的 PropertyDataFetcher .

PropertyDataFetcher 从 Map 和 Java Beans 中获取数据.

所以,当Schema中的field名,与Map中的key值,或 Source Object 中的 java

bean 字段名相同时,不需要为field指定 DataFetcher.

对象 TypeResolver 帮助 graphql-java 判断数据的实际类型(type). 所以

Interface 和 Union 均需要指定关联的 TypeResolver(类型识别器) .

例如,你有一个 Interface 叫 MagicUserType

它有可能是以下的具体类型(Type) Wizard, Witch and Necromancer.

Type resolver(类型识别器) 的作用是在运行时识别出 GraphqlObjectType

的具体类型(Type)。后期具体类型下的field相关的 data

fetcher被调用并获取数据.

new TypeResolver() {

@Override

public GraphQLObjectType getType(TypeResolutionEnvironment env) {

Object javaObject = env.getObject();

if (javaObject instanceof Wizard) {

return (GraphQLObjectType) env.getSchema().getType("WizardType");

} else if (javaObject instanceof Witch) {

return (GraphQLObjectType) env.getSchema().getType("WitchType");

} else {

return (GraphQLObjectType) env.getSchema().getType("NecromancerType");

}

}

};

用 SDL 创建 Schema

当使用SDL方法来开发时,你需要同时编写对应的 DataFetcher 和

TypeResolver。

很大的 Schema 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

}

由于Schema中只是指定了静态的字段和类型,你还需要把它绑定到java方法中。以让Schema可以运行起来

这里的绑定,包括 DataFetcher , TypeResolvers 与自定义 Scalar.

用下页的Builder方法,就可以绑定Schema和Java程序

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();

}

最后,你可以通过整合静态 Schema 和 绑定(wiring),而生成一个可以执行的

Schema。

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);

除了上面的 builder 风格, TypeResolver s 与 DataFetcher s 也可以通过

WiringFactory 接口绑定在一起。通过程序去分析 SDL

,就可以允许更自由的绑定。你可以 通过分析 SDL 声明, 或其它 SDL

定义去决定你的运行时逻辑。

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();

}

用代码方式创建 schema

如果用程序方式来定义 Schema,在创建类型(type)的时候,你需要提供

DataFetcher and TypeResolver 。

如:

DataFetcher fooDataFetcher = environment -> {

// environment.getSource() is the value of the surrounding

// object. In this case described by objectType

Foo value = perhapsFromDatabase(); // Perhaps getting from a DB or whatever

return value;

}

GraphQLObjectType objectType = newObject()

.name("ObjectType")

.field(newFieldDefinition()

.name("foo")

.type(GraphQLString)

.dataFetcher(fooDataFetcher))

.build();

类型(Types)

GraphQL 类型系统支持以下类型

Scalar

Object

Interface

Union

InputObject

Enum

Scalar

graphql-java 支持以下基本数据类型( Scalars)。

GraphQLString

GraphQLBoolean

GraphQLInt

GraphQLFloat

GraphQLID

GraphQLLong

GraphQLShort

GraphQLByte

GraphQLFloat

GraphQLBigDecimal

GraphQLBigInteger

Object

SDL Example:

type SimpsonCharacter {

name: String

mainCharacter: Boolean

}

Java 例子:

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

Interfaces 是抽象的 类型( types)定义.

SDL Example:

interface ComicCharacter {

name: String;

}

Java 例子:

GraphQLInterfaceType comicCharacter = newInterface()

.name("ComicCharacter")

.description("An abstract comic character.")

.field(newFieldDefinition()

.name("name")

.description("The name of the character.")

.type(GraphQLString))

.build();

Union

SDL Example:

interface Cat {

name: String;

lives: Int;

}

interface Dog {

name: String;

bonesOwned: int;

}

union Pet = Cat | Dog

Java 例子:

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

SDL Example:

enum Color {

RED

GREEN

BLUE

}

Java 例子:

GraphQLEnumType colorEnum = newEnum()

.name("Color")

.description("Supported colors.")

.value("RED")

.value("GREEN")

.value("BLUE")

.build();

ObjectInputType

SDL Example:

input Character {

name: String

}

Java 例子:

GraphQLInputObjectType inputObjectType = newInputObject()

.name("inputObjectType")

.field(newInputObjectField()

.name("field")

.type(GraphQLString))

.build();

类型引用 (Type References) (递归类型recursive types)

GraphQL 支持递归类型:如 Person(人)

可以包含很多朋友【译注:当然这些也是人类型的】

为了方便声明这种情况, graphql-java 有一个 GraphQLTypeReference 类。

在实际的 Schema 创建时,GraphQLTypeReference 会变为实际的类型。

例如:

GraphQLObjectType person = newObject()

.name("Person")

.field(newFieldDefinition()

.name("friends")

.type(new GraphQLList(new GraphQLTypeReference("Person"))))

.build();

如果用SDL(ID L)来定义 Schema ,不需要特殊的处理。

Schema IDL的模块化

很大的 Schema IDL 文件很难查看。所以我们有两种方法可以模块化 Schema。

方法一是合并多个 Schema IDL 文件到一个逻辑单元( logic

unit)。下面的例子是,在 Schema 生成前,合并多个独立的文件。

SchemaParser schemaParser = new SchemaParser();

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 registry

typeRegistry.merge(schemaParser.parse(schemaFile1));

typeRegistry.merge(schemaParser.parse(schemaFile2));

typeRegistry.merge(schemaParser.parse(schemaFile3));

GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, buildRuntimeWiring());

Graphql IDL 还有其它方法去做模块化。你可以使用 type extensions

去为现有类型增加字段和 interface。

例如,一开始,你有这样一个文件:

type Human {

id: ID!

name: String!

}

你的系统的其它模块可以扩展这个类型:

extend type Human implements Character {

id: ID!

name: String!

friends: [Character]

appearsIn: [Episode]!

}

你可以按你的需要去扩展。它们会以被发现的顺序组合起来。重复的字段会被合并(但重定义一个字段的类型是不允许的)。

extend type Human {

homePlanet: String

}

完成合并后的 Human 类型会是这样的:

type Human implements Character {

id: ID!

name: String!

friends: [Character]

appearsIn: [Episode]!

homePlanet: String

}

这在顶层查询中特别有用。你可以用 extension types 去为顶层 “query”

增加字段每个团队可以提供自己的字段集,进而合成完整的查询。

schema {

query: CombinedQueryFromMultipleTeams

}

type CombinedQueryFromMultipleTeams {

createdTimestamp: String

}

# maybe the invoicing system team puts in this set of attributes

extend type CombinedQueryFromMultipleTeams {

invoicing: Invoicing

}

# and the billing system team puts in this set of attributes

extend type CombinedQueryFromMultipleTeams {

billing: Billing

}

# and so and so forth

extend type CombinedQueryFromMultipleTeams {

auditing: Auditing

}

Subscription(订阅)的支持

订阅功能还未在规范中: graphql-java 现在只支持简单的实现 ,你可以用

GraphQLSchema.Builder.subscription(...) 在 Schema

中定义订阅。这使你可以处理订阅请求。

subscription foo {

# normal graphql query

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值