GraphQLBasics-SchemaandTypeSystem(类型系统)由于GraphQL查询的结构和结果非常相似,即使不知道服务器,你也可以预测查询会返回什么结果。但是对我们需要的数据有一个准确的描述还是有意义的,我们可以选择哪些字段?服务器会返回什么样的对象?这些对象下有哪些可用字段?这就是引入模式的原因。每个GraphQL服务都定义了一组类型,用于描述您可能从该服务查询的数据。每当查询进入时,服务器都会根据模式进行验证并执行查询。类型语言(TypeLanguage)GraphQL服务可以用任何语言编写,它不依赖于任何特定语言的语法(如JavaScript)来与GraphQLschema通信,我们定义了我们自己的简单语言,称为“GraphQLschema语言”——它与GraphQL的查询语言非常相似,让我们可以在没有语言差异的情况下与GraphQLschema进行通信。对象类型和字段(ObjectTypesandFields)GraphQLschema中最基本的组成部分是对象类型,它表示你可以从服务中得到什么类型的对象,以及这个对象有哪些字段。使用GraphQL模式语言,我们可以这样表示它:typeCharacter{name:String!appearsIn:[Episode!]!}Character是一个GraphQL对象类型,说明它是一个带有一些字段的类型。架构中的大多数类型都是对象类型。name和appearsIn是Character类型的字段。这意味着在对Character类型进行操作的GraphQL查询的任何部分中,只能出现name和appearsIn字段。字符串是内置标量类型之一——标量类型是解析为单个标量对象且不能在查询中被子选择的类型。稍后我们将详细描述标量类型。细绳!表示这个字段是非空的,GraphQL服务保证当你查询这个字段的时候,它总是会返回一个值给你。在类型化语言中,我们用感叹号表示此功能。[插曲!]!代表一组剧集。因为它也是非空的,所以当您查询appearsIn字段时,您总是会得到一个数组(零个或多个元素)。从那一集开始!也是非空的,您总是可以期望数组中的每个项目都是一个Episode对象。参数(Arguments)GraphQL对象类型上的每个字段可能有零个或多个参数,例如下面的长度字段:typeStarship{id:ID!名称:字符串!length(unit:LengthUnit=METER):Float}在GraphQL中,所有参数都必须按名称传递。在这个例子中,长度字段定义了一个参数,单位。参数可以是强制性的或可选的。当一个参数是可选的,我们可以定义一个默认值——如果没有传递单位参数,那么默认设置为METER。查询和变异类型(TheQueryandMutationTypes)你的schema中的大部分类型都是普通的对象类型,但是schema中有两种特殊类型:schema{query:Querymutation:Mutation}标量类型(ScalarTypes)对象类型有自己的名称和字段,有时,这些字段必须解析为特定数据。这就是标量类型的用武之地:它们表示对应于GraphQL查询的叶节点。在以下查询中,name和appearsIn字段将解析为标量类型:{hero{nameappearsIn}}{"data":{"hero":{"name":"R2-D2","appearsIn":["NEWHOPE","EMPIRE","JEDI"]}}}GraphQL带有一组默认的标量类型:Int:一个带符号的32位整数。Float:带符号的双精度浮点值。字符串:UTF-8字符序列。布尔值:真或假。ID:ID标量类型表示唯一标识符,通常用于检索对象或作为缓存中的键。ID类型的序列化方式与String相同;然而,将其定义为ID意味着不需要人类可读的类型。在大多数GraphQL服务实现中,有一种方法可以定义自定义标量类型。例如,我们可以定义一个日期类型:标量日期枚举类型(EnumerationTypes)也称为枚举(enum)。枚举类型是一种特殊的标量,仅限于一组特殊的可选值。这使您可以:1.验证该类型的任何参数是否为可选值之一2.与类型系统沟通,字段始终是一组有限值中的一个。这是一个用GraphQL模式语言表达的枚举定义:enumEpisode{NEWHOPEEMPIREJEDI}这意味着无论我们在模式中使用Episode什么地方,我们都可以确保它返回NEWHOPE、EMPIRE和JEDI之一。列表和非空对象类型、标量和枚举是您可以在GraphQL中定义的唯一类型。但是当您在架构的其他部分或查询变量声明中使用这些类型时,您可以对它们应用其他类型修饰符以影响这些值的验证。我们先来看一个例子:typeCharacter{name:String!appearsIn:[Episode]!}这里我们使用了一个String类型,并通过添加感叹号将其标记为非空!在类型名称之后。这意味着我们的服务器将始终为该字段返回一个非空值,如果它以空值结束,它实际上会触发一个GraphQL执行错误,让客户端知道出了点问题。列表的工作方式类似:我们也可以使用类型修饰符将类型标记为列表,表示该字段将返回该类型的数组。在GraphQL模式语言中,我们通过将类型括在方括号([和])中来标记列表。列表对参数的工作方式相同,验证步骤将要求相应的值是一个数组。非空和列表修饰符可以组合使用。例如,您可以请求不可为null的字符串数组:myField:[String!]不可为null的字符串数组:myField:[String]!接口与许多类型系统一样,GraphQL支持接口。接口是包含某些字段的抽象类型,对象类型必须包含这些字段才能被视为实现接口。接口字符{id:ID!名称:字符串!friends:[Character]appearsIn:[Episode]!}比如也可以实现Character的类型:typeHumanimplementsCharacter{id:ID!名称:字符串!朋友:[人物]出现在:[情节]!starships:[Starship]totalCredits:Int}typeDroidimplementsCharacter{id:ID!名称:字符串!朋友:[人物]出现在:[情节]!primaryFunction:String}如果只想查询一个存在于特定对象类型上的字段,需要使用内联片段:queryHeroForEpisode($ep:Episode!){hero(episode:$ep){name...onDroid{primaryFunction}}}{"data":{"hero":{"name":"R2-D2","primaryFunction":"Astromech"}}}联合类型联合类型与接口非常相似,但它们不是指定类型之间的任何公共字段。unionSearchResult=人类|机器人|Starship在我们的架构中,任何返回SearchResult类型的地方,我们都可以获得Human、Droid或Starship。这时候,如果你需要查询一个返回SearchResult联合类型的字段,那么你就不得不使用条件片段来查询任何一个字段。{search(text:"an"){__typename...在Human{nameheight}...在Droid{nameprimaryFunction}...在Starship{namelength}}}{"data":{"search":[{"__typename":"人类","name":"HanSolo","height":1.8},{"__typename":"人类","name":"LeiaOrgana","height":1.5},{"__typename":"Starship","name":"TIEAdvancedx1","length":9.2}]}}这种情况下,由于Human和Droid共用一个接口(Character),可以查询他们的common一个地方的字段,而不必在多种类型中重复相同的字段:{search(text:"an"){__typename...onCharacter{name}...onHuman{height}...onDroid{primaryFunction}...onStarship{namelength}}}输入类型我们只讨论了将枚举和字符串等标量值作为参数传递给字段,但您也可以轻松传递复杂对象。这在突变中特别有用,因为有时您需要将整个对象作为新对象传递。在GraphQL模式语言中,输入对象看起来与常规对象完全一样,除了键是input而不是type:inputReviewInput{stars:Int!commentary:String}输入对象类型可以在这样的突变中使用://定义变量{"ep":"JEDI","review":{"stars":5,"commentary":"Thisisagreatmovie!“}}//发起变化突变CreateReviewForEpisode($ep:Episode!,$review:ReviewInput!){createReview(episode:$ep,review:$review){starscommentary}}//Response{"data":{"createReview":{"stars":5,"commentary":"这是一部很棒的电影!}}}参考https://graphql.cn/learn/schema/
